Title: [272436] trunk
Revision
272436
Author
wei...@apple.com
Date
2021-02-05 13:08:34 -0800 (Fri, 05 Feb 2021)

Log Message

Generalize color conversion code to reduce number of overloads required
https://bugs.webkit.org/show_bug.cgi?id=221443

Reviewed by Darin Adler.

Source/WebCore:

Replace overloaded named conversion functions (e.g. toSRGBA(), toLab(), etc.)
with template specializion of a new ColorConversion struct:

    template<> struct ColorConversion<Output, Input> {
        Output convert(const Input& color) { ... }
    };

which is accessed via a new generic convertColor<ColorType>() function.

This allows for a few improvements:
  - Removes the need for each color type to define an identity conversion.
  - Removes the need for each color type to define an generic conversion.
  - Allows integration with component type conversion so a call like

      convertTo<SRGBA<uint8_t>>(toSRGBA(hsla))

    can now be written just as

      convertColor<SRGBA<uint8_t>>(hsla)

This also provides a path forward for more optimizations / simplifications
since we can now reason about conversion based purely on types.

* css/parser/CSSPropertyParserHelpers.cpp:
(WebCore::CSSPropertyParserHelpers::parseRGBParameters):
(WebCore::CSSPropertyParserHelpers::parseHSLParameters):
(WebCore::CSSPropertyParserHelpers::parseHWBParameters):
(WebCore::CSSPropertyParserHelpers::parseLabParameters):
(WebCore::CSSPropertyParserHelpers::parseLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseColorFunctionParameters):
Switch to convertColor<> and replace some unnecessary type with auto.

* editing/cocoa/DataDetection.mm:
(WebCore::DataDetection::detectContentInRange):
Adopt Color::toColorTypeLossy<> and convertColor<>.

* platform/graphics/Color.cpp:
(WebCore::Color::invertedColorWithAlpha const):
Adopt convertColor<>.

* platform/graphics/Color.h:
(WebCore::Color::toSRGBALossy const):
(WebCore::Color::toColorTypeLossy const):
Add generic conversion function toColorTypeLossy<>() and re-implement
toSRGBALossy<>() using it.

* platform/graphics/ColorConversion.cpp:
* platform/graphics/ColorConversion.h:
Replace function overloads with explicit specialization of the new ColorConversion
struct. Replace identity functions and fallback functions with a single non-specialized
ColorConversion which uses constexpr to handle the identity case, conversion to/from
SRGBA<uint8_t> (the only non-float color) and the fallback case.

* platform/graphics/ColorUtilities.cpp:
(WebCore::luminance):
Adopt convertColor<>.

* platform/graphics/cg/ColorCG.cpp:
(WebCore::roundAndClampToSRGBALossy):
(WebCore::leakCGColor):
Adopt convertColor<>.

* platform/graphics/filters/FELighting.cpp:
(WebCore::FELighting::drawLighting):
Adopt toColorTypeLossy<>.

* rendering/RenderTheme.cpp:
(WebCore::RenderTheme::datePlaceholderTextColor const):
Adopt Color::toColorTypeLossy<> and convertColor<>.

Tools:

* TestWebKitAPI/Tests/WebCore/ColorTests.cpp:
(TestWebKitAPI::TEST):
Update tests to use convertColor<>.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (272435 => 272436)


--- trunk/Source/WebCore/ChangeLog	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/ChangeLog	2021-02-05 21:08:34 UTC (rev 272436)
@@ -1,3 +1,80 @@
+2021-02-05  Sam Weinig  <wei...@apple.com>
+
+        Generalize color conversion code to reduce number of overloads required
+        https://bugs.webkit.org/show_bug.cgi?id=221443
+
+        Reviewed by Darin Adler.
+
+        Replace overloaded named conversion functions (e.g. toSRGBA(), toLab(), etc.)
+        with template specializion of a new ColorConversion struct:
+        
+            template<> struct ColorConversion<Output, Input> {
+                Output convert(const Input& color) { ... }
+            };
+
+        which is accessed via a new generic convertColor<ColorType>() function.
+
+        This allows for a few improvements:
+          - Removes the need for each color type to define an identity conversion.
+          - Removes the need for each color type to define an generic conversion.
+          - Allows integration with component type conversion so a call like
+          
+              convertTo<SRGBA<uint8_t>>(toSRGBA(hsla))
+            
+            can now be written just as
+            
+              convertColor<SRGBA<uint8_t>>(hsla)
+        
+        This also provides a path forward for more optimizations / simplifications
+        since we can now reason about conversion based purely on types.
+
+        * css/parser/CSSPropertyParserHelpers.cpp:
+        (WebCore::CSSPropertyParserHelpers::parseRGBParameters):
+        (WebCore::CSSPropertyParserHelpers::parseHSLParameters):
+        (WebCore::CSSPropertyParserHelpers::parseHWBParameters):
+        (WebCore::CSSPropertyParserHelpers::parseLabParameters):
+        (WebCore::CSSPropertyParserHelpers::parseLCHParameters):
+        (WebCore::CSSPropertyParserHelpers::parseColorFunctionParameters):
+        Switch to convertColor<> and replace some unnecessary type with auto.
+
+        * editing/cocoa/DataDetection.mm:
+        (WebCore::DataDetection::detectContentInRange):
+        Adopt Color::toColorTypeLossy<> and convertColor<>.
+
+        * platform/graphics/Color.cpp:
+        (WebCore::Color::invertedColorWithAlpha const):
+        Adopt convertColor<>.
+
+        * platform/graphics/Color.h:
+        (WebCore::Color::toSRGBALossy const):
+        (WebCore::Color::toColorTypeLossy const):
+        Add generic conversion function toColorTypeLossy<>() and re-implement
+        toSRGBALossy<>() using it.
+
+        * platform/graphics/ColorConversion.cpp:
+        * platform/graphics/ColorConversion.h:
+        Replace function overloads with explicit specialization of the new ColorConversion
+        struct. Replace identity functions and fallback functions with a single non-specialized
+        ColorConversion which uses constexpr to handle the identity case, conversion to/from
+        SRGBA<uint8_t> (the only non-float color) and the fallback case.
+
+        * platform/graphics/ColorUtilities.cpp:
+        (WebCore::luminance):
+        Adopt convertColor<>.
+
+        * platform/graphics/cg/ColorCG.cpp:
+        (WebCore::roundAndClampToSRGBALossy):
+        (WebCore::leakCGColor):
+        Adopt convertColor<>.
+
+        * platform/graphics/filters/FELighting.cpp:
+        (WebCore::FELighting::drawLighting):
+        Adopt toColorTypeLossy<>.
+
+        * rendering/RenderTheme.cpp:
+        (WebCore::RenderTheme::datePlaceholderTextColor const):
+        Adopt Color::toColorTypeLossy<> and convertColor<>.
+
 2021-02-05  Antti Koivisto  <an...@apple.com>
 
         [LFC][Integration] Hit testing broken for descendants of pointer-events:none boxes

Modified: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (272435 => 272436)


--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -701,7 +701,7 @@
 static Color parseRGBParameters(CSSParserTokenRange& range)
 {
     ASSERT(range.peek().functionId() == CSSValueRgb || range.peek().functionId() == CSSValueRgba);
-    CSSParserTokenRange args = consumeFunction(range);
+    auto args = consumeFunction(range);
 
     bool isPercentage = false;
     double colorParameter;
@@ -772,7 +772,7 @@
 static Color parseHSLParameters(CSSParserTokenRange& range, CSSParserMode cssParserMode)
 {
     ASSERT(range.peek().functionId() == CSSValueHsl || range.peek().functionId() == CSSValueHsla);
-    CSSParserTokenRange args = consumeFunction(range);
+    auto args = consumeFunction(range);
 
     double hueAngleInDegrees;
     if (auto angle = consumeAngleRaw(args, cssParserMode, UnitlessQuirk::Forbid, UnitlessZeroQuirk::Forbid))
@@ -815,7 +815,7 @@
     if (!args.atEnd())
         return { };
 
-    return convertTo<SRGBA<uint8_t>>(toSRGBA(HSLA<float> { static_cast<float>(colorArray[0]), static_cast<float>(colorArray[1]), static_cast<float>(colorArray[2]), static_cast<float>(alpha) }));
+    return convertColor<SRGBA<uint8_t>>(HSLA<float> { static_cast<float>(colorArray[0]), static_cast<float>(colorArray[1]), static_cast<float>(colorArray[2]), static_cast<float>(alpha) });
 }
 
 static Optional<float> parseOptionalAlpha(CSSParserTokenRange& range)
@@ -832,7 +832,7 @@
 static Color parseHWBParameters(CSSParserTokenRange& range, CSSParserMode cssParserMode)
 {
     ASSERT(range.peek().functionId() == CSSValueHwb);
-    CSSParserTokenRange args = consumeFunction(range);
+    auto args = consumeFunction(range);
 
     double hueAngleInDegrees;
     if (auto angle = consumeAngleRaw(args, cssParserMode, UnitlessQuirk::Forbid, UnitlessZeroQuirk::Forbid))
@@ -885,13 +885,13 @@
     nomalizedWhiteness /= 100.0;
     nomalizedBlackness /= 100.0;
 
-    return convertTo<SRGBA<uint8_t>>(toSRGBA(HWBA<float> { static_cast<float>(normalizedHue), static_cast<float>(nomalizedWhiteness), static_cast<float>(nomalizedBlackness), static_cast<float>(*alpha) }));
+    return convertColor<SRGBA<uint8_t>>(HWBA<float> { static_cast<float>(normalizedHue), static_cast<float>(nomalizedWhiteness), static_cast<float>(nomalizedBlackness), static_cast<float>(*alpha) });
 }
 
 static Color parseLabParameters(CSSParserTokenRange& range)
 {
     ASSERT(range.peek().functionId() == CSSValueLab);
-    CSSParserTokenRange args = consumeFunction(range);
+    auto args = consumeFunction(range);
 
     auto lightness = consumePercentRaw(args, ValueRangeAll);
     if (!lightness)
@@ -918,7 +918,7 @@
 static Color parseLCHParameters(CSSParserTokenRange& range, CSSParserMode cssParserMode)
 {
     ASSERT(range.peek().functionId() == CSSValueLch);
-    CSSParserTokenRange args = consumeFunction(range);
+    auto args = consumeFunction(range);
 
     auto lightness = consumePercentRaw(args, ValueRangeAll);
     if (!lightness)
@@ -947,7 +947,7 @@
     if (!args.atEnd())
         return { };
 
-    return toLab(LCHA<float> { static_cast<float>(*lightness), static_cast<float>(*chromaValue), static_cast<float>(hueAngleInDegrees), *alpha });
+    return convertColor<Lab<float>>(LCHA<float> { static_cast<float>(*lightness), static_cast<float>(*chromaValue), static_cast<float>(hueAngleInDegrees), *alpha });
 }
 
 template<typename ColorType>
@@ -1034,7 +1034,7 @@
 static Color parseColorFunctionParameters(CSSParserTokenRange& range)
 {
     ASSERT(range.peek().functionId() == CSSValueColor);
-    CSSParserTokenRange args = consumeFunction(range);
+    auto args = consumeFunction(range);
 
     Color color;
     switch (args.peek().id()) {

Modified: trunk/Source/WebCore/editing/cocoa/DataDetection.mm (272435 => 272436)


--- trunk/Source/WebCore/editing/cocoa/DataDetection.mm	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/editing/cocoa/DataDetection.mm	2021-02-05 21:08:34 UTC (rev 272436)
@@ -595,13 +595,16 @@
                 if (renderStyle) {
                     auto textColor = renderStyle->visitedDependentColor(CSSPropertyColor);
                     if (textColor.isValid()) {
-                        auto hsla = toHSLA(textColor.toSRGBALossy<float>());
+                        // FIXME: Consider using LCHA<float> rather than HSLA<float> for better perceptual results and to avoid clamping to sRGB gamut, which is what HSLA does.
+                        auto hsla = textColor.toColorTypeLossy<HSLA<float>>();
 
                         // Force the lightness of the underline color to the middle, and multiply the alpha by 38%,
                         // so the color will appear on light and dark backgrounds, since only one color can be specified.
                         hsla.lightness = 0.5f;
                         hsla.alpha *= 0.38f;
-                        auto underlineColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hsla));
+                        
+                        // FIXME: Consider keeping color in LCHA (if that change is made) or converting back to the initial underlying color type to avoid unnecessarily clamping colors outside of sRGB.
+                        auto underlineColor = convertColor<SRGBA<uint8_t>>(hsla);
 
                         anchorElement->setInlineStyleProperty(CSSPropertyColor, CSSValueCurrentcolor);
                         anchorElement->setInlineStyleProperty(CSSPropertyTextDecorationColor, serializationForCSS(underlineColor));

Modified: trunk/Source/WebCore/platform/graphics/Color.cpp (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/Color.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/Color.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -149,7 +149,7 @@
         if constexpr (ColorType::Model::isInvertible)
             return invertedColorWithOverridenAlpha(underlyingColor, alpha);
         else
-            return invertedColorWithOverridenAlpha(toSRGBA(underlyingColor), alpha);
+            return invertedColorWithOverridenAlpha(convertColor<SRGBA<float>>(underlyingColor), alpha);
     });
 }
 

Modified: trunk/Source/WebCore/platform/graphics/Color.h (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/Color.h	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/Color.h	2021-02-05 21:08:34 UTC (rev 272436)
@@ -106,9 +106,15 @@
 
     template<typename Functor> decltype(auto) callOnUnderlyingType(Functor&&) const;
 
-    // This will convert non-sRGB colorspace colors into sRGB.
-    template<typename T> SRGBA<T> toSRGBALossy() const;
+    // This will convert the underlying color into ColorType, potentially lossily if the gamut
+    // or precision of ColorType is smaller than the current underlying type.
+    template<typename ColorType> ColorType toColorTypeLossy() const;
 
+    // This will convert the underlying color into sRGB, potentially lossily if the gamut
+    // or precision of sRGB is smaller than the current underlying type. This is a convenience
+    // wrapper around toColorTypeLossy<>().
+    template<typename T> SRGBA<T> toSRGBALossy() const { return toColorTypeLossy<SRGBA<T>>(); }
+
     WEBCORE_EXPORT std::pair<ColorSpace, ColorComponents<float>> colorSpaceAndComponents() const;
 
     WEBCORE_EXPORT Color lightened() const;
@@ -321,22 +327,11 @@
     return std::invoke(std::forward<Functor>(functor), asInline());
 }
 
-template<typename T> SRGBA<T> Color::toSRGBALossy() const
+template<typename ColorType> ColorType Color::toColorTypeLossy() const
 {
-    return callOnUnderlyingType(WTF::makeVisitor(
-        [] (const SRGBA<uint8_t>& color) {
-            if constexpr (std::is_same_v<T, uint8_t>)
-                return color;
-            if constexpr (std::is_same_v<T, float>)
-                return convertTo<SRGBA<float>>(color);
-        },
-        [] (const auto& color) {
-            if constexpr (std::is_same_v<T, uint8_t>)
-                return convertTo<SRGBA<uint8_t>>(toSRGBA(color));
-            if constexpr (std::is_same_v<T, float>)
-                return toSRGBA(color);
-        }
-    ));
+    return callOnUnderlyingType([] (const auto& underlyingColor) {
+        return convertColor<ColorType>(underlyingColor);
+    });
 }
 
 inline Color Color::invertedColorWithAlpha(Optional<float> alpha) const

Modified: trunk/Source/WebCore/platform/graphics/ColorConversion.cpp (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/ColorConversion.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/ColorConversion.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -159,12 +159,12 @@
 
 // A98RGB <-> LinearA98RGB conversions.
 
-LinearA98RGB<float> toLinearA98RGB(const A98RGB<float>& color)
+LinearA98RGB<float> ColorConversion<LinearA98RGB<float>, A98RGB<float>>::convert(const A98RGB<float>& color)
 {
     return toLinear<A98RGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
 
-A98RGB<float> toA98RGB(const LinearA98RGB<float>& color)
+A98RGB<float> ColorConversion<A98RGB<float>, LinearA98RGB<float>>::convert(const LinearA98RGB<float>& color)
 {
     return toGammaEncoded<A98RGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
@@ -171,12 +171,12 @@
 
 // DisplayP3 <-> LinearDisplayP3 conversions.
 
-LinearDisplayP3<float> toLinearDisplayP3(const DisplayP3<float>& color)
+LinearDisplayP3<float> ColorConversion<LinearDisplayP3<float>, DisplayP3<float>>::convert(const DisplayP3<float>& color)
 {
     return toLinear<SRGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
 
-DisplayP3<float> toDisplayP3(const LinearDisplayP3<float>& color)
+DisplayP3<float> ColorConversion<DisplayP3<float>, LinearDisplayP3<float>>::convert(const LinearDisplayP3<float>& color)
 {
     return toGammaEncoded<SRGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
@@ -183,12 +183,12 @@
 
 // ExtendedSRGBA <-> LinearExtendedSRGBA conversions.
 
-LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const ExtendedSRGBA<float>& color)
+LinearExtendedSRGBA<float> ColorConversion<LinearExtendedSRGBA<float>, ExtendedSRGBA<float>>::convert(const ExtendedSRGBA<float>& color)
 {
     return toLinear<SRGBTransferFunction<float, TransferFunctionMode::Unclamped>>(color);
 }
 
-ExtendedSRGBA<float> toExtendedSRGBA(const LinearExtendedSRGBA<float>& color)
+ExtendedSRGBA<float> ColorConversion<ExtendedSRGBA<float>, LinearExtendedSRGBA<float>>::convert(const LinearExtendedSRGBA<float>& color)
 {
     return toGammaEncoded<SRGBTransferFunction<float, TransferFunctionMode::Unclamped>>(color);
 }
@@ -195,12 +195,12 @@
 
 // ProPhotoRGB <-> LinearProPhotoRGB conversions.
 
-LinearProPhotoRGB<float> toLinearProPhotoRGB(const ProPhotoRGB<float>& color)
+LinearProPhotoRGB<float> ColorConversion<LinearProPhotoRGB<float>, ProPhotoRGB<float>>::convert(const ProPhotoRGB<float>& color)
 {
     return toLinear<ProPhotoRGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
 
-ProPhotoRGB<float> toProPhotoRGB(const LinearProPhotoRGB<float>& color)
+ProPhotoRGB<float> ColorConversion<ProPhotoRGB<float>, LinearProPhotoRGB<float>>::convert(const LinearProPhotoRGB<float>& color)
 {
     return toGammaEncoded<ProPhotoRGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
@@ -207,12 +207,12 @@
 
 // Rec2020 <-> LinearRec2020 conversions.
 
-LinearRec2020<float> toLinearRec2020(const Rec2020<float>& color)
+LinearRec2020<float> ColorConversion<LinearRec2020<float>, Rec2020<float>>::convert(const Rec2020<float>& color)
 {
     return toLinear<Rec2020TransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
 
-Rec2020<float> toRec2020(const LinearRec2020<float>& color)
+Rec2020<float> ColorConversion<Rec2020<float>, LinearRec2020<float>>::convert(const LinearRec2020<float>& color)
 {
     return toGammaEncoded<Rec2020TransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
@@ -219,12 +219,12 @@
 
 // SRGBA <-> LinearSRGBA conversions.
 
-LinearSRGBA<float> toLinearSRGBA(const SRGBA<float>& color)
+LinearSRGBA<float> ColorConversion<LinearSRGBA<float>, SRGBA<float>>::convert(const SRGBA<float>& color)
 {
     return toLinear<SRGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
 
-SRGBA<float> toSRGBA(const LinearSRGBA<float>& color)
+SRGBA<float> ColorConversion<SRGBA<float>, LinearSRGBA<float>>::convert(const LinearSRGBA<float>& color)
 {
     return toGammaEncoded<SRGBTransferFunction<float, TransferFunctionMode::Clamped>>(color);
 }
@@ -233,12 +233,12 @@
 
 // - LinearA98RGB matrix conversions.
 
-LinearA98RGB<float> toLinearA98RGB(const LinearA98RGB<float>::ReferenceXYZ& color)
+LinearA98RGB<float> ColorConversion<LinearA98RGB<float>, LinearA98RGB<float>::ReferenceXYZ>::convert(const LinearA98RGB<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearA98RGB<float>>(xyzToLinearA98RGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-LinearA98RGB<float>::ReferenceXYZ toXYZA(const LinearA98RGB<float>& color)
+LinearA98RGB<float>::ReferenceXYZ ColorConversion<LinearA98RGB<float>::ReferenceXYZ, LinearA98RGB<float>>::convert(const LinearA98RGB<float>& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearA98RGB<float>::ReferenceXYZ>(linearA98RGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
@@ -245,12 +245,12 @@
 
 // - LinearDisplayP3 matrix conversions.
 
-LinearDisplayP3<float> toLinearDisplayP3(const LinearDisplayP3<float>::ReferenceXYZ& color)
+LinearDisplayP3<float> ColorConversion<LinearDisplayP3<float>, LinearDisplayP3<float>::ReferenceXYZ>::convert(const LinearDisplayP3<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearDisplayP3<float>>(xyzToLinearDisplayP3Matrix.transformedColorComponents(asColorComponents(color)));
 }
 
-LinearDisplayP3<float>::ReferenceXYZ toXYZA(const LinearDisplayP3<float>& color)
+LinearDisplayP3<float>::ReferenceXYZ ColorConversion<LinearDisplayP3<float>::ReferenceXYZ, LinearDisplayP3<float>>::convert(const LinearDisplayP3<float>& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearDisplayP3<float>::ReferenceXYZ>(linearDisplayP3ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
@@ -257,12 +257,12 @@
 
 // - LinearExtendedSRGBA matrix conversions.
 
-LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const LinearExtendedSRGBA<float>::ReferenceXYZ& color)
+LinearExtendedSRGBA<float> ColorConversion<LinearExtendedSRGBA<float>, LinearExtendedSRGBA<float>::ReferenceXYZ>::convert(const LinearExtendedSRGBA<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearExtendedSRGBA<float>>(xyzToLinearSRGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-LinearExtendedSRGBA<float>::ReferenceXYZ toXYZA(const LinearExtendedSRGBA<float>& color)
+LinearExtendedSRGBA<float>::ReferenceXYZ ColorConversion<LinearExtendedSRGBA<float>::ReferenceXYZ, LinearExtendedSRGBA<float>>::convert(const LinearExtendedSRGBA<float>& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearExtendedSRGBA<float>::ReferenceXYZ>(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
@@ -269,12 +269,12 @@
 
 // - LinearProPhotoRGB matrix conversions.
 
-LinearProPhotoRGB<float> toLinearProPhotoRGB(const LinearProPhotoRGB<float>::ReferenceXYZ& color)
+LinearProPhotoRGB<float> ColorConversion<LinearProPhotoRGB<float>, LinearProPhotoRGB<float>::ReferenceXYZ>::convert(const LinearProPhotoRGB<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearProPhotoRGB<float>>(xyzToLinearProPhotoRGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-LinearProPhotoRGB<float>::ReferenceXYZ toXYZA(const LinearProPhotoRGB<float>& color)
+LinearProPhotoRGB<float>::ReferenceXYZ ColorConversion<LinearProPhotoRGB<float>::ReferenceXYZ, LinearProPhotoRGB<float>>::convert(const LinearProPhotoRGB<float>& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearProPhotoRGB<float>::ReferenceXYZ>(linearProPhotoRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
@@ -281,12 +281,12 @@
 
 // - LinearRec2020 matrix conversions.
 
-LinearRec2020<float> toLinearRec2020(const LinearRec2020<float>::ReferenceXYZ& color)
+LinearRec2020<float> ColorConversion<LinearRec2020<float>, LinearRec2020<float>::ReferenceXYZ>::convert(const LinearRec2020<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearRec2020<float>>(xyzToLinearRec2020Matrix.transformedColorComponents(asColorComponents(color)));
 }
 
-LinearRec2020<float>::ReferenceXYZ toXYZA(const LinearRec2020<float>& color)
+LinearRec2020<float>::ReferenceXYZ ColorConversion<LinearRec2020<float>::ReferenceXYZ, LinearRec2020<float>>::convert(const LinearRec2020<float>& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearRec2020<float>::ReferenceXYZ>(linearRec2020ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
@@ -293,12 +293,12 @@
 
 // - LinearSRGBA matrix conversions.
 
-LinearSRGBA<float> toLinearSRGBA(const LinearSRGBA<float>::ReferenceXYZ& color)
+LinearSRGBA<float> ColorConversion<LinearSRGBA<float>, LinearSRGBA<float>::ReferenceXYZ>::convert(const LinearSRGBA<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearSRGBA<float>>(xyzToLinearSRGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-LinearSRGBA<float>::ReferenceXYZ toXYZA(const LinearSRGBA<float>& color)
+LinearSRGBA<float>::ReferenceXYZ ColorConversion<LinearSRGBA<float>::ReferenceXYZ, LinearSRGBA<float>>::convert(const LinearSRGBA<float>& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearSRGBA<float>::ReferenceXYZ>(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
@@ -336,7 +336,7 @@
     return { hue, min, max, chroma };
 }
 
-HSLA<float> toHSLA(const SRGBA<float>& color)
+HSLA<float> ColorConversion<HSLA<float>, SRGBA<float>>::convert(const SRGBA<float>& color)
 {
     // https://drafts.csswg.org/css-color-4/#hsl-to-rgb
     auto [r, g, b, alpha] = color;
@@ -354,7 +354,7 @@
     return { hue, saturation, lightness, alpha };
 }
 
-SRGBA<float> toSRGBA(const HSLA<float>& color)
+SRGBA<float> ColorConversion<SRGBA<float>, HSLA<float>>::convert(const HSLA<float>& color)
 {
     // https://drafts.csswg.org/css-color-4/#hsl-to-rgb
     auto [hue, saturation, lightness, alpha] = color;
@@ -397,7 +397,7 @@
 
 // MARK: HWB conversions.
 
-HWBA<float> toHWBA(const SRGBA<float>& color)
+HWBA<float> ColorConversion<HWBA<float>, SRGBA<float>>::convert(const SRGBA<float>& color)
 {
     // https://drafts.csswg.org/css-color-4/#rgb-to-hwb
     auto [hue, min, max, chroma] = calculateHSLHue(color);
@@ -407,7 +407,7 @@
     return { hue, whiteness, blackness, color.alpha };
 }
 
-SRGBA<float> toSRGBA(const HWBA<float>& color)
+SRGBA<float> ColorConversion<SRGBA<float>, HWBA<float>>::convert(const HWBA<float>& color)
 {
     // https://drafts.csswg.org/css-color-4/#hwb-to-rgb
     auto [hue, whiteness, blackness, alpha] = color;
@@ -415,7 +415,7 @@
     if (whiteness + blackness == 1.0f)
         return { whiteness, whiteness, whiteness, alpha };
 
-    // This is the hueToRGB function in toSRGBA(const HSLA&) with temp1 == 0
+    // This is the hueToRGB function in convertColor<SRGBA<float>>(const HSLA&) with temp1 == 0
     // and temp2 == 1 strength reduced through it.
     auto hueToRGB = [](float hue) {
         if (hue < 1.0f)
@@ -456,7 +456,7 @@
 static constexpr float LABk = 24389.0f / 27.0f;
 static constexpr float D50WhiteValues[] = { 0.96422f, 1.0f, 0.82521f };
 
-Lab<float>::ReferenceXYZ toXYZA(const Lab<float>& color)
+Lab<float>::ReferenceXYZ ColorConversion<Lab<float>::ReferenceXYZ, Lab<float>>::convert(const Lab<float>& color)
 {
     float f1 = (color.lightness + 16.0f) / 116.0f;
     float f0 = f1 + (color.a / 500.0f);
@@ -486,7 +486,7 @@
     return { x, y, z, color.alpha };
 }
 
-Lab<float> toLab(const Lab<float>::ReferenceXYZ& color)
+Lab<float> ColorConversion<Lab<float>, Lab<float>::ReferenceXYZ>::convert(const Lab<float>::ReferenceXYZ& color)
 {
     float x = color.x / D50WhiteValues[0];
     float y = color.y / D50WhiteValues[1];
@@ -510,7 +510,7 @@
 
 // MARK: LCH conversions.
 
-LCHA<float> toLCHA(const Lab<float>& color)
+LCHA<float> ColorConversion<LCHA<float>, Lab<float>>::convert(const Lab<float>& color)
 {
     // https://www.w3.org/TR/css-color-4/#lab-to-lch
     float hue = rad2deg(atan2(color.b, color.a));
@@ -523,7 +523,7 @@
     };
 }
 
-Lab<float> toLab(const LCHA<float>& color)
+Lab<float> ColorConversion<Lab<float>, LCHA<float>>::convert(const LCHA<float>& color)
 {
     // https://www.w3.org/TR/css-color-4/#lch-to-lab
     float hueAngleRadians = deg2rad(color.hue);
@@ -540,110 +540,110 @@
 
 // - A98RGB combination functions.
 
-A98RGB<float>::ReferenceXYZ toXYZA(const A98RGB<float>& color)
+A98RGB<float>::ReferenceXYZ ColorConversion<A98RGB<float>::ReferenceXYZ, A98RGB<float>>::convert(const A98RGB<float>& color)
 {
-    return toXYZA(toLinearA98RGB(color));
+    return convertColor<A98RGB<float>::ReferenceXYZ>(convertColor<LinearA98RGB<float>>(color));
 }
 
-A98RGB<float> toA98RGB(const A98RGB<float>::ReferenceXYZ& color)
+A98RGB<float> ColorConversion<A98RGB<float>, A98RGB<float>::ReferenceXYZ>::convert(const A98RGB<float>::ReferenceXYZ& color)
 {
-    return toA98RGB(toLinearA98RGB(color));
+    return convertColor<A98RGB<float>>(convertColor<LinearA98RGB<float>>(color));
 }
 
 // - DisplayP3 combination functions.
 
-DisplayP3<float>::ReferenceXYZ toXYZA(const DisplayP3<float>& color)
+DisplayP3<float>::ReferenceXYZ ColorConversion<DisplayP3<float>::ReferenceXYZ, DisplayP3<float>>::convert(const DisplayP3<float>& color)
 {
-    return toXYZA(toLinearDisplayP3(color));
+    return convertColor<DisplayP3<float>::ReferenceXYZ>(convertColor<LinearDisplayP3<float>>(color));
 }
 
-DisplayP3<float> toDisplayP3(const DisplayP3<float>::ReferenceXYZ& color)
+DisplayP3<float> ColorConversion<DisplayP3<float>, DisplayP3<float>::ReferenceXYZ>::convert(const DisplayP3<float>::ReferenceXYZ& color)
 {
-    return toDisplayP3(toLinearDisplayP3(color));
+    return convertColor<DisplayP3<float>>(convertColor<LinearDisplayP3<float>>(color));
 }
 
 // - ExtendedSRGB combination functions.
 
-ExtendedSRGBA<float>::ReferenceXYZ toXYZA(const ExtendedSRGBA<float>& color)
+ExtendedSRGBA<float>::ReferenceXYZ ColorConversion<ExtendedSRGBA<float>::ReferenceXYZ, ExtendedSRGBA<float>>::convert(const ExtendedSRGBA<float>& color)
 {
-    return toXYZA(toLinearExtendedSRGBA(color));
+    return convertColor<ExtendedSRGBA<float>::ReferenceXYZ>(convertColor<LinearExtendedSRGBA<float>>(color));
 }
 
-ExtendedSRGBA<float> toExtendedSRGBA(const ExtendedSRGBA<float>::ReferenceXYZ& color)
+ExtendedSRGBA<float> ColorConversion<ExtendedSRGBA<float>, ExtendedSRGBA<float>::ReferenceXYZ>::convert(const ExtendedSRGBA<float>::ReferenceXYZ& color)
 {
-    return toExtendedSRGBA(toLinearExtendedSRGBA(color));
+    return convertColor<ExtendedSRGBA<float>>(convertColor<LinearExtendedSRGBA<float>>(color));
 }
 
 // - HSLA combination functions.
 
-HSLA<float>::ReferenceXYZ toXYZA(const HSLA<float>& color)
+HSLA<float>::ReferenceXYZ ColorConversion<HSLA<float>::ReferenceXYZ, HSLA<float>>::convert(const HSLA<float>& color)
 {
-    return toXYZA(toSRGBA(color));
+    return convertColor<HSLA<float>::ReferenceXYZ>(convertColor<SRGBA<float>>(color));
 }
 
-HSLA<float> toHSLA(const HSLA<float>::ReferenceXYZ& color)
+HSLA<float> ColorConversion<HSLA<float>, HSLA<float>::ReferenceXYZ>::convert(const HSLA<float>::ReferenceXYZ& color)
 {
-    return toHSLA(toSRGBA(color));
+    return convertColor<HSLA<float>>(convertColor<SRGBA<float>>(color));
 }
 
 // - HWBA combination functions.
 
-HWBA<float>::ReferenceXYZ toXYZA(const HWBA<float>& color)
+HWBA<float>::ReferenceXYZ ColorConversion<HWBA<float>::ReferenceXYZ, HWBA<float>>::convert(const HWBA<float>& color)
 {
-    return toXYZA(toSRGBA(color));
+    return convertColor<HWBA<float>::ReferenceXYZ>(convertColor<SRGBA<float>>(color));
 }
 
-HWBA<float> toHWBA(const HWBA<float>::ReferenceXYZ& color)
+HWBA<float> ColorConversion<HWBA<float>, HWBA<float>::ReferenceXYZ>::convert(const HWBA<float>::ReferenceXYZ& color)
 {
-    return toHWBA(toSRGBA(color));
+    return convertColor<HWBA<float>>(convertColor<SRGBA<float>>(color));
 }
 
 // - LCHA combination functions.
 
-LCHA<float>::ReferenceXYZ toXYZA(const LCHA<float>& color)
+LCHA<float>::ReferenceXYZ ColorConversion<LCHA<float>::ReferenceXYZ, LCHA<float>>::convert(const LCHA<float>& color)
 {
-    return toXYZA(toLab(color));
+    return convertColor<LCHA<float>::ReferenceXYZ>(convertColor<Lab<float>>(color));
 }
 
-LCHA<float> toLCHA(const LCHA<float>::ReferenceXYZ& color)
+LCHA<float> ColorConversion<LCHA<float>, LCHA<float>::ReferenceXYZ>::convert(const LCHA<float>::ReferenceXYZ& color)
 {
-    return toLCHA(toLab(color));
+    return convertColor<LCHA<float>>(convertColor<Lab<float>>(color));
 }
 
 // - ProPhotoRGB combination functions.
 
-ProPhotoRGB<float>::ReferenceXYZ toXYZA(const ProPhotoRGB<float>& color)
+ProPhotoRGB<float>::ReferenceXYZ ColorConversion<ProPhotoRGB<float>::ReferenceXYZ, ProPhotoRGB<float>>::convert(const ProPhotoRGB<float>& color)
 {
-    return toXYZA(toLinearProPhotoRGB(color));
+    return convertColor<ProPhotoRGB<float>::ReferenceXYZ>(convertColor<LinearProPhotoRGB<float>>(color));
 }
 
-ProPhotoRGB<float> toProPhotoRGB(const ProPhotoRGB<float>::ReferenceXYZ& color)
+ProPhotoRGB<float> ColorConversion<ProPhotoRGB<float>, ProPhotoRGB<float>::ReferenceXYZ>::convert(const ProPhotoRGB<float>::ReferenceXYZ& color)
 {
-    return toProPhotoRGB(toLinearProPhotoRGB(color));
+    return convertColor<ProPhotoRGB<float>>(convertColor<LinearProPhotoRGB<float>>(color));
 }
 
 // - Rec2020 combination functions.
 
-Rec2020<float>::ReferenceXYZ toXYZA(const Rec2020<float>& color)
+Rec2020<float>::ReferenceXYZ ColorConversion<Rec2020<float>::ReferenceXYZ, Rec2020<float>>::convert(const Rec2020<float>& color)
 {
-    return toXYZA(toLinearRec2020(color));
+    return convertColor<Rec2020<float>::ReferenceXYZ>(convertColor<LinearRec2020<float>>(color));
 }
 
-Rec2020<float> toRec2020(const Rec2020<float>::ReferenceXYZ& color)
+Rec2020<float> ColorConversion<Rec2020<float>, Rec2020<float>::ReferenceXYZ>::convert(const Rec2020<float>::ReferenceXYZ& color)
 {
-    return toRec2020(toLinearRec2020(color));
+    return convertColor<Rec2020<float>>(convertColor<LinearRec2020<float>>(color));
 }
 
 // - SRGB combination functions.
 
-SRGBA<float>::ReferenceXYZ toXYZA(const SRGBA<float>& color)
+SRGBA<float>::ReferenceXYZ ColorConversion<SRGBA<float>::ReferenceXYZ, SRGBA<float>>::convert(const SRGBA<float>& color)
 {
-    return toXYZA(toLinearSRGBA(color));
+    return convertColor<SRGBA<float>::ReferenceXYZ>(convertColor<LinearSRGBA<float>>(color));
 }
 
-SRGBA<float> toSRGBA(const SRGBA<float>::ReferenceXYZ& color)
+SRGBA<float> ColorConversion<SRGBA<float>, SRGBA<float>::ReferenceXYZ>::convert(const SRGBA<float>::ReferenceXYZ& color)
 {
-    return toSRGBA(toLinearSRGBA(color));
+    return convertColor<SRGBA<float>>(convertColor<LinearSRGBA<float>>(color));
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/ColorConversion.h (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/ColorConversion.h	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/ColorConversion.h	2021-02-05 21:08:34 UTC (rev 272436)
@@ -26,126 +26,281 @@
 #pragma once
 
 #include "ColorTypes.h"
+#include "ColorUtilities.h"
 
 namespace WebCore {
 
 // All color types must at least implement the following conversions to and from their reference XYZ color space
 //
-//    `ColorType`<float>::ReferenceXYZ toXYZA(const `ColorType`<float>&);
-//    `ColorType`<float> to`ColorType`(const `ColorType`<float>::ReferenceXYZ&);
+//    template<> struct ColorConversion<`ColorType`<float>::ReferenceXYZ, `ColorType`<float>> {
+//        WEBCORE_EXPORT static `ColorType`<float>::ReferenceXYZ convert(const `ColorType`<float>&);
+//    };
+//    
+//    template<> struct ColorConversion<`ColorType`<float>, `ColorType`<float>::ReferenceXYZ> {
+//        WEBCORE_EXPORT static `ColorType`<float> convert(const `ColorType`<float>::ReferenceXYZ&);
+//    };
 //
-// as well as an identity conversion
-//
-//    constexpr `ColorType`<float> to`ColorType`(const `ColorType`<float>& color) { return color; }
-//
-// and a generic conversion utilizing a conversion to the reference XYZ color space and a chromatic
-// adapatation if the white points differ
-//
-//    template<typename T> `ColorType`<float> to`ColorType`(const T& color)
-//
 // Any additional conversions can be thought of as optimizations, shortcutting unnecessary steps, though
 // some may be integral to the base conversion.
 
 
+template<typename Output, typename Input> struct ColorConversion;
+
+template<typename Output, typename Input> inline Output convertColor(const Input& color)
+{
+    return ColorConversion<Output, Input>::convert(color);
+}
+
+
 // A98RGB
-WEBCORE_EXPORT A98RGB<float>::ReferenceXYZ toXYZA(const A98RGB<float>&);
-WEBCORE_EXPORT A98RGB<float> toA98RGB(const A98RGB<float>::ReferenceXYZ&);
+template<> struct ColorConversion<A98RGB<float>::ReferenceXYZ, A98RGB<float>> {
+    WEBCORE_EXPORT static A98RGB<float>::ReferenceXYZ convert(const A98RGB<float>&);
+};
+
+template<> struct ColorConversion<A98RGB<float>, A98RGB<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static A98RGB<float> convert(const A98RGB<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LinearA98RGB<float> toLinearA98RGB(const A98RGB<float>&);
+template<> struct ColorConversion<LinearA98RGB<float>, A98RGB<float>> {
+    WEBCORE_EXPORT static LinearA98RGB<float> convert(const A98RGB<float>&);
+};
 
+
 // DisplayP3
-WEBCORE_EXPORT DisplayP3<float>::ReferenceXYZ toXYZA(const DisplayP3<float>&);
-WEBCORE_EXPORT DisplayP3<float> toDisplayP3(const DisplayP3<float>::ReferenceXYZ&);
+template<> struct ColorConversion<DisplayP3<float>::ReferenceXYZ, DisplayP3<float>> {
+    WEBCORE_EXPORT static DisplayP3<float>::ReferenceXYZ convert(const DisplayP3<float>&);
+};
+
+template<> struct ColorConversion<DisplayP3<float>, DisplayP3<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static DisplayP3<float> convert(const DisplayP3<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LinearDisplayP3<float> toLinearDisplayP3(const DisplayP3<float>&);
+template<> struct ColorConversion<LinearDisplayP3<float>, DisplayP3<float>> {
+    WEBCORE_EXPORT static LinearDisplayP3<float> convert(const DisplayP3<float>&);
+};
 
+
 // ExtendedSRGBA
-WEBCORE_EXPORT ExtendedSRGBA<float>::ReferenceXYZ toXYZA(const ExtendedSRGBA<float>&);
-WEBCORE_EXPORT ExtendedSRGBA<float> toExtendedSRGBA(const ExtendedSRGBA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<ExtendedSRGBA<float>::ReferenceXYZ, ExtendedSRGBA<float>> {
+    WEBCORE_EXPORT static ExtendedSRGBA<float>::ReferenceXYZ convert(const ExtendedSRGBA<float>&);
+};
+
+template<> struct ColorConversion<ExtendedSRGBA<float>, ExtendedSRGBA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static ExtendedSRGBA<float> convert(const ExtendedSRGBA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const ExtendedSRGBA<float>&);
+template<> struct ColorConversion<LinearExtendedSRGBA<float>, ExtendedSRGBA<float>> {
+    WEBCORE_EXPORT static LinearExtendedSRGBA<float> convert(const ExtendedSRGBA<float>&);
+};
 
+
 // HSLA
-WEBCORE_EXPORT HSLA<float>::ReferenceXYZ toXYZA(const HSLA<float>&);
-WEBCORE_EXPORT HSLA<float> toHSLA(const HSLA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<HSLA<float>::ReferenceXYZ, HSLA<float>> {
+    WEBCORE_EXPORT static HSLA<float>::ReferenceXYZ convert(const HSLA<float>&);
+};
+
+template<> struct ColorConversion<HSLA<float>, HSLA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static HSLA<float> convert(const HSLA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT SRGBA<float> toSRGBA(const HSLA<float>&);
+template<> struct ColorConversion<SRGBA<float>, HSLA<float>> {
+    WEBCORE_EXPORT static SRGBA<float> convert(const HSLA<float>&);
+};
 
+
 // HWBA
-WEBCORE_EXPORT HWBA<float>::ReferenceXYZ toXYZA(const HWBA<float>&);
-WEBCORE_EXPORT HWBA<float> toHWBA(const HWBA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<HWBA<float>::ReferenceXYZ, HWBA<float>> {
+    WEBCORE_EXPORT static HWBA<float>::ReferenceXYZ convert(const HWBA<float>&);
+};
+
+template<> struct ColorConversion<HWBA<float>, HWBA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static HWBA<float> convert(const HWBA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT SRGBA<float> toSRGBA(const HWBA<float>&);
+template<> struct ColorConversion<SRGBA<float>, HWBA<float>> {
+    WEBCORE_EXPORT static SRGBA<float> convert(const HWBA<float>&);
+};
 
+
 // LCHA
-WEBCORE_EXPORT LCHA<float>::ReferenceXYZ toXYZA(const LCHA<float>&);
-WEBCORE_EXPORT LCHA<float> toLCHA(const LCHA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LCHA<float>::ReferenceXYZ, LCHA<float>> {
+    WEBCORE_EXPORT static LCHA<float>::ReferenceXYZ convert(const LCHA<float>&);
+};
+
+template<> struct ColorConversion<LCHA<float>, LCHA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LCHA<float> convert(const LCHA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT Lab<float> toLab(const LCHA<float>&);
+template<> struct ColorConversion<Lab<float>, LCHA<float>> {
+    WEBCORE_EXPORT static Lab<float> convert(const LCHA<float>&);
+};
 
+
 // Lab
-WEBCORE_EXPORT Lab<float>::ReferenceXYZ toXYZA(const Lab<float>&);
-WEBCORE_EXPORT Lab<float> toLab(const Lab<float>::ReferenceXYZ&);
+template<> struct ColorConversion<Lab<float>::ReferenceXYZ, Lab<float>> {
+    WEBCORE_EXPORT static Lab<float>::ReferenceXYZ convert(const Lab<float>&);
+};
+
+template<> struct ColorConversion<Lab<float>, Lab<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static Lab<float> convert(const Lab<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LCHA<float> toLCHA(const Lab<float>&);
+template<> struct ColorConversion<LCHA<float>, Lab<float>> {
+    WEBCORE_EXPORT static LCHA<float> convert(const Lab<float>&);
+};
 
+
 // LinearA98RGB
-WEBCORE_EXPORT LinearA98RGB<float>::ReferenceXYZ toXYZA(const LinearA98RGB<float>&);
-WEBCORE_EXPORT LinearA98RGB<float> toLinearA98RGB(const LinearA98RGB<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LinearA98RGB<float>::ReferenceXYZ, LinearA98RGB<float>> {
+    WEBCORE_EXPORT static LinearA98RGB<float>::ReferenceXYZ convert(const LinearA98RGB<float>&);
+};
+
+template<> struct ColorConversion<LinearA98RGB<float>, LinearA98RGB<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LinearA98RGB<float> convert(const LinearA98RGB<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT A98RGB<float> toA98RGB(const LinearA98RGB<float>& color);
+template<> struct ColorConversion<A98RGB<float>, LinearA98RGB<float>> {
+    WEBCORE_EXPORT static A98RGB<float> convert(const LinearA98RGB<float>&);
+};
 
+
 // LinearDisplayP3
-WEBCORE_EXPORT LinearDisplayP3<float>::ReferenceXYZ toXYZA(const LinearDisplayP3<float>&);
-WEBCORE_EXPORT LinearDisplayP3<float> toLinearDisplayP3(const LinearDisplayP3<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LinearDisplayP3<float>::ReferenceXYZ, LinearDisplayP3<float>> {
+    WEBCORE_EXPORT static LinearDisplayP3<float>::ReferenceXYZ convert(const LinearDisplayP3<float>&);
+};
+
+template<> struct ColorConversion<LinearDisplayP3<float>, LinearDisplayP3<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LinearDisplayP3<float> convert(const LinearDisplayP3<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT DisplayP3<float> toDisplayP3(const LinearDisplayP3<float>&);
+template<> struct ColorConversion<DisplayP3<float>, LinearDisplayP3<float>> {
+    WEBCORE_EXPORT static DisplayP3<float> convert(const LinearDisplayP3<float>&);
+};
 
+
 // LinearExtendedSRGBA
-WEBCORE_EXPORT LinearExtendedSRGBA<float>::ReferenceXYZ toXYZA(const LinearExtendedSRGBA<float>&);
-WEBCORE_EXPORT LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const LinearExtendedSRGBA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LinearExtendedSRGBA<float>::ReferenceXYZ, LinearExtendedSRGBA<float>> {
+    WEBCORE_EXPORT static LinearExtendedSRGBA<float>::ReferenceXYZ convert(const LinearExtendedSRGBA<float>&);
+};
+
+template<> struct ColorConversion<LinearExtendedSRGBA<float>, LinearExtendedSRGBA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LinearExtendedSRGBA<float> convert(const LinearExtendedSRGBA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT ExtendedSRGBA<float> toExtendedSRGBA(const LinearExtendedSRGBA<float>&);
+template<> struct ColorConversion<ExtendedSRGBA<float>, LinearExtendedSRGBA<float>> {
+    WEBCORE_EXPORT static ExtendedSRGBA<float> convert(const LinearExtendedSRGBA<float>&);
+};
 
+
 // LinearProPhotoRGB
-WEBCORE_EXPORT LinearProPhotoRGB<float>::ReferenceXYZ toXYZA(const LinearProPhotoRGB<float>&);
-WEBCORE_EXPORT LinearProPhotoRGB<float> toLinearProPhotoRGB(const LinearProPhotoRGB<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LinearProPhotoRGB<float>::ReferenceXYZ, LinearProPhotoRGB<float>> {
+    WEBCORE_EXPORT static LinearProPhotoRGB<float>::ReferenceXYZ convert(const LinearProPhotoRGB<float>&);
+};
+
+template<> struct ColorConversion<LinearProPhotoRGB<float>, LinearProPhotoRGB<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LinearProPhotoRGB<float> convert(const LinearProPhotoRGB<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT ProPhotoRGB<float> toProPhotoRGB(const LinearProPhotoRGB<float>&);
+template<> struct ColorConversion<ProPhotoRGB<float>, LinearProPhotoRGB<float>> {
+    WEBCORE_EXPORT static ProPhotoRGB<float> convert(const LinearProPhotoRGB<float>&);
+};
 
+
 // LinearRec2020
-WEBCORE_EXPORT LinearRec2020<float>::ReferenceXYZ toXYZA(const LinearRec2020<float>&);
-WEBCORE_EXPORT LinearRec2020<float> toLinearRec2020(const LinearRec2020<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LinearRec2020<float>::ReferenceXYZ, LinearRec2020<float>> {
+    WEBCORE_EXPORT static LinearRec2020<float>::ReferenceXYZ convert(const LinearRec2020<float>&);
+};
+
+template<> struct ColorConversion<LinearRec2020<float>, LinearRec2020<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LinearRec2020<float> convert(const LinearRec2020<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT Rec2020<float> toRec2020(const LinearRec2020<float>&);
+template<> struct ColorConversion<Rec2020<float>, LinearRec2020<float>> {
+    WEBCORE_EXPORT static Rec2020<float> convert(const LinearRec2020<float>&);
+};
 
+
 // LinearSRGBA
-WEBCORE_EXPORT LinearSRGBA<float>::ReferenceXYZ toXYZA(const LinearSRGBA<float>&);
-WEBCORE_EXPORT LinearSRGBA<float> toLinearSRGBA(const LinearSRGBA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<LinearSRGBA<float>::ReferenceXYZ, LinearSRGBA<float>> {
+    WEBCORE_EXPORT static LinearSRGBA<float>::ReferenceXYZ convert(const LinearSRGBA<float>&);
+};
+
+template<> struct ColorConversion<LinearSRGBA<float>, LinearSRGBA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static LinearSRGBA<float> convert(const LinearSRGBA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT SRGBA<float> toSRGBA(const LinearSRGBA<float>&);
+template<> struct ColorConversion<SRGBA<float>, LinearSRGBA<float>> {
+    WEBCORE_EXPORT static SRGBA<float> convert(const LinearSRGBA<float>&);
+};
 
+
 // ProPhotoRGB
-WEBCORE_EXPORT ProPhotoRGB<float>::ReferenceXYZ toXYZA(const ProPhotoRGB<float>&);
-WEBCORE_EXPORT ProPhotoRGB<float> toProPhotoRGB(const ProPhotoRGB<float>::ReferenceXYZ&);
+template<> struct ColorConversion<ProPhotoRGB<float>::ReferenceXYZ, ProPhotoRGB<float>> {
+    WEBCORE_EXPORT static ProPhotoRGB<float>::ReferenceXYZ convert(const ProPhotoRGB<float>&);
+};
+
+template<> struct ColorConversion<ProPhotoRGB<float>, ProPhotoRGB<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static ProPhotoRGB<float> convert(const ProPhotoRGB<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LinearProPhotoRGB<float> toLinearProPhotoRGB(const ProPhotoRGB<float>&);
+template<> struct ColorConversion<LinearProPhotoRGB<float>, ProPhotoRGB<float>> {
+    WEBCORE_EXPORT static LinearProPhotoRGB<float> convert(const ProPhotoRGB<float>&);
+};
 
+
 // Rec2020
-WEBCORE_EXPORT Rec2020<float>::ReferenceXYZ toXYZA(const Rec2020<float>&);
-WEBCORE_EXPORT Rec2020<float> toRec2020(const Rec2020<float>::ReferenceXYZ&);
+template<> struct ColorConversion<Rec2020<float>::ReferenceXYZ, Rec2020<float>> {
+    WEBCORE_EXPORT static Rec2020<float>::ReferenceXYZ convert(const Rec2020<float>&);
+};
+
+template<> struct ColorConversion<Rec2020<float>, Rec2020<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static Rec2020<float> convert(const Rec2020<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LinearRec2020<float> toLinearRec2020(const Rec2020<float>&);
+template<> struct ColorConversion<LinearRec2020<float>, Rec2020<float>> {
+    WEBCORE_EXPORT static LinearRec2020<float> convert(const Rec2020<float>&);
+};
 
+
 // SRGBA
-WEBCORE_EXPORT SRGBA<float>::ReferenceXYZ toXYZA(const SRGBA<float>&);
-WEBCORE_EXPORT SRGBA<float> toSRGBA(const SRGBA<float>::ReferenceXYZ&);
+template<> struct ColorConversion<SRGBA<float>::ReferenceXYZ, SRGBA<float>> {
+    WEBCORE_EXPORT static SRGBA<float>::ReferenceXYZ convert(const SRGBA<float>&);
+};
+
+template<> struct ColorConversion<SRGBA<float>, SRGBA<float>::ReferenceXYZ> {
+    WEBCORE_EXPORT static SRGBA<float> convert(const SRGBA<float>::ReferenceXYZ&);
+};
+
 // Additions
-WEBCORE_EXPORT LinearSRGBA<float> toLinearSRGBA(const SRGBA<float>&);
-WEBCORE_EXPORT HSLA<float> toHSLA(const SRGBA<float>&);
-WEBCORE_EXPORT HWBA<float> toHWBA(const SRGBA<float>&);
+template<> struct ColorConversion<LinearSRGBA<float>, SRGBA<float>> {
+    WEBCORE_EXPORT static LinearSRGBA<float> convert(const SRGBA<float>&);
+};
 
+template<> struct ColorConversion<HSLA<float>, SRGBA<float>> {
+    WEBCORE_EXPORT static HSLA<float> convert(const SRGBA<float>&);
+};
 
+template<> struct ColorConversion<HWBA<float>, SRGBA<float>> {
+    WEBCORE_EXPORT static HWBA<float> convert(const SRGBA<float>&);
+};
+
+
+
 // Chromatic Adaptation conversions.
 WEBCORE_EXPORT XYZA<float, WhitePoint::D65> convertFromD50WhitePointToD65WhitePoint(const XYZA<float, WhitePoint::D50>&);
 WEBCORE_EXPORT XYZA<float, WhitePoint::D50> convertFromD65WhitePointToD50WhitePoint(const XYZA<float, WhitePoint::D65>&);
@@ -162,111 +317,58 @@
         return convertFromD50WhitePointToD65WhitePoint(color);
 }
 
-
-// Identity conversions (useful for generic contexts).
-
-constexpr A98RGB<float> toA98RGB(const A98RGB<float>& color) { return color; }
-constexpr DisplayP3<float> toDisplayP3(const DisplayP3<float>& color) { return color; }
-constexpr ExtendedSRGBA<float> toExtendedSRGBA(const ExtendedSRGBA<float>& color) { return color; }
-constexpr HSLA<float> toHSLA(const HSLA<float>& color) { return color; }
-constexpr HWBA<float> toHWBA(const HWBA<float>& color) { return color; }
-constexpr LCHA<float> toLCHA(const LCHA<float>& color) { return color; }
-constexpr Lab<float> toLab(const Lab<float>& color) { return color; }
-constexpr LinearA98RGB<float> toLinearA98RGB(const LinearA98RGB<float>& color) { return color; }
-constexpr LinearDisplayP3<float> toLinearDisplayP3(const LinearDisplayP3<float>& color) { return color; }
-constexpr LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const LinearExtendedSRGBA<float>& color) { return color; }
-constexpr LinearProPhotoRGB<float> toLinearRec2020(const LinearProPhotoRGB<float>& color) { return color; }
-constexpr LinearRec2020<float> toLinearRec2020(const LinearRec2020<float>& color) { return color; }
-constexpr LinearSRGBA<float> toLinearSRGBA(const LinearSRGBA<float>& color) { return color; }
-constexpr ProPhotoRGB<float> toProPhotoRGB(const ProPhotoRGB<float>& color) { return color; }
-constexpr Rec2020<float> toRec2020(const Rec2020<float>& color) { return color; }
-constexpr SRGBA<float> toSRGBA(const SRGBA<float>& color) { return color; }
-template<WhitePoint W> constexpr XYZA<float, W> toXYZA(const XYZA<float, W>& color) { return color; }
-
-
 // Fallback conversions.
 
-// All types are required to have a conversion to their reference XYZ space, so these are guaranteed
-// to work if another overload is not already provided.
+// All types are required to have a conversion to their reference XYZ space, so this is guaranteed
+// to work if another specialization is not already provided.
 
-template<typename T> A98RGB<float> toA98RGB(const T& color)
-{
-    return toA98RGB(performChomaticAdapatation<A98RGB<float>>(toXYZA(color)));
-}
+// FIXME: Rather than always converting through reference XYZ color space
+// we should instead switch to computing the least common reference ancestor
+// type where each color type defines its reference type as the color it needs
+// to get one step closer to the reference XYZ color space. For instance,
+// the reference type of SRGBA is LinearSRGBA, and the reference type of LCHA
+// is Lab. Together, the color types make a tree with XYZ at the root. The
+// conversion should end up looking something like:
+//
+//   using LCA = LeastCommonAncestor<Output, Input>::Type;
+//   return convertColor<Output>(convertColor<LCA>(color));
+//
+// An example of where this would be more efficient is when converting from
+// HSLA<float> to HWBA<float>. LCA for this pair is SRGBA<float> so conversion
+// through XYZ is wasteful. This model would also allow us to remove the
+// combination conversions, reducing the number of things each new color type
+// requires.
+//
+// FIXME: Reduce total number of matrix tranforms by concatenating the matrices
+// of sequential matrix transforms at compile time. Take the conversion from
+// ProPhotoRGB<float> to SRGBA<float> as an example:
+//
+//   1. ProPhotoRGB<float> -> LinearProPhotoRGB<float>                  (transfer function transform, not matrix)
+//   2. LinearProPhotoRGB<float> -> XYZA<float, WhitePoint::D50>        MATRIX TRANSFORM
+//   3. XYZA<float, WhitePoint::D50> -> XYZA<float, WhitePoint::D65>    MATRIX TRANSFORM
+//   4. XYZA<float, WhitePoint::D65> -> LinearSRGBA<float>              MATRIX TRANSFORM
+//   5. LinearSRGBA<float> -> SRGBA<float>                              (transfer function transform, not matrix)
+//
+// Steps 2, 3, and 4 can be combined into one single matrix if we linearly
+// concatented the three matrices. To do this, we will have to tag which conversions
+// are matrix based, expose the matrices, add support for constexpr concatenting
+// of ColorMatrix and find a way to merge the conversions.
 
-template<typename T> DisplayP3<float> toDisplayP3(const T& color)
-{
-    return toDisplayP3(performChomaticAdapatation<DisplayP3<float>>(toXYZA(color)));
-}
+template<typename Output, typename Input> struct ColorConversion {
+    static Output convert(const Input& color)
+    {
+        if constexpr(std::is_same_v<Output, Input>)
+            return color;
+        else if constexpr (std::is_same_v<typename Input::ComponentType, uint8_t>)
+            return convertColor<Output>(convertTo<SRGBA<float>>(color));
+        else if constexpr (std::is_same_v<typename Output::ComponentType, uint8_t>)
+            return convertTo<SRGBA<uint8_t>>(convertColor<SRGBA<float>>(color));
+        else {
+            auto xyz1 = convertColor<typename Input::ReferenceXYZ>(color);
+            auto xyz2 = performChomaticAdapatation<Output>(xyz1);
+            return convertColor<Output>(xyz2);
+        }
+    }
+};
 
-template<typename T> ExtendedSRGBA<float> toExtendedSRGBA(const T& color)
-{
-    return toExtendedSRGBA(performChomaticAdapatation<ExtendedSRGBA<float>>(toXYZA(color)));
-}
-
-template<typename T> HSLA<float> toHSLA(const T& color)
-{
-    return toHSLA(performChomaticAdapatation<HSLA<float>>(toXYZA(color)));
-}
-
-template<typename T> HWBA<float> toHWBA(const T& color)
-{
-    return toHWBA(performChomaticAdapatation<HWBA<float>>(toXYZA(color)));
-}
-
-template<typename T> LCHA<float> toLCHA(const T& color)
-{
-    return toLCHA(performChomaticAdapatation<LCHA<float>>(toXYZA(color)));
-}
-
-template<typename T> Lab<float> toLab(const T& color)
-{
-    return toLab(performChomaticAdapatation<Lab<float>>(toXYZA(color)));
-}
-
-template<typename T> LinearA98RGB<float> toLinearA98RGB(const T& color)
-{
-    return toLinearA98RGB(performChomaticAdapatation<LinearA98RGB<float>>(toXYZA(color)));
-}
-
-template<typename T> LinearDisplayP3<float> toLinearDisplayP3(const T& color)
-{
-    return toLinearDisplayP3(performChomaticAdapatation<LinearDisplayP3<float>>(toXYZA(color)));
-}
-
-template<typename T> LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const T& color)
-{
-    return toLinearExtendedSRGBA(performChomaticAdapatation<LinearExtendedSRGBA<float>>(toXYZA(color)));
-}
-
-template<typename T> LinearProPhotoRGB<float> toLinearProPhotoRGB(const T& color)
-{
-    return toLinearProPhotoRGB(performChomaticAdapatation<LinearProPhotoRGB<float>>(toXYZA(color)));
-}
-
-template<typename T> LinearRec2020<float> toLinearRec2020(const T& color)
-{
-    return toLinearRec2020(performChomaticAdapatation<LinearRec2020<float>>(toXYZA(color)));
-}
-
-template<typename T> LinearSRGBA<float> toLinearSRGBA(const T& color)
-{
-    return toLinearSRGBA(performChomaticAdapatation<LinearSRGBA<float>>(toXYZA(color)));
-}
-
-template<typename T> ProPhotoRGB<float> toProPhotoRGB(const T& color)
-{
-    return toProPhotoRGB(performChomaticAdapatation<ProPhotoRGB<float>>(toXYZA(color)));
-}
-
-template<typename T> Rec2020<float> toRec2020(const T& color)
-{
-    return toRec2020(performChomaticAdapatation<Rec2020<float>>(toXYZA(color)));
-}
-
-template<typename T> SRGBA<float> toSRGBA(const T& color)
-{
-    return toSRGBA(performChomaticAdapatation<SRGBA<float>>(toXYZA(color)));
-}
-
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/ColorUtilities.cpp (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/ColorUtilities.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/ColorUtilities.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -39,10 +39,10 @@
 
 float luminance(const SRGBA<float>& color)
 {
-    // NOTE: This is the equivalent of toXYZA(toLinearSRGBA(color)).y
+    // NOTE: This is the equivalent of convertColor<XYZA<float, WhitePoint::D65>>(color).y
     // FIMXE: If we can generalize ColorMatrix a bit more, it might be nice to write this as:
-    //      return toLinearSRGBA(color) * linearSRGBToXYZMatrix.row(1);
-    auto [r, g, b, a] = toLinearSRGBA(color);
+    //      return convertColor<LinearSRGBA<float>>(color) * linearSRGBToXYZMatrix.row(1);
+    auto [r, g, b, a] = convertColor<LinearSRGBA<float>>(color);
     return 0.2126f * r + 0.7152f * g + 0.0722f * b;
 }
 

Modified: trunk/Source/WebCore/platform/graphics/cg/ColorCG.cpp (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/cg/ColorCG.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/cg/ColorCG.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -81,7 +81,7 @@
         ASSERT_NOT_REACHED();
     }
 
-    return convertTo<SRGBA<uint8_t>>(SRGBA { r, g, b, a });
+    return convertColor<SRGBA<uint8_t>>(SRGBA { r, g, b, a });
 }
 
 Color::Color(CGColorRef color)
@@ -108,7 +108,7 @@
     // more explicit.
     if (colorSpace != ColorSpace::SRGB && cgColorSpace == sRGBColorSpaceRef()) {
         auto colorConvertedToExtendedSRGBA = callWithColorType(components, colorSpace, [] (const auto& color) {
-            return toExtendedSRGBA(color);
+            return convertColor<ExtendedSRGBA<float>>(color);
         });
         components = asColorComponents(colorConvertedToExtendedSRGBA);
         cgColorSpace = extendedSRGBColorSpaceRef();

Modified: trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp (272435 => 272436)


--- trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/platform/graphics/filters/FELighting.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -405,7 +405,7 @@
     data.heightDecreasedByOne = height - 1;
     
     if (operatingColorSpace() == ColorSpace::LinearRGB) {
-        auto [r, g, b, a] = toLinearSRGBA(m_lightingColor.toSRGBALossy<float>());
+        auto [r, g, b, a] = m_lightingColor.toColorTypeLossy<LinearSRGBA<float>>();
         paintingData.initialLightingData.colorVector = FloatPoint3D(r, g, b);
     } else {
         auto [r, g, b, a] = m_lightingColor.toSRGBALossy<float>();

Modified: trunk/Source/WebCore/rendering/RenderTheme.cpp (272435 => 272436)


--- trunk/Source/WebCore/rendering/RenderTheme.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Source/WebCore/rendering/RenderTheme.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -1419,13 +1419,15 @@
 
 Color RenderTheme::datePlaceholderTextColor(const Color& textColor, const Color& backgroundColor) const
 {
-    auto hsla = toHSLA(textColor.toSRGBALossy<float>());
+    // FIXME: Consider using LCHA<float> rather than HSLA<float> for better perceptual results and to avoid clamping to sRGB gamut, which is what HSLA does.
+    auto hsla = textColor.toColorTypeLossy<HSLA<float>>();
     if (textColor.luminance() < backgroundColor.luminance())
         hsla.lightness += datePlaceholderColorLightnessAdjustmentFactor * (1.0f - hsla.lightness);
     else
         hsla.lightness *= datePlaceholderColorLightnessAdjustmentFactor;
 
-    return toSRGBA(hsla);
+    // FIXME: Consider keeping color in LCHA (if that change is made) or converting back to the initial underlying color type to avoid unnecessarily clamping colors outside of sRGB.
+    return convertColor<SRGBA<float>>(hsla);
 }
 
 void RenderTheme::setCustomFocusRingColor(const Color& color)

Modified: trunk/Tools/ChangeLog (272435 => 272436)


--- trunk/Tools/ChangeLog	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Tools/ChangeLog	2021-02-05 21:08:34 UTC (rev 272436)
@@ -1,3 +1,14 @@
+2021-02-05  Sam Weinig  <wei...@apple.com>
+
+        Generalize color conversion code to reduce number of overloads required
+        https://bugs.webkit.org/show_bug.cgi?id=221443
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WebCore/ColorTests.cpp:
+        (TestWebKitAPI::TEST):
+        Update tests to use convertColor<>.
+
 2021-02-05  Aakash Jain  <aakash_j...@apple.com>
 
         [ews] commit-queue should use commits.webkit.org url instead of trac url

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ColorTests.cpp (272435 => 272436)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ColorTests.cpp	2021-02-05 20:48:22 UTC (rev 272435)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ColorTests.cpp	2021-02-05 21:08:34 UTC (rev 272436)
@@ -38,7 +38,7 @@
 {
     Color color = Color::white;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0, hslaColor.hue);
     EXPECT_FLOAT_EQ(0, hslaColor.saturation);
@@ -46,7 +46,7 @@
     
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
     
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -54,7 +54,7 @@
 {
     Color color = Color::black;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0, hslaColor.hue);
     EXPECT_FLOAT_EQ(0, hslaColor.saturation);
@@ -62,7 +62,7 @@
 
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -70,7 +70,7 @@
 {
     Color color = Color::red;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0, hslaColor.hue);
     EXPECT_FLOAT_EQ(1, hslaColor.saturation);
@@ -78,7 +78,7 @@
 
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -86,7 +86,7 @@
 {
     Color color = Color::green;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0.33333334, hslaColor.hue);
     EXPECT_FLOAT_EQ(1, hslaColor.saturation);
@@ -94,7 +94,7 @@
 
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -102,7 +102,7 @@
 {
     Color color = Color::blue;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0.66666669, hslaColor.hue);
     EXPECT_FLOAT_EQ(1, hslaColor.saturation);
@@ -110,7 +110,7 @@
 
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -118,7 +118,7 @@
 {
     Color color = Color::darkGray;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0, hslaColor.hue);
     EXPECT_FLOAT_EQ(0, hslaColor.saturation);
@@ -126,7 +126,7 @@
     
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -134,7 +134,7 @@
 {
     Color color = Color::gray;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0, hslaColor.hue);
     EXPECT_FLOAT_EQ(0, hslaColor.saturation);
@@ -142,7 +142,7 @@
 
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
@@ -150,7 +150,7 @@
 {
     Color color = Color::lightGray;
 
-    auto hslaColor = toHSLA(color.toSRGBALossy<float>());
+    auto hslaColor = color.toColorTypeLossy<HSLA<float>>();
 
     EXPECT_FLOAT_EQ(0, hslaColor.hue);
     EXPECT_FLOAT_EQ(0, hslaColor.saturation);
@@ -158,7 +158,7 @@
 
     EXPECT_FLOAT_EQ(color.lightness(), hslaColor.lightness);
 
-    auto roundTrippedColor = convertTo<SRGBA<uint8_t>>(toSRGBA(hslaColor));
+    auto roundTrippedColor = convertColor<SRGBA<uint8_t>>(hslaColor);
     EXPECT_EQ(color, roundTrippedColor);
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to