Title: [272837] trunk/Source/WebCore
Revision
272837
Author
wei...@apple.com
Date
2021-02-13 16:05:59 -0800 (Sat, 13 Feb 2021)

Log Message

Reduce requirements for color types to only conversion to their reference color
https://bugs.webkit.org/show_bug.cgi?id=221868

Reviewed by Darin Adler.

We currently require every new color type to define a conversion to/from xyz and then perhaps
some more conversions to reference colors to avoid unnecessary trips through XYZ. For example,
if every conversion from HSL to sRGB went through XYZ it would be very silly and inefficient,
and the fact that we require the boiler plate for HSL -> XYZ, even though it's always going to
convert to SRGB first seems unfortunate. We can do better.

At first I thought we could model color conversion as DAG, with XYZ at the root, and each color
type declaring a "reference color" that would get them closer to XYZ. So, HSL would have a
"reference color" of sRGB, sRGB would have a "reference color" of linearSRGB, and linearSRGB
would have a "reference color" XYZ. Then, as long as there was a defined conversion to/from the
"reference color", we could do a least common ancestor graph search between the two color types
being converted between to find the optimal set of conversions needed.

That almost works, but the relationships between the four color types that make up each RGB type
(bounded-gamma-encoded, bounded-linear-encoded, extended-gamma-encoded, extended-linear-encoded)
make it not quite ideal, since a conversion from something like sRGB to ExtendedSRGB would wind
up going through XYZ (since the "reference color" for sRGB is LinearSRGB and the "reference color"
for ExtendedSRGB is LinearExtendedSRGB, and both either "reference colors" are XYZ).

Ultimately, the depth of the type graph is not all that large (though the ASCII art I made is
quite big, though I did remove A98RGB and Rec2020 as they are same as DisplayP3 here):

                ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
                 Matrix Conversions    ┌───────────┐│┌───────────┐
                │                      │ XYZ (D50) │││ XYZ (D65) │                                                      │
                                       └─────▲─────┘│└─────▲─────┘
                │                            │      │      │                                                            │
       ┌─────────────────────────┬───────────┘      │      └───────────┬───────────────────────────────┐
       │        │                │                  │                  │                               │                │
       │                         │                  │                  │                               │
       │        │                │                  │                  │                               │                │
       │          ProPhotoRGB───────────────────┐   │   SRGB──────────────────────────┐ DisplayP3─────────────────────┐
       │        │ │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │
       │          ││ Linear │ │ LinearExtended ││   │   ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││
       │        │ │└────────┘ └────────────────┘│   │   │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │
       │         ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─│─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─
 ┌───────────┐    │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│
 │    Lab    │    ││ Gamma  │ │ GammaExtended  ││   │   ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││
 └─────▲─────┘    │└────────┘ └────────────────┘│   │   │└────▲───┘ └────────────────┘│ │└────────┘ └────────────────┘│
       │          └─────────────────────────────┘   │   └─────┼───────────────────────┘ └─────────────────────────────┘
       │                                            │      ┌──┴──────────┬─────────────┐
       │                                            │      │             │             │
 ┌───────────┐                                      │┌───────────┐ ┌───────────┐┌─────────────┐
 │    LCH    │                                      ││    HSL    │ │    HWB    ││SRGB<uint8_t>│
 └───────────┘                                      │└───────────┘ └───────────┘└─────────────┘

>From this, it turns out you can handle all the cases in about 5 steps, with most peeling off a
conversion from the front or back or the path and using recursion to continue on. It ultimately
leaves a final step where only matrix conversions remain, which can potentially be further
optimized in another patch to concatenate the matrices at compile time.

1. Handle the special case SRGBA<uint8_t> for Input and Output, and recursively call conversion.

2. Handle all color types that are not IsRGBType<T> or IsXYZA<T> for Input and Output. For all
   these other color types, we can uncondtionally convert them to their "reference" color, as
   either they have already been handled by a ColorConversion specialization or this will
   get us closer to the final conversion, and recursively call conversion.

3. Handle conversions within a RGBFamily (e.g. all have the same descriptor). This will conclude
   the conversion.

4. Handle any gamma conversions for the Input and Output, recursively call conversion

5. At this point, Input and Output are each either Linear-RGB types (of different familes) or XYZA
   and therefore all additional conversion can happen via matrix transformation. This will conclude
   the conversion.

With these steps, we group the color types into 3 distinct groups.

1. RGB types.

    These inherit from the RGBType struct and are defined in terms of their xyzToLinear / linearToXYZ
    matrices, their transfer function, whether they are bounded or extended and their white point. New
    RGB color types can be added without any new conversion code being required, as long as they specify
    those properties.

2. The XYZ type.

    This is the root type, and only varies on its white point. If other white points beside D50 and D65
    are ever needed, we will need to extend the ChromaticAdapation specializations to also have conversion
    matrices between those.

3. All other types.

    All other types (e.g. Lab, LCHA, HSLA, HWBA (and SRGBA<uint8_t>, kind of, it's a special flower) are
    the set currently) have their conversions defined in terms of single reference color and require
    explicit specialization of the ColorConversion struct to work.

* platform/graphics/ColorConversion.cpp:
(WebCore::Lab<float>>::convert):
(WebCore::WhitePoint::D50>>::convert):
(): Deleted.
(WebCore::WhitePoint::D65>>::convert): Deleted.
(WebCore::toLinear): Deleted.
(WebCore::toGammaEncoded): Deleted.
(WebCore::A98RGB<float>>::convert): Deleted.
(WebCore::LinearA98RGB<float>>::convert): Deleted.
(WebCore::DisplayP3<float>>::convert): Deleted.
(WebCore::LinearDisplayP3<float>>::convert): Deleted.
(WebCore::ExtendedSRGBA<float>>::convert): Deleted.
(WebCore::LinearExtendedSRGBA<float>>::convert): Deleted.
(WebCore::ProPhotoRGB<float>>::convert): Deleted.
(WebCore::LinearProPhotoRGB<float>>::convert): Deleted.
(WebCore::Rec2020<float>>::convert): Deleted.
(WebCore::LinearRec2020<float>>::convert): Deleted.
(WebCore::LinearSRGBA<float>>::convert): Deleted.
(WebCore::xyzToLinear): Deleted.
(WebCore::linearToXYZ): Deleted.
(WebCore::XYZFor<LinearA98RGB<float>>>::convert): Deleted.
(WebCore::XYZFor<LinearDisplayP3<float>>>::convert): Deleted.
(WebCore::XYZFor<LinearExtendedSRGBA<float>>>::convert): Deleted.
(WebCore::XYZFor<LinearProPhotoRGB<float>>>::convert): Deleted.
(WebCore::XYZFor<LinearRec2020<float>>>::convert): Deleted.
(WebCore::XYZFor<LinearSRGBA<float>>>::convert): Deleted.
(WebCore::XYZFor<Lab<float>>>::convert): Deleted.
(WebCore::XYZFor<A98RGB<float>>>::convert): Deleted.
(WebCore::XYZFor<DisplayP3<float>>>::convert): Deleted.
(WebCore::XYZFor<ExtendedSRGBA<float>>>::convert): Deleted.
(WebCore::XYZFor<HSLA<float>>>::convert): Deleted.
(WebCore::XYZFor<HWBA<float>>>::convert): Deleted.
(WebCore::XYZFor<LCHA<float>>>::convert): Deleted.
(WebCore::XYZFor<ProPhotoRGB<float>>>::convert): Deleted.
(WebCore::XYZFor<Rec2020<float>>>::convert): Deleted.
(WebCore::XYZFor<SRGBA<float>>>::convert): Deleted.
* platform/graphics/ColorConversion.h:
(WebCore::ColorConversion::convert):
(WebCore::ColorConversion::toLinearEncoded):
(WebCore::ColorConversion::toGammaEncoded):
(WebCore::ColorConversion::toExtended):
(WebCore::ColorConversion::toBounded):
(WebCore::ColorConversion::handleRGBFamilyConversion):
(WebCore::ColorConversion::handleMatrixConversion):
* platform/graphics/ColorMatrix.h:
(WebCore::operator==):
(WebCore::operator!=):
(WebCore::applyMatricesToColorComponents):
* platform/graphics/ColorTypes.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (272836 => 272837)


--- trunk/Source/WebCore/ChangeLog	2021-02-13 20:35:07 UTC (rev 272836)
+++ trunk/Source/WebCore/ChangeLog	2021-02-14 00:05:59 UTC (rev 272837)
@@ -1,3 +1,148 @@
+2021-02-13  Sam Weinig  <wei...@apple.com>
+
+        Reduce requirements for color types to only conversion to their reference color
+        https://bugs.webkit.org/show_bug.cgi?id=221868
+
+        Reviewed by Darin Adler.
+
+        We currently require every new color type to define a conversion to/from xyz and then perhaps
+        some more conversions to reference colors to avoid unnecessary trips through XYZ. For example,
+        if every conversion from HSL to sRGB went through XYZ it would be very silly and inefficient,
+        and the fact that we require the boiler plate for HSL -> XYZ, even though it's always going to
+        convert to SRGB first seems unfortunate. We can do better.
+
+        At first I thought we could model color conversion as DAG, with XYZ at the root, and each color
+        type declaring a "reference color" that would get them closer to XYZ. So, HSL would have a
+        "reference color" of sRGB, sRGB would have a "reference color" of linearSRGB, and linearSRGB 
+        would have a "reference color" XYZ. Then, as long as there was a defined conversion to/from the
+        "reference color", we could do a least common ancestor graph search between the two color types
+        being converted between to find the optimal set of conversions needed.
+
+        That almost works, but the relationships between the four color types that make up each RGB type
+        (bounded-gamma-encoded, bounded-linear-encoded, extended-gamma-encoded, extended-linear-encoded)
+        make it not quite ideal, since a conversion from something like sRGB to ExtendedSRGB would wind
+        up going through XYZ (since the "reference color" for sRGB is LinearSRGB and the "reference color"
+        for ExtendedSRGB is LinearExtendedSRGB, and both either "reference colors" are XYZ). 
+
+        Ultimately, the depth of the type graph is not all that large (though the ASCII art I made is
+        quite big, though I did remove A98RGB and Rec2020 as they are same as DisplayP3 here):
+
+                        ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
+                         Matrix Conversions    ┌───────────┐│┌───────────┐
+                        │                      │ XYZ (D50) │││ XYZ (D65) │                                                      │
+                                               └─────▲─────┘│└─────▲─────┘
+                        │                            │      │      │                                                            │
+               ┌─────────────────────────┬───────────┘      │      └───────────┬───────────────────────────────┐
+               │        │                │                  │                  │                               │                │
+               │                         │                  │                  │                               │               
+               │        │                │                  │                  │                               │                │
+               │          ProPhotoRGB───────────────────┐   │   SRGB──────────────────────────┐ DisplayP3─────────────────────┐
+               │        │ │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │
+               │          ││ Linear │ │ LinearExtended ││   │   ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││
+               │        │ │└────────┘ └────────────────┘│   │   │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │
+               │         ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─│─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─
+         ┌───────────┐    │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│
+         │    Lab    │    ││ Gamma  │ │ GammaExtended  ││   │   ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││
+         └─────▲─────┘    │└────────┘ └────────────────┘│   │   │└────▲───┘ └────────────────┘│ │└────────┘ └────────────────┘│
+               │          └─────────────────────────────┘   │   └─────┼───────────────────────┘ └─────────────────────────────┘
+               │                                            │      ┌──┴──────────┬─────────────┐
+               │                                            │      │             │             │
+         ┌───────────┐                                      │┌───────────┐ ┌───────────┐┌─────────────┐
+         │    LCH    │                                      ││    HSL    │ │    HWB    ││SRGB<uint8_t>│
+         └───────────┘                                      │└───────────┘ └───────────┘└─────────────┘
+
+        From this, it turns out you can handle all the cases in about 5 steps, with most peeling off a
+        conversion from the front or back or the path and using recursion to continue on. It ultimately 
+        leaves a final step where only matrix conversions remain, which can potentially be further
+        optimized in another patch to concatenate the matrices at compile time.
+
+        1. Handle the special case SRGBA<uint8_t> for Input and Output, and recursively call conversion.
+
+        2. Handle all color types that are not IsRGBType<T> or IsXYZA<T> for Input and Output. For all
+           these other color types, we can uncondtionally convert them to their "reference" color, as
+           either they have already been handled by a ColorConversion specialization or this will
+           get us closer to the final conversion, and recursively call conversion.
+
+        3. Handle conversions within a RGBFamily (e.g. all have the same descriptor). This will conclude
+           the conversion.
+
+        4. Handle any gamma conversions for the Input and Output, recursively call conversion
+
+        5. At this point, Input and Output are each either Linear-RGB types (of different familes) or XYZA
+           and therefore all additional conversion can happen via matrix transformation. This will conclude
+           the conversion.
+
+        With these steps, we group the color types into 3 distinct groups.
+
+        1. RGB types.
+
+            These inherit from the RGBType struct and are defined in terms of their xyzToLinear / linearToXYZ 
+            matrices, their transfer function, whether they are bounded or extended and their white point. New 
+            RGB color types can be added without any new conversion code being required, as long as they specify
+            those properties.
+
+        2. The XYZ type.
+
+            This is the root type, and only varies on its white point. If other white points beside D50 and D65 
+            are ever needed, we will need to extend the ChromaticAdapation specializations to also have conversion
+            matrices between those.
+
+        3. All other types.
+
+            All other types (e.g. Lab, LCHA, HSLA, HWBA (and SRGBA<uint8_t>, kind of, it's a special flower) are
+            the set currently) have their conversions defined in terms of single reference color and require
+            explicit specialization of the ColorConversion struct to work.
+
+        * platform/graphics/ColorConversion.cpp:
+        (WebCore::Lab<float>>::convert):
+        (WebCore::WhitePoint::D50>>::convert):
+        (): Deleted.
+        (WebCore::WhitePoint::D65>>::convert): Deleted.
+        (WebCore::toLinear): Deleted.
+        (WebCore::toGammaEncoded): Deleted.
+        (WebCore::A98RGB<float>>::convert): Deleted.
+        (WebCore::LinearA98RGB<float>>::convert): Deleted.
+        (WebCore::DisplayP3<float>>::convert): Deleted.
+        (WebCore::LinearDisplayP3<float>>::convert): Deleted.
+        (WebCore::ExtendedSRGBA<float>>::convert): Deleted.
+        (WebCore::LinearExtendedSRGBA<float>>::convert): Deleted.
+        (WebCore::ProPhotoRGB<float>>::convert): Deleted.
+        (WebCore::LinearProPhotoRGB<float>>::convert): Deleted.
+        (WebCore::Rec2020<float>>::convert): Deleted.
+        (WebCore::LinearRec2020<float>>::convert): Deleted.
+        (WebCore::LinearSRGBA<float>>::convert): Deleted.
+        (WebCore::xyzToLinear): Deleted.
+        (WebCore::linearToXYZ): Deleted.
+        (WebCore::XYZFor<LinearA98RGB<float>>>::convert): Deleted.
+        (WebCore::XYZFor<LinearDisplayP3<float>>>::convert): Deleted.
+        (WebCore::XYZFor<LinearExtendedSRGBA<float>>>::convert): Deleted.
+        (WebCore::XYZFor<LinearProPhotoRGB<float>>>::convert): Deleted.
+        (WebCore::XYZFor<LinearRec2020<float>>>::convert): Deleted.
+        (WebCore::XYZFor<LinearSRGBA<float>>>::convert): Deleted.
+        (WebCore::XYZFor<Lab<float>>>::convert): Deleted.
+        (WebCore::XYZFor<A98RGB<float>>>::convert): Deleted.
+        (WebCore::XYZFor<DisplayP3<float>>>::convert): Deleted.
+        (WebCore::XYZFor<ExtendedSRGBA<float>>>::convert): Deleted.
+        (WebCore::XYZFor<HSLA<float>>>::convert): Deleted.
+        (WebCore::XYZFor<HWBA<float>>>::convert): Deleted.
+        (WebCore::XYZFor<LCHA<float>>>::convert): Deleted.
+        (WebCore::XYZFor<ProPhotoRGB<float>>>::convert): Deleted.
+        (WebCore::XYZFor<Rec2020<float>>>::convert): Deleted.
+        (WebCore::XYZFor<SRGBA<float>>>::convert): Deleted.
+        * platform/graphics/ColorConversion.h:
+        (WebCore::ColorConversion::convert):
+        (WebCore::ColorConversion::toLinearEncoded):
+        (WebCore::ColorConversion::toGammaEncoded):
+        (WebCore::ColorConversion::toExtended):
+        (WebCore::ColorConversion::toBounded):
+        (WebCore::ColorConversion::handleRGBFamilyConversion):
+        (WebCore::ColorConversion::handleMatrixConversion):
+        * platform/graphics/ColorMatrix.h:
+        (WebCore::operator==):
+        (WebCore::operator!=):
+        (WebCore::applyMatricesToColorComponents):
+        * platform/graphics/ColorTypes.h:
+
 2021-02-12  Darin Adler  <da...@apple.com>
 
         Improve computed style handling in degenerate grid cases, sizes and lengths of zero

Modified: trunk/Source/WebCore/platform/graphics/ColorConversion.cpp (272836 => 272837)


--- trunk/Source/WebCore/platform/graphics/ColorConversion.cpp	2021-02-13 20:35:07 UTC (rev 272836)
+++ trunk/Source/WebCore/platform/graphics/ColorConversion.cpp	2021-02-14 00:05:59 UTC (rev 272837)
@@ -30,204 +30,6 @@
 
 namespace WebCore {
 
-// Chromatic Adaptation Matrices.
-
-// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
-static constexpr ColorMatrix<3, 3> D50ToD65Matrix {
-     0.9555766f, -0.0230393f, 0.0631636f,
-    -0.0282895f,  1.0099416f, 0.0210077f,
-     0.0122982f, -0.0204830f, 1.3299098f
-};
-
-// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
-static constexpr ColorMatrix<3, 3> D65ToD50Matrix {
-     1.0478112f, 0.0228866f, -0.0501270f,
-     0.0295424f, 0.9904844f, -0.0170491f,
-    -0.0092345f, 0.0150436f,  0.7521316f
-};
-
-// MARK: Chromatic Adaptation conversions.
-
-XYZA<float, WhitePoint::D65> ColorConversion<XYZA<float, WhitePoint::D65>, XYZA<float, WhitePoint::D50>>::convert(const XYZA<float, WhitePoint::D50>& color)
-{
-    return makeFromComponentsClampingExceptAlpha<XYZA<float, WhitePoint::D65>>(D50ToD65Matrix.transformedColorComponents(asColorComponents(color)));
-}
-
-XYZA<float, WhitePoint::D50> ColorConversion<XYZA<float, WhitePoint::D50>, XYZA<float, WhitePoint::D65>>::convert(const XYZA<float, WhitePoint::D65>& color)
-{
-    return makeFromComponentsClampingExceptAlpha<XYZA<float, WhitePoint::D50>>(D65ToD50Matrix.transformedColorComponents(asColorComponents(color)));
-}
-
-// MARK: Gamma conversions.
-
-template<typename ColorType> static auto toLinear(const ColorType& color) -> typename ColorType::LinearCounterpart
-{
-    auto [c1, c2, c3, alpha] = color;
-    return { ColorType::TransferFunction::toLinear(c1), ColorType::TransferFunction::toLinear(c2), ColorType::TransferFunction::toLinear(c3), alpha };
-}
-
-template<typename ColorType> static auto toGammaEncoded(const ColorType& color) -> typename ColorType::GammaEncodedCounterpart
-{
-    auto [c1, c2, c3, alpha] = color;
-    return { ColorType::TransferFunction::toGammaEncoded(c1), ColorType::TransferFunction::toGammaEncoded(c2), ColorType::TransferFunction::toGammaEncoded(c3), alpha };
-}
-
-// A98RGB <-> LinearA98RGB conversions.
-
-LinearA98RGB<float> ColorConversion<LinearA98RGB<float>, A98RGB<float>>::convert(const A98RGB<float>& color)
-{
-    return toLinear(color);
-}
-
-A98RGB<float> ColorConversion<A98RGB<float>, LinearA98RGB<float>>::convert(const LinearA98RGB<float>& color)
-{
-    return toGammaEncoded(color);
-}
-
-// DisplayP3 <-> LinearDisplayP3 conversions.
-
-LinearDisplayP3<float> ColorConversion<LinearDisplayP3<float>, DisplayP3<float>>::convert(const DisplayP3<float>& color)
-{
-    return toLinear(color);
-}
-
-DisplayP3<float> ColorConversion<DisplayP3<float>, LinearDisplayP3<float>>::convert(const LinearDisplayP3<float>& color)
-{
-    return toGammaEncoded(color);
-}
-
-// ExtendedSRGBA <-> LinearExtendedSRGBA conversions.
-
-LinearExtendedSRGBA<float> ColorConversion<LinearExtendedSRGBA<float>, ExtendedSRGBA<float>>::convert(const ExtendedSRGBA<float>& color)
-{
-    return toLinear(color);
-}
-
-ExtendedSRGBA<float> ColorConversion<ExtendedSRGBA<float>, LinearExtendedSRGBA<float>>::convert(const LinearExtendedSRGBA<float>& color)
-{
-    return toGammaEncoded(color);
-}
-
-// ProPhotoRGB <-> LinearProPhotoRGB conversions.
-
-LinearProPhotoRGB<float> ColorConversion<LinearProPhotoRGB<float>, ProPhotoRGB<float>>::convert(const ProPhotoRGB<float>& color)
-{
-    return toLinear(color);
-}
-
-ProPhotoRGB<float> ColorConversion<ProPhotoRGB<float>, LinearProPhotoRGB<float>>::convert(const LinearProPhotoRGB<float>& color)
-{
-    return toGammaEncoded(color);
-}
-
-// Rec2020 <-> LinearRec2020 conversions.
-
-LinearRec2020<float> ColorConversion<LinearRec2020<float>, Rec2020<float>>::convert(const Rec2020<float>& color)
-{
-    return toLinear(color);
-}
-
-Rec2020<float> ColorConversion<Rec2020<float>, LinearRec2020<float>>::convert(const LinearRec2020<float>& color)
-{
-    return toGammaEncoded(color);
-}
-
-// SRGBA <-> LinearSRGBA conversions.
-
-LinearSRGBA<float> ColorConversion<LinearSRGBA<float>, SRGBA<float>>::convert(const SRGBA<float>& color)
-{
-    return toLinear(color);
-}
-
-SRGBA<float> ColorConversion<SRGBA<float>, LinearSRGBA<float>>::convert(const LinearSRGBA<float>& color)
-{
-    return toGammaEncoded(color);
-}
-
-// MARK: Matrix conversions (to and from XYZ for all linear color types).
-
-template<typename ColorType> static auto xyzToLinear(const XYZFor<ColorType>& color) -> ColorType
-{
-    return makeFromComponentsClampingExceptAlpha<ColorType>(ColorType::xyzToLinear.transformedColorComponents(asColorComponents(color)));
-}
-
-template<typename ColorType> static auto linearToXYZ(const ColorType& color) -> XYZFor<ColorType>
-{
-    return makeFromComponentsClampingExceptAlpha<XYZFor<ColorType>>(ColorType::linearToXYZ.transformedColorComponents(asColorComponents(color)));
-}
-
-// - LinearA98RGB matrix conversions.
-
-LinearA98RGB<float> ColorConversion<LinearA98RGB<float>, XYZFor<LinearA98RGB<float>>>::convert(const XYZFor<LinearA98RGB<float>>& color)
-{
-    return xyzToLinear<LinearA98RGB<float>>(color);
-}
-
-XYZFor<LinearA98RGB<float>> ColorConversion<XYZFor<LinearA98RGB<float>>, LinearA98RGB<float>>::convert(const LinearA98RGB<float>& color)
-{
-    return linearToXYZ<LinearA98RGB<float>>(color);
-}
-
-// - LinearDisplayP3 matrix conversions.
-
-LinearDisplayP3<float> ColorConversion<LinearDisplayP3<float>, XYZFor<LinearDisplayP3<float>>>::convert(const XYZFor<LinearDisplayP3<float>>& color)
-{
-    return xyzToLinear<LinearDisplayP3<float>>(color);
-}
-
-XYZFor<LinearDisplayP3<float>> ColorConversion<XYZFor<LinearDisplayP3<float>>, LinearDisplayP3<float>>::convert(const LinearDisplayP3<float>& color)
-{
-    return linearToXYZ<LinearDisplayP3<float>>(color);
-}
-
-// - LinearExtendedSRGBA matrix conversions.
-
-LinearExtendedSRGBA<float> ColorConversion<LinearExtendedSRGBA<float>, XYZFor<LinearExtendedSRGBA<float>>>::convert(const XYZFor<LinearExtendedSRGBA<float>>& color)
-{
-    return xyzToLinear<LinearExtendedSRGBA<float>>(color);
-}
-
-XYZFor<LinearExtendedSRGBA<float>> ColorConversion<XYZFor<LinearExtendedSRGBA<float>>, LinearExtendedSRGBA<float>>::convert(const LinearExtendedSRGBA<float>& color)
-{
-    return linearToXYZ<LinearExtendedSRGBA<float>>(color);
-}
-
-// - LinearProPhotoRGB matrix conversions.
-
-LinearProPhotoRGB<float> ColorConversion<LinearProPhotoRGB<float>, XYZFor<LinearProPhotoRGB<float>>>::convert(const XYZFor<LinearProPhotoRGB<float>>& color)
-{
-    return xyzToLinear<LinearProPhotoRGB<float>>(color);
-}
-
-XYZFor<LinearProPhotoRGB<float>> ColorConversion<XYZFor<LinearProPhotoRGB<float>>, LinearProPhotoRGB<float>>::convert(const LinearProPhotoRGB<float>& color)
-{
-    return linearToXYZ<LinearProPhotoRGB<float>>(color);
-}
-
-// - LinearRec2020 matrix conversions.
-
-LinearRec2020<float> ColorConversion<LinearRec2020<float>, XYZFor<LinearRec2020<float>>>::convert(const XYZFor<LinearRec2020<float>>& color)
-{
-    return xyzToLinear<LinearRec2020<float>>(color);
-}
-
-XYZFor<LinearRec2020<float>> ColorConversion<XYZFor<LinearRec2020<float>>, LinearRec2020<float>>::convert(const LinearRec2020<float>& color)
-{
-    return linearToXYZ<LinearRec2020<float>>(color);
-}
-
-// - LinearSRGBA matrix conversions.
-
-LinearSRGBA<float> ColorConversion<LinearSRGBA<float>, XYZFor<LinearSRGBA<float>>>::convert(const XYZFor<LinearSRGBA<float>>& color)
-{
-    return xyzToLinear<LinearSRGBA<float>>(color);
-}
-
-XYZFor<LinearSRGBA<float>> ColorConversion<XYZFor<LinearSRGBA<float>>, LinearSRGBA<float>>::convert(const LinearSRGBA<float>& color)
-{
-    return linearToXYZ<LinearSRGBA<float>>(color);
-}
-
 // MARK: HSL conversions.
 
 struct HSLHueCalculationResult {
@@ -381,7 +183,7 @@
 static constexpr float LABk = 24389.0f / 27.0f;
 static constexpr float D50WhiteValues[] = { 0.96422f, 1.0f, 0.82521f };
 
-XYZFor<Lab<float>> ColorConversion<XYZFor<Lab<float>>, Lab<float>>::convert(const Lab<float>& color)
+XYZA<float, WhitePoint::D50> ColorConversion<XYZA<float, WhitePoint::D50>, Lab<float>>::convert(const Lab<float>& color)
 {
     float f1 = (color.lightness + 16.0f) / 116.0f;
     float f0 = f1 + (color.a / 500.0f);
@@ -411,7 +213,7 @@
     return { x, y, z, color.alpha };
 }
 
-Lab<float> ColorConversion<Lab<float>, XYZFor<Lab<float>>>::convert(const XYZFor<Lab<float>>& color)
+Lab<float> ColorConversion<Lab<float>, XYZA<float, WhitePoint::D50>>::convert(const XYZA<float, WhitePoint::D50>& color)
 {
     float x = color.x / D50WhiteValues[0];
     float y = color.y / D50WhiteValues[1];
@@ -461,118 +263,8 @@
     };
 }
 
-// MARK: Combination conversions (constructed from more basic conversions above).
+// MARK: SRGBA<uint8_t> conversions.
 
-// - A98RGB combination functions.
-
-XYZFor<A98RGB<float>> ColorConversion<XYZFor<A98RGB<float>>, A98RGB<float>>::convert(const A98RGB<float>& color)
-{
-    return convertColor<XYZFor<A98RGB<float>>>(convertColor<LinearA98RGB<float>>(color));
-}
-
-A98RGB<float> ColorConversion<A98RGB<float>, XYZFor<A98RGB<float>>>::convert(const XYZFor<A98RGB<float>>& color)
-{
-    return convertColor<A98RGB<float>>(convertColor<LinearA98RGB<float>>(color));
-}
-
-// - DisplayP3 combination functions.
-
-XYZFor<DisplayP3<float>> ColorConversion<XYZFor<DisplayP3<float>>, DisplayP3<float>>::convert(const DisplayP3<float>& color)
-{
-    return convertColor<XYZFor<DisplayP3<float>>>(convertColor<LinearDisplayP3<float>>(color));
-}
-
-DisplayP3<float> ColorConversion<DisplayP3<float>, XYZFor<DisplayP3<float>>>::convert(const XYZFor<DisplayP3<float>>& color)
-{
-    return convertColor<DisplayP3<float>>(convertColor<LinearDisplayP3<float>>(color));
-}
-
-// - ExtendedSRGB combination functions.
-
-XYZFor<ExtendedSRGBA<float>> ColorConversion<XYZFor<ExtendedSRGBA<float>>, ExtendedSRGBA<float>>::convert(const ExtendedSRGBA<float>& color)
-{
-    return convertColor<XYZFor<ExtendedSRGBA<float>>>(convertColor<LinearExtendedSRGBA<float>>(color));
-}
-
-ExtendedSRGBA<float> ColorConversion<ExtendedSRGBA<float>, XYZFor<ExtendedSRGBA<float>>>::convert(const XYZFor<ExtendedSRGBA<float>>& color)
-{
-    return convertColor<ExtendedSRGBA<float>>(convertColor<LinearExtendedSRGBA<float>>(color));
-}
-
-// - HSLA combination functions.
-
-XYZFor<HSLA<float>> ColorConversion<XYZFor<HSLA<float>>, HSLA<float>>::convert(const HSLA<float>& color)
-{
-    return convertColor<XYZFor<HSLA<float>>>(convertColor<SRGBA<float>>(color));
-}
-
-HSLA<float> ColorConversion<HSLA<float>, XYZFor<HSLA<float>>>::convert(const XYZFor<HSLA<float>>& color)
-{
-    return convertColor<HSLA<float>>(convertColor<SRGBA<float>>(color));
-}
-
-// - HWBA combination functions.
-
-XYZFor<HWBA<float>> ColorConversion<XYZFor<HWBA<float>>, HWBA<float>>::convert(const HWBA<float>& color)
-{
-    return convertColor<XYZFor<HWBA<float>>>(convertColor<SRGBA<float>>(color));
-}
-
-HWBA<float> ColorConversion<HWBA<float>, XYZFor<HWBA<float>>>::convert(const XYZFor<HWBA<float>>& color)
-{
-    return convertColor<HWBA<float>>(convertColor<SRGBA<float>>(color));
-}
-
-// - LCHA combination functions.
-
-XYZFor<LCHA<float>> ColorConversion<XYZFor<LCHA<float>>, LCHA<float>>::convert(const LCHA<float>& color)
-{
-    return convertColor<XYZFor<LCHA<float>>>(convertColor<Lab<float>>(color));
-}
-
-LCHA<float> ColorConversion<LCHA<float>, XYZFor<LCHA<float>>>::convert(const XYZFor<LCHA<float>>& color)
-{
-    return convertColor<LCHA<float>>(convertColor<Lab<float>>(color));
-}
-
-// - ProPhotoRGB combination functions.
-
-XYZFor<ProPhotoRGB<float>> ColorConversion<XYZFor<ProPhotoRGB<float>>, ProPhotoRGB<float>>::convert(const ProPhotoRGB<float>& color)
-{
-    return convertColor<XYZFor<ProPhotoRGB<float>>>(convertColor<LinearProPhotoRGB<float>>(color));
-}
-
-ProPhotoRGB<float> ColorConversion<ProPhotoRGB<float>, XYZFor<ProPhotoRGB<float>>>::convert(const XYZFor<ProPhotoRGB<float>>& color)
-{
-    return convertColor<ProPhotoRGB<float>>(convertColor<LinearProPhotoRGB<float>>(color));
-}
-
-// - Rec2020 combination functions.
-
-XYZFor<Rec2020<float>> ColorConversion<XYZFor<Rec2020<float>>, Rec2020<float>>::convert(const Rec2020<float>& color)
-{
-    return convertColor<XYZFor<Rec2020<float>>>(convertColor<LinearRec2020<float>>(color));
-}
-
-Rec2020<float> ColorConversion<Rec2020<float>, XYZFor<Rec2020<float>>>::convert(const XYZFor<Rec2020<float>>& color)
-{
-    return convertColor<Rec2020<float>>(convertColor<LinearRec2020<float>>(color));
-}
-
-// - SRGB combination functions.
-
-XYZFor<SRGBA<float>> ColorConversion<XYZFor<SRGBA<float>>, SRGBA<float>>::convert(const SRGBA<float>& color)
-{
-    return convertColor<XYZFor<SRGBA<float>>>(convertColor<LinearSRGBA<float>>(color));
-}
-
-SRGBA<float> ColorConversion<SRGBA<float>, XYZFor<SRGBA<float>>>::convert(const XYZFor<SRGBA<float>>& color)
-{
-    return convertColor<SRGBA<float>>(convertColor<LinearSRGBA<float>>(color));
-}
-
-// MARK: SRGBA<uint8_t> component type conversions.
-
 SRGBA<float> ColorConversion<SRGBA<float>, SRGBA<uint8_t>>::convert(const SRGBA<uint8_t>& color)
 {
     return makeFromComponents<SRGBA<float>>(asColorComponents(color).map([](uint8_t value) -> float {

Modified: trunk/Source/WebCore/platform/graphics/ColorConversion.h (272836 => 272837)


--- trunk/Source/WebCore/platform/graphics/ColorConversion.h	2021-02-13 20:35:07 UTC (rev 272836)
+++ trunk/Source/WebCore/platform/graphics/ColorConversion.h	2021-02-14 00:05:59 UTC (rev 272837)
@@ -26,356 +26,269 @@
 #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
+// All color types, other than XYZA or those inheriting from RGBType, must implement
+// the following conversions to and from their "Reference" color.
 //
-//    template<> struct ColorConversion<XYZFor<`ColorType`<float>>, `ColorType`<float>> {
-//        WEBCORE_EXPORT static XYZFor<`ColorType`<float>> convert(const `ColorType`<float>&);
+//    template<> struct ColorConversion<`ColorType`<float>::Reference, `ColorType`<float>> {
+//        WEBCORE_EXPORT static `ColorType`<float>::Reference convert(const `ColorType`<float>&);
 //    };
 //    
-//    template<> struct ColorConversion<`ColorType`<float>, XYZFor<`ColorType`<float>>> {
-//        WEBCORE_EXPORT static `ColorType`<float> convert(const XYZFor<`ColorType`<float>>&);
+//    template<> struct ColorConversion<`ColorType`<float>, `ColorType`<float>::Reference> {
+//        WEBCORE_EXPORT static `ColorType`<float> convert(const `ColorType`<float>::Reference&);
 //    };
 //
-// Any additional conversions can be thought of as optimizations, shortcutting unnecessary steps, though
-// some may be integral to the base conversion.
 
-template<typename ColorType> using XYZFor = XYZA<typename ColorType::ComponentType, ColorType::whitePoint>;
+template<typename Output, typename Input, typename = void> struct ColorConversion;
 
-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
-template<> struct ColorConversion<XYZFor<A98RGB<float>>, A98RGB<float>> {
-    WEBCORE_EXPORT static XYZFor<A98RGB<float>> convert(const A98RGB<float>&);
-};
 
-template<> struct ColorConversion<A98RGB<float>, XYZFor<A98RGB<float>>> {
-    WEBCORE_EXPORT static A98RGB<float> convert(const XYZFor<A98RGB<float>>&);
-};
+// MARK: Chromatic Adaptation conversions.
 
-// Additions
-template<> struct ColorConversion<LinearA98RGB<float>, A98RGB<float>> {
-    WEBCORE_EXPORT static LinearA98RGB<float> convert(const A98RGB<float>&);
-};
+// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+template<WhitePoint From, WhitePoint To> struct ChromaticAdapation;
 
-
-// DisplayP3
-template<> struct ColorConversion<XYZFor<DisplayP3<float>>, DisplayP3<float>> {
-    WEBCORE_EXPORT static XYZFor<DisplayP3<float>> convert(const DisplayP3<float>&);
+template<> struct ChromaticAdapation<WhitePoint::D65, WhitePoint::D50> {
+    static constexpr ColorMatrix<3, 3> matrix {
+         1.0478112f, 0.0228866f, -0.0501270f,
+         0.0295424f, 0.9904844f, -0.0170491f,
+        -0.0092345f, 0.0150436f,  0.7521316f
+    };
 };
 
-template<> struct ColorConversion<DisplayP3<float>, XYZFor<DisplayP3<float>>> {
-    WEBCORE_EXPORT static DisplayP3<float> convert(const XYZFor<DisplayP3<float>>&);
+template<> struct ChromaticAdapation<WhitePoint::D50, WhitePoint::D65> {
+    static constexpr ColorMatrix<3, 3> matrix {
+         0.9555766f, -0.0230393f, 0.0631636f,
+        -0.0282895f,  1.0099416f, 0.0210077f,
+         0.0122982f, -0.0204830f, 1.3299098f
+    };
 };
 
-// Additions
-template<> struct ColorConversion<LinearDisplayP3<float>, DisplayP3<float>> {
-    WEBCORE_EXPORT static LinearDisplayP3<float> convert(const DisplayP3<float>&);
-};
-
-
-// ExtendedSRGBA
-template<> struct ColorConversion<XYZFor<ExtendedSRGBA<float>>, ExtendedSRGBA<float>> {
-    WEBCORE_EXPORT static XYZFor<ExtendedSRGBA<float>> convert(const ExtendedSRGBA<float>&);
-};
-
-template<> struct ColorConversion<ExtendedSRGBA<float>, XYZFor<ExtendedSRGBA<float>>> {
-    WEBCORE_EXPORT static ExtendedSRGBA<float> convert(const XYZFor<ExtendedSRGBA<float>>&);
-};
-
-// Additions
-template<> struct ColorConversion<LinearExtendedSRGBA<float>, ExtendedSRGBA<float>> {
-    WEBCORE_EXPORT static LinearExtendedSRGBA<float> convert(const ExtendedSRGBA<float>&);
-};
-
-
-// HSLA
-template<> struct ColorConversion<XYZFor<HSLA<float>>, HSLA<float>> {
-    WEBCORE_EXPORT static XYZFor<HSLA<float>> convert(const HSLA<float>&);
-};
-
-template<> struct ColorConversion<HSLA<float>, XYZFor<HSLA<float>>> {
-    WEBCORE_EXPORT static HSLA<float> convert(const XYZFor<HSLA<float>>&);
-};
-
-// Additions
+// MARK: HSLA
 template<> struct ColorConversion<SRGBA<float>, HSLA<float>> {
     WEBCORE_EXPORT static SRGBA<float> convert(const HSLA<float>&);
 };
-
-
-// HWBA
-template<> struct ColorConversion<XYZFor<HWBA<float>>, HWBA<float>> {
-    WEBCORE_EXPORT static XYZFor<HWBA<float>> convert(const HWBA<float>&);
+template<> struct ColorConversion<HSLA<float>, SRGBA<float>> {
+    WEBCORE_EXPORT static HSLA<float> convert(const SRGBA<float>&);
 };
 
-template<> struct ColorConversion<HWBA<float>, XYZFor<HWBA<float>>> {
-    WEBCORE_EXPORT static HWBA<float> convert(const XYZFor<HWBA<float>>&);
-};
-
-// Additions
+// MARK: HWBA
 template<> struct ColorConversion<SRGBA<float>, HWBA<float>> {
     WEBCORE_EXPORT static SRGBA<float> convert(const HWBA<float>&);
 };
-
-
-// LCHA
-template<> struct ColorConversion<XYZFor<LCHA<float>>, LCHA<float>> {
-    WEBCORE_EXPORT static XYZFor<LCHA<float>> convert(const LCHA<float>&);
+template<> struct ColorConversion<HWBA<float>, SRGBA<float>> {
+    WEBCORE_EXPORT static HWBA<float> convert(const SRGBA<float>&);
 };
 
-template<> struct ColorConversion<LCHA<float>, XYZFor<LCHA<float>>> {
-    WEBCORE_EXPORT static LCHA<float> convert(const XYZFor<LCHA<float>>&);
-};
-
-// Additions
+// MARK: LCHA
 template<> struct ColorConversion<Lab<float>, LCHA<float>> {
     WEBCORE_EXPORT static Lab<float> convert(const LCHA<float>&);
 };
-
-
-// Lab
-template<> struct ColorConversion<XYZFor<Lab<float>>, Lab<float>> {
-    WEBCORE_EXPORT static XYZFor<Lab<float>> convert(const Lab<float>&);
-};
-
-template<> struct ColorConversion<Lab<float>, XYZFor<Lab<float>>> {
-    WEBCORE_EXPORT static Lab<float> convert(const XYZFor<Lab<float>>&);
-};
-
-// Additions
 template<> struct ColorConversion<LCHA<float>, Lab<float>> {
     WEBCORE_EXPORT static LCHA<float> convert(const Lab<float>&);
 };
 
-
-// LinearA98RGB
-template<> struct ColorConversion<XYZFor<LinearA98RGB<float>>, LinearA98RGB<float>> {
-    WEBCORE_EXPORT static XYZFor<LinearA98RGB<float>> convert(const LinearA98RGB<float>&);
+// MARK: Lab
+template<> struct ColorConversion<XYZA<float, WhitePoint::D50>, Lab<float>> {
+    WEBCORE_EXPORT static XYZA<float, WhitePoint::D50> convert(const Lab<float>&);
 };
-
-template<> struct ColorConversion<LinearA98RGB<float>, XYZFor<LinearA98RGB<float>>> {
-    WEBCORE_EXPORT static LinearA98RGB<float> convert(const XYZFor<LinearA98RGB<float>>&);
+template<> struct ColorConversion<Lab<float>, XYZA<float, WhitePoint::D50>> {
+    WEBCORE_EXPORT static Lab<float> convert(const XYZA<float, WhitePoint::D50>&);
 };
 
-// Additions
-template<> struct ColorConversion<A98RGB<float>, LinearA98RGB<float>> {
-    WEBCORE_EXPORT static A98RGB<float> convert(const LinearA98RGB<float>&);
+// MARK: SRGBA<uint8_t>
+// Only sRGB supports non-floating point component types.
+template<> struct ColorConversion<SRGBA<float>, SRGBA<uint8_t>> {
+    WEBCORE_EXPORT static SRGBA<float> convert(const SRGBA<uint8_t>&);
 };
-
-
-// LinearDisplayP3
-template<> struct ColorConversion<XYZFor<LinearDisplayP3<float>>, LinearDisplayP3<float>> {
-    WEBCORE_EXPORT static XYZFor<LinearDisplayP3<float>> convert(const LinearDisplayP3<float>&);
+template<> struct ColorConversion<SRGBA<uint8_t>, SRGBA<float>> {
+    WEBCORE_EXPORT static SRGBA<uint8_t> convert(const SRGBA<float>&);
 };
 
-template<> struct ColorConversion<LinearDisplayP3<float>, XYZFor<LinearDisplayP3<float>>> {
-    WEBCORE_EXPORT static LinearDisplayP3<float> convert(const XYZFor<LinearDisplayP3<float>>&);
-};
 
-// Additions
-template<> struct ColorConversion<DisplayP3<float>, LinearDisplayP3<float>> {
-    WEBCORE_EXPORT static DisplayP3<float> convert(const LinearDisplayP3<float>&);
-};
+// Identity conversion.
 
-
-// LinearExtendedSRGBA
-template<> struct ColorConversion<XYZFor<LinearExtendedSRGBA<float>>, LinearExtendedSRGBA<float>> {
-    WEBCORE_EXPORT static XYZFor<LinearExtendedSRGBA<float>> convert(const LinearExtendedSRGBA<float>&);
+template<typename ColorType> struct ColorConversion<ColorType, ColorType> {
+    static ColorType convert(const ColorType& color)
+    {
+        return color;
+    }
 };
 
-template<> struct ColorConversion<LinearExtendedSRGBA<float>, XYZFor<LinearExtendedSRGBA<float>>> {
-    WEBCORE_EXPORT static LinearExtendedSRGBA<float> convert(const XYZFor<LinearExtendedSRGBA<float>>&);
-};
 
-// Additions
-template<> struct ColorConversion<ExtendedSRGBA<float>, LinearExtendedSRGBA<float>> {
-    WEBCORE_EXPORT static ExtendedSRGBA<float> convert(const LinearExtendedSRGBA<float>&);
-};
+// Main conversion.
 
+//                ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
+//                 Matrix Conversions    ┌───────────┐│┌───────────┐
+//                │                      │ XYZ (D50) │││ XYZ (D65) │                                                                                                                      │
+//                                       └─────▲─────┘│└─────▲─────┘
+//                │                            │      │      │                                                                                                                            │
+//       ┌─────────────────────────┬───────────┘      │      └───────────┬───────────────────────────────┬───────────────────────────────┬───────────────────────────────┐
+//       │        │                │                  │                  │                               │                               │                               │                │
+//       │                         │                  │                  │                               │                               │                               │
+//       │        │                │                  │                  │                               │                               │                               │                │
+//       │          ProPhotoRGB───────────────────┐   │   SRGB──────────────────────────┐ DisplayP3─────────────────────┐ A98RGB────────────────────────┐ Rec2020───────────────────────┐
+//       │        │ │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │
+//       │          ││ Linear │ │ LinearExtended ││   │   ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││
+//       │        │ │└────────┘ └────────────────┘│   │   │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │
+//       │         ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─│─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─
+// ┌───────────┐    │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│
+// │    Lab    │    ││ Gamma  │ │ GammaExtended  ││   │   ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││
+// └─────▲─────┘    │└────────┘ └────────────────┘│   │   │└────▲───┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│
+//       │          └─────────────────────────────┘   │   └─────┼───────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘
+//       │                                            │      ┌──┴──────────┬─────────────┐
+//       │                                            │      │             │             │
+// ┌───────────┐                                      │┌───────────┐ ┌───────────┐┌─────────────┐
+// │    LCH    │                                      ││    HSL    │ │    HWB    ││SRGB<uint8_t>│
+// └───────────┘                                      │└───────────┘ └───────────┘└─────────────┘
 
-// LinearProPhotoRGB
-template<> struct ColorConversion<XYZFor<LinearProPhotoRGB<float>>, LinearProPhotoRGB<float>> {
-    WEBCORE_EXPORT static XYZFor<LinearProPhotoRGB<float>> convert(const LinearProPhotoRGB<float>&);
-};
+template<typename Output, typename Input, typename> struct ColorConversion {
+public:
+    static constexpr Output convert(const Input& color)
+    {
+        // 1. Handle the special case SRGBA<uint8_t> for Input and Output.
+        if constexpr (std::is_same_v<Input, SRGBA<uint8_t>> || std::is_same_v<Output, SRGBA<uint8_t>>)
+            return convertColor<Output>(convertColor<SRGBA<float>>(color));
 
-template<> struct ColorConversion<LinearProPhotoRGB<float>, XYZFor<LinearProPhotoRGB<float>>> {
-    WEBCORE_EXPORT static LinearProPhotoRGB<float> convert(const XYZFor<LinearProPhotoRGB<float>>&);
-};
+        // 2. Handle all color types that are not IsRGBType<T> or IsXYZA<T> for Input and Output. For all
+        //    these other color types, we can uncondtionally convert them to their "reference" color, as
+        //    either they have already been handled by a ColorConversion specialization or this will
+        //    get us closer to the final conversion.
+        else if constexpr (!IsRGBType<Input> && !IsXYZA<Input>)
+            return convertColor<Output>(convertColor<typename Input::Reference>(color));
+        else if constexpr (!IsRGBType<Output> && !IsXYZA<Output>)
+            return convertColor<Output>(convertColor<typename Output::Reference>(color));
 
-// Additions
-template<> struct ColorConversion<ProPhotoRGB<float>, LinearProPhotoRGB<float>> {
-    WEBCORE_EXPORT static ProPhotoRGB<float> convert(const LinearProPhotoRGB<float>&);
-};
+        // 3. Handle conversions within a RGBFamily (e.g. all have the same descriptor).
+        else if constexpr (IsSameRGBTypeFamily<Output, Input>)
+            return handleRGBFamilyConversion(color);
 
+        // 4. Handle any gamma conversions for the Input and Output.
+        else if constexpr (IsRGBGammaEncodedType<Input>)
+            return convertColor<Output>(convertColor<typename Input::LinearCounterpart>(color));
+        else if constexpr (IsRGBGammaEncodedType<Output>)
+            return convertColor<Output>(convertColor<typename Output::LinearCounterpart>(color));
 
-// LinearRec2020
-template<> struct ColorConversion<XYZFor<LinearRec2020<float>>, LinearRec2020<float>> {
-    WEBCORE_EXPORT static XYZFor<LinearRec2020<float>> convert(const LinearRec2020<float>&);
-};
+        // 5. At this point, Input and Output are each either Linear-RGB types (of different familes) or XYZA
+        //    and therefore all additional conversion can happen via matrix transformation.
+        else
+            return handleMatrixConversion(color);
+    }
 
-template<> struct ColorConversion<LinearRec2020<float>, XYZFor<LinearRec2020<float>>> {
-    WEBCORE_EXPORT static LinearRec2020<float> convert(const XYZFor<LinearRec2020<float>>&);
-};
+private:
+    template<typename ColorType> static inline constexpr auto toLinearEncoded(const ColorType& color) -> typename ColorType::LinearCounterpart
+    {
+        auto [c1, c2, c3, alpha] = color;
+        return { ColorType::TransferFunction::toLinear(c1), ColorType::TransferFunction::toLinear(c2), ColorType::TransferFunction::toLinear(c3), alpha };
+    }
 
-// Additions
-template<> struct ColorConversion<Rec2020<float>, LinearRec2020<float>> {
-    WEBCORE_EXPORT static Rec2020<float> convert(const LinearRec2020<float>&);
-};
+    template<typename ColorType> static inline constexpr auto toGammaEncoded(const ColorType& color) -> typename ColorType::GammaEncodedCounterpart
+    {
+        auto [c1, c2, c3, alpha] = color;
+        return { ColorType::TransferFunction::toGammaEncoded(c1), ColorType::TransferFunction::toGammaEncoded(c2), ColorType::TransferFunction::toGammaEncoded(c3), alpha };
+    }
 
+    template<typename ColorType> static inline constexpr auto toExtended(const ColorType& color) -> typename ColorType::ExtendedCounterpart
+    {
+        return makeFromComponents<typename ColorType::ExtendedCounterpart>(asColorComponents(color));
+    }
 
-// LinearSRGBA
-template<> struct ColorConversion<XYZFor<LinearSRGBA<float>>, LinearSRGBA<float>> {
-    WEBCORE_EXPORT static XYZFor<LinearSRGBA<float>> convert(const LinearSRGBA<float>&);
-};
+    template<typename ColorType> static inline constexpr auto toBounded(const ColorType& color) -> typename ColorType::BoundedCounterpart
+    {
+        return makeFromComponentsClampingExceptAlpha<typename ColorType::BoundedCounterpart>(asColorComponents(color));
+    }
 
-template<> struct ColorConversion<LinearSRGBA<float>, XYZFor<LinearSRGBA<float>>> {
-    WEBCORE_EXPORT static LinearSRGBA<float> convert(const XYZFor<LinearSRGBA<float>>&);
-};
+    static inline constexpr Output handleRGBFamilyConversion(const Input& color)
+    {
+        static_assert(IsSameRGBTypeFamily<Output, Input>);
 
-// Additions
-template<> struct ColorConversion<SRGBA<float>, LinearSRGBA<float>> {
-    WEBCORE_EXPORT static SRGBA<float> convert(const LinearSRGBA<float>&);
-};
+        //  RGB Family────────────────────┐
+        //  │┌────────┐ ┌────────────────┐│
+        //  ││ Linear │ │ LinearExtended ││
+        //  │└────────┘ └────────────────┘│
+        //  │┌────────┐ ┌────────────────┐│
+        //  ││ Gamma  │ │ GammaExtended  ││
+        //  │└────────┘ └────────────────┘│
+        //  └─────────────────────────────┘
 
+        // This handles conversions between any two of these within the same family, so SRGBLinear -> SRGB, but not
+        // SRGBLinear -> A98RGB.
 
-// ProPhotoRGB
-template<> struct ColorConversion<XYZFor<ProPhotoRGB<float>>, ProPhotoRGB<float>> {
-    WEBCORE_EXPORT static XYZFor<ProPhotoRGB<float>> convert(const ProPhotoRGB<float>&);
-};
+        auto boundsConversion = [](auto color) {
+            if constexpr (IsRGBExtendedType<Output> && IsRGBBoundedType<Input>)
+                return toExtended(color);
+            else if constexpr (IsRGBBoundedType<Output> && IsRGBExtendedType<Input>)
+                return toBounded(color);
+            else
+                return color;
+        };
 
-template<> struct ColorConversion<ProPhotoRGB<float>, XYZFor<ProPhotoRGB<float>>> {
-    WEBCORE_EXPORT static ProPhotoRGB<float> convert(const XYZFor<ProPhotoRGB<float>>&);
-};
+        auto gammaConversion = [](auto color) {
+            if constexpr (IsRGBGammaEncodedType<Output> && IsRGBLinearEncodedType<Input>)
+                return toGammaEncoded(color);
+            else if constexpr (IsRGBLinearEncodedType<Output> && IsRGBGammaEncodedType<Input>)
+                return toLinearEncoded(color);
+            else
+                return color;
+        };
 
-// Additions
-template<> struct ColorConversion<LinearProPhotoRGB<float>, ProPhotoRGB<float>> {
-    WEBCORE_EXPORT static LinearProPhotoRGB<float> convert(const ProPhotoRGB<float>&);
-};
+        return boundsConversion(gammaConversion(color));
+    }
 
-
-// Rec2020
-template<> struct ColorConversion<XYZFor<Rec2020<float>>, Rec2020<float>> {
-    WEBCORE_EXPORT static XYZFor<Rec2020<float>> convert(const Rec2020<float>&);
-};
-
-template<> struct ColorConversion<Rec2020<float>, XYZFor<Rec2020<float>>> {
-    WEBCORE_EXPORT static Rec2020<float> convert(const XYZFor<Rec2020<float>>&);
-};
-
-// Additions
-template<> struct ColorConversion<LinearRec2020<float>, Rec2020<float>> {
-    WEBCORE_EXPORT static LinearRec2020<float> convert(const Rec2020<float>&);
-};
-
-
-// SRGBA
-template<> struct ColorConversion<XYZFor<SRGBA<float>>, SRGBA<float>> {
-    WEBCORE_EXPORT static XYZFor<SRGBA<float>> convert(const SRGBA<float>&);
-};
-
-template<> struct ColorConversion<SRGBA<float>, XYZFor<SRGBA<float>>> {
-    WEBCORE_EXPORT static SRGBA<float> convert(const XYZFor<SRGBA<float>>&);
-};
-
-// Additions
-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>&);
-};
-
-// Special cases for SRGBA<uint8_t>. Only sRGB supports non-floating point component types.
-template<> struct ColorConversion<SRGBA<float>, SRGBA<uint8_t>> {
-    WEBCORE_EXPORT static SRGBA<float> convert(const SRGBA<uint8_t>&);
-};
-
-template<> struct ColorConversion<SRGBA<uint8_t>, SRGBA<float>> {
-    WEBCORE_EXPORT static SRGBA<uint8_t> convert(const SRGBA<float>&);
-};
-
-
-// XYZA Chromatic Adaptation conversions.
-template<> struct ColorConversion<XYZA<float, WhitePoint::D65>, XYZA<float, WhitePoint::D50>> {
-    WEBCORE_EXPORT static XYZA<float, WhitePoint::D65> convert(const XYZA<float, WhitePoint::D50>&);
-};
-
-template<> struct ColorConversion<XYZA<float, WhitePoint::D50>, XYZA<float, WhitePoint::D65>> {
-    WEBCORE_EXPORT static XYZA<float, WhitePoint::D50> convert(const XYZA<float, WhitePoint::D65>&);
-};
-
-
-// Identity conversion.
-
-template<typename ColorType> struct ColorConversion<ColorType, ColorType> {
-    static ColorType convert(const ColorType& color)
+    static inline constexpr Output handleMatrixConversion(const Input& color)
     {
-        return color;
-    }
-};
+        static_assert(IsRGBLinearEncodedType<Input> || IsXYZA<Input>);
+        static_assert(IsRGBLinearEncodedType<Output> || IsXYZA<Output>);
 
-// Fallback conversion.
+        //  ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
+        //   Matrix Conversions    ┌───────────┐│┌───────────┐
+        //  │                      │ XYZ (D50) │││ XYZ (D65) │                                                                                                                      │
+        //                         └─────▲─────┘│└─────▲─────┘
+        //  │                            │      │      │                                                                                                                            │
+        //                   ┌───────────┘      │      └───────────┬───────────────────────────────┬───────────────────────────────┬───────────────────────────────┐
+        //  │                │                  │                  │                               │                               │                               │                │
+        //                   │                  │                  │                               │                               │                               │
+        //  │                │                  │                  │                               │                               │                               │                │
+        //    ProPhotoRGB───────────────────┐   │   SRGB──────────────────────────┐ DisplayP3─────────────────────┐ A98RGB────────────────────────┐ Rec2020───────────────────────┐
+        //  │ │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │
+        //    ││ Linear │ │ LinearExtended ││   │   ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││
+        //  │ │└────────┘ └────────────────┘│   │   │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │
+        //   ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─│─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─
 
-// 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.
+        // This handles conversions between linear color types that can be converted using pre-defined
+        // 3x3 matrices.
+        
+        // FIXME: Pre-compute (using constexpr) the concatenation of the matrices prior to applying them
+        // to reduce number of matrix multiplications to a minimum. This will likely give subtly different
+        // results (due to floating point effects) so if this optimization is considered we should ensure we
+        // have sufficient testing coverage to notice any adverse effects.
 
-// 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.
+        auto applyMatrices = [](const Input& color, auto... matrices) {
+            return makeFromComponentsClampingExceptAlpha<Output>(applyMatricesToColorComponents(asColorComponents(color), matrices...));
+        };
 
-template<typename Output, typename Input> struct ColorConversion {
-    static Output convert(const Input& color)
-    {
-        if constexpr (std::is_same_v<Input, SRGBA<uint8_t>>)
-            return convertColor<Output>(convertColor<SRGBA<float>>(color));
-        else if constexpr (std::is_same_v<Output, SRGBA<uint8_t>>)
-            return convertColor<SRGBA<uint8_t>>(convertColor<SRGBA<float>>(color));
-        else {
-            auto xyz1 = convertColor<XYZFor<Input>>(color);
-            auto xyz2 = convertColor<XYZFor<Output>>(xyz1);
-            return convertColor<Output>(xyz2);
+        if constexpr (Input::whitePoint == Output::whitePoint) {
+            if constexpr (IsXYZA<Input>)
+                return applyMatrices(color, Output::xyzToLinear);
+            else if constexpr (IsXYZA<Output>)
+                return applyMatrices(color, Input::linearToXYZ);
+            else
+                return applyMatrices(color, Input::linearToXYZ, Output::xyzToLinear);
+        } else {
+            if constexpr (IsXYZA<Input> && IsXYZA<Output>)
+                return applyMatrices(color, ChromaticAdapation<Input::whitePoint, Output::whitePoint>::matrix);
+            else if constexpr (IsXYZA<Input>)
+                return applyMatrices(color, ChromaticAdapation<Input::whitePoint, Output::whitePoint>::matrix, Output::xyzToLinear);
+            else if constexpr (IsXYZA<Output>)
+                return applyMatrices(color, Input::linearToXYZ, ChromaticAdapation<Input::whitePoint, Output::whitePoint>::matrix);
+            else
+                return applyMatrices(color, Input::linearToXYZ, ChromaticAdapation<Input::whitePoint, Output::whitePoint>::matrix, Output::xyzToLinear);
         }
     }
 };

Modified: trunk/Source/WebCore/platform/graphics/ColorMatrix.h (272836 => 272837)


--- trunk/Source/WebCore/platform/graphics/ColorMatrix.h	2021-02-13 20:35:07 UTC (rev 272836)
+++ trunk/Source/WebCore/platform/graphics/ColorMatrix.h	2021-02-14 00:05:59 UTC (rev 272837)
@@ -32,7 +32,7 @@
 
 template<typename> struct ColorComponents;
 
-template<size_t Columns, size_t Rows>
+template<size_t ColumnCount, size_t RowCount>
 class ColorMatrix {
 public:
     template<typename ...Ts>
@@ -39,7 +39,7 @@
     explicit constexpr ColorMatrix(Ts ...input)
         : m_matrix {{ input ... }}
     {
-        static_assert(sizeof...(Ts) == Rows * Columns);
+        static_assert(sizeof...(Ts) == RowCount * ColumnCount);
     }
 
     constexpr ColorComponents<float> transformedColorComponents(const ColorComponents<float>&) const;
@@ -46,13 +46,32 @@
 
     constexpr float at(size_t row, size_t column) const
     {
-        return m_matrix[(row * Columns) + column];
+        return m_matrix[(row * ColumnCount) + column];
     }
 
 private:
-    std::array<float, Rows * Columns> m_matrix;
+    std::array<float, RowCount * ColumnCount> m_matrix;
 };
 
+template<size_t ColumnCount, size_t RowCount>
+constexpr bool operator==(const ColorMatrix<ColumnCount, RowCount>& a, const ColorMatrix<ColumnCount, RowCount>& b)
+{
+    for (size_t row = 0; row < RowCount; ++row) {
+        for (size_t column = 0; column < ColumnCount; ++column) {
+            if (a.at(row, column) != b.at(row, column))
+                return false;
+        }
+    }
+    return true;
+}
+
+template<size_t ColumnCount, size_t RowCount>
+constexpr bool operator!=(const ColorMatrix<ColumnCount, RowCount>& a, const ColorMatrix<ColumnCount, RowCount>& b)
+{
+    return !(a == b);
+}
+
+
 // FIXME: These are only used in FilterOperations.cpp. Consider moving them there.
 constexpr ColorMatrix<3, 3> grayscaleColorMatrix(float amount)
 {
@@ -100,25 +119,25 @@
     };
 }
 
-template<size_t Columns, size_t Rows>
-constexpr ColorComponents<float> ColorMatrix<Columns, Rows>::transformedColorComponents(const ColorComponents<float>& inputVector) const
+template<size_t ColumnCount, size_t RowCount>
+constexpr ColorComponents<float> ColorMatrix<ColumnCount, RowCount>::transformedColorComponents(const ColorComponents<float>& inputVector) const
 {
-    static_assert(ColorComponents<float>::Size >= Rows);
+    static_assert(ColorComponents<float>::Size >= RowCount);
     
     ColorComponents<float> result;
-    for (size_t row = 0; row < Rows; ++row) {
-        if constexpr (Columns <= ColorComponents<float>::Size) {
-            for (size_t column = 0; column < Columns; ++column)
+    for (size_t row = 0; row < RowCount; ++row) {
+        if constexpr (ColumnCount <= ColorComponents<float>::Size) {
+            for (size_t column = 0; column < ColumnCount; ++column)
                 result[row] += at(row, column) * inputVector[column];
-        } else if constexpr (Columns > ColorComponents<float>::Size) {
+        } else if constexpr (ColumnCount > ColorComponents<float>::Size) {
             for (size_t column = 0; column < ColorComponents<float>::Size; ++column)
                 result[row] += at(row, column) * inputVector[column];
-            for (size_t additionalColumn = ColorComponents<float>::Size; additionalColumn < Columns; ++additionalColumn)
+            for (size_t additionalColumn = ColorComponents<float>::Size; additionalColumn < ColumnCount; ++additionalColumn)
                 result[row] += at(row, additionalColumn);
         }
     }
-    if constexpr (ColorComponents<float>::Size > Rows) {
-        for (size_t additionalRow = Rows; additionalRow < ColorComponents<float>::Size; ++additionalRow)
+    if constexpr (ColorComponents<float>::Size > RowCount) {
+        for (size_t additionalRow = RowCount; additionalRow < ColorComponents<float>::Size; ++additionalRow)
             result[additionalRow] = inputVector[additionalRow];
     }
 
@@ -125,4 +144,14 @@
     return result;
 }
 
+template<typename T, typename M> inline constexpr auto applyMatricesToColorComponents(const ColorComponents<T>& components, M matrix) -> ColorComponents<T>
+{
+    return matrix.transformedColorComponents(components);
+}
+
+template<typename T, typename M, typename... Matrices> inline constexpr auto applyMatricesToColorComponents(const ColorComponents<T>& components, M matrix, Matrices... matrices) -> ColorComponents<T>
+{
+    return applyMatricesToColorComponents(matrix.transformedColorComponents(components), matrices...);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/graphics/ColorTypes.h (272836 => 272837)


--- trunk/Source/WebCore/platform/graphics/ColorTypes.h	2021-02-13 20:35:07 UTC (rev 272836)
+++ trunk/Source/WebCore/platform/graphics/ColorTypes.h	2021-02-14 00:05:59 UTC (rev 272837)
@@ -189,6 +189,7 @@
     using ComponentType = T;
     using Model = M;
     using TransferFunction = TF;
+    using Descriptor = D;
     static constexpr WhitePoint whitePoint = D::whitePoint;
 
     constexpr RGBAType(T red, T green, T blue, T alpha = AlphaTraits<T>::opaque)
@@ -257,6 +258,31 @@
     using Reference = XYZA<T, D::whitePoint>;
 };
 
+template<typename, typename = void> inline constexpr bool HasDescriptorMember = false;
+template<typename ColorType> inline constexpr bool HasDescriptorMember<ColorType, std::void_t<typename ColorType::Descriptor>> = true;
+
+template<typename, typename = void> inline constexpr bool HasExtendedCounterpartMember = false;
+template<typename ColorType> inline constexpr bool HasExtendedCounterpartMember<ColorType, std::void_t<typename ColorType::ExtendedCounterpart>> = true;
+
+template<typename, typename = void> inline constexpr bool HasBoundedCounterpartMember = false;
+template<typename ColorType> inline constexpr bool HasBoundedCounterpartMember<ColorType, std::void_t<typename ColorType::BoundedCounterpart>> = true;
+
+template<typename, typename = void> inline constexpr bool HasGammaEncodedCounterpartMember = false;
+template<typename ColorType> inline constexpr bool HasGammaEncodedCounterpartMember<ColorType, std::void_t<typename ColorType::GammaEncodedCounterpart>> = true;
+
+template<typename, typename = void> inline constexpr bool HasLinearCounterpartMember = false;
+template<typename ColorType> inline constexpr bool HasLinearCounterpartMember<ColorType, std::void_t<typename ColorType::LinearCounterpart>> = true;
+
+template<typename ColorType> inline constexpr bool IsRGBType = HasDescriptorMember<ColorType>;
+template<typename ColorType> inline constexpr bool IsRGBExtendedType = IsRGBType<ColorType> && HasBoundedCounterpartMember<ColorType>;
+template<typename ColorType> inline constexpr bool IsRGBBoundedType = IsRGBType<ColorType> && HasExtendedCounterpartMember<ColorType>;
+template<typename ColorType> inline constexpr bool IsRGBGammaEncodedType = IsRGBType<ColorType> && HasLinearCounterpartMember<ColorType>;
+template<typename ColorType> inline constexpr bool IsRGBLinearEncodedType = IsRGBType<ColorType> && HasGammaEncodedCounterpartMember<ColorType>;
+
+template<typename ColorType1, typename ColorType2, bool enabled> inline constexpr bool IsSameRGBTypeFamilyValue = false;
+template<typename ColorType1, typename ColorType2> inline constexpr bool IsSameRGBTypeFamilyValue<ColorType1, ColorType2, true> = std::is_same_v<typename ColorType1::Descriptor, typename ColorType2::Descriptor>;
+template<typename ColorType1, typename ColorType2> inline constexpr bool IsSameRGBTypeFamily = IsSameRGBTypeFamilyValue<ColorType1, ColorType2, IsRGBType<ColorType1> && IsRGBType<ColorType2>>;
+
 template<typename T> struct SRGBADescriptor {
     template<TransferFunctionMode Mode> using TransferFunction = SRGBTransferFunction<T, Mode>;
     static constexpr WhitePoint whitePoint = WhitePoint::D65;
@@ -397,6 +423,8 @@
     return { c.lightness, c.a, c.b, c.alpha };
 }
 
+template<typename ColorType> inline constexpr bool IsLab = std::is_same_v<Lab<typename ColorType::ComponentType>, ColorType>;
+
 // MARK: - LCHA Color Type.
 
 template<typename T> struct LCHA : ColorWithAlphaHelper<LCHA<T>> {
@@ -430,7 +458,9 @@
     return { c.lightness, c.chroma, c.hue, c.alpha };
 }
 
+template<typename ColorType> inline constexpr bool IsLCHA = std::is_same_v<LCHA<typename ColorType::ComponentType>, ColorType>;
 
+
 // MARK: - HSLA Color Type.
 
 template<typename T> struct HSLA : ColorWithAlphaHelper<HSLA<T>> {
@@ -464,6 +494,8 @@
     return { c.hue, c.saturation, c.lightness, c.alpha };
 }
 
+template<typename ColorType> inline constexpr bool IsHSLA = std::is_same_v<HSLA<typename ColorType::ComponentType>, ColorType>;
+
 // MARK: - HWBA Color Type.
 
 template<typename T> struct HWBA : ColorWithAlphaHelper<HWBA<T>> {
@@ -497,6 +529,8 @@
     return { c.hue, c.whiteness, c.blackness, c.alpha };
 }
 
+template<typename ColorType> inline constexpr bool IsHWBA = std::is_same_v<HWBA<typename ColorType::ComponentType>, ColorType>;
+
 // MARK: - XYZ Color Type.
 
 template<typename T, WhitePoint W> struct XYZA : ColorWithAlphaHelper<XYZA<T, W>> {
@@ -530,6 +564,7 @@
     return { c.x, c.y, c.z, c.alpha };
 }
 
+template<typename ColorType> inline constexpr bool IsXYZA = std::is_same_v<XYZA<typename ColorType::ComponentType, ColorType::whitePoint>, ColorType>;
 
 // Packed Color Formats
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to