#include "config.h"
#include "Color.h"
#include "ColorSerialization.h"
#include "ColorUtilities.h"
#include <wtf/Assertions.h>
#include <wtf/text/TextStream.h>
namespace WebCore {
static constexpr auto lightenedBlack = SRGBA<uint8_t> { 84, 84, 84 };
static constexpr auto darkenedWhite = SRGBA<uint8_t> { 171, 171, 171 };
Color::Color(const Color& other)
: m_colorData(other.m_colorData)
{
if (isExtended())
m_colorData.extendedColor->ref();
}
Color::Color(Color&& other)
{
*this = WTFMove(other);
}
Color& Color::operator=(const Color& other)
{
if (*this == other)
return *this;
if (isExtended())
m_colorData.extendedColor->deref();
m_colorData = other.m_colorData;
if (isExtended())
m_colorData.extendedColor->ref();
return *this;
}
Color& Color::operator=(Color&& other)
{
if (*this == other)
return *this;
if (isExtended())
m_colorData.extendedColor->deref();
m_colorData = other.m_colorData;
other.m_colorData.inlineColorAndFlags = invalidInlineColor;
return *this;
}
Color Color::lightened() const
{
if (isInline() && asInline() == black)
return lightenedBlack;
auto [r, g, b, a] = toSRGBALossy<float>();
float v = std::max({ r, g, b });
if (v == 0.0f)
return lightenedBlack.colorWithAlphaByte(alphaByte());
float multiplier = std::min(1.0f, v + 0.33f) / v;
return convertToComponentBytes(SRGBA { multiplier * r, multiplier * g, multiplier * b, a });
}
Color Color::darkened() const
{
if (isInline() && asInline() == white)
return darkenedWhite;
auto [r, g, b, a] = toSRGBALossy<float>();
float v = std::max({ r, g, b });
float multiplier = std::max(0.0f, (v - 0.33f) / v);
return convertToComponentBytes(SRGBA { multiplier * r, multiplier * g, multiplier * b, a });
}
float Color::lightness() const
{
return WebCore::lightness(toSRGBALossy<float>());
}
float Color::luminance() const
{
return WebCore::luminance(toSRGBALossy<float>());
}
Color Color::colorWithAlpha(float alpha) const
{
return callOnUnderlyingType(WTF::makeVisitor(
[&] (const SRGBA<uint8_t>& underlyingColor) -> Color {
Color result = colorWithOverridenAlpha(underlyingColor, alpha);
if (isSemantic())
result.tagAsSemantic();
return result;
},
[&] (const auto& underlyingColor) -> Color {
return colorWithOverridenAlpha(underlyingColor, alpha);
}
));
}
Color Color::invertedColorWithAlpha(float alpha) const
{
return callOnUnderlyingType([&] (const auto& underlyingColor) -> Color {
return invertedColorWithOverridenAlpha(underlyingColor, alpha);
});
}
Color Color::semanticColor() const
{
if (isSemantic())
return *this;
return { toSRGBALossy<uint8_t>(), Semantic };
}
std::pair<ColorSpace, ColorComponents<float>> Color::colorSpaceAndComponents() const
{
if (isExtended())
return { asExtended().colorSpace(), asExtended().components() };
return { ColorSpace::SRGB, asColorComponents(convertToComponentFloats(asInline())) };
}
TextStream& operator<<(TextStream& ts, const Color& color)
{
return ts << serializationForRenderTreeAsText(color);
}
TextStream& operator<<(TextStream& ts, ColorSpace colorSpace)
{
switch (colorSpace) {
case ColorSpace::SRGB:
ts << "sRGB";
break;
case ColorSpace::LinearRGB:
ts << "LinearRGB";
break;
case ColorSpace::DisplayP3:
ts << "DisplayP3";
break;
}
return ts;
}
}