blob: 98d0a847875117fb310ff8cf4f4b777965c8eced [file] [log] [blame]
/*
* Copyright (C) 2011-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "Test.h"
#include "WTFStringUtilities.h"
#include <WebCore/Color.h>
#include <WebCore/ColorConversion.h>
#include <WebCore/ColorSerialization.h>
#include <WebCore/ColorTypes.h>
#include <wtf/MathExtras.h>
using namespace WebCore;
namespace TestWebKitAPI {
TEST(Color, RGBToHSL_White)
{
Color color = Color::white;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(0, hslaColor.hue);
EXPECT_FLOAT_EQ(0, hslaColor.saturation);
EXPECT_FLOAT_EQ(100, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_Black)
{
Color color = Color::black;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(0, hslaColor.hue);
EXPECT_FLOAT_EQ(0, hslaColor.saturation);
EXPECT_FLOAT_EQ(0, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_Red)
{
Color color = Color::red;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(0, hslaColor.hue);
EXPECT_FLOAT_EQ(100, hslaColor.saturation);
EXPECT_FLOAT_EQ(50, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_Green)
{
Color color = Color::green;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(120, hslaColor.hue);
EXPECT_FLOAT_EQ(100, hslaColor.saturation);
EXPECT_FLOAT_EQ(50, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_Blue)
{
Color color = Color::blue;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(240, hslaColor.hue);
EXPECT_FLOAT_EQ(100, hslaColor.saturation);
EXPECT_FLOAT_EQ(50, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_DarkGray)
{
Color color = Color::darkGray;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(0, hslaColor.hue);
EXPECT_FLOAT_EQ(0, hslaColor.saturation);
EXPECT_FLOAT_EQ(50.196083, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_Gray)
{
Color color = Color::gray;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(0, hslaColor.hue);
EXPECT_FLOAT_EQ(0, hslaColor.saturation);
EXPECT_FLOAT_EQ(62.745102, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, RGBToHSL_LightGray)
{
Color color = Color::lightGray;
auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
EXPECT_FLOAT_EQ(0, hslaColor.hue);
EXPECT_FLOAT_EQ(0, hslaColor.saturation);
EXPECT_FLOAT_EQ(75.294121, hslaColor.lightness);
EXPECT_FLOAT_EQ(color.lightness() * 100, hslaColor.lightness);
auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
EXPECT_EQ(color, roundTrippedColor);
}
TEST(Color, Validity)
{
Color invalidColor;
EXPECT_FALSE(invalidColor.isValid());
Color otherInvalidColor = invalidColor;
EXPECT_FALSE(otherInvalidColor.isValid());
Color validColor = Color::red;
EXPECT_TRUE(validColor.isValid());
Color otherValidColor = validColor;
EXPECT_TRUE(otherValidColor.isValid());
validColor = SRGBA<uint8_t> { 1, 2, 3, 4 };
EXPECT_TRUE(validColor.isValid());
auto validColorComponents = validColor.toSRGBALossy<uint8_t>();
EXPECT_EQ(validColorComponents.red, 1);
EXPECT_EQ(validColorComponents.green, 2);
EXPECT_EQ(validColorComponents.blue, 3);
EXPECT_EQ(validColorComponents.alpha, 4);
Color yetAnotherValidColor(WTFMove(validColor));
EXPECT_TRUE(yetAnotherValidColor.isValid());
auto yetAnotherValidColorComponents = yetAnotherValidColor.toSRGBALossy<uint8_t>();
EXPECT_EQ(yetAnotherValidColorComponents.red, 1);
EXPECT_EQ(yetAnotherValidColorComponents.green, 2);
EXPECT_EQ(yetAnotherValidColorComponents.blue, 3);
EXPECT_EQ(yetAnotherValidColorComponents.alpha, 4);
otherValidColor = WTFMove(yetAnotherValidColor);
EXPECT_TRUE(otherValidColor.isValid());
auto otherValidColorComponents = otherValidColor.toSRGBALossy<uint8_t>();
EXPECT_EQ(otherValidColorComponents.red, 1);
EXPECT_EQ(otherValidColorComponents.green, 2);
EXPECT_EQ(otherValidColorComponents.blue, 3);
EXPECT_EQ(otherValidColorComponents.alpha, 4);
}
TEST(Color, Luminance)
{
EXPECT_FLOAT_EQ(Color(Color::black).luminance(), 0);
EXPECT_FLOAT_EQ(Color(Color::white).luminance(), 1);
auto cComponents = SRGBA<uint8_t> { 85, 90, 160 };
EXPECT_FLOAT_EQ(Color(cComponents).luminance(), 0.11781455);
EXPECT_EQ(cComponents.red, 85);
EXPECT_EQ(cComponents.green, 90);
EXPECT_EQ(cComponents.blue, 160);
auto cLigtened = Color(cComponents).lightened().toSRGBALossy<uint8_t>();
EXPECT_FLOAT_EQ(Color(cLigtened).luminance(), 0.291682);
EXPECT_EQ(cLigtened.red, 130);
EXPECT_EQ(cLigtened.green, 137);
EXPECT_EQ(cLigtened.blue, 244);
auto cDarkened = Color(cComponents).darkened().toSRGBALossy<uint8_t>();
EXPECT_FLOAT_EQ(Color(cDarkened).luminance(), 0.027006242);
EXPECT_EQ(cDarkened.red, 40);
EXPECT_EQ(cDarkened.green, 43);
EXPECT_EQ(cDarkened.blue, 76);
}
TEST(Color, Constructor)
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
auto [colorSpace, components] = c1.colorSpaceAndComponents();
auto [r, g, b, alpha] = components;
EXPECT_FLOAT_EQ(1.0, r);
EXPECT_FLOAT_EQ(0.5, g);
EXPECT_FLOAT_EQ(0.25, b);
EXPECT_FLOAT_EQ(1.0, alpha);
EXPECT_EQ(serializationForCSS(c1), "color(display-p3 1 0.5 0.25)");
}
TEST(Color, CopyConstructor)
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2(c1);
auto [colorSpace, components] = c2.colorSpaceAndComponents();
auto [r, g, b, alpha] = components;
EXPECT_FLOAT_EQ(1.0, r);
EXPECT_FLOAT_EQ(0.5, g);
EXPECT_FLOAT_EQ(0.25, b);
EXPECT_FLOAT_EQ(1.0, alpha);
EXPECT_EQ(serializationForCSS(c2), "color(display-p3 1 0.5 0.25)");
}
TEST(Color, Assignment)
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2 = c1;
auto [colorSpace, components] = c2.colorSpaceAndComponents();
auto [r, g, b, alpha] = components;
EXPECT_FLOAT_EQ(1.0, r);
EXPECT_FLOAT_EQ(0.5, g);
EXPECT_FLOAT_EQ(0.25, b);
EXPECT_FLOAT_EQ(1.0, alpha);
EXPECT_EQ(serializationForCSS(c2), "color(display-p3 1 0.5 0.25)");
}
TEST(Color, Equality)
{
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
EXPECT_EQ(c1, c2);
}
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2 { SRGBA<float> { 1.0, 0.5, 0.25, 1.0 } };
EXPECT_NE(c1, c2);
}
auto componentBytes = SRGBA<uint8_t> { 255, 128, 63, 127 };
Color rgb1 { convertColor<SRGBA<float>>(componentBytes) };
Color rgb2 { componentBytes };
EXPECT_NE(rgb1, rgb2);
EXPECT_NE(rgb2, rgb1);
}
TEST(Color, Hash)
{
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
EXPECT_EQ(c1.hash(), c2.hash());
}
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2 { SRGBA<float> { 1.0, 0.5, 0.25, 1.0 } };
EXPECT_NE(c1.hash(), c2.hash());
}
auto componentBytes = SRGBA<uint8_t> { 255, 128, 63, 127 };
Color rgb1 { convertColor<SRGBA<float>>(componentBytes) };
Color rgb2 { componentBytes };
EXPECT_NE(rgb1.hash(), rgb2.hash());
}
TEST(Color, MoveConstructor)
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2(WTFMove(c1));
// We should have moved the out of line color pointer into c2,
// and set c1 to invalid so that it doesn't cause deletion.
EXPECT_FALSE(c1.isValid());
auto [colorSpace, components] = c2.colorSpaceAndComponents();
EXPECT_EQ(colorSpace, ColorSpace::DisplayP3);
auto [r, g, b, alpha] = components;
EXPECT_FLOAT_EQ(1.0, r);
EXPECT_FLOAT_EQ(0.5, g);
EXPECT_FLOAT_EQ(0.25, b);
EXPECT_FLOAT_EQ(1.0, alpha);
EXPECT_EQ(serializationForCSS(c2), "color(display-p3 1 0.5 0.25)");
}
TEST(Color, MoveAssignment)
{
Color c1 { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
Color c2 = WTFMove(c1);
// We should have moved the out of line color pointer into c2,
// and set c1 to invalid so that it doesn't cause deletion.
EXPECT_FALSE(c1.isValid());
auto [colorSpace, components] = c2.colorSpaceAndComponents();
EXPECT_EQ(colorSpace, ColorSpace::DisplayP3);
auto [r, g, b, alpha] = components;
EXPECT_FLOAT_EQ(1.0, r);
EXPECT_FLOAT_EQ(0.5, g);
EXPECT_FLOAT_EQ(0.25, b);
EXPECT_FLOAT_EQ(1.0, alpha);
EXPECT_EQ(serializationForCSS(c2), "color(display-p3 1 0.5 0.25)");
}
Color makeColor()
{
return Color { DisplayP3<float> { 1.0, 0.5, 0.25, 1.0 } };
}
TEST(Color, ReturnValues)
{
Color c2 = makeColor();
EXPECT_EQ(serializationForCSS(c2), "color(display-p3 1 0.5 0.25)");
}
TEST(Color, P3ConversionToSRGB)
{
Color p3Color { DisplayP3<float> { 1.0, 0.5, 0.25, 0.75 } };
auto sRGBAColor = p3Color.toSRGBALossy<float>();
EXPECT_FLOAT_EQ(sRGBAColor.red, 1.0f);
EXPECT_FLOAT_EQ(sRGBAColor.green, 0.46253282f);
EXPECT_FLOAT_EQ(sRGBAColor.blue, 0.14912748f);
EXPECT_FLOAT_EQ(sRGBAColor.alpha, 0.75f);
}
TEST(Color, LinearSRGBConversionToSRGB)
{
Color linearSRGBAColor { LinearSRGBA<float> { 1.0, 0.5, 0.25, 0.75 } };
auto sRGBAColor = linearSRGBAColor.toSRGBALossy<float>();
EXPECT_FLOAT_EQ(sRGBAColor.red, 1.0f);
EXPECT_FLOAT_EQ(sRGBAColor.green, 0.735356927f);
EXPECT_FLOAT_EQ(sRGBAColor.blue, 0.537098706f);
EXPECT_FLOAT_EQ(sRGBAColor.alpha, 0.75f);
}
TEST(Color, ColorWithAlphaMultipliedBy)
{
Color color { SRGBA<float> { 0., 0., 1., 0.6 } };
{
Color colorWithAlphaMultipliedBy = color.colorWithAlphaMultipliedBy(1.);
EXPECT_EQ(color, colorWithAlphaMultipliedBy);
}
{
Color colorWithAlphaMultipliedBy = color.colorWithAlphaMultipliedBy(0.5);
auto [colorSpace, components] = colorWithAlphaMultipliedBy.colorSpaceAndComponents();
EXPECT_EQ(colorSpace, ColorSpace::SRGB);
auto [r, g, b, a] = components;
EXPECT_FLOAT_EQ(r, 0.);
EXPECT_FLOAT_EQ(g, 0.);
EXPECT_FLOAT_EQ(b, 1.);
EXPECT_FLOAT_EQ(a, 0.3);
}
{
Color colorWithAlphaMultipliedBy = color.colorWithAlphaMultipliedBy(0.);
auto [colorSpace, components] = colorWithAlphaMultipliedBy.colorSpaceAndComponents();
EXPECT_EQ(colorSpace, ColorSpace::SRGB);
auto [r, g, b, a] = components;
EXPECT_FLOAT_EQ(r, 0.);
EXPECT_FLOAT_EQ(g, 0.);
EXPECT_FLOAT_EQ(b, 1.);
EXPECT_FLOAT_EQ(a, 0.);
}
}
} // namespace TestWebKitAPI