Changeset 261828 in webkit


Ignore:
Timestamp:
May 18, 2020 1:22:15 PM (4 years ago)
Author:
Simon Fraser
Message:

Implement conversion between P3 and sRGB color
https://bugs.webkit.org/show_bug.cgi?id=211998

Reviewed by Daniel Bates.
Source/WebCore:

Color::toSRGBAComponentsLossy() was a lie because it didn't actually convert extended
colors into sRGB. Fix that by converting P3 and linaerRGB colors into sRGB, using the color
math from CSS Color 4.

Renamed the various "linear to sRGB" functions because they work for any RGB colors,
not just sRGB.

  • platform/graphics/Color.cpp:

(WebCore::Color::toSRGBAComponentsLossy const):

  • platform/graphics/Color.h:
  • platform/graphics/ColorUtilities.cpp:

(WebCore::linearToRGBColorComponent):
(WebCore::RGBToLinearColorComponent):
(WebCore::sRGBColorToLinearComponents):
(WebCore::RGBToLinearComponents):
(WebCore::linearToRGBComponents):
(WebCore::XYZToLinearSRGB):
(WebCore::linearSRGBToXYZ):
(WebCore::XYZToLinearP3):
(WebCore::linearP3ToXYZ):
(WebCore::P3ToSRGB):
(WebCore::sRGBToP3):
(WebCore::ColorMatrix::transformedColorComponents const):
(WebCore::linearToSRGBColorComponent): Deleted.
(WebCore::sRGBToLinearColorComponent): Deleted.
(WebCore::sRGBToLinearComponents): Deleted.
(WebCore::linearToSRGBComponents): Deleted.

  • platform/graphics/ColorUtilities.h:

Tools:

API test for conversions from P3 to sRGB, and linearRGB to sRGB. Values were confirmed
as close to those provided by ColorSync Utility.

  • TestWebKitAPI/Tests/WebCore/ExtendedColorTests.cpp:

(TestWebKitAPI::TEST):

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r261825 r261828  
     12020-05-18  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Implement conversion between P3 and sRGB color
     4        https://bugs.webkit.org/show_bug.cgi?id=211998
     5
     6        Reviewed by Daniel Bates.
     7       
     8        Color::toSRGBAComponentsLossy() was a lie because it didn't actually convert extended
     9        colors into sRGB. Fix that by converting P3 and linaerRGB colors into sRGB, using the color
     10        math from CSS Color 4.
     11
     12        Renamed the various "linear to sRGB" functions because they work for any RGB colors,
     13        not just sRGB.
     14
     15        * platform/graphics/Color.cpp:
     16        (WebCore::Color::toSRGBAComponentsLossy const):
     17        * platform/graphics/Color.h:
     18        * platform/graphics/ColorUtilities.cpp:
     19        (WebCore::linearToRGBColorComponent):
     20        (WebCore::RGBToLinearColorComponent):
     21        (WebCore::sRGBColorToLinearComponents):
     22        (WebCore::RGBToLinearComponents):
     23        (WebCore::linearToRGBComponents):
     24        (WebCore::XYZToLinearSRGB):
     25        (WebCore::linearSRGBToXYZ):
     26        (WebCore::XYZToLinearP3):
     27        (WebCore::linearP3ToXYZ):
     28        (WebCore::P3ToSRGB):
     29        (WebCore::sRGBToP3):
     30        (WebCore::ColorMatrix::transformedColorComponents const):
     31        (WebCore::linearToSRGBColorComponent): Deleted.
     32        (WebCore::sRGBToLinearColorComponent): Deleted.
     33        (WebCore::sRGBToLinearComponents): Deleted.
     34        (WebCore::linearToSRGBComponents): Deleted.
     35        * platform/graphics/ColorUtilities.h:
     36
    1372020-05-18  Wenson Hsieh  <wenson_hsieh@apple.com>
    238
  • trunk/Source/WebCore/platform/graphics/Color.cpp

    r261794 r261828  
    8080{
    8181    const float scaleFactor = 255.0;
    82     FloatComponents floatResult = HSLToSRGB({ hue, saturation, lightness, alpha });
     82    FloatComponents floatResult = hslToSRGB({ hue, saturation, lightness, alpha });
    8383    return makeRGBA(
    8484        round(floatResult.components[0] * scaleFactor),
     
    562562        switch (extendedColor.colorSpace()) {
    563563        case ColorSpace::SRGB:
     564            return extendedColor.channels();
    564565        case ColorSpace::LinearRGB:
     566            return linearToRGBComponents(extendedColor.channels());
    565567        case ColorSpace::DisplayP3:
    566             // FIXME: This doesn't convert into sRGB and should.
    567             return extendedColor.channels();
     568            return p3ToSRGB(extendedColor.channels());
    568569        }
    569570    }
  • trunk/Source/WebCore/platform/graphics/Color.h

    r261794 r261828  
    212212    WEBCORE_EXPORT void getRGBA(float& r, float& g, float& b, float& a) const;
    213213    WEBCORE_EXPORT void getRGBA(double& r, double& g, double& b, double& a) const;
     214
    214215    WEBCORE_EXPORT void getHSL(double& h, double& s, double& l) const;
    215216    WEBCORE_EXPORT void getHSV(double& h, double& s, double& v) const;
    216217
    217218    // This will convert non-sRGB colorspace colors into sRGB.
    218     FloatComponents toSRGBAComponentsLossy() const;
     219    WEBCORE_EXPORT FloatComponents toSRGBAComponentsLossy() const;
    219220
    220221    Color light() const;
  • trunk/Source/WebCore/platform/graphics/ColorUtilities.cpp

    r261794 r261828  
    5454
    5555// These are the standard sRGB <-> linearRGB conversion functions (https://en.wikipedia.org/wiki/SRGB).
    56 float linearToSRGBColorComponent(float c)
     56float linearToRGBColorComponent(float c)
    5757{
    5858    if (c < 0.0031308f)
     
    6262}
    6363
    64 float sRGBToLinearColorComponent(float c)
     64float rgbToLinearColorComponent(float c)
    6565{
    6666    if (c <= 0.04045f)
     
    7575    color.getRGBA(r, g, b, a);
    7676    return {
    77         sRGBToLinearColorComponent(r),
    78         sRGBToLinearColorComponent(g),
    79         sRGBToLinearColorComponent(b),
     77        rgbToLinearColorComponent(r),
     78        rgbToLinearColorComponent(g),
     79        rgbToLinearColorComponent(b),
    8080        a
    8181    };
    8282}
    8383
    84 FloatComponents sRGBToLinearComponents(const FloatComponents& sRGBColor)
    85 {
    86     return {
    87         sRGBToLinearColorComponent(sRGBColor.components[0]),
    88         sRGBToLinearColorComponent(sRGBColor.components[1]),
    89         sRGBToLinearColorComponent(sRGBColor.components[2]),
    90         sRGBColor.components[3]
    91     };
    92 }
    93 
    94 FloatComponents linearToSRGBComponents(const FloatComponents& linearRGB)
    95 {
    96     return {
    97         linearToSRGBColorComponent(linearRGB.components[0]),
    98         linearToSRGBColorComponent(linearRGB.components[1]),
    99         linearToSRGBColorComponent(linearRGB.components[2]),
     84FloatComponents rgbToLinearComponents(const FloatComponents& RGBColor)
     85{
     86    return {
     87        rgbToLinearColorComponent(RGBColor.components[0]),
     88        rgbToLinearColorComponent(RGBColor.components[1]),
     89        rgbToLinearColorComponent(RGBColor.components[2]),
     90        RGBColor.components[3]
     91    };
     92}
     93
     94FloatComponents linearToRGBComponents(const FloatComponents& linearRGB)
     95{
     96    return {
     97        linearToRGBColorComponent(linearRGB.components[0]),
     98        linearToRGBColorComponent(linearRGB.components[1]),
     99        linearToRGBColorComponent(linearRGB.components[2]),
    100100        linearRGB.components[3]
    101101    };
     102}
     103
     104static FloatComponents xyzToLinearSRGB(const FloatComponents& XYZComponents)
     105{
     106    // https://en.wikipedia.org/wiki/SRGB
     107    // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
     108    const float values[] = {
     109         3.2404542f, -1.5371385f, -0.4985314f, 0.0f, 0.0f,
     110        -0.9692660f,  1.8760108f,  0.0415560f, 0.0f, 0.0f,
     111         0.0556434f, -0.2040259f,  1.0572252f, 0.0f, 0.0f,
     112         0.0f,        0.0f,        0.0f,       1.0f, 0.0f,
     113    };
     114    ColorMatrix xyzToLinearSRGBMatrix(values);
     115    return xyzToLinearSRGBMatrix.transformedColorComponents(XYZComponents);
     116}
     117
     118static FloatComponents linearSRGBToXYZ(const FloatComponents& XYZComponents)
     119{
     120    // https://en.wikipedia.org/wiki/SRGB
     121    // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
     122    const float values[] = {
     123        0.4124564f,  0.3575761f,  0.1804375f, 0.0f, 0.0f,
     124        0.2126729f,  0.7151522f,  0.0721750f, 0.0f, 0.0f,
     125        0.0193339f,  0.1191920f,  0.9503041f, 0.0f, 0.0f,
     126        0.0f,        0.0f,        0.0f,       1.0f, 0.0f,
     127    };
     128    ColorMatrix linearSRGBToXYZMatrix(values);
     129    return linearSRGBToXYZMatrix.transformedColorComponents(XYZComponents);
     130}
     131
     132static FloatComponents XYZToLinearP3(const FloatComponents& XYZComponents)
     133{
     134    // https://drafts.csswg.org/css-color/#color-conversion-code
     135    const float values[] = {
     136         2.493496911941425f,  -0.9313836179191239f, -0.4027107844507168f, 0.0f, 0.0f,
     137        -0.8294889695615747f,  1.7626640603183463f,  0.0236246858419436f, 0.0f, 0.0f,
     138         0.0358458302437845f, -0.0761723892680418f,  0.9568845240076872f, 0.0f, 0.0f,
     139         0.0f,                 0.0f,                 0.0f,                1.0f, 0.0f,
     140    };
     141    ColorMatrix xyzToLinearSRGBMatrix(values);
     142    return xyzToLinearSRGBMatrix.transformedColorComponents(XYZComponents);
     143}
     144
     145static FloatComponents linearP3ToXYZ(const FloatComponents& XYZComponents)
     146{
     147    // https://drafts.csswg.org/css-color/#color-conversion-code
     148    const float values[] = {
     149        0.4865709486482162f, 0.2656676931690931f, 0.198217285234363f, 0.0f, 0.0f,
     150        0.2289745640697488f, 0.6917385218365064f, 0.079286914093745f, 0.0f, 0.0f,
     151        0.0f,                0.0451133818589026f, 1.043944368900976f, 0.0f, 0.0f,
     152        0.0f,                0.0f,                0.0f,               1.0f, 0.0f,
     153    };
     154    ColorMatrix linearP3ToXYZMatrix(values);
     155    return linearP3ToXYZMatrix.transformedColorComponents(XYZComponents);
     156}
     157
     158FloatComponents p3ToSRGB(const FloatComponents& p3)
     159{
     160    auto linearP3 = rgbToLinearComponents(p3);
     161    auto xyz = linearP3ToXYZ(linearP3);
     162    auto linearSRGB = xyzToLinearSRGB(xyz);
     163    return linearToRGBComponents(linearSRGB);
     164}
     165
     166FloatComponents sRGBToP3(const FloatComponents& sRGB)
     167{
     168    auto linearSRGB = rgbToLinearComponents(sRGB);
     169    auto xyz = linearSRGBToXYZ(linearSRGB);
     170    auto linearP3 = XYZToLinearP3(xyz);
     171    return linearToRGBComponents(linearP3);
    102172}
    103173
     
    196266// specification at https://drafts.csswg.org/css-color-4/#hsl-to-rgb with
    197267// further explanation available at http://en.wikipedia.org/wiki/HSL_color_space
    198 FloatComponents HSLToSRGB(const FloatComponents& hslColor)
     268FloatComponents hslToSRGB(const FloatComponents& hslColor)
    199269{
    200270    float hue = hslColor.components[0];
     
    352422}
    353423
    354 void ColorMatrix::transformColorComponents(FloatComponents& colorComonents) const
    355 {
    356     float red = colorComonents.components[0];
    357     float green = colorComonents.components[1];
    358     float blue = colorComonents.components[2];
    359     float alpha = colorComonents.components[3];
    360 
    361     colorComonents.components[0] = m_matrix[0][0] * red + m_matrix[0][1] * green + m_matrix[0][2] * blue + m_matrix[0][3] * alpha + m_matrix[0][4];
    362     colorComonents.components[1] = m_matrix[1][0] * red + m_matrix[1][1] * green + m_matrix[1][2] * blue + m_matrix[1][3] * alpha + m_matrix[1][4];
    363     colorComonents.components[2] = m_matrix[2][0] * red + m_matrix[2][1] * green + m_matrix[2][2] * blue + m_matrix[2][3] * alpha + m_matrix[2][4];
    364     colorComonents.components[3] = m_matrix[3][0] * red + m_matrix[3][1] * green + m_matrix[3][2] * blue + m_matrix[3][3] * alpha + m_matrix[3][4];
     424void ColorMatrix::transformColorComponents(FloatComponents& colorComponents) const
     425{
     426    float red = colorComponents.components[0];
     427    float green = colorComponents.components[1];
     428    float blue = colorComponents.components[2];
     429    float alpha = colorComponents.components[3];
     430
     431    colorComponents.components[0] = m_matrix[0][0] * red + m_matrix[0][1] * green + m_matrix[0][2] * blue + m_matrix[0][3] * alpha + m_matrix[0][4];
     432    colorComponents.components[1] = m_matrix[1][0] * red + m_matrix[1][1] * green + m_matrix[1][2] * blue + m_matrix[1][3] * alpha + m_matrix[1][4];
     433    colorComponents.components[2] = m_matrix[2][0] * red + m_matrix[2][1] * green + m_matrix[2][2] * blue + m_matrix[2][3] * alpha + m_matrix[2][4];
     434    colorComponents.components[3] = m_matrix[3][0] * red + m_matrix[3][1] * green + m_matrix[3][2] * blue + m_matrix[3][3] * alpha + m_matrix[3][4];
     435}
     436
     437FloatComponents ColorMatrix::transformedColorComponents(const FloatComponents& colorComponents) const
     438{
     439    float red = colorComponents.components[0];
     440    float green = colorComponents.components[1];
     441    float blue = colorComponents.components[2];
     442    float alpha = colorComponents.components[3];
     443
     444    return {
     445        m_matrix[0][0] * red + m_matrix[0][1] * green + m_matrix[0][2] * blue + m_matrix[0][3] * alpha + m_matrix[0][4],
     446        m_matrix[1][0] * red + m_matrix[1][1] * green + m_matrix[1][2] * blue + m_matrix[1][3] * alpha + m_matrix[1][4],
     447        m_matrix[2][0] * red + m_matrix[2][1] * green + m_matrix[2][2] * blue + m_matrix[2][3] * alpha + m_matrix[2][4],
     448        m_matrix[3][0] * red + m_matrix[3][1] * green + m_matrix[3][2] * blue + m_matrix[3][3] * alpha + m_matrix[3][4]
     449    };
    365450}
    366451
  • trunk/Source/WebCore/platform/graphics/ColorUtilities.h

    r261794 r261828  
    174174
    175175// 0-1 components, result is clamped.
    176 float linearToSRGBColorComponent(float);
    177 float sRGBToLinearColorComponent(float);
     176float linearToRGBColorComponent(float);
     177float rgbToLinearColorComponent(float);
    178178
    179179FloatComponents sRGBColorToLinearComponents(const Color&);
    180 FloatComponents sRGBToLinearComponents(const FloatComponents&);
    181 FloatComponents linearToSRGBComponents(const FloatComponents&);
     180FloatComponents rgbToLinearComponents(const FloatComponents&);
     181FloatComponents linearToRGBComponents(const FloatComponents&);
     182
     183FloatComponents p3ToSRGB(const FloatComponents&);
     184FloatComponents sRGBToP3(const FloatComponents&);
    182185
    183186FloatComponents sRGBToHSL(const FloatComponents&);
    184 FloatComponents HSLToSRGB(const FloatComponents&);
     187FloatComponents hslToSRGB(const FloatComponents&);
    185188
    186189float luminance(const FloatComponents& sRGBCompontents);
     
    198201   
    199202    void transformColorComponents(FloatComponents&) const;
     203    FloatComponents transformedColorComponents(const FloatComponents&) const;
    200204
    201205private:
  • trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairoBackend.cpp

    r256892 r261828  
    8383            for (unsigned i = 0; i < 256; i++) {
    8484                float color = i / 255.0f;
    85                 color = sRGBToLinearColorComponent(color);
     85                color = rgbToLinearColorComponent(color);
    8686                array[i] = static_cast<uint8_t>(round(color * 255));
    8787            }
     
    9494            for (unsigned i = 0; i < 256; i++) {
    9595                float color = i / 255.0f;
    96                 color = linearToSRGBColorComponent(color);
     96                color = linearToRGBColorComponent(color);
    9797                array[i] = static_cast<uint8_t>(round(color * 255));
    9898            }
  • trunk/Source/WebCore/platform/graphics/filters/FilterOperation.cpp

    r261791 r261828  
    234234   
    235235    // Convert back to RGB.
    236     sRGBColorComponents = HSLToSRGB(hslComponents);
     236    sRGBColorComponents = hslToSRGB(hslComponents);
    237237   
    238238    // Apply the matrix. See rdar://problem/41146650 for how this matrix was derived.
     
    267267    hslComponents.components[0] = fmod(hslComponents.components[0] + 0.5f, 1.0f);
    268268    // And return RGB.
    269     sRGBColorComponents = HSLToSRGB(hslComponents);
     269    sRGBColorComponents = hslToSRGB(hslComponents);
    270270    return true;
    271271}
  • trunk/Tools/ChangeLog

    r261827 r261828  
     12020-05-18  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Implement conversion between P3 and sRGB color
     4        https://bugs.webkit.org/show_bug.cgi?id=211998
     5
     6        Reviewed by Daniel Bates.
     7
     8        API test for conversions from P3 to sRGB, and linearRGB to sRGB. Values were confirmed
     9        as close to those provided by ColorSync Utility.
     10
     11        * TestWebKitAPI/Tests/WebCore/ExtendedColorTests.cpp:
     12        (TestWebKitAPI::TEST):
     13
    1142020-05-18  Mark Lam  <mark.lam@apple.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/ExtendedColorTests.cpp

    r261794 r261828  
    2929#include "WTFStringUtilities.h"
    3030#include <WebCore/Color.h>
     31#include <wtf/MathExtras.h>
    3132
    3233using namespace WebCore;
     
    222223}
    223224
     225TEST(ExtendedColor, P3ConversionToSRGB)
     226{
     227    {
     228        Color p3Color(1.0, 0.5, 0.25, 0.75, ColorSpace::DisplayP3);
     229        EXPECT_TRUE(p3Color.isExtended());
     230
     231        auto sRGBComponents = p3Color.toSRGBAComponentsLossy();
     232        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[0], 1.0f));
     233        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[1], 0.462537885f));
     234        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[2], 0.149147838f));
     235        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[3], 0.75f));
     236    }
     237
     238    {
     239        Color linearColor(1.0, 0.5, 0.25, 0.75, ColorSpace::LinearRGB);
     240        EXPECT_TRUE(linearColor.isExtended());
     241        auto sRGBComponents = linearColor.toSRGBAComponentsLossy();
     242        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[0], 1.0f));
     243        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[1], 0.735356927f));
     244        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[2], 0.537098706f));
     245        EXPECT_TRUE(WTF::areEssentiallyEqual(sRGBComponents.components[3], 0.75f));
     246    }
     247}
     248
    224249
    225250} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.