Title: [272146] trunk/Source/WebCore
Revision
272146
Author
[email protected]
Date
2021-02-01 09:50:06 -0800 (Mon, 01 Feb 2021)

Log Message

Avoid unnecessary chromatic adaptation when converting between colors with the same white point
https://bugs.webkit.org/show_bug.cgi?id=221193

Reviewed by Simon Fraser.

Delay chromatic adapation, which is implemented as the conversion from a color in the XYZ color
space with one white point to a color in the XYZ color space with another white point, until
it is actually needed, rather than eagerly converting colors that use a D50 white point (just
Lab, LCH and ProPhotoRGB at the moment) to D65 for every conversion.

To do this, we introduce a new template parameter for the XYZA color to explicitly annotate
what white point it has, and further annotate all color types with which XYZ color matches
their defined white point. Then, in the generic color conversion functions, we apply chromatic
adaptation if needed by comparing the input and output white points of the types (at compile
time) and doing the conversion only when necessary.

This allows us to remove the explicit chromatic adapatations in the LinearProPhotoRGB matrix
conversions as well as the Lab conversions.

* platform/graphics/ColorConversion.cpp:
* platform/graphics/ColorConversion.h:
* platform/graphics/ColorTypes.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (272145 => 272146)


--- trunk/Source/WebCore/ChangeLog	2021-02-01 17:24:41 UTC (rev 272145)
+++ trunk/Source/WebCore/ChangeLog	2021-02-01 17:50:06 UTC (rev 272146)
@@ -1,3 +1,28 @@
+2021-02-01  Sam Weinig  <[email protected]>
+
+        Avoid unnecessary chromatic adaptation when converting between colors with the same white point
+        https://bugs.webkit.org/show_bug.cgi?id=221193
+
+        Reviewed by Simon Fraser.
+
+        Delay chromatic adapation, which is implemented as the conversion from a color in the XYZ color
+        space with one white point to a color in the XYZ color space with another white point, until
+        it is actually needed, rather than eagerly converting colors that use a D50 white point (just 
+        Lab, LCH and ProPhotoRGB at the moment) to D65 for every conversion.
+
+        To do this, we introduce a new template parameter for the XYZA color to explicitly annotate
+        what white point it has, and further annotate all color types with which XYZ color matches
+        their defined white point. Then, in the generic color conversion functions, we apply chromatic
+        adaptation if needed by comparing the input and output white points of the types (at compile 
+        time) and doing the conversion only when necessary.
+        
+        This allows us to remove the explicit chromatic adapatations in the LinearProPhotoRGB matrix
+        conversions as well as the Lab conversions.
+
+        * platform/graphics/ColorConversion.cpp:
+        * platform/graphics/ColorConversion.h:
+        * platform/graphics/ColorTypes.h:
+
 2021-02-01  Antti Koivisto  <[email protected]>
 
         [LFC][Integration] Fix editing/execCommand/primitive-value.html

Modified: trunk/Source/WebCore/platform/graphics/ColorConversion.cpp (272145 => 272146)


--- trunk/Source/WebCore/platform/graphics/ColorConversion.cpp	2021-02-01 17:24:41 UTC (rev 272145)
+++ trunk/Source/WebCore/platform/graphics/ColorConversion.cpp	2021-02-01 17:50:06 UTC (rev 272146)
@@ -133,14 +133,14 @@
 
 // MARK: Chromatic Adaptation conversions.
 
-static XYZA<float> convertFromD50WhitePointToD65WhitePoint(const XYZA<float>& color)
+XYZA<float, WhitePoint::D65> convertFromD50WhitePointToD65WhitePoint(const XYZA<float, WhitePoint::D50>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(D50ToD65Matrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<XYZA<float, WhitePoint::D65>>(D50ToD65Matrix.transformedColorComponents(asColorComponents(color)));
 }
 
-static XYZA<float> convertFromD65WhitePointToD50WhitePoint(const XYZA<float>& color)
+XYZA<float, WhitePoint::D50> convertFromD65WhitePointToD50WhitePoint(const XYZA<float, WhitePoint::D65>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(D65ToD50Matrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<XYZA<float, WhitePoint::D50>>(D65ToD50Matrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // MARK: Gamma conversions.
@@ -233,83 +233,74 @@
 
 // - LinearA98RGB matrix conversions.
 
-LinearA98RGB<float> toLinearA98RGB(const XYZA<float>& color)
+LinearA98RGB<float> toLinearA98RGB(const LinearA98RGB<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearA98RGB<float>>(xyzToLinearA98RGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-XYZA<float> toXYZA(const LinearA98RGB<float>& color)
+LinearA98RGB<float>::ReferenceXYZ toXYZA(const LinearA98RGB<float>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(linearA98RGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<LinearA98RGB<float>::ReferenceXYZ>(linearA98RGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // - LinearDisplayP3 matrix conversions.
 
-LinearDisplayP3<float> toLinearDisplayP3(const XYZA<float>& color)
+LinearDisplayP3<float> toLinearDisplayP3(const LinearDisplayP3<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearDisplayP3<float>>(xyzToLinearDisplayP3Matrix.transformedColorComponents(asColorComponents(color)));
 }
 
-XYZA<float> toXYZA(const LinearDisplayP3<float>& color)
+LinearDisplayP3<float>::ReferenceXYZ toXYZA(const LinearDisplayP3<float>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(linearDisplayP3ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<LinearDisplayP3<float>::ReferenceXYZ>(linearDisplayP3ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // - LinearExtendedSRGBA matrix conversions.
 
-LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const XYZA<float>& color)
+LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const LinearExtendedSRGBA<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearExtendedSRGBA<float>>(xyzToLinearSRGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-XYZA<float> toXYZA(const LinearExtendedSRGBA<float>& color)
+LinearExtendedSRGBA<float>::ReferenceXYZ toXYZA(const LinearExtendedSRGBA<float>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<LinearExtendedSRGBA<float>::ReferenceXYZ>(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // - LinearProPhotoRGB matrix conversions.
 
-LinearProPhotoRGB<float> toLinearProPhotoRGB(const XYZA<float>& color)
+LinearProPhotoRGB<float> toLinearProPhotoRGB(const LinearProPhotoRGB<float>::ReferenceXYZ& color)
 {
-    // We expect XYZA colors to be using the D65 white point, unlike ProPhotoRGB, which
-    // uses a D50 white point, so as a first step, use the Bradford transform to convert
-    // the incoming XYZA color to D50 white point.
-    auto xyzWithD50WhitePoint = convertFromD65WhitePointToD50WhitePoint(color);
-    return makeFromComponentsClampingExceptAlpha<LinearProPhotoRGB<float>>(xyzToLinearProPhotoRGBMatrix.transformedColorComponents(asColorComponents(xyzWithD50WhitePoint)));
+    return makeFromComponentsClampingExceptAlpha<LinearProPhotoRGB<float>>(xyzToLinearProPhotoRGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-XYZA<float> toXYZA(const LinearProPhotoRGB<float>& color)
+LinearProPhotoRGB<float>::ReferenceXYZ toXYZA(const LinearProPhotoRGB<float>& color)
 {
-    auto xyzWithD50WhitePoint = makeFromComponentsClampingExceptAlpha<XYZA<float>>(linearProPhotoRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
-
-    // We expect XYZA colors to be using the D65 white point, unlike ProPhotoRGB, which
-    // uses a D50 white point, so as a final step, use the Bradford transform to convert
-    // the resulting XYZA color to a D65 white point.
-    return convertFromD50WhitePointToD65WhitePoint(xyzWithD50WhitePoint);
+    return makeFromComponentsClampingExceptAlpha<LinearProPhotoRGB<float>::ReferenceXYZ>(linearProPhotoRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // - LinearRec2020 matrix conversions.
 
-LinearRec2020<float> toLinearRec2020(const XYZA<float>& color)
+LinearRec2020<float> toLinearRec2020(const LinearRec2020<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearRec2020<float>>(xyzToLinearRec2020Matrix.transformedColorComponents(asColorComponents(color)));
 }
 
-XYZA<float> toXYZA(const LinearRec2020<float>& color)
+LinearRec2020<float>::ReferenceXYZ toXYZA(const LinearRec2020<float>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(linearRec2020ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<LinearRec2020<float>::ReferenceXYZ>(linearRec2020ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // - LinearSRGBA matrix conversions.
 
-LinearSRGBA<float> toLinearSRGBA(const XYZA<float>& color)
+LinearSRGBA<float> toLinearSRGBA(const LinearSRGBA<float>::ReferenceXYZ& color)
 {
     return makeFromComponentsClampingExceptAlpha<LinearSRGBA<float>>(xyzToLinearSRGBMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
-XYZA<float> toXYZA(const LinearSRGBA<float>& color)
+LinearSRGBA<float>::ReferenceXYZ toXYZA(const LinearSRGBA<float>& color)
 {
-    return makeFromComponentsClampingExceptAlpha<XYZA<float>>(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
+    return makeFromComponentsClampingExceptAlpha<LinearSRGBA<float>::ReferenceXYZ>(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
 }
 
 // MARK: HSL conversions.
@@ -405,7 +396,7 @@
 static constexpr float LABk = 24389.0f / 27.0f;
 static constexpr float D50WhiteValues[] = { 0.96422f, 1.0f, 0.82521f };
 
-XYZA<float> toXYZA(const Lab<float>& color)
+Lab<float>::ReferenceXYZ toXYZA(const Lab<float>& color)
 {
     float f1 = (color.lightness + 16.0f) / 116.0f;
     float f0 = f1 + (color.a / 500.0f);
@@ -432,25 +423,15 @@
     float y = D50WhiteValues[1] * computeY(color.lightness);
     float z = D50WhiteValues[2] * computeXAndZ(f2);
 
-    XYZA<float> result { x, y, z, color.alpha };
-
-    // We expect XYZA colors to be using the D65 white point, unlike Lab, which uses a
-    // D50 white point, so as a final step, use the Bradford transform to convert the
-    // resulting XYZA color to a D65 white point.
-    return convertFromD50WhitePointToD65WhitePoint(result);
+    return { x, y, z, color.alpha };
 }
 
-Lab<float> toLab(const XYZA<float>& color)
+Lab<float> toLab(const Lab<float>::ReferenceXYZ& color)
 {
-    // We expect XYZA colors to be using the D65 white point, unlike Lab, which uses a
-    // D50 white point, so as a first step, use the Bradford transform to convert the
-    // incoming XYZA color to D50 white point.
-    auto colorWithD50WhitePoint = convertFromD65WhitePointToD50WhitePoint(color);
+    float x = color.x / D50WhiteValues[0];
+    float y = color.y / D50WhiteValues[1];
+    float z = color.z / D50WhiteValues[2];
 
-    float x = colorWithD50WhitePoint.x / D50WhiteValues[0];
-    float y = colorWithD50WhitePoint.y / D50WhiteValues[1];
-    float z = colorWithD50WhitePoint.z / D50WhiteValues[2];
-
     auto fTransform = [](float value) {
         return value > LABe ? std::cbrt(value) : (LABk * value + 16.0f) / 116.0f;
     };
@@ -463,7 +444,7 @@
     float a = 500.0f * (f0 - f1);
     float b = 200.0f * (f1 - f2);
 
-    return { lightness, a, b, colorWithD50WhitePoint.alpha };
+    return { lightness, a, b, color.alpha };
 }
 
 
@@ -499,12 +480,12 @@
 
 // - A98RGB combination functions.
 
-XYZA<float> toXYZA(const A98RGB<float>& color)
+A98RGB<float>::ReferenceXYZ toXYZA(const A98RGB<float>& color)
 {
     return toXYZA(toLinearA98RGB(color));
 }
 
-A98RGB<float> toA98RGB(const XYZA<float>& color)
+A98RGB<float> toA98RGB(const A98RGB<float>::ReferenceXYZ& color)
 {
     return toA98RGB(toLinearA98RGB(color));
 }
@@ -511,12 +492,12 @@
 
 // - DisplayP3 combination functions.
 
-XYZA<float> toXYZA(const DisplayP3<float>& color)
+DisplayP3<float>::ReferenceXYZ toXYZA(const DisplayP3<float>& color)
 {
     return toXYZA(toLinearDisplayP3(color));
 }
 
-DisplayP3<float> toDisplayP3(const XYZA<float>& color)
+DisplayP3<float> toDisplayP3(const DisplayP3<float>::ReferenceXYZ& color)
 {
     return toDisplayP3(toLinearDisplayP3(color));
 }
@@ -523,12 +504,12 @@
 
 // - ExtendedSRGB combination functions.
 
-XYZA<float> toXYZA(const ExtendedSRGBA<float>& color)
+ExtendedSRGBA<float>::ReferenceXYZ toXYZA(const ExtendedSRGBA<float>& color)
 {
     return toXYZA(toLinearExtendedSRGBA(color));
 }
 
-ExtendedSRGBA<float> toExtendedSRGBA(const XYZA<float>& color)
+ExtendedSRGBA<float> toExtendedSRGBA(const ExtendedSRGBA<float>::ReferenceXYZ& color)
 {
     return toExtendedSRGBA(toLinearExtendedSRGBA(color));
 }
@@ -535,12 +516,12 @@
 
 // - HSLA combination functions.
 
-XYZA<float> toXYZA(const HSLA<float>& color)
+HSLA<float>::ReferenceXYZ toXYZA(const HSLA<float>& color)
 {
     return toXYZA(toSRGBA(color));
 }
 
-HSLA<float> toHSLA(const XYZA<float>& color)
+HSLA<float> toHSLA(const HSLA<float>::ReferenceXYZ& color)
 {
     return toHSLA(toSRGBA(color));
 }
@@ -547,12 +528,12 @@
 
 // - LCHA combination functions.
 
-XYZA<float> toXYZA(const LCHA<float>& color)
+LCHA<float>::ReferenceXYZ toXYZA(const LCHA<float>& color)
 {
     return toXYZA(toLab(color));
 }
 
-LCHA<float> toLCHA(const XYZA<float>& color)
+LCHA<float> toLCHA(const LCHA<float>::ReferenceXYZ& color)
 {
     return toLCHA(toLab(color));
 }
@@ -559,12 +540,12 @@
 
 // - ProPhotoRGB combination functions.
 
-XYZA<float> toXYZA(const ProPhotoRGB<float>& color)
+ProPhotoRGB<float>::ReferenceXYZ toXYZA(const ProPhotoRGB<float>& color)
 {
     return toXYZA(toLinearProPhotoRGB(color));
 }
 
-ProPhotoRGB<float> toProPhotoRGB(const XYZA<float>& color)
+ProPhotoRGB<float> toProPhotoRGB(const ProPhotoRGB<float>::ReferenceXYZ& color)
 {
     return toProPhotoRGB(toLinearProPhotoRGB(color));
 }
@@ -571,12 +552,12 @@
 
 // - Rec2020 combination functions.
 
-XYZA<float> toXYZA(const Rec2020<float>& color)
+Rec2020<float>::ReferenceXYZ toXYZA(const Rec2020<float>& color)
 {
     return toXYZA(toLinearRec2020(color));
 }
 
-Rec2020<float> toRec2020(const XYZA<float>& color)
+Rec2020<float> toRec2020(const Rec2020<float>::ReferenceXYZ& color)
 {
     return toRec2020(toLinearRec2020(color));
 }
@@ -583,12 +564,12 @@
 
 // - SRGB combination functions.
 
-XYZA<float> toXYZA(const SRGBA<float>& color)
+SRGBA<float>::ReferenceXYZ toXYZA(const SRGBA<float>& color)
 {
     return toXYZA(toLinearSRGBA(color));
 }
 
-SRGBA<float> toSRGBA(const XYZA<float>& color)
+SRGBA<float> toSRGBA(const SRGBA<float>::ReferenceXYZ& color)
 {
     return toSRGBA(toLinearSRGBA(color));
 }

Modified: trunk/Source/WebCore/platform/graphics/ColorConversion.h (272145 => 272146)


--- trunk/Source/WebCore/platform/graphics/ColorConversion.h	2021-02-01 17:24:41 UTC (rev 272145)
+++ trunk/Source/WebCore/platform/graphics/ColorConversion.h	2021-02-01 17:50:06 UTC (rev 272146)
@@ -29,16 +29,17 @@
 
 namespace WebCore {
 
-// All color types must at least implement the following conversions to and from the XYZA color space
+// All color types must at least implement the following conversions to and from their reference XYZ color space
 //
-//    XYZA<float> toXYZA(const `ColorType`<float>&);
-//    `ColorType`<float> to`ColorType`(const XYZA<float>&);
+//    `ColorType`<float>::ReferenceXYZ toXYZA(const `ColorType`<float>&);
+//    `ColorType`<float> to`ColorType`(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 the XYZ color space
+// 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)
 //
@@ -47,97 +48,114 @@
 
 
 // A98RGB
-WEBCORE_EXPORT XYZA<float> toXYZA(const A98RGB<float>&);
-WEBCORE_EXPORT A98RGB<float> toA98RGB(const XYZA<float>&);
+WEBCORE_EXPORT A98RGB<float>::ReferenceXYZ toXYZA(const A98RGB<float>&);
+WEBCORE_EXPORT A98RGB<float> toA98RGB(const A98RGB<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LinearA98RGB<float> toLinearA98RGB(const A98RGB<float>&);
 
 // DisplayP3
-WEBCORE_EXPORT XYZA<float> toXYZA(const DisplayP3<float>&);
-WEBCORE_EXPORT DisplayP3<float> toDisplayP3(const XYZA<float>&);
+WEBCORE_EXPORT DisplayP3<float>::ReferenceXYZ toXYZA(const DisplayP3<float>&);
+WEBCORE_EXPORT DisplayP3<float> toDisplayP3(const DisplayP3<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LinearDisplayP3<float> toLinearDisplayP3(const DisplayP3<float>&);
 
 // ExtendedSRGBA
-WEBCORE_EXPORT XYZA<float> toXYZA(const ExtendedSRGBA<float>&);
-WEBCORE_EXPORT ExtendedSRGBA<float> toExtendedSRGBA(const XYZA<float>&);
+WEBCORE_EXPORT ExtendedSRGBA<float>::ReferenceXYZ toXYZA(const ExtendedSRGBA<float>&);
+WEBCORE_EXPORT ExtendedSRGBA<float> toExtendedSRGBA(const ExtendedSRGBA<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const ExtendedSRGBA<float>&);
 
 // HSLA
-WEBCORE_EXPORT XYZA<float> toXYZA(const HSLA<float>&);
-WEBCORE_EXPORT HSLA<float> toHSLA(const XYZA<float>&);
+WEBCORE_EXPORT HSLA<float>::ReferenceXYZ toXYZA(const HSLA<float>&);
+WEBCORE_EXPORT HSLA<float> toHSLA(const HSLA<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT SRGBA<float> toSRGBA(const HSLA<float>&);
 
 // LCHA
-WEBCORE_EXPORT XYZA<float> toXYZA(const LCHA<float>&);
-WEBCORE_EXPORT LCHA<float> toLCHA(const XYZA<float>&);
+WEBCORE_EXPORT LCHA<float>::ReferenceXYZ toXYZA(const LCHA<float>&);
+WEBCORE_EXPORT LCHA<float> toLCHA(const LCHA<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT Lab<float> toLab(const LCHA<float>&);
 
 // Lab
-WEBCORE_EXPORT XYZA<float> toXYZA(const Lab<float>&);
-WEBCORE_EXPORT Lab<float> toLab(const XYZA<float>&);
+WEBCORE_EXPORT Lab<float>::ReferenceXYZ toXYZA(const Lab<float>&);
+WEBCORE_EXPORT Lab<float> toLab(const Lab<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LCHA<float> toLCHA(const Lab<float>&);
 
 // LinearA98RGB
-WEBCORE_EXPORT XYZA<float> toXYZA(const LinearA98RGB<float>&);
-WEBCORE_EXPORT LinearA98RGB<float> toLinearA98RGB(const XYZA<float>&);
+WEBCORE_EXPORT LinearA98RGB<float>::ReferenceXYZ toXYZA(const LinearA98RGB<float>&);
+WEBCORE_EXPORT LinearA98RGB<float> toLinearA98RGB(const LinearA98RGB<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT A98RGB<float> toA98RGB(const LinearA98RGB<float>& color);
 
 // LinearDisplayP3
-WEBCORE_EXPORT XYZA<float> toXYZA(const LinearDisplayP3<float>&);
-WEBCORE_EXPORT LinearDisplayP3<float> toLinearDisplayP3(const XYZA<float>&);
+WEBCORE_EXPORT LinearDisplayP3<float>::ReferenceXYZ toXYZA(const LinearDisplayP3<float>&);
+WEBCORE_EXPORT LinearDisplayP3<float> toLinearDisplayP3(const LinearDisplayP3<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT DisplayP3<float> toDisplayP3(const LinearDisplayP3<float>&);
 
 // LinearExtendedSRGBA
-WEBCORE_EXPORT XYZA<float> toXYZA(const LinearExtendedSRGBA<float>&);
-WEBCORE_EXPORT LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const XYZA<float>&);
+WEBCORE_EXPORT LinearExtendedSRGBA<float>::ReferenceXYZ toXYZA(const LinearExtendedSRGBA<float>&);
+WEBCORE_EXPORT LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const LinearExtendedSRGBA<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT ExtendedSRGBA<float> toExtendedSRGBA(const LinearExtendedSRGBA<float>&);
 
 // LinearProPhotoRGB
-WEBCORE_EXPORT XYZA<float> toXYZA(const LinearProPhotoRGB<float>&);
-WEBCORE_EXPORT LinearProPhotoRGB<float> toLinearProPhotoRGB(const XYZA<float>&);
+WEBCORE_EXPORT LinearProPhotoRGB<float>::ReferenceXYZ toXYZA(const LinearProPhotoRGB<float>&);
+WEBCORE_EXPORT LinearProPhotoRGB<float> toLinearProPhotoRGB(const LinearProPhotoRGB<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT ProPhotoRGB<float> toProPhotoRGB(const LinearProPhotoRGB<float>&);
 
 // LinearRec2020
-WEBCORE_EXPORT XYZA<float> toXYZA(const LinearRec2020<float>&);
-WEBCORE_EXPORT LinearRec2020<float> toLinearRec2020(const XYZA<float>&);
+WEBCORE_EXPORT LinearRec2020<float>::ReferenceXYZ toXYZA(const LinearRec2020<float>&);
+WEBCORE_EXPORT LinearRec2020<float> toLinearRec2020(const LinearRec2020<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT Rec2020<float> toRec2020(const LinearRec2020<float>&);
 
 // LinearSRGBA
-WEBCORE_EXPORT XYZA<float> toXYZA(const LinearSRGBA<float>&);
-WEBCORE_EXPORT LinearSRGBA<float> toLinearSRGBA(const XYZA<float>&);
+WEBCORE_EXPORT LinearSRGBA<float>::ReferenceXYZ toXYZA(const LinearSRGBA<float>&);
+WEBCORE_EXPORT LinearSRGBA<float> toLinearSRGBA(const LinearSRGBA<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT SRGBA<float> toSRGBA(const LinearSRGBA<float>&);
 
 // ProPhotoRGB
-WEBCORE_EXPORT XYZA<float> toXYZA(const ProPhotoRGB<float>&);
-WEBCORE_EXPORT ProPhotoRGB<float> toProPhotoRGB(const XYZA<float>&);
+WEBCORE_EXPORT ProPhotoRGB<float>::ReferenceXYZ toXYZA(const ProPhotoRGB<float>&);
+WEBCORE_EXPORT ProPhotoRGB<float> toProPhotoRGB(const ProPhotoRGB<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LinearProPhotoRGB<float> toLinearProPhotoRGB(const ProPhotoRGB<float>&);
 
 // Rec2020
-WEBCORE_EXPORT XYZA<float> toXYZA(const Rec2020<float>&);
-WEBCORE_EXPORT Rec2020<float> toRec2020(const XYZA<float>&);
+WEBCORE_EXPORT Rec2020<float>::ReferenceXYZ toXYZA(const Rec2020<float>&);
+WEBCORE_EXPORT Rec2020<float> toRec2020(const Rec2020<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LinearRec2020<float> toLinearRec2020(const Rec2020<float>&);
 
 // SRGBA
-WEBCORE_EXPORT XYZA<float> toXYZA(const SRGBA<float>&);
-WEBCORE_EXPORT SRGBA<float> toSRGBA(const XYZA<float>&);
+WEBCORE_EXPORT SRGBA<float>::ReferenceXYZ toXYZA(const SRGBA<float>&);
+WEBCORE_EXPORT SRGBA<float> toSRGBA(const SRGBA<float>::ReferenceXYZ&);
 // Additions
 WEBCORE_EXPORT LinearSRGBA<float> toLinearSRGBA(const SRGBA<float>&);
 WEBCORE_EXPORT HSLA<float> toHSLA(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>&);
+
+template<typename T, WhitePoint inputWhitePoint> constexpr typename T::ReferenceXYZ performChomaticAdapatation(const XYZA<float, inputWhitePoint>& color)
+{
+    constexpr WhitePoint outputWhitePoint = T::ReferenceXYZ::whitePoint;
+
+    if constexpr (outputWhitePoint == inputWhitePoint)
+        return color;
+    else if constexpr (outputWhitePoint == WhitePoint::D50)
+        return convertFromD65WhitePointToD50WhitePoint(color);
+    else if constexpr (outputWhitePoint == WhitePoint::D65)
+        return convertFromD50WhitePointToD65WhitePoint(color);
+}
+
+
 // Identity conversions (useful for generic contexts).
 
 constexpr A98RGB<float> toA98RGB(const A98RGB<float>& color) { return color; }
@@ -155,87 +173,87 @@
 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; }
-constexpr XYZA<float> toXYZA(const XYZA<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 XYZA, 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 these are guaranteed
+// to work if another overload is not already provided.
 
 template<typename T> A98RGB<float> toA98RGB(const T& color)
 {
-    return toA98RGB(toXYZA(color));
+    return toA98RGB(performChomaticAdapatation<A98RGB<float>>(toXYZA(color)));
 }
 
 template<typename T> DisplayP3<float> toDisplayP3(const T& color)
 {
-    return toDisplayP3(toXYZA(color));
+    return toDisplayP3(performChomaticAdapatation<DisplayP3<float>>(toXYZA(color)));
 }
 
 template<typename T> ExtendedSRGBA<float> toExtendedSRGBA(const T& color)
 {
-    return toExtendedSRGBA(toXYZA(color));
+    return toExtendedSRGBA(performChomaticAdapatation<ExtendedSRGBA<float>>(toXYZA(color)));
 }
 
 template<typename T> HSLA<float> toHSLA(const T& color)
 {
-    return toHSLA(toXYZA(color));
+    return toHSLA(performChomaticAdapatation<HSLA<float>>(toXYZA(color)));
 }
 
 template<typename T> LCHA<float> toLCHA(const T& color)
 {
-    return toLCHA(toXYZA(color));
+    return toLCHA(performChomaticAdapatation<LCHA<float>>(toXYZA(color)));
 }
 
 template<typename T> Lab<float> toLab(const T& color)
 {
-    return toLab(toXYZA(color));
+    return toLab(performChomaticAdapatation<Lab<float>>(toXYZA(color)));
 }
 
 template<typename T> LinearA98RGB<float> toLinearA98RGB(const T& color)
 {
-    return toLinearA98RGB(toXYZA(color));
+    return toLinearA98RGB(performChomaticAdapatation<LinearA98RGB<float>>(toXYZA(color)));
 }
 
 template<typename T> LinearDisplayP3<float> toLinearDisplayP3(const T& color)
 {
-    return toLinearDisplayP3(toXYZA(color));
+    return toLinearDisplayP3(performChomaticAdapatation<LinearDisplayP3<float>>(toXYZA(color)));
 }
 
 template<typename T> LinearExtendedSRGBA<float> toLinearExtendedSRGBA(const T& color)
 {
-    return toLinearExtendedSRGBA(toXYZA(color));
+    return toLinearExtendedSRGBA(performChomaticAdapatation<LinearExtendedSRGBA<float>>(toXYZA(color)));
 }
 
 template<typename T> LinearProPhotoRGB<float> toLinearProPhotoRGB(const T& color)
 {
-    return toLinearProPhotoRGB(toXYZA(color));
+    return toLinearProPhotoRGB(performChomaticAdapatation<LinearProPhotoRGB<float>>(toXYZA(color)));
 }
 
 template<typename T> LinearRec2020<float> toLinearRec2020(const T& color)
 {
-    return toLinearRec2020(toXYZA(color));
+    return toLinearRec2020(performChomaticAdapatation<LinearRec2020<float>>(toXYZA(color)));
 }
 
 template<typename T> LinearSRGBA<float> toLinearSRGBA(const T& color)
 {
-    return toLinearSRGBA(toXYZA(color));
+    return toLinearSRGBA(performChomaticAdapatation<LinearSRGBA<float>>(toXYZA(color)));
 }
 
 template<typename T> ProPhotoRGB<float> toProPhotoRGB(const T& color)
 {
-    return toProPhotoRGB(toXYZA(color));
+    return toProPhotoRGB(performChomaticAdapatation<ProPhotoRGB<float>>(toXYZA(color)));
 }
 
 template<typename T> Rec2020<float> toRec2020(const T& color)
 {
-    return toRec2020(toXYZA(color));
+    return toRec2020(performChomaticAdapatation<Rec2020<float>>(toXYZA(color)));
 }
 
 template<typename T> SRGBA<float> toSRGBA(const T& color)
 {
-    return toSRGBA(toXYZA(color));
+    return toSRGBA(performChomaticAdapatation<SRGBA<float>>(toXYZA(color)));
 }
 
 

Modified: trunk/Source/WebCore/platform/graphics/ColorTypes.h (272145 => 272146)


--- trunk/Source/WebCore/platform/graphics/ColorTypes.h	2021-02-01 17:24:41 UTC (rev 272145)
+++ trunk/Source/WebCore/platform/graphics/ColorTypes.h	2021-02-01 17:50:06 UTC (rev 272146)
@@ -31,6 +31,8 @@
 
 namespace WebCore {
 
+enum class WhitePoint { D50, D65 };
+
 template<typename> struct A98RGB;
 template<typename> struct DisplayP3;
 template<typename> struct ExtendedSRGBA;
@@ -46,7 +48,7 @@
 template<typename> struct ProPhotoRGB;
 template<typename> struct Rec2020;
 template<typename> struct SRGBA;
-template<typename> struct XYZA;
+template<typename, WhitePoint> struct XYZA;
 
 // MARK: Make functions.
 
@@ -225,6 +227,7 @@
 template<typename T> struct A98RGB : RGBAType<A98RGB, T, RGBModel<T>> {
     using RGBAType<A98RGB, T, RGBModel<T>>::RGBAType;
     using LinearCounterpart = LinearA98RGB<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
     static constexpr auto colorSpace = ColorSpace::A98RGB;
 };
 template<typename T> A98RGB(T, T, T, T) -> A98RGB<T>;
@@ -232,6 +235,7 @@
 template<typename T> struct DisplayP3 : RGBAType<DisplayP3, T, RGBModel<T>> {
     using RGBAType<DisplayP3, T, RGBModel<T>>::RGBAType;
     using LinearCounterpart = LinearDisplayP3<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
     static constexpr auto colorSpace = ColorSpace::DisplayP3;
 };
 template<typename T> DisplayP3(T, T, T, T) -> DisplayP3<T>;
@@ -239,6 +243,7 @@
 template<typename T> struct ExtendedSRGBA : RGBAType<ExtendedSRGBA, T, ExtendedRGBModel<T>> {
     using RGBAType<ExtendedSRGBA, T, ExtendedRGBModel<T>>::RGBAType;
     using LinearCounterpart = LinearExtendedSRGBA<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
 };
 template<typename T> ExtendedSRGBA(T, T, T, T) -> ExtendedSRGBA<T>;
 
@@ -245,6 +250,7 @@
 template<typename T> struct LinearA98RGB : RGBAType<LinearA98RGB, T, RGBModel<T>> {
     using RGBAType<LinearA98RGB, T, RGBModel<T>>::RGBAType;
     using GammaEncodedCounterpart = A98RGB<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
 };
 template<typename T> LinearA98RGB(T, T, T, T) -> LinearA98RGB<T>;
 
@@ -251,6 +257,7 @@
 template<typename T> struct LinearDisplayP3 : RGBAType<LinearDisplayP3, T, RGBModel<T>> {
     using RGBAType<LinearDisplayP3, T, RGBModel<T>>::RGBAType;
     using GammaEncodedCounterpart = DisplayP3<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
 };
 template<typename T> LinearDisplayP3(T, T, T, T) -> LinearDisplayP3<T>;
 
@@ -257,6 +264,7 @@
 template<typename T> struct LinearExtendedSRGBA : RGBAType<LinearExtendedSRGBA, T, ExtendedRGBModel<T>> {
     using RGBAType<LinearExtendedSRGBA, T, ExtendedRGBModel<T>>::RGBAType;
     using GammaEncodedCounterpart = ExtendedSRGBA<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
 };
 template<typename T> LinearExtendedSRGBA(T, T, T, T) -> LinearExtendedSRGBA<T>;
 
@@ -263,6 +271,7 @@
 template<typename T> struct LinearProPhotoRGB : RGBAType<LinearProPhotoRGB, T, RGBModel<T>> {
     using RGBAType<LinearProPhotoRGB, T, RGBModel<T>>::RGBAType;
     using GammaEncodedCounterpart = ProPhotoRGB<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D50>;
 };
 template<typename T> LinearProPhotoRGB(T, T, T, T) -> LinearProPhotoRGB<T>;
 
@@ -269,6 +278,7 @@
 template<typename T> struct LinearRec2020 : RGBAType<LinearRec2020, T, RGBModel<T>> {
     using RGBAType<LinearRec2020, T, RGBModel<T>>::RGBAType;
     using GammaEncodedCounterpart = Rec2020<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
 };
 template<typename T> LinearRec2020(T, T, T, T) -> LinearRec2020<T>;
 
@@ -275,6 +285,7 @@
 template<typename T> struct LinearSRGBA : RGBAType<LinearSRGBA, T, RGBModel<T>> {
     using RGBAType<LinearSRGBA, T, RGBModel<T>>::RGBAType;
     using GammaEncodedCounterpart = SRGBA<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
     static constexpr auto colorSpace = ColorSpace::LinearRGB;
 };
 template<typename T> LinearSRGBA(T, T, T, T) -> LinearSRGBA<T>;
@@ -282,6 +293,7 @@
 template<typename T> struct ProPhotoRGB : RGBAType<ProPhotoRGB, T, RGBModel<T>> {
     using RGBAType<ProPhotoRGB, T, RGBModel<T>>::RGBAType;
     using LinearCounterpart = LinearProPhotoRGB<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D50>;
     static constexpr auto colorSpace = ColorSpace::ProPhotoRGB;
 };
 template<typename T> ProPhotoRGB(T, T, T, T) -> ProPhotoRGB<T>;
@@ -289,6 +301,7 @@
 template<typename T> struct Rec2020 : RGBAType<Rec2020, T, RGBModel<T>> {
     using RGBAType<Rec2020, T, RGBModel<T>>::RGBAType;
     using LinearCounterpart = LinearRec2020<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
     static constexpr auto colorSpace { ColorSpace::Rec2020 };
 };
 template<typename T> Rec2020(T, T, T, T) -> Rec2020<T>;
@@ -296,6 +309,7 @@
 template<typename T> struct SRGBA : RGBAType<SRGBA, T, RGBModel<T>> {
     using RGBAType<SRGBA, T, RGBModel<T>>::RGBAType;
     using LinearCounterpart = LinearSRGBA<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
     static constexpr auto colorSpace { ColorSpace::SRGB };
 };
 template<typename T> SRGBA(T, T, T, T) -> SRGBA<T>;
@@ -305,6 +319,7 @@
 template<typename T> struct Lab : ColorWithAlphaHelper<Lab<T>> {
     using ComponentType = T;
     using Model = LabModel<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D50>;
     static constexpr auto colorSpace = ColorSpace::Lab;
 
     constexpr Lab(T lightness, T a, T b, T alpha = AlphaTraits<T>::opaque)
@@ -337,6 +352,7 @@
 template<typename T> struct LCHA : ColorWithAlphaHelper<LCHA<T>> {
     using ComponentType = T;
     using Model = LCHModel<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D50>;
 
     constexpr LCHA(T lightness, T chroma, T hue, T alpha = AlphaTraits<T>::opaque)
         : lightness { lightness }
@@ -369,6 +385,7 @@
 template<typename T> struct HSLA : ColorWithAlphaHelper<HSLA<T>> {
     using ComponentType = T;
     using Model = HSLModel<T>;
+    using ReferenceXYZ = XYZA<T, WhitePoint::D65>;
 
     constexpr HSLA(T hue, T saturation, T lightness, T alpha = AlphaTraits<T>::opaque)
         : hue { hue }
@@ -397,9 +414,11 @@
 
 // MARK: - XYZ Color Type.
 
-template<typename T> struct XYZA : ColorWithAlphaHelper<XYZA<T>> {
+template<typename T, WhitePoint W> struct XYZA : ColorWithAlphaHelper<XYZA<T, W>> {
     using ComponentType = T;
     using Model = XYZModel<T>;
+    using ReferenceXYZ = XYZA<T, W>;
+    static constexpr WhitePoint whitePoint = W;
 
     constexpr XYZA(T x, T y, T z, T alpha = AlphaTraits<T>::opaque)
         : x { x }
@@ -421,7 +440,7 @@
     T alpha;
 };
 
-template<typename T> constexpr ColorComponents<T> asColorComponents(const XYZA<T>& c)
+template<typename T, WhitePoint W> constexpr ColorComponents<T> asColorComponents(const XYZA<T, W>& c)
 {
     return { c.x, c.y, c.z, c.alpha };
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to