Changeset 286191 in webkit


Ignore:
Timestamp:
Nov 27, 2021, 12:54:28 PM (4 years ago)
Author:
[email protected]
Message:

[CSS Color 4] Add support for oklab() and oklch() colors
https://bugs.webkit.org/show_bug.cgi?id=233507

Reviewed by Cameron McCormack.

LayoutTests/imported/w3c:

Add new tests for oklab() and oklch() based on the existing lab()
and lch() tests.

  • web-platform-tests/css/css-color/oklab-001-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-001.html: Added.
  • web-platform-tests/css/css-color/oklab-002-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-002.html: Added.
  • web-platform-tests/css/css-color/oklab-003-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-003.html: Added.
  • web-platform-tests/css/css-color/oklab-004-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-004.html: Added.
  • web-platform-tests/css/css-color/oklab-005-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-005.html: Added.
  • web-platform-tests/css/css-color/oklab-006-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-006.html: Added.
  • web-platform-tests/css/css-color/oklab-007-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-007.html: Added.
  • web-platform-tests/css/css-color/oklab-008-expected.html: Added.
  • web-platform-tests/css/css-color/oklab-008.html: Added.
  • web-platform-tests/css/css-color/oklch-001-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-001.html: Added.
  • web-platform-tests/css/css-color/oklch-002-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-002.html: Added.
  • web-platform-tests/css/css-color/oklch-003-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-003.html: Added.
  • web-platform-tests/css/css-color/oklch-004-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-004.html: Added.
  • web-platform-tests/css/css-color/oklch-005-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-005.html: Added.
  • web-platform-tests/css/css-color/oklch-006-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-006.html: Added.
  • web-platform-tests/css/css-color/oklch-007-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-007.html: Added.
  • web-platform-tests/css/css-color/oklch-008-expected.html: Added.
  • web-platform-tests/css/css-color/oklch-008.html: Added.

Source/WebCore:

Tests: imported/w3c/web-platform-tests/css/css-color/oklab-001.html

imported/w3c/web-platform-tests/css/css-color/oklab-002.html
imported/w3c/web-platform-tests/css/css-color/oklab-003.html
imported/w3c/web-platform-tests/css/css-color/oklab-004.html
imported/w3c/web-platform-tests/css/css-color/oklab-005.html
imported/w3c/web-platform-tests/css/css-color/oklab-006.html
imported/w3c/web-platform-tests/css/css-color/oklab-007.html
imported/w3c/web-platform-tests/css/css-color/oklab-008.html
imported/w3c/web-platform-tests/css/css-color/oklch-001.html
imported/w3c/web-platform-tests/css/css-color/oklch-002.html
imported/w3c/web-platform-tests/css/css-color/oklch-003.html
imported/w3c/web-platform-tests/css/css-color/oklch-004.html
imported/w3c/web-platform-tests/css/css-color/oklch-005.html
imported/w3c/web-platform-tests/css/css-color/oklch-006.html
imported/w3c/web-platform-tests/css/css-color/oklch-007.html
imported/w3c/web-platform-tests/css/css-color/oklch-008.html

Adds support for oklab() and oklch() CSS colors and as interpolation
parameters for color-mix().

OKLab (and its polar form OKLCH) is a relatively new Lab-like colorspace that aims
to be an improved (improved hue linearity, hue uniformity, and chroma uniformity)
Lab. It was create by Björn Ottosson and is documented at https://bottosson.github.io/posts/oklab/.

  • css/CSSValueKeywords.in:

Add 'oklab' and 'oklch' to the keyword list so they can be used as function
identifiers. Remove old mention of 'lab' in the color() function section,
since 'lab' is no longer a valid colorspace to use in the color() function
(rather, only lab() is supported).

  • css/parser/CSSPropertyParserHelpers.cpp:

(WebCore::CSSPropertyParserHelpers::parseLabParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeLabParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeLabParameters):
(WebCore::CSSPropertyParserHelpers::parseLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseColorFunction):
Generalize lab and lch function parsing to also support the oklab and
oklch variants (they have the same parsing rules).

(WebCore::CSSPropertyParserHelpers::consumeColorMixColorSpaceAndComma):
(WebCore::CSSPropertyParserHelpers::mixColorComponents):
Add support for using oklab and oklch as the interpolation space of a color-mix().
This was already generalized so all it meant doing was adding mappings of the
new identifiers to enums and mixColorComponentsInColorSpace calls.

  • platform/graphics/ColorComponents.h:

(WebCore::ColorComponents::subset const):
Fix compile error (no one had used subset yet it seems). 'std::remove_const_t<decltype(T::Size)>'
was likely copied from mapColorComponents() where it is templatized and needs to deduce the loop
variable, but that is not needed here.

  • platform/graphics/ColorConversion.cpp:

(WebCore::convertToPolarForm):
(WebCore::convertToRectangularForm):
Move conversion to/from polar/rectangular forms from the LCHA conversion
code here, so that it can be reused for OKLCHA.

(WebCore::OKLab<float>>::convert):
Add support for converting OKLab to/from XYZ D65. Matrix values come from https://bottosson.github.io/posts/oklab/
with updates from https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484

(WebCore::OKLCHA<float>>::convert):
Add support for converting OKLCHA. This is identical to the LCHA code above.

(WebCore::converColorComponents):
Add cases for new colorspaces.

  • platform/graphics/ColorConversion.h:

Add converters for new colorspaces. Update diagram with them as well.

  • platform/graphics/ColorMatrix.h:

(WebCore::ColorMatrix::transformedColorComponents const):
Generalize transformedColorComponents to work with any size ColorComponents object. This allows
the OKLab conversion code to be a bit simpler as it can operate on just the non-alpha components
in a more systematic way.

  • platform/graphics/ColorModels.h:

Add new predicate template variables to help when needing to check what model a particular
color type uses.

  • platform/graphics/ColorSerialization.cpp:

(WebCore::serialization):
(WebCore::serializationForCSS):
(WebCore::serializationForHTML):
(WebCore::serializationForRenderTreeAsText):
Add serialization support for new colorspaces. Also removes unused support for serializing lab
colors using the color(lab ...) syntax which has not been supported for some time.

  • platform/graphics/ColorSpace.cpp:
  • platform/graphics/ColorSpace.h:
  • platform/graphics/cg/ColorSpaceCG.h:

Add OKLab and OKLCH to the list of enumerated colorspaces and add mappings to their
newly defined types OKLab<T> and OKLCHA<T>.

  • platform/graphics/ColorTypes.h:

(WebCore::OKLab::OKLab):
(WebCore::OKLCHA::OKLCHA):
Add new types OKLab<T> and OKLCHA<T> (it looks like at some point an earlier version of this
must have partially landed as there were existing forward declarations). Like Lab<T> and LCHA<T>,
these new types use the LabModel<T> and LCHModel<T> models, but unlike them they use a whitepoint
of D65.

  • platform/graphics/ColorUtilities.h:

Generalize isBlack and isWhite to have a variant that works with Lab, LCH, OKLab and OKLCH (as they
all are identical) using SFINAE, use the new model predicates to make this more clear.

LayoutTests:

Update existing tests for lab() and lch() to also test oklab() and oklch().
As they have the same parsing rules, this is mostly done by templatizing
the tests and running them in a loop.

  • fast/css/parsing-color-mix-expected.txt:
  • fast/css/parsing-color-mix.html:
  • fast/css/parsing-lab-colors-expected.txt:
  • fast/css/parsing-lab-colors.html:
  • fast/css/parsing-relative-color-syntax-expected.txt:
  • fast/css/parsing-relative-color-syntax.html:
Location:
trunk
Files:
32 added
22 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r286181 r286191  
     12021-11-27  Sam Weinig  <[email protected]>
     2
     3        [CSS Color 4] Add support for oklab() and oklch() colors
     4        https://bugs.webkit.org/show_bug.cgi?id=233507
     5
     6        Reviewed by Cameron McCormack.
     7
     8        Update existing tests for lab() and lch() to also test oklab() and oklch().
     9        As they have the same parsing rules, this is mostly done by templatizing
     10        the tests and running them in a loop.
     11
     12        * fast/css/parsing-color-mix-expected.txt:
     13        * fast/css/parsing-color-mix.html:
     14        * fast/css/parsing-lab-colors-expected.txt:
     15        * fast/css/parsing-lab-colors.html:
     16        * fast/css/parsing-relative-color-syntax-expected.txt:
     17        * fast/css/parsing-relative-color-syntax.html:
     18
    1192021-11-26  Tim Nguyen  <[email protected]>
    220
  • trunk/LayoutTests/fast/css/parsing-color-mix-expected.txt

    r286168 r286191  
    4040PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))") is "lch(54% 64 74 / 0.84000003)"
    4141
     42color-mix(in oklch, ...)
     43PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4), oklch(50% 60 70deg / .8))") is "oklch(30% 40 50 / 0.6)"
     44PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 25%, oklch(50% 60 70deg / .8))") is "oklch(40% 50 60 / 0.7)"
     45PASS computedStyle("background-color", "color-mix(in oklch, 25% oklch(10% 20 30deg / .4), oklch(50% 60 70deg / .8))") is "oklch(40% 50 60 / 0.7)"
     46PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4), 25% oklch(50% 60 70deg / .8))") is "oklch(20% 30 40 / 0.5)"
     47PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4), oklch(50% 60 70deg / .8) 25%)") is "oklch(20% 30 40 / 0.5)"
     48PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 25%, oklch(50% 60 70deg / .8) 75%)") is "oklch(40% 50 60 / 0.7)"
     49PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 50%, oklch(50% 60 70deg / .8) 150%)") is "oklch(40% 50 60 / 0.7)"
     50PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 12.5%, oklch(50% 60 70deg / .8) 37.5%)") is "oklch(40% 50 60 / 0.7)"
     51PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 0%, oklch(50% 60 70deg / .8))") is "oklch(50% 60 70 / 0.8)"
     52PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) -10%, oklch(50% 60 70deg / .8))") is "oklch(54% 64 74 / 0.84000003)"
     53
    4254color-mix(in lab, ...)
    4355PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))") is "lab(30% 40 50 / 0.6)"
     
    5264PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))") is "lab(54% 64 74 / 0.84000003)"
    5365
     66color-mix(in oklab, ...)
     67PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4), oklab(50% 60 70 / .8))") is "oklab(30% 40 50 / 0.6)"
     68PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 25%, oklab(50% 60 70 / .8))") is "oklab(40% 50 60 / 0.7)"
     69PASS computedStyle("background-color", "color-mix(in oklab, 25% oklab(10% 20 30 / .4), oklab(50% 60 70 / .8))") is "oklab(40% 50 60 / 0.7)"
     70PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4), 25% oklab(50% 60 70 / .8))") is "oklab(20% 30 40 / 0.5)"
     71PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4), oklab(50% 60 70 / .8) 25%)") is "oklab(20% 30 40 / 0.5)"
     72PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 25%, oklab(50% 60 70 / .8) 75%)") is "oklab(40% 50 60 / 0.7)"
     73PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 50%, oklab(50% 60 70 / .8) 150%)") is "oklab(40% 50 60 / 0.7)"
     74PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 12.5%, oklab(50% 60 70 / .8) 37.5%)") is "oklab(40% 50 60 / 0.7)"
     75PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 0%, oklab(50% 60 70 / .8))") is "oklab(50% 60 70 / 0.8)"
     76PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) -10%, oklab(50% 60 70 / .8))") is "oklab(54% 64 74 / 0.84000003)"
     77
    5478color-mix(in srgb, ...)
    5579PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.4 0.5 / 0.6)"
    5680PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.4 0.5 0.6 / 0.7)"
    5781PASS computedStyle("background-color", "color-mix(in srgb, 25% color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))") is "color(srgb 0.4 0.5 0.6 / 0.7)"
     82PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) 25%)") is "color(srgb 0.2 0.3 0.4 / 0.5)"
    5883PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4), 25% color(srgb .5 .6 .7 / .8))") is "color(srgb 0.2 0.3 0.4 / 0.5)"
    59 PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) 25%)") is "color(srgb 0.2 0.3 0.4 / 0.5)"
    6084PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8) 75%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
    6185PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 50%, color(srgb .5 .6 .7 / .8) 150%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
  • trunk/LayoutTests/fast/css/parsing-color-mix.html

    r286168 r286191  
    5959    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))`, `rgb(148, 105, 82)`);
    6060   
     61    for (const colorSpace of [ "lch", "oklch" ]) {
     62        debug('');
     63        debug(`color-mix(in ${colorSpace}, ...)`);
    6164
    62     debug('');
    63     debug('color-mix(in lch, ...)');
     65        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4), ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(30% 40 50 / 0.6)`);
     66        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 25%, ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(40% 50 60 / 0.7)`);
     67        testComputed(`color-mix(in ${colorSpace}, 25% ${colorSpace}(10% 20 30deg / .4), ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(40% 50 60 / 0.7)`);
     68        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4), 25% ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(20% 30 40 / 0.5)`);
     69        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4), ${colorSpace}(50% 60 70deg / .8) 25%)`, `${colorSpace}(20% 30 40 / 0.5)`);
     70        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 25%, ${colorSpace}(50% 60 70deg / .8) 75%)`, `${colorSpace}(40% 50 60 / 0.7)`);
     71        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 50%, ${colorSpace}(50% 60 70deg / .8) 150%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale down > 100% sum.
     72        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 12.5%, ${colorSpace}(50% 60 70deg / .8) 37.5%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale up < 100% sum.
     73        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 0%, ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(50% 60 70 / 0.8)`);
    6474
    65     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))`, `lch(30% 40 50 / 0.6)`);
    66     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8))`, `lch(40% 50 60 / 0.7)`);
    67     testComputed(`color-mix(in lch, 25% lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))`, `lch(40% 50 60 / 0.7)`);
    68     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4), 25% lch(50% 60 70deg / .8))`, `lch(20% 30 40 / 0.5)`);
    69     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) 25%)`, `lch(20% 30 40 / 0.5)`);
    70     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8) 75%)`, `lch(40% 50 60 / 0.7)`);
    71     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4) 50%, lch(50% 60 70deg / .8) 150%)`, `lch(40% 50 60 / 0.7)`); // Scale down > 100% sum.
    72     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4) 12.5%, lch(50% 60 70deg / .8) 37.5%)`, `lch(40% 50 60 / 0.7)`); // Scale up < 100% sum.
    73     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
     75        // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
     76        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) -10%, ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(54% 64 74 / 0.84000003)`);
     77    }
    7478
    75     // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
    76     testComputed(`color-mix(in lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))`, `lch(54% 64 74 / 0.84000003)`);
     79    for (const colorSpace of [ "lab", "oklab" ]) {
     80        debug('');
     81        debug(`color-mix(in ${colorSpace}, ...)`);
    7782
     83        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4), ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(30% 40 50 / 0.6)`);
     84        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 25%, ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(40% 50 60 / 0.7)`);
     85        testComputed(`color-mix(in ${colorSpace}, 25% ${colorSpace}(10% 20 30 / .4), ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(40% 50 60 / 0.7)`);
     86        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4), 25% ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(20% 30 40 / 0.5)`);
     87        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4), ${colorSpace}(50% 60 70 / .8) 25%)`, `${colorSpace}(20% 30 40 / 0.5)`);
     88        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 25%, ${colorSpace}(50% 60 70 / .8) 75%)`, `${colorSpace}(40% 50 60 / 0.7)`);
     89        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 50%, ${colorSpace}(50% 60 70 / .8) 150%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale down > 100% sum.
     90        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 12.5%, ${colorSpace}(50% 60 70 / .8) 37.5%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale up < 100% sum.
     91        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 0%, ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(50% 60 70 / 0.8)`);
    7892
    79     debug('');
    80     debug('color-mix(in lab, ...)');
    81 
    82     testComputed(`color-mix(in lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))`, `lab(30% 40 50 / 0.6)`);
    83     testComputed(`color-mix(in lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8))`, `lab(40% 50 60 / 0.7)`);
    84     testComputed(`color-mix(in lab, 25% lab(10% 20 30 / .4), lab(50% 60 70 / .8))`, `lab(40% 50 60 / 0.7)`);
    85     testComputed(`color-mix(in lab, lab(10% 20 30 / .4), 25% lab(50% 60 70 / .8))`, `lab(20% 30 40 / 0.5)`);
    86     testComputed(`color-mix(in lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) 25%)`, `lab(20% 30 40 / 0.5)`);
    87     testComputed(`color-mix(in lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8) 75%)`, `lab(40% 50 60 / 0.7)`);
    88     testComputed(`color-mix(in lab, lab(10% 20 30 / .4) 50%, lab(50% 60 70 / .8) 150%)`, `lab(40% 50 60 / 0.7)`); // Scale down > 100% sum.
    89     testComputed(`color-mix(in lab, lab(10% 20 30 / .4) 12.5%, lab(50% 60 70 / .8) 37.5%)`, `lab(40% 50 60 / 0.7)`); // Scale up < 100% sum.
    90     testComputed(`color-mix(in lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8))`, `lab(50% 60 70 / 0.8)`);
    91 
    92     // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
    93     testComputed(`color-mix(in lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))`, `lab(54% 64 74 / 0.84000003)`);
     93        // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
     94        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) -10%, ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(54% 64 74 / 0.84000003)`);
     95    }
    9496 
    95     debug('');
    96     debug('color-mix(in srgb, ...)');
    97 
    98     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.4 0.5 / 0.6)`);
    99     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.4 0.5 0.6 / 0.7)`);
    100     testComputed(`color-mix(in srgb, 25% color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))`, `color(srgb 0.4 0.5 0.6 / 0.7)`);
    101     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4), 25% color(srgb .5 .6 .7 / .8))`, `color(srgb 0.2 0.3 0.4 / 0.5)`);
    102     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) 25%)`, `color(srgb 0.2 0.3 0.4 / 0.5)`);
    103     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8) 75%)`, `color(srgb 0.4 0.5 0.6 / 0.7)`);
    104     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4) 50%, color(srgb .5 .6 .7 / .8) 150%)`, `color(srgb 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
    105     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4) 12.5%, color(srgb .5 .6 .7 / .8) 37.5%)`, `color(srgb 0.4 0.5 0.6 / 0.7)`); // Scale up < 100% sum.
    106     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.6 0.7 / 0.8)`);
    107 
    108     // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
    109     testComputed(`color-mix(in srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.54 0.64000005 0.74 / 0.84000003)`);
    110 
    111     for (const colorSpace of [ "xyz", "xyz-d50", "xyz-d65" ]) {
     97    for (const colorSpace of [ "srgb", "xyz", "xyz-d50", "xyz-d65" ]) {
    11298        debug('');
    11399        debug(`color-mix(in ${colorSpace}, ...)`);
  • trunk/LayoutTests/fast/css/parsing-lab-colors-expected.txt

    r278268 r286191  
    1 Test the parsing of lab(...) and lch(...) colors.
     1Test the parsing of lab(...), lch(...), oklab(...) and oklch(...) colors.
    22
    33On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
    44
    55
    6 lab()
     6
     7lab(...)
    78PASS computedStyle("background-color", "lab(0% 0 0)") is "lab(0% 0 0)"
    89PASS computedStyle("background-color", "lab(0% 0 0 / 1)") is "lab(0% 0 0)"
     
    2021PASS computedStyle("background-color", "lab(50% 0 -20)") is "lab(50% 0 -20)"
    2122
    22 lch()
     23Test invalid values
     24PASS computedStyle("background-color", "lab(0 0 0)") is "rgba(0, 0, 0, 0)"
     25PASS computedStyle("background-color", "lab(0% 0% 0)") is "rgba(0, 0, 0, 0)"
     26PASS computedStyle("background-color", "lab(0% 0 0 1)") is "rgba(0, 0, 0, 0)"
     27PASS computedStyle("background-color", "lab(0% 0 0 10%)") is "rgba(0, 0, 0, 0)"
     28PASS computedStyle("background-color", "lab(0% 0 0deg)") is "rgba(0, 0, 0, 0)"
     29PASS computedStyle("background-color", "lab(0% 0% 0deg)") is "rgba(0, 0, 0, 0)"
     30PASS computedStyle("background-color", "lab(40% 0 0deg)") is "rgba(0, 0, 0, 0)"
     31PASS computedStyle("background-color", "color(lab 20% 0 10 / 50%)") is "rgba(0, 0, 0, 0)"
     32
     33oklab(...)
     34PASS computedStyle("background-color", "oklab(0% 0 0)") is "oklab(0% 0 0)"
     35PASS computedStyle("background-color", "oklab(0% 0 0 / 1)") is "oklab(0% 0 0)"
     36PASS computedStyle("background-color", "oklab(0% 0 0 / 0.5)") is "oklab(0% 0 0 / 0.5)"
     37PASS computedStyle("background-color", "oklab(20% 0 10/0.5)") is "oklab(20% 0 10 / 0.5)"
     38PASS computedStyle("background-color", "oklab(20% 0 10/50%)") is "oklab(20% 0 10 / 0.5)"
     39PASS computedStyle("background-color", "oklab(400% 0 10/50%)") is "oklab(400% 0 10 / 0.5)"
     40PASS computedStyle("background-color", "oklab(50% -160 160)") is "oklab(50% -160 160)"
     41PASS computedStyle("background-color", "oklab(50% -200 200)") is "oklab(50% -200 200)"
     42PASS computedStyle("background-color", "oklab(0% 0 0 / -10%)") is "oklab(0% 0 0 / 0)"
     43PASS computedStyle("background-color", "oklab(0% 0 0 / 110%)") is "oklab(0% 0 0)"
     44PASS computedStyle("background-color", "oklab(0% 0 0 / 300%)") is "oklab(0% 0 0)"
     45PASS computedStyle("background-color", "oklab(-40% 0 0)") is "oklab(0% 0 0)"
     46PASS computedStyle("background-color", "oklab(50% -20 0)") is "oklab(50% -20 0)"
     47PASS computedStyle("background-color", "oklab(50% 0 -20)") is "oklab(50% 0 -20)"
     48
     49Test invalid values
     50PASS computedStyle("background-color", "oklab(0 0 0)") is "rgba(0, 0, 0, 0)"
     51PASS computedStyle("background-color", "oklab(0% 0% 0)") is "rgba(0, 0, 0, 0)"
     52PASS computedStyle("background-color", "oklab(0% 0 0 1)") is "rgba(0, 0, 0, 0)"
     53PASS computedStyle("background-color", "oklab(0% 0 0 10%)") is "rgba(0, 0, 0, 0)"
     54PASS computedStyle("background-color", "oklab(0% 0 0deg)") is "rgba(0, 0, 0, 0)"
     55PASS computedStyle("background-color", "oklab(0% 0% 0deg)") is "rgba(0, 0, 0, 0)"
     56PASS computedStyle("background-color", "oklab(40% 0 0deg)") is "rgba(0, 0, 0, 0)"
     57PASS computedStyle("background-color", "color(oklab 20% 0 10 / 50%)") is "rgba(0, 0, 0, 0)"
     58
     59lch(...)
    2360PASS computedStyle("background-color", "lch(0% 0 0deg)") is "lch(0% 0 0)"
    2461PASS computedStyle("background-color", "lch(0% 0 0deg / 1)") is "lch(0% 0 0)"
     
    4178
    4279Test invalid values
    43 PASS computedStyle("background-color", "lab(0 0 0)") is "rgba(0, 0, 0, 0)"
    44 PASS computedStyle("background-color", "lab(0% 0% 0)") is "rgba(0, 0, 0, 0)"
    45 PASS computedStyle("background-color", "lab(0% 0 0 1)") is "rgba(0, 0, 0, 0)"
    46 PASS computedStyle("background-color", "lab(0% 0 0 10%)") is "rgba(0, 0, 0, 0)"
    47 PASS computedStyle("background-color", "lab(0% 0 0deg)") is "rgba(0, 0, 0, 0)"
    48 PASS computedStyle("background-color", "lab(0% 0% 0deg)") is "rgba(0, 0, 0, 0)"
    49 PASS computedStyle("background-color", "lab(40% 0 0deg)") is "rgba(0, 0, 0, 0)"
    5080PASS computedStyle("background-color", "lch(0 0 0 / 0.5)") is "rgba(0, 0, 0, 0)"
    5181PASS computedStyle("background-color", "lch(20% 10 10deg 10)") is "rgba(0, 0, 0, 0)"
    5282PASS computedStyle("background-color", "lch(20% 10 10deg 10 / 0.5)") is "rgba(0, 0, 0, 0)"
    53 PASS computedStyle("background-color", "color(lab 20% 0 10 / 50%)") is "rgba(0, 0, 0, 0)"
     83PASS computedStyle("background-color", "color(lch 20% 0 10 / 50%)") is "rgba(0, 0, 0, 0)"
     84
     85oklch(...)
     86PASS computedStyle("background-color", "oklch(0% 0 0deg)") is "oklch(0% 0 0)"
     87PASS computedStyle("background-color", "oklch(0% 0 0deg / 1)") is "oklch(0% 0 0)"
     88PASS computedStyle("background-color", "oklch(0% 0 0deg / 0.5)") is "oklch(0% 0 0 / 0.5)"
     89PASS computedStyle("background-color", "oklch(100% 230 0deg / 0.5)") is "oklch(100% 230 0 / 0.5)"
     90PASS computedStyle("background-color", "oklch(20% 50 20deg/0.5)") is "oklch(20% 50 20 / 0.5)"
     91PASS computedStyle("background-color", "oklch(20% 50 20deg/50%)") is "oklch(20% 50 20 / 0.5)"
     92PASS computedStyle("background-color", "oklch(10% 20 20deg / -10%)") is "oklch(10% 20 20 / 0)"
     93PASS computedStyle("background-color", "oklch(10% 20 20deg / 110%)") is "oklch(10% 20 20)"
     94PASS computedStyle("background-color", "oklch(10% 20 1.28rad)") is "oklch(10% 20 73.3386)"
     95PASS computedStyle("background-color", "oklch(10% 20 380deg)") is "oklch(10% 20 20)"
     96PASS computedStyle("background-color", "oklch(10% 20 -340deg)") is "oklch(10% 20 20)"
     97PASS computedStyle("background-color", "oklch(10% 20 740deg)") is "oklch(10% 20 20)"
     98PASS computedStyle("background-color", "oklch(10% 20 -700deg)") is "oklch(10% 20 20)"
     99PASS computedStyle("background-color", "oklch(-40% 0 0)") is "oklch(0% 0 0)"
     100PASS computedStyle("background-color", "oklch(20% -20 0)") is "oklch(20% 0 0)"
     101PASS computedStyle("background-color", "oklch(0% 0 0 / 0.5)") is "oklch(0% 0 0 / 0.5)"
     102PASS computedStyle("background-color", "oklch(10% 20 20 / 110%)") is "oklch(10% 20 20)"
     103PASS computedStyle("background-color", "oklch(10% 20 -700)") is "oklch(10% 20 20)"
     104
     105Test invalid values
     106PASS computedStyle("background-color", "oklch(0 0 0 / 0.5)") is "rgba(0, 0, 0, 0)"
     107PASS computedStyle("background-color", "oklch(20% 10 10deg 10)") is "rgba(0, 0, 0, 0)"
     108PASS computedStyle("background-color", "oklch(20% 10 10deg 10 / 0.5)") is "rgba(0, 0, 0, 0)"
     109PASS computedStyle("background-color", "color(oklch 20% 0 10 / 50%)") is "rgba(0, 0, 0, 0)"
    54110PASS successfullyParsed is true
    55111
  • trunk/LayoutTests/fast/css/parsing-lab-colors.html

    r278268 r286191  
    44<body>
    55<script>
    6     description("Test the parsing of lab(...) and lch(...) colors.");
     6    description("Test the parsing of lab(...), lch(...), oklab(...) and oklch(...) colors.");
    77
    88    function computedStyle(property, value)
     
    3535    }
    3636
    37     debug('lab()');
    38     testComputed("background-color", "lab(0% 0 0)", "lab(0% 0 0)");
    39     testComputed("background-color", "lab(0% 0 0 / 1)", "lab(0% 0 0)");
    40     testComputed("background-color", "lab(0% 0 0 / 0.5)", "lab(0% 0 0 / 0.5)");
    41     testComputed("background-color", "lab(20% 0 10/0.5)", "lab(20% 0 10 / 0.5)");
    42     testComputed("background-color", "lab(20% 0 10/50%)", "lab(20% 0 10 / 0.5)");
    43     testComputed("background-color", "lab(400% 0 10/50%)", "lab(400% 0 10 / 0.5)");
    44     testComputed("background-color", "lab(50% -160 160)", "lab(50% -160 160)");
    45     testComputed("background-color", "lab(50% -200 200)", "lab(50% -200 200)");
    46     testComputed("background-color", "lab(0% 0 0 / -10%)", "lab(0% 0 0 / 0)");
    47     testComputed("background-color", "lab(0% 0 0 / 110%)", "lab(0% 0 0)");
    48     testComputed("background-color", "lab(0% 0 0 / 300%)", "lab(0% 0 0)");
    49     testComputed("background-color", "lab(-40% 0 0)", "lab(0% 0 0)");
    50     testComputed("background-color", "lab(50% -20 0)", "lab(50% -20 0)");
    51     testComputed("background-color", "lab(50% 0 -20)", "lab(50% 0 -20)");
     37    for (const colorSpace of [ "lab", "oklab" ]) {
     38        debug('');
     39        debug(`${colorSpace}(...)`);
     40        testComputed(`background-color`, `${colorSpace}(0% 0 0)`, `${colorSpace}(0% 0 0)`);
     41        testComputed(`background-color`, `${colorSpace}(0% 0 0 / 1)`, `${colorSpace}(0% 0 0)`);
     42        testComputed(`background-color`, `${colorSpace}(0% 0 0 / 0.5)`, `${colorSpace}(0% 0 0 / 0.5)`);
     43        testComputed(`background-color`, `${colorSpace}(20% 0 10/0.5)`, `${colorSpace}(20% 0 10 / 0.5)`);
     44        testComputed(`background-color`, `${colorSpace}(20% 0 10/50%)`, `${colorSpace}(20% 0 10 / 0.5)`);
     45        testComputed(`background-color`, `${colorSpace}(400% 0 10/50%)`, `${colorSpace}(400% 0 10 / 0.5)`);
     46        testComputed(`background-color`, `${colorSpace}(50% -160 160)`, `${colorSpace}(50% -160 160)`);
     47        testComputed(`background-color`, `${colorSpace}(50% -200 200)`, `${colorSpace}(50% -200 200)`);
     48        testComputed(`background-color`, `${colorSpace}(0% 0 0 / -10%)`, `${colorSpace}(0% 0 0 / 0)`);
     49        testComputed(`background-color`, `${colorSpace}(0% 0 0 / 110%)`, `${colorSpace}(0% 0 0)`);
     50        testComputed(`background-color`, `${colorSpace}(0% 0 0 / 300%)`, `${colorSpace}(0% 0 0)`);
     51        testComputed(`background-color`, `${colorSpace}(-40% 0 0)`, `${colorSpace}(0% 0 0)`);
     52        testComputed(`background-color`, `${colorSpace}(50% -20 0)`, `${colorSpace}(50% -20 0)`);
     53        testComputed(`background-color`, `${colorSpace}(50% 0 -20)`, `${colorSpace}(50% 0 -20)`);
    5254
    53     debug('');
    54     debug('lch()');
    55     testComputed("background-color", "lch(0% 0 0deg)", "lch(0% 0 0)");
    56     testComputed("background-color", "lch(0% 0 0deg / 1)", "lch(0% 0 0)");
    57     testComputed("background-color", "lch(0% 0 0deg / 0.5)", "lch(0% 0 0 / 0.5)");
    58     testComputed("background-color", "lch(100% 230 0deg / 0.5)", "lch(100% 230 0 / 0.5)");
    59     testComputed("background-color", "lch(20% 50 20deg/0.5)", "lch(20% 50 20 / 0.5)");
    60     testComputed("background-color", "lch(20% 50 20deg/50%)", "lch(20% 50 20 / 0.5)");
    61     testComputed("background-color", "lch(10% 20 20deg / -10%)", "lch(10% 20 20 / 0)");
    62     testComputed("background-color", "lch(10% 20 20deg / 110%)", "lch(10% 20 20)");
    63     testComputed("background-color", "lch(10% 20 1.28rad)", "lch(10% 20 73.3386)");
    64     testComputed("background-color", "lch(10% 20 380deg)", "lch(10% 20 20)");
    65     testComputed("background-color", "lch(10% 20 -340deg)", "lch(10% 20 20)");
    66     testComputed("background-color", "lch(10% 20 740deg)", "lch(10% 20 20)");
    67     testComputed("background-color", "lch(10% 20 -700deg)", "lch(10% 20 20)");
    68     testComputed("background-color", "lch(-40% 0 0)", "lch(0% 0 0)");
    69     testComputed("background-color", "lch(20% -20 0)", "lch(20% 0 0)");
    70     // hue (the third argument) can be either an angle or number, with number interpreted as degrees.
    71     testComputed("background-color", "lch(0% 0 0 / 0.5)", "lch(0% 0 0 / 0.5)");
    72     testComputed("background-color", "lch(10% 20 20 / 110%)", "lch(10% 20 20)");
    73     testComputed("background-color", "lch(10% 20 -700)", "lch(10% 20 20)");
     55        debug('');
     56        debug('Test invalid values');
     57        testComputed(`background-color`, `${colorSpace}(0 0 0)`, `rgba(0, 0, 0, 0)`);
     58        testComputed(`background-color`, `${colorSpace}(0% 0% 0)`, `rgba(0, 0, 0, 0)`);
     59        testComputed(`background-color`, `${colorSpace}(0% 0 0 1)`, `rgba(0, 0, 0, 0)`);
     60        testComputed(`background-color`, `${colorSpace}(0% 0 0 10%)`, `rgba(0, 0, 0, 0)`);
     61        testComputed(`background-color`, `${colorSpace}(0% 0 0deg)`, `rgba(0, 0, 0, 0)`);
     62        testComputed(`background-color`, `${colorSpace}(0% 0% 0deg)`, `rgba(0, 0, 0, 0)`);
     63        testComputed(`background-color`, `${colorSpace}(40% 0 0deg)`, `rgba(0, 0, 0, 0)`);
     64        testComputed(`background-color`, `color(${colorSpace} 20% 0 10 / 50%)`, `rgba(0, 0, 0, 0)`);
     65    }
    7466
    75     debug('');
    76     debug('Test invalid values');
    77     testComputed("background-color", "lab(0 0 0)", "rgba(0, 0, 0, 0)");
    78     testComputed("background-color", "lab(0% 0% 0)", "rgba(0, 0, 0, 0)");
    79     testComputed("background-color", "lab(0% 0 0 1)", "rgba(0, 0, 0, 0)");
    80     testComputed("background-color", "lab(0% 0 0 10%)", "rgba(0, 0, 0, 0)");
    81     testComputed("background-color", "lab(0% 0 0deg)", "rgba(0, 0, 0, 0)");
    82     testComputed("background-color", "lab(0% 0% 0deg)", "rgba(0, 0, 0, 0)");
    83     testComputed("background-color", "lab(40% 0 0deg)", "rgba(0, 0, 0, 0)");
     67    for (const colorSpace of [ "lch", "oklch" ]) {
     68        debug('');
     69        debug(`${colorSpace}(...)`);
     70        testComputed(`background-color`, `${colorSpace}(0% 0 0deg)`, `${colorSpace}(0% 0 0)`);
     71        testComputed(`background-color`, `${colorSpace}(0% 0 0deg / 1)`, `${colorSpace}(0% 0 0)`);
     72        testComputed(`background-color`, `${colorSpace}(0% 0 0deg / 0.5)`, `${colorSpace}(0% 0 0 / 0.5)`);
     73        testComputed(`background-color`, `${colorSpace}(100% 230 0deg / 0.5)`, `${colorSpace}(100% 230 0 / 0.5)`);
     74        testComputed(`background-color`, `${colorSpace}(20% 50 20deg/0.5)`, `${colorSpace}(20% 50 20 / 0.5)`);
     75        testComputed(`background-color`, `${colorSpace}(20% 50 20deg/50%)`, `${colorSpace}(20% 50 20 / 0.5)`);
     76        testComputed(`background-color`, `${colorSpace}(10% 20 20deg / -10%)`, `${colorSpace}(10% 20 20 / 0)`);
     77        testComputed(`background-color`, `${colorSpace}(10% 20 20deg / 110%)`, `${colorSpace}(10% 20 20)`);
     78        testComputed(`background-color`, `${colorSpace}(10% 20 1.28rad)`, `${colorSpace}(10% 20 73.3386)`);
     79        testComputed(`background-color`, `${colorSpace}(10% 20 380deg)`, `${colorSpace}(10% 20 20)`);
     80        testComputed(`background-color`, `${colorSpace}(10% 20 -340deg)`, `${colorSpace}(10% 20 20)`);
     81        testComputed(`background-color`, `${colorSpace}(10% 20 740deg)`, `${colorSpace}(10% 20 20)`);
     82        testComputed(`background-color`, `${colorSpace}(10% 20 -700deg)`, `${colorSpace}(10% 20 20)`);
     83        testComputed(`background-color`, `${colorSpace}(-40% 0 0)`, `${colorSpace}(0% 0 0)`);
     84        testComputed(`background-color`, `${colorSpace}(20% -20 0)`, `${colorSpace}(20% 0 0)`);
     85        // hue (the third argument) can be either an angle or number, with number interpreted as degrees.
     86        testComputed(`background-color`, `${colorSpace}(0% 0 0 / 0.5)`, `${colorSpace}(0% 0 0 / 0.5)`);
     87        testComputed(`background-color`, `${colorSpace}(10% 20 20 / 110%)`, `${colorSpace}(10% 20 20)`);
     88        testComputed(`background-color`, `${colorSpace}(10% 20 -700)`, `${colorSpace}(10% 20 20)`);
    8489
    85     testComputed("background-color", "lch(0 0 0 / 0.5)", "rgba(0, 0, 0, 0)");
    86     testComputed("background-color", "lch(20% 10 10deg 10)", "rgba(0, 0, 0, 0)");
    87     testComputed("background-color", "lch(20% 10 10deg 10 / 0.5)", "rgba(0, 0, 0, 0)");
     90        debug('');
     91        debug('Test invalid values');
    8892
    89     testComputed("background-color", "color(lab 20% 0 10 / 50%)", "rgba(0, 0, 0, 0)");
     93        testComputed(`background-color`, `${colorSpace}(0 0 0 / 0.5)`, `rgba(0, 0, 0, 0)`);
     94        testComputed(`background-color`, `${colorSpace}(20% 10 10deg 10)`, `rgba(0, 0, 0, 0)`);
     95        testComputed(`background-color`, `${colorSpace}(20% 10 10deg 10 / 0.5)`, `rgba(0, 0, 0, 0)`);
     96        testComputed(`background-color`, `color(${colorSpace} 20% 0 10 / 50%)`, `rgba(0, 0, 0, 0)`);
     97    }
    9098
    9199</script>
  • trunk/LayoutTests/fast/css/parsing-relative-color-syntax-expected.txt

    r286168 r286191  
    230230PASS computedStyle("background-color", "lab(from lab(25% 20 50) h g b)") is "rgba(0, 0, 0, 0)"
    231231
     232oklab(from ...)
     233PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a b)") is "oklab(25% 20 50)"
     234PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a b / alpha)") is "oklab(25% 20 50)"
     235PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l a b / alpha)") is "oklab(25% 20 50 / 0.4)"
     236PASS computedStyle("background-color", "oklab(from oklab(from oklab(25% 20 50) l a b) l a b)") is "oklab(25% 20 50)"
     237PASS computedStyle("background-color", "oklab(from color(display-p3 0 0 0) l a b / alpha)") is "oklab(0% 0 0)"
     238PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) 0% 0 0)") is "oklab(0% 0 0)"
     239PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) 0% 0 0 / 0)") is "oklab(0% 0 0 / 0)"
     240PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) 0% a b / alpha)") is "oklab(0% 20 50)"
     241PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l 0 b / alpha)") is "oklab(25% 0 50)"
     242PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a 0 / alpha)") is "oklab(25% 20 0)"
     243PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a b / 0)") is "oklab(25% 20 50 / 0)"
     244PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) 0% a b / alpha)") is "oklab(0% 20 50 / 0.4)"
     245PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l 0 b / alpha)") is "oklab(25% 0 50 / 0.4)"
     246PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l a 0 / alpha)") is "oklab(25% 20 0 / 0.4)"
     247PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l a b / 0)") is "oklab(25% 20 50 / 0)"
     248PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) 35% a b / alpha)") is "oklab(35% 20 50)"
     249PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l 35 b / alpha)") is "oklab(25% 35 50)"
     250PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a 35 / alpha)") is "oklab(25% 20 35)"
     251PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a b / .35)") is "oklab(25% 20 50 / 0.35)"
     252PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) 35% a b / alpha)") is "oklab(35% 20 50 / 0.4)"
     253PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l 35 b / alpha)") is "oklab(25% 35 50 / 0.4)"
     254PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l a 35 / alpha)") is "oklab(25% 20 35 / 0.4)"
     255PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l a b / .35)") is "oklab(25% 20 50 / 0.35)"
     256PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l b a)") is "oklab(25% 50 20)"
     257PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l a a / a)") is "oklab(25% 20 20)"
     258PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l b a)") is "oklab(25% 50 20)"
     259PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l a a / a)") is "oklab(25% 20 20)"
     260PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l alpha a / b)") is "rgba(0, 0, 0, 0)"
     261PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l alpha alpha / alpha)") is "rgba(0, 0, 0, 0)"
     262PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l alpha a / b)") is "rgba(0, 0, 0, 0)"
     263PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l alpha alpha / alpha)") is "rgba(0, 0, 0, 0)"
     264PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) calc(l) calc(a) calc(b))") is "oklab(25% 20 50)"
     265PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) calc(l) calc(a) calc(b) / calc(alpha))") is "oklab(25% 20 50 / 0.4)"
     266PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l 10% 10)") is "rgba(0, 0, 0, 0)"
     267PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) l 10 10%)") is "rgba(0, 0, 0, 0)"
     268PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) 10 a b)") is "rgba(0, 0, 0, 0)"
     269PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l 10% 10)") is "rgba(0, 0, 0, 0)"
     270PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) l 10 10%)") is "rgba(0, 0, 0, 0)"
     271PASS computedStyle("background-color", "oklab(from oklab(25% 20 50 / 40%) 10 a b)") is "rgba(0, 0, 0, 0)"
     272PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) lightness a b)") is "rgba(0, 0, 0, 0)"
     273PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) x a b)") is "rgba(0, 0, 0, 0)"
     274PASS computedStyle("background-color", "oklab(from oklab(25% 20 50) h g b)") is "rgba(0, 0, 0, 0)"
     275
    232276lch(from ...)
    233277PASS computedStyle("background-color", "lch(from lch(70% 45 30) l c h)") is "lch(70% 45 30)"
     
    287331PASS computedStyle("background-color", "lch(from lch(70% 45 30) l g b)") is "rgba(0, 0, 0, 0)"
    288332
    289 color(from ... ${color} ...)
     333oklch(from ...)
     334PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c h)") is "oklch(70% 45 30)"
     335PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c h / alpha)") is "oklch(70% 45 30)"
     336PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c h/ alpha)") is "oklch(70% 45 30 / 0.4)"
     337PASS computedStyle("background-color", "oklch(from oklch(from oklch(70% 45 30) l c h) l c h)") is "oklch(70% 45 30)"
     338PASS computedStyle("background-color", "oklch(from color(display-p3 0 0 0) l c h / alpha)") is "oklch(0% 0 0)"
     339PASS computedStyle("background-color", "oklch(from oklab(70% 45 30) l c h / alpha)") is "oklch(70% 54.08327 33.690067)"
     340PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 0% 0 0)") is "oklch(0% 0 0)"
     341PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 0% 0 0deg)") is "oklch(0% 0 0)"
     342PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 0% 0 0 / 0)") is "oklch(0% 0 0 / 0)"
     343PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 0% 0 0deg / 0)") is "oklch(0% 0 0 / 0)"
     344PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 0% c h / alpha)") is "oklch(0% 45 30)"
     345PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l 0 h / alpha)") is "oklch(70% 0 30)"
     346PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c 0 / alpha)") is "oklch(70% 45 0)"
     347PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c 0deg / alpha)") is "oklch(70% 45 0)"
     348PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c h / 0)") is "oklch(70% 45 30 / 0)"
     349PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) 0% c h / alpha)") is "oklch(0% 45 30 / 0.4)"
     350PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l 0 h / alpha)") is "oklch(70% 0 30 / 0.4)"
     351PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c 0 / alpha)") is "oklch(70% 45 0 / 0.4)"
     352PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c 0deg / alpha)") is "oklch(70% 45 0 / 0.4)"
     353PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c h / 0)") is "oklch(70% 45 30 / 0)"
     354PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 25% c h / alpha)") is "oklch(25% 45 30)"
     355PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l 25 h / alpha)") is "oklch(70% 25 30)"
     356PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c 25 / alpha)") is "oklch(70% 45 25)"
     357PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c 25deg / alpha)") is "oklch(70% 45 25)"
     358PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c h / .25)") is "oklch(70% 45 30 / 0.25)"
     359PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) 25% c h / alpha)") is "oklch(25% 45 30 / 0.4)"
     360PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l 25 h / alpha)") is "oklch(70% 25 30 / 0.4)"
     361PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c 25 / alpha)") is "oklch(70% 45 25 / 0.4)"
     362PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c 25deg / alpha)") is "oklch(70% 45 25 / 0.4)"
     363PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c h / .25)") is "oklch(70% 45 30 / 0.25)"
     364PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) alpha c h / l)") is "oklch(100% 45 30 / 0.7)"
     365PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c c / alpha)") is "oklch(70% 45 45)"
     366PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) alpha c h / alpha)") is "oklch(100% 45 30)"
     367PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) alpha c c / alpha)") is "oklch(100% 45 45)"
     368PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) alpha c h / l)") is "oklch(40% 45 30 / 0.7)"
     369PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c c / alpha)") is "oklch(70% 45 45 / 0.4)"
     370PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) alpha c h / alpha)") is "oklch(40% 45 30 / 0.4)"
     371PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) alpha c c / alpha)") is "oklch(40% 45 45 / 0.4)"
     372PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) h l c / alpha)") is "rgba(0, 0, 0, 0)"
     373PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) c c c / c)") is "rgba(0, 0, 0, 0)"
     374PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) alpha alpha alpha / alpha)") is "rgba(0, 0, 0, 0)"
     375PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) h l c / alpha)") is "rgba(0, 0, 0, 0)"
     376PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) c c c / c)") is "rgba(0, 0, 0, 0)"
     377PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) alpha alpha alpha / alpha)") is "rgba(0, 0, 0, 0)"
     378PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) calc(l) calc(c) calc(h))") is "oklch(70% 45 30)"
     379PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) calc(l) calc(c) calc(h) / calc(alpha))") is "oklch(70% 45 30 / 0.4)"
     380PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l 10% h)") is "rgba(0, 0, 0, 0)"
     381PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l c 10%)") is "rgba(0, 0, 0, 0)"
     382PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) 10 c h)") is "rgba(0, 0, 0, 0)"
     383PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l 10% h)") is "rgba(0, 0, 0, 0)"
     384PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) l c 10%)") is "rgba(0, 0, 0, 0)"
     385PASS computedStyle("background-color", "oklch(from oklch(70% 45 30 / 40%) 10 c h)") is "rgba(0, 0, 0, 0)"
     386PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) lightness c h)") is "rgba(0, 0, 0, 0)"
     387PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) x c h)") is "rgba(0, 0, 0, 0)"
     388PASS computedStyle("background-color", "oklch(from oklch(70% 45 30) l g b)") is "rgba(0, 0, 0, 0)"
     389
     390color(from ... srgb ...)
    290391PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b)") is "color(srgb 0.7 0.5 0.3)"
    291392PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b / alpha)") is "color(srgb 0.7 0.5 0.3)"
     
    339440PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb l g b)") is "rgba(0, 0, 0, 0)"
    340441
    341 color(from ... ${color} ...)
     442color(from ... srgb-linear ...)
    342443PASS computedStyle("background-color", "color(from color(srgb-linear 0.7 0.5 0.3) srgb-linear r g b)") is "color(srgb-linear 0.7 0.5 0.3)"
    343444PASS computedStyle("background-color", "color(from color(srgb-linear 0.7 0.5 0.3) srgb-linear r g b / alpha)") is "color(srgb-linear 0.7 0.5 0.3)"
     
    391492PASS computedStyle("background-color", "color(from color(srgb-linear 0.7 0.5 0.3) srgb-linear l g b)") is "rgba(0, 0, 0, 0)"
    392493
    393 color(from ... ${color} ...)
     494color(from ... a98-rgb ...)
    394495PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b)") is "color(a98-rgb 0.7 0.5 0.3)"
    395496PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b / alpha)") is "color(a98-rgb 0.7 0.5 0.3)"
     
    443544PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb l g b)") is "rgba(0, 0, 0, 0)"
    444545
    445 color(from ... ${color} ...)
     546color(from ... rec2020 ...)
    446547PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b)") is "color(rec2020 0.7 0.5 0.3)"
    447548PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b / alpha)") is "color(rec2020 0.7 0.5 0.3)"
     
    495596PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 l g b)") is "rgba(0, 0, 0, 0)"
    496597
    497 color(from ... ${color} ...)
     598color(from ... prophoto-rgb ...)
    498599PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b)") is "color(prophoto-rgb 0.7 0.5 0.3)"
    499600PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b / alpha)") is "color(prophoto-rgb 0.7 0.5 0.3)"
  • trunk/LayoutTests/fast/css/parsing-relative-color-syntax.html

    r286168 r286191  
    298298    testComputed(`hwb(from rebeccapurple h g b)`, `rgba(0, 0, 0, 0)`);
    299299
    300 
    301     debug('');
    302     debug('lab(from ...)');
    303 
    304     // Testing no modifications.
    305     testComputed(`lab(from lab(25% 20 50) l a b)`, `lab(25% 20 50)`);
    306     testComputed(`lab(from lab(25% 20 50) l a b / alpha)`, `lab(25% 20 50)`);
    307     testComputed(`lab(from lab(25% 20 50 / 40%) l a b / alpha)`, `lab(25% 20 50 / 0.4)`);
    308 
    309     // Test nesting relative colors.
    310     testComputed(`lab(from lab(from lab(25% 20 50) l a b) l a b)`, `lab(25% 20 50)`);
    311 
    312     // Testing non-lab origin to see conversion.
    313     testComputed(`lab(from color(display-p3 0 0 0) l a b / alpha)`, `lab(0% 0 0)`);
    314 
    315     // Testing replacement with 0.
    316     testComputed(`lab(from lab(25% 20 50) 0% 0 0)`, `lab(0% 0 0)`);
    317     testComputed(`lab(from lab(25% 20 50) 0% 0 0 / 0)`, `lab(0% 0 0 / 0)`);
    318     testComputed(`lab(from lab(25% 20 50) 0% a b / alpha)`, `lab(0% 20 50)`);
    319     testComputed(`lab(from lab(25% 20 50) l 0 b / alpha)`, `lab(25% 0 50)`);
    320     testComputed(`lab(from lab(25% 20 50) l a 0 / alpha)`, `lab(25% 20 0)`);
    321     testComputed(`lab(from lab(25% 20 50) l a b / 0)`, `lab(25% 20 50 / 0)`);
    322     testComputed(`lab(from lab(25% 20 50 / 40%) 0% a b / alpha)`, `lab(0% 20 50 / 0.4)`);
    323     testComputed(`lab(from lab(25% 20 50 / 40%) l 0 b / alpha)`, `lab(25% 0 50 / 0.4)`);
    324     testComputed(`lab(from lab(25% 20 50 / 40%) l a 0 / alpha)`, `lab(25% 20 0 / 0.4)`);
    325     testComputed(`lab(from lab(25% 20 50 / 40%) l a b / 0)`, `lab(25% 20 50 / 0)`);
    326 
    327     // Testing replacement with a constant.
    328     testComputed(`lab(from lab(25% 20 50) 35% a b / alpha)`, `lab(35% 20 50)`);
    329     testComputed(`lab(from lab(25% 20 50) l 35 b / alpha)`, `lab(25% 35 50)`);
    330     testComputed(`lab(from lab(25% 20 50) l a 35 / alpha)`, `lab(25% 20 35)`);
    331     testComputed(`lab(from lab(25% 20 50) l a b / .35)`, `lab(25% 20 50 / 0.35)`);
    332     testComputed(`lab(from lab(25% 20 50 / 40%) 35% a b / alpha)`, `lab(35% 20 50 / 0.4)`);
    333     testComputed(`lab(from lab(25% 20 50 / 40%) l 35 b / alpha)`, `lab(25% 35 50 / 0.4)`);
    334     testComputed(`lab(from lab(25% 20 50 / 40%) l a 35 / alpha)`, `lab(25% 20 35 / 0.4)`);
    335     testComputed(`lab(from lab(25% 20 50 / 40%) l a b / .35)`, `lab(25% 20 50 / 0.35)`);
    336 
    337     // Testing valid permutation (types match).
    338     testComputed(`lab(from lab(25% 20 50) l b a)`, `lab(25% 50 20)`);
    339     testComputed(`lab(from lab(25% 20 50) l a a / a)`, `lab(25% 20 20)`);
    340     testComputed(`lab(from lab(25% 20 50 / 40%) l b a)`, `lab(25% 50 20)`);
    341     testComputed(`lab(from lab(25% 20 50 / 40%) l a a / a)`, `lab(25% 20 20)`);
    342 
    343     // Testing invalid permutation (types don't match).
    344     testComputed(`lab(from lab(25% 20 50) l alpha a / b)`, `rgba(0, 0, 0, 0)`);
    345     testComputed(`lab(from lab(25% 20 50) l alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
    346     testComputed(`lab(from lab(25% 20 50 / 40%) l alpha a / b)`, `rgba(0, 0, 0, 0)`);
    347     testComputed(`lab(from lab(25% 20 50 / 40%) l alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
    348 
    349     // Testing with calc().
    350     testComputed(`lab(from lab(25% 20 50) calc(l) calc(a) calc(b))`, `lab(25% 20 50)`);
    351     testComputed(`lab(from lab(25% 20 50 / 40%) calc(l) calc(a) calc(b) / calc(alpha))`, `lab(25% 20 50 / 0.4)`);
    352 
    353     // Testing invalid values.
    354     testComputed(`lab(from lab(25% 20 50) l 10% 10)`, `rgba(0, 0, 0, 0)`);
    355     testComputed(`lab(from lab(25% 20 50) l 10 10%)`, `rgba(0, 0, 0, 0)`);
    356     testComputed(`lab(from lab(25% 20 50) 10 a b)`, `rgba(0, 0, 0, 0)`);
    357     testComputed(`lab(from lab(25% 20 50 / 40%) l 10% 10)`, `rgba(0, 0, 0, 0)`);
    358     testComputed(`lab(from lab(25% 20 50 / 40%) l 10 10%)`, `rgba(0, 0, 0, 0)`);
    359     testComputed(`lab(from lab(25% 20 50 / 40%) 10 a b)`, `rgba(0, 0, 0, 0)`);
    360 
    361     // Testing invalid component names
    362     testComputed(`lab(from lab(25% 20 50) lightness a b)`, `rgba(0, 0, 0, 0)`);
    363     testComputed(`lab(from lab(25% 20 50) x a b)`, `rgba(0, 0, 0, 0)`);
    364     testComputed(`lab(from lab(25% 20 50) h g b)`, `rgba(0, 0, 0, 0)`);
    365 
    366 
    367     debug('');
    368     debug('lch(from ...)');
    369 
    370     // Testing no modifications.
    371     testComputed(`lch(from lch(70% 45 30) l c h)`, `lch(70% 45 30)`);
    372     testComputed(`lch(from lch(70% 45 30) l c h / alpha)`, `lch(70% 45 30)`);
    373     testComputed(`lch(from lch(70% 45 30 / 40%) l c h/ alpha)`, `lch(70% 45 30 / 0.4)`);
    374 
    375     // Test nesting relative colors.
    376     testComputed(`lch(from lch(from lch(70% 45 30) l c h) l c h)`, `lch(70% 45 30)`);
    377 
    378     // Testing non-sRGB origin colors to see gamut clipping.
    379     testComputed(`lch(from color(display-p3 0 0 0) l c h / alpha)`, `lch(0% 0 0)`);
    380     testComputed(`lch(from lab(70% 45 30) l c h / alpha)`, `lch(70% 54.08327 33.690067)`);
    381 
    382     // Testing replacement with 0.
    383     testComputed(`lch(from lch(70% 45 30) 0% 0 0)`, `lch(0% 0 0)`);
    384     testComputed(`lch(from lch(70% 45 30) 0% 0 0deg)`, `lch(0% 0 0)`);
    385     testComputed(`lch(from lch(70% 45 30) 0% 0 0 / 0)`, `lch(0% 0 0 / 0)`);
    386     testComputed(`lch(from lch(70% 45 30) 0% 0 0deg / 0)`, `lch(0% 0 0 / 0)`);
    387     testComputed(`lch(from lch(70% 45 30) 0% c h / alpha)`, `lch(0% 45 30)`);
    388     testComputed(`lch(from lch(70% 45 30) l 0 h / alpha)`, `lch(70% 0 30)`);
    389     testComputed(`lch(from lch(70% 45 30) l c 0 / alpha)`, `lch(70% 45 0)`);
    390     testComputed(`lch(from lch(70% 45 30) l c 0deg / alpha)`, `lch(70% 45 0)`);
    391     testComputed(`lch(from lch(70% 45 30) l c h / 0)`, `lch(70% 45 30 / 0)`);
    392     testComputed(`lch(from lch(70% 45 30 / 40%) 0% c h / alpha)`, `lch(0% 45 30 / 0.4)`);
    393     testComputed(`lch(from lch(70% 45 30 / 40%) l 0 h / alpha)`, `lch(70% 0 30 / 0.4)`);
    394     testComputed(`lch(from lch(70% 45 30 / 40%) l c 0 / alpha)`, `lch(70% 45 0 / 0.4)`);
    395     testComputed(`lch(from lch(70% 45 30 / 40%) l c 0deg / alpha)`, `lch(70% 45 0 / 0.4)`);
    396     testComputed(`lch(from lch(70% 45 30 / 40%) l c h / 0)`, `lch(70% 45 30 / 0)`);
    397 
    398     // Testing replacement with a constant.
    399     testComputed(`lch(from lch(70% 45 30) 25% c h / alpha)`, `lch(25% 45 30)`);
    400     testComputed(`lch(from lch(70% 45 30) l 25 h / alpha)`, `lch(70% 25 30)`);
    401     testComputed(`lch(from lch(70% 45 30) l c 25 / alpha)`, `lch(70% 45 25)`);
    402     testComputed(`lch(from lch(70% 45 30) l c 25deg / alpha)`, `lch(70% 45 25)`);
    403     testComputed(`lch(from lch(70% 45 30) l c h / .25)`, `lch(70% 45 30 / 0.25)`);
    404     testComputed(`lch(from lch(70% 45 30 / 40%) 25% c h / alpha)`, `lch(25% 45 30 / 0.4)`);
    405     testComputed(`lch(from lch(70% 45 30 / 40%) l 25 h / alpha)`, `lch(70% 25 30 / 0.4)`);
    406     testComputed(`lch(from lch(70% 45 30 / 40%) l c 25 / alpha)`, `lch(70% 45 25 / 0.4)`);
    407     testComputed(`lch(from lch(70% 45 30 / 40%) l c 25deg / alpha)`, `lch(70% 45 25 / 0.4)`);
    408     testComputed(`lch(from lch(70% 45 30 / 40%) l c h / .25)`, `lch(70% 45 30 / 0.25)`);
    409 
    410     // Testing valid permutation (types match).
    411     // NOTE: 'c' is a vaild hue, as hue is <angle>|<number>.
    412     testComputed(`lch(from lch(70% 45 30) alpha c h / l)`, `lch(100% 45 30 / 0.7)`);
    413     testComputed(`lch(from lch(70% 45 30) l c c / alpha)`, `lch(70% 45 45)`);
    414     testComputed(`lch(from lch(70% 45 30) alpha c h / alpha)`, `lch(100% 45 30)`);
    415     testComputed(`lch(from lch(70% 45 30) alpha c c / alpha)`, `lch(100% 45 45)`);
    416     testComputed(`lch(from lch(70% 45 30 / 40%) alpha c h / l)`, `lch(40% 45 30 / 0.7)`);
    417     testComputed(`lch(from lch(70% 45 30 / 40%) l c c / alpha)`, `lch(70% 45 45 / 0.4)`);
    418     testComputed(`lch(from lch(70% 45 30 / 40%) alpha c h / alpha)`, `lch(40% 45 30 / 0.4)`);
    419     testComputed(`lch(from lch(70% 45 30 / 40%) alpha c c / alpha)`, `lch(40% 45 45 / 0.4)`);
    420 
    421     // Testing invalid permutation (types don't match).
    422     testComputed(`lch(from lch(70% 45 30) h l c / alpha)`, `rgba(0, 0, 0, 0)`);
    423     testComputed(`lch(from lch(70% 45 30) c c c / c)`, `rgba(0, 0, 0, 0)`);
    424     testComputed(`lch(from lch(70% 45 30) alpha alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
    425     testComputed(`lch(from lch(70% 45 30 / 40%) h l c / alpha)`, `rgba(0, 0, 0, 0)`);
    426     testComputed(`lch(from lch(70% 45 30 / 40%) c c c / c)`, `rgba(0, 0, 0, 0)`);
    427     testComputed(`lch(from lch(70% 45 30 / 40%) alpha alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
    428 
    429     // Testing with calc().
    430     testComputed(`lch(from lch(70% 45 30) calc(l) calc(c) calc(h))`, `lch(70% 45 30)`);
    431     testComputed(`lch(from lch(70% 45 30 / 40%) calc(l) calc(c) calc(h) / calc(alpha))`, `lch(70% 45 30 / 0.4)`);
    432 
    433     // Testing invalid values.
    434     testComputed(`lch(from lch(70% 45 30) l 10% h)`, `rgba(0, 0, 0, 0)`);
    435     testComputed(`lch(from lch(70% 45 30) l c 10%)`, `rgba(0, 0, 0, 0)`);
    436     testComputed(`lch(from lch(70% 45 30) 10 c h)`, `rgba(0, 0, 0, 0)`);
    437     testComputed(`lch(from lch(70% 45 30 / 40%) l 10% h)`, `rgba(0, 0, 0, 0)`);
    438     testComputed(`lch(from lch(70% 45 30 / 40%) l c 10%)`, `rgba(0, 0, 0, 0)`);
    439     testComputed(`lch(from lch(70% 45 30 / 40%) 10 c h)`, `rgba(0, 0, 0, 0)`);
    440 
    441     // Testing invalid component names
    442     testComputed(`lch(from lch(70% 45 30) lightness c h)`, `rgba(0, 0, 0, 0)`);
    443     testComputed(`lch(from lch(70% 45 30) x c h)`, `rgba(0, 0, 0, 0)`);
    444     testComputed(`lch(from lch(70% 45 30) l g b)`, `rgba(0, 0, 0, 0)`);
    445 
    446 
    447     for (const color of [ "srgb", "srgb-linear", "a98-rgb", "rec2020", "prophoto-rgb" ]) {
     300    for (const colorSpace of [ "lab", "oklab" ]) {
    448301        debug('');
    449         debug('color(from ... ${color} ...)');
     302        debug(`${colorSpace}(from ...)`);
    450303
    451304        // Testing no modifications.
    452         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b)`,                              `color(${color} 0.7 0.5 0.3)`);
    453         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / alpha)`,                      `color(${color} 0.7 0.5 0.3)`);
    454         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b)`,                        `color(${color} 0.7 0.5 0.3)`);
    455         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / alpha)`,                `color(${color} 0.7 0.5 0.3 / 0.4)`);
     305        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a b)`, `${colorSpace}(25% 20 50)`);
     306        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a b / alpha)`, `${colorSpace}(25% 20 50)`);
     307        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l a b / alpha)`, `${colorSpace}(25% 20 50 / 0.4)`);
    456308
    457309        // Test nesting relative colors.
    458         testComputed(`color(from color(from color(${color} 0.7 0.5 0.3) ${color} r g b) ${color} r g b)`,   `color(${color} 0.7 0.5 0.3)`);
     310        testComputed(`${colorSpace}(from ${colorSpace}(from ${colorSpace}(25% 20 50) l a b) l a b)`, `${colorSpace}(25% 20 50)`);
     311
     312        // Testing non-${colorSpace} origin to see conversion.
     313        testComputed(`${colorSpace}(from color(display-p3 0 0 0) l a b / alpha)`, `${colorSpace}(0% 0 0)`);
    459314
    460315        // Testing replacement with 0.
    461         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0)`,                              `color(${color} 0 0 0)`);
    462         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0)`,                              `color(${color} 0 0 0)`);
    463         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0 / 0)`,                          `color(${color} 0 0 0 / 0)`);
    464         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0 / 0)`,                          `color(${color} 0 0 0 / 0)`);
    465         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 g b / alpha)`,                      `color(${color} 0 0.5 0.3)`);
    466         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 0 b / alpha)`,                      `color(${color} 0.7 0 0.3)`);
    467         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 0 / alpha)`,                      `color(${color} 0.7 0.5 0)`);
    468         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 0)`,                          `color(${color} 0.7 0.5 0.3 / 0)`);
    469         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} 0 g b / alpha)`,                `color(${color} 0 0.5 0.3 / 0.4)`);
    470         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r 0 b / alpha)`,                `color(${color} 0.7 0 0.3 / 0.4)`);
    471         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g 0 / alpha)`,                `color(${color} 0.7 0.5 0 / 0.4)`);
    472         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / 0)`,                    `color(${color} 0.7 0.5 0.3 / 0)`);
     316        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) 0% 0 0)`, `${colorSpace}(0% 0 0)`);
     317        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) 0% 0 0 / 0)`, `${colorSpace}(0% 0 0 / 0)`);
     318        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) 0% a b / alpha)`, `${colorSpace}(0% 20 50)`);
     319        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l 0 b / alpha)`, `${colorSpace}(25% 0 50)`);
     320        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a 0 / alpha)`, `${colorSpace}(25% 20 0)`);
     321        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a b / 0)`, `${colorSpace}(25% 20 50 / 0)`);
     322        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) 0% a b / alpha)`, `${colorSpace}(0% 20 50 / 0.4)`);
     323        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l 0 b / alpha)`, `${colorSpace}(25% 0 50 / 0.4)`);
     324        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l a 0 / alpha)`, `${colorSpace}(25% 20 0 / 0.4)`);
     325        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l a b / 0)`, `${colorSpace}(25% 20 50 / 0)`);
    473326
    474327        // Testing replacement with a constant.
    475         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0.2 g b / alpha)`,                    `color(${color} 0.2 0.5 0.3)`);
    476         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 20% g b / alpha)`,                    `color(${color} 0.2 0.5 0.3)`);
    477         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 0.2 b / alpha)`,                    `color(${color} 0.7 0.2 0.3)`);
    478         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 20% b / alpha)`,                    `color(${color} 0.7 0.2 0.3)`);
    479         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 0.2 / alpha)`,                    `color(${color} 0.7 0.5 0.2)`);
    480         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 20% / alpha)`,                    `color(${color} 0.7 0.5 0.2)`);
    481         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 0.2)`,                        `color(${color} 0.7 0.5 0.3 / 0.2)`);
    482         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 20%)`,                        `color(${color} 0.7 0.5 0.3 / 0.2)`);
    483         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} 0.2 g b / alpha)`,              `color(${color} 0.2 0.5 0.3 / 0.4)`);
    484         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} 20% g b / alpha)`,              `color(${color} 0.2 0.5 0.3 / 0.4)`);
    485         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r 0.2 b / alpha)`,              `color(${color} 0.7 0.2 0.3 / 0.4)`);
    486         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r 20% b / alpha)`,              `color(${color} 0.7 0.2 0.3 / 0.4)`);
    487         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g 0.2 / alpha)`,              `color(${color} 0.7 0.5 0.2 / 0.4)`);
    488         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g 20% / alpha)`,              `color(${color} 0.7 0.5 0.2 / 0.4)`);
    489         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / 0.2)`,                  `color(${color} 0.7 0.5 0.3 / 0.2)`);
    490         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / 20%)`,                  `color(${color} 0.7 0.5 0.3 / 0.2)`);
     328        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) 35% a b / alpha)`, `${colorSpace}(35% 20 50)`);
     329        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l 35 b / alpha)`, `${colorSpace}(25% 35 50)`);
     330        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a 35 / alpha)`, `${colorSpace}(25% 20 35)`);
     331        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a b / .35)`, `${colorSpace}(25% 20 50 / 0.35)`);
     332        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) 35% a b / alpha)`, `${colorSpace}(35% 20 50 / 0.4)`);
     333        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l 35 b / alpha)`, `${colorSpace}(25% 35 50 / 0.4)`);
     334        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l a 35 / alpha)`, `${colorSpace}(25% 20 35 / 0.4)`);
     335        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l a b / .35)`, `${colorSpace}(25% 20 50 / 0.35)`);
    491336
    492337        // Testing valid permutation (types match).
    493         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} g b r)`,                              `color(${color} 0.5 0.3 0.7)`);
    494         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} b alpha r / g)`,                      `color(${color} 0.3 1 0.7 / 0.5)`);
    495         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r r r / r)`,                          `color(${color} 0.7 0.7 0.7 / 0.7)`);
    496         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} alpha alpha alpha / alpha)`,          `color(${color} 1 1 1)`);
    497         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} g b r)`,                        `color(${color} 0.5 0.3 0.7)`);
    498         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} b alpha r / g)`,                `color(${color} 0.3 0.4 0.7 / 0.5)`);
    499         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r r r / r)`,                    `color(${color} 0.7 0.7 0.7 / 0.7)`);
    500         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} alpha alpha alpha / alpha)`,    `color(${color} 0.4 0.4 0.4 / 0.4)`);
     338        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l b a)`, `${colorSpace}(25% 50 20)`);
     339        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l a a / a)`, `${colorSpace}(25% 20 20)`);
     340        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l b a)`, `${colorSpace}(25% 50 20)`);
     341        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l a a / a)`, `${colorSpace}(25% 20 20)`);
     342
     343        // Testing invalid permutation (types don't match).
     344        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l alpha a / b)`, `rgba(0, 0, 0, 0)`);
     345        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
     346        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l alpha a / b)`, `rgba(0, 0, 0, 0)`);
     347        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
    501348
    502349        // Testing with calc().
    503         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} calc(r) calc(g) calc(b))`,                        `color(${color} 0.7 0.5 0.3)`);
    504         testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} calc(r) calc(g) calc(b) / calc(alpha))`,    `color(${color} 0.7 0.5 0.3 / 0.4)`);
     350        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) calc(l) calc(a) calc(b))`, `${colorSpace}(25% 20 50)`);
     351        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) calc(l) calc(a) calc(b) / calc(alpha))`, `${colorSpace}(25% 20 50 / 0.4)`);
    505352
    506353        // Testing invalid values.
    507         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 10deg g b)`,                          `rgba(0, 0, 0, 0)`);
    508         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 10deg b)`,                          `rgba(0, 0, 0, 0)`);
    509         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 10deg)`,                          `rgba(0, 0, 0, 0)`);
    510         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 10deg)`,                      `rgba(0, 0, 0, 0)`);
     354        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l 10% 10)`, `rgba(0, 0, 0, 0)`);
     355        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) l 10 10%)`, `rgba(0, 0, 0, 0)`);
     356        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) 10 a b)`, `rgba(0, 0, 0, 0)`);
     357        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l 10% 10)`, `rgba(0, 0, 0, 0)`);
     358        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) l 10 10%)`, `rgba(0, 0, 0, 0)`);
     359        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50 / 40%) 10 a b)`, `rgba(0, 0, 0, 0)`);
    511360
    512361        // Testing invalid component names
    513         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} red g b)`,                            `rgba(0, 0, 0, 0)`);
    514         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} x g b)`,                              `rgba(0, 0, 0, 0)`);
    515         testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} l g b)`,                              `rgba(0, 0, 0, 0)`);
    516     }
    517 
    518     for (const color of [ "xyz", "xyz-d50", "xyz-d65" ]) {
     362        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) lightness a b)`, `rgba(0, 0, 0, 0)`);
     363        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) x a b)`, `rgba(0, 0, 0, 0)`);
     364        testComputed(`${colorSpace}(from ${colorSpace}(25% 20 50) h g b)`, `rgba(0, 0, 0, 0)`);
     365    }
     366
     367    for (const colorSpace of [ "lch", "oklch" ]) {
     368        debug('');
     369        debug(`${colorSpace}(from ...)`);
     370
     371        const rectangularForm = colorSpace == "lch" ? "lab" : "oklab";
     372
     373        // Testing no modifications.
     374        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c h)`, `${colorSpace}(70% 45 30)`);
     375        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c h / alpha)`, `${colorSpace}(70% 45 30)`);
     376        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c h/ alpha)`, `${colorSpace}(70% 45 30 / 0.4)`);
     377
     378        // Test nesting relative colors.
     379        testComputed(`${colorSpace}(from ${colorSpace}(from ${colorSpace}(70% 45 30) l c h) l c h)`, `${colorSpace}(70% 45 30)`);
     380
     381        // Testing non-sRGB origin colors to see gamut clipping.
     382        testComputed(`${colorSpace}(from color(display-p3 0 0 0) l c h / alpha)`, `${colorSpace}(0% 0 0)`);
     383        testComputed(`${colorSpace}(from ${rectangularForm}(70% 45 30) l c h / alpha)`, `${colorSpace}(70% 54.08327 33.690067)`);
     384
     385        // Testing replacement with 0.
     386        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 0% 0 0)`, `${colorSpace}(0% 0 0)`);
     387        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 0% 0 0deg)`, `${colorSpace}(0% 0 0)`);
     388        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 0% 0 0 / 0)`, `${colorSpace}(0% 0 0 / 0)`);
     389        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 0% 0 0deg / 0)`, `${colorSpace}(0% 0 0 / 0)`);
     390        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 0% c h / alpha)`, `${colorSpace}(0% 45 30)`);
     391        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l 0 h / alpha)`, `${colorSpace}(70% 0 30)`);
     392        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c 0 / alpha)`, `${colorSpace}(70% 45 0)`);
     393        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c 0deg / alpha)`, `${colorSpace}(70% 45 0)`);
     394        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c h / 0)`, `${colorSpace}(70% 45 30 / 0)`);
     395        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) 0% c h / alpha)`, `${colorSpace}(0% 45 30 / 0.4)`);
     396        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l 0 h / alpha)`, `${colorSpace}(70% 0 30 / 0.4)`);
     397        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c 0 / alpha)`, `${colorSpace}(70% 45 0 / 0.4)`);
     398        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c 0deg / alpha)`, `${colorSpace}(70% 45 0 / 0.4)`);
     399        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c h / 0)`, `${colorSpace}(70% 45 30 / 0)`);
     400
     401        // Testing replacement with a constant.
     402        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 25% c h / alpha)`, `${colorSpace}(25% 45 30)`);
     403        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l 25 h / alpha)`, `${colorSpace}(70% 25 30)`);
     404        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c 25 / alpha)`, `${colorSpace}(70% 45 25)`);
     405        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c 25deg / alpha)`, `${colorSpace}(70% 45 25)`);
     406        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c h / .25)`, `${colorSpace}(70% 45 30 / 0.25)`);
     407        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) 25% c h / alpha)`, `${colorSpace}(25% 45 30 / 0.4)`);
     408        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l 25 h / alpha)`, `${colorSpace}(70% 25 30 / 0.4)`);
     409        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c 25 / alpha)`, `${colorSpace}(70% 45 25 / 0.4)`);
     410        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c 25deg / alpha)`, `${colorSpace}(70% 45 25 / 0.4)`);
     411        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c h / .25)`, `${colorSpace}(70% 45 30 / 0.25)`);
     412
     413        // Testing valid permutation (types match).
     414        // NOTE: 'c' is a vaild hue, as hue is <angle>|<number>.
     415        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) alpha c h / l)`, `${colorSpace}(100% 45 30 / 0.7)`);
     416        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c c / alpha)`, `${colorSpace}(70% 45 45)`);
     417        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) alpha c h / alpha)`, `${colorSpace}(100% 45 30)`);
     418        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) alpha c c / alpha)`, `${colorSpace}(100% 45 45)`);
     419        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) alpha c h / l)`, `${colorSpace}(40% 45 30 / 0.7)`);
     420        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c c / alpha)`, `${colorSpace}(70% 45 45 / 0.4)`);
     421        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) alpha c h / alpha)`, `${colorSpace}(40% 45 30 / 0.4)`);
     422        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) alpha c c / alpha)`, `${colorSpace}(40% 45 45 / 0.4)`);
     423
     424        // Testing invalid permutation (types don't match).
     425        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) h l c / alpha)`, `rgba(0, 0, 0, 0)`);
     426        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) c c c / c)`, `rgba(0, 0, 0, 0)`);
     427        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) alpha alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
     428        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) h l c / alpha)`, `rgba(0, 0, 0, 0)`);
     429        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) c c c / c)`, `rgba(0, 0, 0, 0)`);
     430        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) alpha alpha alpha / alpha)`, `rgba(0, 0, 0, 0)`);
     431
     432        // Testing with calc().
     433        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) calc(l) calc(c) calc(h))`, `${colorSpace}(70% 45 30)`);
     434        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) calc(l) calc(c) calc(h) / calc(alpha))`, `${colorSpace}(70% 45 30 / 0.4)`);
     435
     436        // Testing invalid values.
     437        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l 10% h)`, `rgba(0, 0, 0, 0)`);
     438        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l c 10%)`, `rgba(0, 0, 0, 0)`);
     439        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) 10 c h)`, `rgba(0, 0, 0, 0)`);
     440        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l 10% h)`, `rgba(0, 0, 0, 0)`);
     441        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) l c 10%)`, `rgba(0, 0, 0, 0)`);
     442        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30 / 40%) 10 c h)`, `rgba(0, 0, 0, 0)`);
     443
     444        // Testing invalid component names
     445        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) lightness c h)`, `rgba(0, 0, 0, 0)`);
     446        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) x c h)`, `rgba(0, 0, 0, 0)`);
     447        testComputed(`${colorSpace}(from ${colorSpace}(70% 45 30) l g b)`, `rgba(0, 0, 0, 0)`);
     448    }
     449
     450    for (const colorSpace of [ "srgb", "srgb-linear", "a98-rgb", "rec2020", "prophoto-rgb" ]) {
     451        debug('');
     452        debug(`color(from ... ${colorSpace} ...)`);
     453
     454        // Testing no modifications.
     455        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b)`,                              `color(${colorSpace} 0.7 0.5 0.3)`);
     456        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b / alpha)`,                      `color(${colorSpace} 0.7 0.5 0.3)`);
     457        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g b)`,                        `color(${colorSpace} 0.7 0.5 0.3)`);
     458        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g b / alpha)`,                `color(${colorSpace} 0.7 0.5 0.3 / 0.4)`);
     459
     460        // Test nesting relative colors.
     461        testComputed(`color(from color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b) ${colorSpace} r g b)`,   `color(${colorSpace} 0.7 0.5 0.3)`);
     462
     463        // Testing replacement with 0.
     464        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 0 0 0)`,                              `color(${colorSpace} 0 0 0)`);
     465        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 0 0 0)`,                              `color(${colorSpace} 0 0 0)`);
     466        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 0 0 0 / 0)`,                          `color(${colorSpace} 0 0 0 / 0)`);
     467        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 0 0 0 / 0)`,                          `color(${colorSpace} 0 0 0 / 0)`);
     468        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 0 g b / alpha)`,                      `color(${colorSpace} 0 0.5 0.3)`);
     469        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r 0 b / alpha)`,                      `color(${colorSpace} 0.7 0 0.3)`);
     470        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g 0 / alpha)`,                      `color(${colorSpace} 0.7 0.5 0)`);
     471        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b / 0)`,                          `color(${colorSpace} 0.7 0.5 0.3 / 0)`);
     472        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} 0 g b / alpha)`,                `color(${colorSpace} 0 0.5 0.3 / 0.4)`);
     473        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r 0 b / alpha)`,                `color(${colorSpace} 0.7 0 0.3 / 0.4)`);
     474        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g 0 / alpha)`,                `color(${colorSpace} 0.7 0.5 0 / 0.4)`);
     475        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g b / 0)`,                    `color(${colorSpace} 0.7 0.5 0.3 / 0)`);
     476
     477        // Testing replacement with a constant.
     478        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 0.2 g b / alpha)`,                    `color(${colorSpace} 0.2 0.5 0.3)`);
     479        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 20% g b / alpha)`,                    `color(${colorSpace} 0.2 0.5 0.3)`);
     480        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r 0.2 b / alpha)`,                    `color(${colorSpace} 0.7 0.2 0.3)`);
     481        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r 20% b / alpha)`,                    `color(${colorSpace} 0.7 0.2 0.3)`);
     482        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g 0.2 / alpha)`,                    `color(${colorSpace} 0.7 0.5 0.2)`);
     483        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g 20% / alpha)`,                    `color(${colorSpace} 0.7 0.5 0.2)`);
     484        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b / 0.2)`,                        `color(${colorSpace} 0.7 0.5 0.3 / 0.2)`);
     485        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b / 20%)`,                        `color(${colorSpace} 0.7 0.5 0.3 / 0.2)`);
     486        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} 0.2 g b / alpha)`,              `color(${colorSpace} 0.2 0.5 0.3 / 0.4)`);
     487        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} 20% g b / alpha)`,              `color(${colorSpace} 0.2 0.5 0.3 / 0.4)`);
     488        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r 0.2 b / alpha)`,              `color(${colorSpace} 0.7 0.2 0.3 / 0.4)`);
     489        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r 20% b / alpha)`,              `color(${colorSpace} 0.7 0.2 0.3 / 0.4)`);
     490        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g 0.2 / alpha)`,              `color(${colorSpace} 0.7 0.5 0.2 / 0.4)`);
     491        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g 20% / alpha)`,              `color(${colorSpace} 0.7 0.5 0.2 / 0.4)`);
     492        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g b / 0.2)`,                  `color(${colorSpace} 0.7 0.5 0.3 / 0.2)`);
     493        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r g b / 20%)`,                  `color(${colorSpace} 0.7 0.5 0.3 / 0.2)`);
     494
     495        // Testing valid permutation (types match).
     496        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} g b r)`,                              `color(${colorSpace} 0.5 0.3 0.7)`);
     497        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} b alpha r / g)`,                      `color(${colorSpace} 0.3 1 0.7 / 0.5)`);
     498        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r r r / r)`,                          `color(${colorSpace} 0.7 0.7 0.7 / 0.7)`);
     499        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} alpha alpha alpha / alpha)`,          `color(${colorSpace} 1 1 1)`);
     500        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} g b r)`,                        `color(${colorSpace} 0.5 0.3 0.7)`);
     501        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} b alpha r / g)`,                `color(${colorSpace} 0.3 0.4 0.7 / 0.5)`);
     502        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} r r r / r)`,                    `color(${colorSpace} 0.7 0.7 0.7 / 0.7)`);
     503        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} alpha alpha alpha / alpha)`,    `color(${colorSpace} 0.4 0.4 0.4 / 0.4)`);
     504
     505        // Testing with calc().
     506        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} calc(r) calc(g) calc(b))`,                        `color(${colorSpace} 0.7 0.5 0.3)`);
     507        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3 / 40%) ${colorSpace} calc(r) calc(g) calc(b) / calc(alpha))`,    `color(${colorSpace} 0.7 0.5 0.3 / 0.4)`);
     508
     509        // Testing invalid values.
     510        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} 10deg g b)`,                          `rgba(0, 0, 0, 0)`);
     511        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r 10deg b)`,                          `rgba(0, 0, 0, 0)`);
     512        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g 10deg)`,                          `rgba(0, 0, 0, 0)`);
     513        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} r g b / 10deg)`,                      `rgba(0, 0, 0, 0)`);
     514
     515        // Testing invalid component names
     516        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} red g b)`,                            `rgba(0, 0, 0, 0)`);
     517        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} x g b)`,                              `rgba(0, 0, 0, 0)`);
     518        testComputed(`color(from color(${colorSpace} 0.7 0.5 0.3) ${colorSpace} l g b)`,                              `rgba(0, 0, 0, 0)`);
     519    }
     520
     521    for (const colorSpace of [ "xyz", "xyz-d50", "xyz-d65" ]) {
    519522            debug('');
    520             debug(`color(from ... ${color} ...)`);
    521 
    522                 const resultColorSpace = color == "xyz" ? "xyz-d65" : color;
     523        debug(`color(from ... ${colorSpace} ...)`);
     524
     525                const resultColorSpace = colorSpace == "xyz" ? "xyz-d65" : colorSpace;
    523526
    524527            // Testing no modifications.
    525             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y z)`,                              `color(${resultColorSpace} 7 -20.5 100)`);
    526             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y z / alpha)`,                      `color(${resultColorSpace} 7 -20.5 100)`);
    527             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x y z)`,                        `color(${resultColorSpace} 7 -20.5 100)`);
    528             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x y z / alpha)`,                `color(${resultColorSpace} 7 -20.5 100 / 0.4)`);
     528            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z)`,                              `color(${resultColorSpace} 7 -20.5 100)`);
     529            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z / alpha)`,                      `color(${resultColorSpace} 7 -20.5 100)`);
     530            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x y z)`,                        `color(${resultColorSpace} 7 -20.5 100)`);
     531            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x y z / alpha)`,                `color(${resultColorSpace} 7 -20.5 100 / 0.4)`);
    529532
    530533            // Test nesting relative colors.
    531             testComputed(`color(from color(from color(${color} 7 -20.5 100) ${color} x y z) ${color} x y z)`,        `color(${resultColorSpace} 7 -20.5 100)`);
     534            testComputed(`color(from color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z) ${colorSpace} x y z)`,        `color(${resultColorSpace} 7 -20.5 100)`);
    532535
    533536            // Testing replacement with 0.
    534             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 0 0 0)`,                              `color(${resultColorSpace} 0 0 0)`);
    535             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 0 0 0)`,                              `color(${resultColorSpace} 0 0 0)`);
    536             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 0 0 0 / 0)`,                          `color(${resultColorSpace} 0 0 0 / 0)`);
    537             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 0 0 0 / 0)`,                          `color(${resultColorSpace} 0 0 0 / 0)`);
    538             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 0 y z / alpha)`,                      `color(${resultColorSpace} 0 -20.5 100)`);
    539             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x 0 z / alpha)`,                      `color(${resultColorSpace} 7 0 100)`);
    540             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y 0 / alpha)`,                      `color(${resultColorSpace} 7 -20.5 0)`);
    541             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y z / 0)`,                          `color(${resultColorSpace} 7 -20.5 100 / 0)`);
    542             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} 0 y z / alpha)`,                `color(${resultColorSpace} 0 -20.5 100 / 0.4)`);
    543             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x 0 z / alpha)`,                `color(${resultColorSpace} 7 0 100 / 0.4)`);
    544             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x y 0 / alpha)`,                `color(${resultColorSpace} 7 -20.5 0 / 0.4)`);
    545             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x y z / 0)`,                    `color(${resultColorSpace} 7 -20.5 100 / 0)`);
     537            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 0 0 0)`,                              `color(${resultColorSpace} 0 0 0)`);
     538            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 0 0 0)`,                              `color(${resultColorSpace} 0 0 0)`);
     539            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 0 0 0 / 0)`,                          `color(${resultColorSpace} 0 0 0 / 0)`);
     540            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 0 0 0 / 0)`,                          `color(${resultColorSpace} 0 0 0 / 0)`);
     541            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 0 y z / alpha)`,                      `color(${resultColorSpace} 0 -20.5 100)`);
     542            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x 0 z / alpha)`,                      `color(${resultColorSpace} 7 0 100)`);
     543            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y 0 / alpha)`,                      `color(${resultColorSpace} 7 -20.5 0)`);
     544            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z / 0)`,                          `color(${resultColorSpace} 7 -20.5 100 / 0)`);
     545            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} 0 y z / alpha)`,                `color(${resultColorSpace} 0 -20.5 100 / 0.4)`);
     546            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x 0 z / alpha)`,                `color(${resultColorSpace} 7 0 100 / 0.4)`);
     547            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x y 0 / alpha)`,                `color(${resultColorSpace} 7 -20.5 0 / 0.4)`);
     548            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x y z / 0)`,                    `color(${resultColorSpace} 7 -20.5 100 / 0)`);
    546549
    547550            // Testing replacement with a constant.
    548             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 0.2 y z / alpha)`,                    `color(${resultColorSpace} 0.2 -20.5 100)`);
    549             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x 0.2 z / alpha)`,                    `color(${resultColorSpace} 7 0.2 100)`);
    550             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y 0.2 / alpha)`,                    `color(${resultColorSpace} 7 -20.5 0.2)`);
    551             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y z / 0.2)`,                        `color(${resultColorSpace} 7 -20.5 100 / 0.2)`);
    552             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y z / 20%)`,                        `color(${resultColorSpace} 7 -20.5 100 / 0.2)`);
    553             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} 0.2 y z / alpha)`,              `color(${resultColorSpace} 0.2 -20.5 100 / 0.4)`);
    554             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x 0.2 z / alpha)`,              `color(${resultColorSpace} 7 0.2 100 / 0.4)`);
    555             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x y 0.2 / alpha)`,              `color(${resultColorSpace} 7 -20.5 0.2 / 0.4)`);
    556             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x y z / 0.2)`,                  `color(${resultColorSpace} 7 -20.5 100 / 0.2)`);
     551            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 0.2 y z / alpha)`,                    `color(${resultColorSpace} 0.2 -20.5 100)`);
     552            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x 0.2 z / alpha)`,                    `color(${resultColorSpace} 7 0.2 100)`);
     553            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y 0.2 / alpha)`,                    `color(${resultColorSpace} 7 -20.5 0.2)`);
     554            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z / 0.2)`,                        `color(${resultColorSpace} 7 -20.5 100 / 0.2)`);
     555            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z / 20%)`,                        `color(${resultColorSpace} 7 -20.5 100 / 0.2)`);
     556            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} 0.2 y z / alpha)`,              `color(${resultColorSpace} 0.2 -20.5 100 / 0.4)`);
     557            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x 0.2 z / alpha)`,              `color(${resultColorSpace} 7 0.2 100 / 0.4)`);
     558            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x y 0.2 / alpha)`,              `color(${resultColorSpace} 7 -20.5 0.2 / 0.4)`);
     559            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x y z / 0.2)`,                  `color(${resultColorSpace} 7 -20.5 100 / 0.2)`);
    557560
    558561            // Testing valid permutation (types match).
    559             testComputed(`color(from color(${color} 7 -20.5 100) ${color} y z x)`,                              `color(${resultColorSpace} -20.5 100 7)`);
    560             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x x x / x)`,                          `color(${resultColorSpace} 7 7 7)`);
    561             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} y z x)`,                        `color(${resultColorSpace} -20.5 100 7)`);
    562             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} x x x / x)`,                    `color(${resultColorSpace} 7 7 7)`);
     562            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} y z x)`,                              `color(${resultColorSpace} -20.5 100 7)`);
     563            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x x x / x)`,                          `color(${resultColorSpace} 7 7 7)`);
     564            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} y z x)`,                        `color(${resultColorSpace} -20.5 100 7)`);
     565            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} x x x / x)`,                    `color(${resultColorSpace} 7 7 7)`);
    563566
    564567            // Testing invalid permutation (types don't match).
    565             testComputed(`color(from color(${color} 7 -20.5 100) ${color} z alpha x / y)`,                      `rgba(0, 0, 0, 0)`);
    566             testComputed(`color(from color(${color} 7 -20.5 100) ${color} alpha alpha alpha / alpha)`,          `rgba(0, 0, 0, 0)`);
    567             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} z alpha x / y)`,                `rgba(0, 0, 0, 0)`);
    568             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} alpha alpha alpha / alpha)`,    `rgba(0, 0, 0, 0)`);
     568            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} z alpha x / y)`,                      `rgba(0, 0, 0, 0)`);
     569            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} alpha alpha alpha / alpha)`,          `rgba(0, 0, 0, 0)`);
     570            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} z alpha x / y)`,                `rgba(0, 0, 0, 0)`);
     571            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} alpha alpha alpha / alpha)`,    `rgba(0, 0, 0, 0)`);
    569572
    570573            // Testing with calc().
    571             testComputed(`color(from color(${color} 7 -20.5 100) ${color} calc(x) calc(y) calc(z))`,                        `color(${resultColorSpace} 7 -20.5 100)`);
    572             testComputed(`color(from color(${color} 7 -20.5 100 / 40%) ${color} calc(x) calc(y) calc(z) / calc(alpha))`,    `color(${resultColorSpace} 7 -20.5 100 / 0.4)`);
     574            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} calc(x) calc(y) calc(z))`,                        `color(${resultColorSpace} 7 -20.5 100)`);
     575            testComputed(`color(from color(${colorSpace} 7 -20.5 100 / 40%) ${colorSpace} calc(x) calc(y) calc(z) / calc(alpha))`,    `color(${resultColorSpace} 7 -20.5 100 / 0.4)`);
    573576
    574577            // Testing invalid values.
    575             testComputed(`color(from color(${color} 7 -20.5 100) ${color} 10deg y z)`,                          `rgba(0, 0, 0, 0)`);
    576             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x 10deg z)`,                          `rgba(0, 0, 0, 0)`);
    577             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y 10deg)`,                          `rgba(0, 0, 0, 0)`);
    578             testComputed(`color(from color(${color} 7 -20.5 100) ${color} x y z / 10deg)`,                      `rgba(0, 0, 0, 0)`);
     578            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} 10deg y z)`,                          `rgba(0, 0, 0, 0)`);
     579            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x 10deg z)`,                          `rgba(0, 0, 0, 0)`);
     580            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y 10deg)`,                          `rgba(0, 0, 0, 0)`);
     581            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} x y z / 10deg)`,                      `rgba(0, 0, 0, 0)`);
    579582
    580583            // Testing invalid component names
    581             testComputed(`color(from color(${color} 7 -20.5 100) ${color} red y)`,                              `rgba(0, 0, 0, 0)`);
    582             testComputed(`color(from color(${color} 7 -20.5 100) ${color} r y z)`,                              `rgba(0, 0, 0, 0)`);
    583             testComputed(`color(from color(${color} 7 -20.5 100) ${color} l y z)`,                              `rgba(0, 0, 0, 0)`);
     584            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} red y)`,                              `rgba(0, 0, 0, 0)`);
     585            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} r y z)`,                              `rgba(0, 0, 0, 0)`);
     586            testComputed(`color(from color(${colorSpace} 7 -20.5 100) ${colorSpace} l y z)`,                              `rgba(0, 0, 0, 0)`);
    584587        }
    585588
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r286174 r286191  
     12021-11-27  Sam Weinig  <[email protected]>
     2
     3        [CSS Color 4] Add support for oklab() and oklch() colors
     4        https://bugs.webkit.org/show_bug.cgi?id=233507
     5
     6        Reviewed by Cameron McCormack.
     7
     8        Add new tests for oklab() and oklch() based on the existing lab()
     9        and lch() tests.
     10
     11        * web-platform-tests/css/css-color/oklab-001-expected.html: Added.
     12        * web-platform-tests/css/css-color/oklab-001.html: Added.
     13        * web-platform-tests/css/css-color/oklab-002-expected.html: Added.
     14        * web-platform-tests/css/css-color/oklab-002.html: Added.
     15        * web-platform-tests/css/css-color/oklab-003-expected.html: Added.
     16        * web-platform-tests/css/css-color/oklab-003.html: Added.
     17        * web-platform-tests/css/css-color/oklab-004-expected.html: Added.
     18        * web-platform-tests/css/css-color/oklab-004.html: Added.
     19        * web-platform-tests/css/css-color/oklab-005-expected.html: Added.
     20        * web-platform-tests/css/css-color/oklab-005.html: Added.
     21        * web-platform-tests/css/css-color/oklab-006-expected.html: Added.
     22        * web-platform-tests/css/css-color/oklab-006.html: Added.
     23        * web-platform-tests/css/css-color/oklab-007-expected.html: Added.
     24        * web-platform-tests/css/css-color/oklab-007.html: Added.
     25        * web-platform-tests/css/css-color/oklab-008-expected.html: Added.
     26        * web-platform-tests/css/css-color/oklab-008.html: Added.
     27        * web-platform-tests/css/css-color/oklch-001-expected.html: Added.
     28        * web-platform-tests/css/css-color/oklch-001.html: Added.
     29        * web-platform-tests/css/css-color/oklch-002-expected.html: Added.
     30        * web-platform-tests/css/css-color/oklch-002.html: Added.
     31        * web-platform-tests/css/css-color/oklch-003-expected.html: Added.
     32        * web-platform-tests/css/css-color/oklch-003.html: Added.
     33        * web-platform-tests/css/css-color/oklch-004-expected.html: Added.
     34        * web-platform-tests/css/css-color/oklch-004.html: Added.
     35        * web-platform-tests/css/css-color/oklch-005-expected.html: Added.
     36        * web-platform-tests/css/css-color/oklch-005.html: Added.
     37        * web-platform-tests/css/css-color/oklch-006-expected.html: Added.
     38        * web-platform-tests/css/css-color/oklch-006.html: Added.
     39        * web-platform-tests/css/css-color/oklch-007-expected.html: Added.
     40        * web-platform-tests/css/css-color/oklch-007.html: Added.
     41        * web-platform-tests/css/css-color/oklch-008-expected.html: Added.
     42        * web-platform-tests/css/css-color/oklch-008.html: Added.
     43
    1442021-11-26  Tim Nguyen  <[email protected]>
    245
  • trunk/Source/WebCore/ChangeLog

    r286190 r286191  
     12021-11-27  Sam Weinig  <[email protected]>
     2
     3        [CSS Color 4] Add support for oklab() and oklch() colors
     4        https://bugs.webkit.org/show_bug.cgi?id=233507
     5
     6        Reviewed by Cameron McCormack.
     7
     8        Tests: imported/w3c/web-platform-tests/css/css-color/oklab-001.html
     9               imported/w3c/web-platform-tests/css/css-color/oklab-002.html
     10               imported/w3c/web-platform-tests/css/css-color/oklab-003.html
     11               imported/w3c/web-platform-tests/css/css-color/oklab-004.html
     12               imported/w3c/web-platform-tests/css/css-color/oklab-005.html
     13               imported/w3c/web-platform-tests/css/css-color/oklab-006.html
     14               imported/w3c/web-platform-tests/css/css-color/oklab-007.html
     15               imported/w3c/web-platform-tests/css/css-color/oklab-008.html
     16               imported/w3c/web-platform-tests/css/css-color/oklch-001.html
     17               imported/w3c/web-platform-tests/css/css-color/oklch-002.html
     18               imported/w3c/web-platform-tests/css/css-color/oklch-003.html
     19               imported/w3c/web-platform-tests/css/css-color/oklch-004.html
     20               imported/w3c/web-platform-tests/css/css-color/oklch-005.html
     21               imported/w3c/web-platform-tests/css/css-color/oklch-006.html
     22               imported/w3c/web-platform-tests/css/css-color/oklch-007.html
     23               imported/w3c/web-platform-tests/css/css-color/oklch-008.html
     24
     25        Adds support for oklab() and oklch() CSS colors and as interpolation
     26        parameters for color-mix().
     27
     28        OKLab (and its polar form OKLCH) is a relatively new Lab-like colorspace that aims
     29        to be an improved (improved hue linearity, hue uniformity, and chroma uniformity)
     30        Lab. It was create by Björn Ottosson and is documented at https://bottosson.github.io/posts/oklab/.
     31
     32        * css/CSSValueKeywords.in:
     33        Add 'oklab' and 'oklch' to the keyword list so they can be used as function
     34        identifiers. Remove old mention of 'lab' in the color() function section,
     35        since 'lab' is no longer a valid colorspace to use in the color() function
     36        (rather, only lab() is supported).
     37
     38        * css/parser/CSSPropertyParserHelpers.cpp:
     39        (WebCore::CSSPropertyParserHelpers::parseLabParameters):
     40        (WebCore::CSSPropertyParserHelpers::parseRelativeLabParameters):
     41        (WebCore::CSSPropertyParserHelpers::parseNonRelativeLabParameters):
     42        (WebCore::CSSPropertyParserHelpers::parseLCHParameters):
     43        (WebCore::CSSPropertyParserHelpers::parseRelativeLCHParameters):
     44        (WebCore::CSSPropertyParserHelpers::parseNonRelativeLCHParameters):
     45        (WebCore::CSSPropertyParserHelpers::parseColorFunction):
     46        Generalize lab and lch function parsing to also support the oklab and
     47        oklch variants (they have the same parsing rules).
     48
     49        (WebCore::CSSPropertyParserHelpers::consumeColorMixColorSpaceAndComma):
     50        (WebCore::CSSPropertyParserHelpers::mixColorComponents):
     51        Add support for using oklab and oklch as the interpolation space of a color-mix().
     52        This was already generalized so all it meant doing was adding mappings of the
     53        new identifiers to enums and mixColorComponentsInColorSpace calls.
     54
     55        * platform/graphics/ColorComponents.h:
     56        (WebCore::ColorComponents::subset const):
     57        Fix compile error (no one had used subset yet it seems). 'std::remove_const_t<decltype(T::Size)>'
     58        was likely copied from mapColorComponents() where it is templatized and needs to deduce the loop
     59        variable, but that is not needed here.
     60
     61        * platform/graphics/ColorConversion.cpp:
     62        (WebCore::convertToPolarForm):
     63        (WebCore::convertToRectangularForm):
     64        Move conversion to/from polar/rectangular forms from the LCHA conversion
     65        code here, so that it can be reused for OKLCHA.
     66
     67        (WebCore::OKLab<float>>::convert):
     68        Add support for converting OKLab to/from XYZ D65. Matrix values come from https://bottosson.github.io/posts/oklab/
     69        with updates from https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
     70
     71        (WebCore::OKLCHA<float>>::convert):
     72        Add support for converting OKLCHA. This is identical to the LCHA code above.
     73
     74        (WebCore::converColorComponents):
     75        Add cases for new colorspaces.
     76
     77        * platform/graphics/ColorConversion.h:
     78        Add converters for new colorspaces. Update diagram with them as well.
     79
     80        * platform/graphics/ColorMatrix.h:
     81        (WebCore::ColorMatrix::transformedColorComponents const):
     82        Generalize transformedColorComponents to work with any size ColorComponents object. This allows
     83        the OKLab conversion code to be a bit simpler as it can operate on just the non-alpha components
     84        in a more systematic way.
     85
     86        * platform/graphics/ColorModels.h:
     87        Add new predicate template variables to help when needing to check what model a particular
     88        color type uses.
     89
     90        * platform/graphics/ColorSerialization.cpp:
     91        (WebCore::serialization):
     92        (WebCore::serializationForCSS):
     93        (WebCore::serializationForHTML):
     94        (WebCore::serializationForRenderTreeAsText):
     95        Add serialization support for new colorspaces. Also removes unused support for serializing lab
     96        colors using the color(lab ...) syntax which has not been supported for some time.
     97
     98        * platform/graphics/ColorSpace.cpp:
     99        * platform/graphics/ColorSpace.h:
     100        * platform/graphics/cg/ColorSpaceCG.h:
     101        Add OKLab and OKLCH to the list of enumerated colorspaces and add mappings to their
     102        newly defined types OKLab<T> and OKLCHA<T>.
     103
     104        * platform/graphics/ColorTypes.h:
     105        (WebCore::OKLab::OKLab):
     106        (WebCore::OKLCHA::OKLCHA):
     107        Add new types OKLab<T> and OKLCHA<T> (it looks like at some point an earlier version of this
     108        must have partially landed as there were existing forward declarations). Like Lab<T> and LCHA<T>,
     109        these new types use the LabModel<T> and LCHModel<T> models, but unlike them they use a whitepoint
     110        of D65.
     111
     112        * platform/graphics/ColorUtilities.h:
     113        Generalize isBlack and isWhite to have a variant that works with Lab, LCH, OKLab and OKLCH (as they
     114        all are identical) using SFINAE, use the new model predicates to make this more clear.
     115
    11162021-11-27  Alan Bujtas  <[email protected]>
    2117
  • trunk/Source/WebCore/css/CSSValueKeywords.in

    r286168 r286191  
    12851285lab
    12861286lch
     1287oklab
     1288oklch
    12871289//color
    12881290
     
    14661468a98-rgb
    14671469display-p3
    1468 // lab
    14691470prophoto-rgb
    14701471// rec2020
  • trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp

    r286168 r286191  
    18331833}
    18341834
    1835 template<typename ConsumerForLightness, typename ConsumerForAB, typename ConsumerForAlpha>
     1835template<typename ColorType, typename ConsumerForLightness, typename ConsumerForAB, typename ConsumerForAlpha>
    18361836static Color parseLabParameters(CSSParserTokenRange& args, ConsumerForLightness&& lightnessConsumer, ConsumerForAB&& abConsumer, ConsumerForAlpha&& alphaConsumer)
    18371837{
     
    18571857    auto normalizedLightness = std::max(0.0, *lightness);
    18581858
    1859     return Lab<float> { static_cast<float>(normalizedLightness), static_cast<float>(*aValue), static_cast<float>(*bValue), static_cast<float>(*alpha) };
    1860 }
    1861 
     1859    return ColorType { static_cast<float>(normalizedLightness), static_cast<float>(*aValue), static_cast<float>(*bValue), static_cast<float>(*alpha) };
     1860}
     1861
     1862template<typename ColorType>
    18621863static Color parseRelativeLabParameters(CSSParserTokenRange& args, const CSSParserContext& context)
    18631864{
     
    18691870        return { };
    18701871
    1871     auto originColorAsLab = originColor.toColorTypeLossy<Lab<float>>();
     1872    auto originColorAsLab = originColor.toColorTypeLossy<ColorType>();
    18721873
    18731874    CSSCalcSymbolTable symbolTable {
     
    18821883    auto alphaConsumer = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
    18831884
    1884     return parseLabParameters(args, WTFMove(lightnessConsumer), WTFMove(abConsumer), WTFMove(alphaConsumer));
    1885 }
    1886 
     1885    return parseLabParameters<ColorType>(args, WTFMove(lightnessConsumer), WTFMove(abConsumer), WTFMove(alphaConsumer));
     1886}
     1887
     1888template<typename ColorType>
    18871889static Color parseNonRelativeLabParameters(CSSParserTokenRange& args)
    18881890{
     
    18911893    auto alphaConsumer = [](auto& args) { return consumeOptionalAlpha(args); };
    18921894
    1893     return parseLabParameters(args, WTFMove(lightnessConsumer), WTFMove(abConsumer), WTFMove(alphaConsumer));
    1894 }
    1895 
     1895    return parseLabParameters<ColorType>(args, WTFMove(lightnessConsumer), WTFMove(abConsumer), WTFMove(alphaConsumer));
     1896}
     1897
     1898template<typename ColorType>
    18961899static Color parseLabParameters(CSSParserTokenRange& range, const CSSParserContext& context)
    18971900{
    1898     ASSERT(range.peek().functionId() == CSSValueLab);
     1901    ASSERT(range.peek().functionId() == CSSValueLab || range.peek().functionId() == CSSValueOklab);
    18991902
    19001903    if (!context.cssColor4)
     
    19041907
    19051908    if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
    1906         return parseRelativeLabParameters(args, context);
    1907     return parseNonRelativeLabParameters(args);
    1908 }
    1909 
    1910 template<typename ConsumerForLightness, typename ConsumerForChroma, typename ConsumerForHue, typename ConsumerForAlpha>
     1909        return parseRelativeLabParameters<ColorType>(args, context);
     1910    return parseNonRelativeLabParameters<ColorType>(args);
     1911}
     1912
     1913template<typename ColorType, typename ConsumerForLightness, typename ConsumerForChroma, typename ConsumerForHue, typename ConsumerForAlpha>
    19111914static Color parseLCHParameters(CSSParserTokenRange& args, ConsumerForLightness&& lightnessConsumer, ConsumerForChroma&& chromaConsumer, ConsumerForHue&& hueConsumer, ConsumerForAlpha&& alphaConsumer)
    19121915{
     
    19341937    auto normalizedHue = normalizeHue(*hue);
    19351938
    1936     return LCHA<float> { static_cast<float>(normalizedLightness), static_cast<float>(normalizedChroma), static_cast<float>(normalizedHue), static_cast<float>(*alpha) };
    1937 }
    1938 
     1939    return ColorType { static_cast<float>(normalizedLightness), static_cast<float>(normalizedChroma), static_cast<float>(normalizedHue), static_cast<float>(*alpha) };
     1940}
     1941
     1942template<typename ColorType>
    19391943static Color parseRelativeLCHParameters(CSSParserTokenRange& args, const CSSParserContext& context)
    19401944{
     
    19461950        return { };
    19471951
    1948     auto originColorAsLCH = originColor.toColorTypeLossy<LCHA<float>>();
     1952    auto originColorAsLCH = originColor.toColorTypeLossy<ColorType>();
    19491953
    19501954    CSSCalcSymbolTable symbolTable {
     
    19601964    auto alphaConsumer = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
    19611965
    1962     return parseLCHParameters(args, WTFMove(lightnessConsumer), WTFMove(chromaConsumer), WTFMove(hueConsumer), WTFMove(alphaConsumer));
    1963 }
    1964 
     1966    return parseLCHParameters<ColorType>(args, WTFMove(lightnessConsumer), WTFMove(chromaConsumer), WTFMove(hueConsumer), WTFMove(alphaConsumer));
     1967}
     1968
     1969template<typename ColorType>
    19651970static Color parseNonRelativeLCHParameters(CSSParserTokenRange& args, const CSSParserContext& context)
    19661971{
     
    19701975    auto alphaConsumer = [](auto& args) { return consumeOptionalAlpha(args); };
    19711976
    1972     return parseLCHParameters(args, WTFMove(lightnessConsumer), WTFMove(chromaConsumer), WTFMove(hueConsumer), WTFMove(alphaConsumer));
    1973 }
    1974 
     1977    return parseLCHParameters<ColorType>(args, WTFMove(lightnessConsumer), WTFMove(chromaConsumer), WTFMove(hueConsumer), WTFMove(alphaConsumer));
     1978}
     1979
     1980template<typename ColorType>
    19751981static Color parseLCHParameters(CSSParserTokenRange& range, const CSSParserContext& context)
    19761982{
    1977     ASSERT(range.peek().functionId() == CSSValueLch);
     1983    ASSERT(range.peek().functionId() == CSSValueLch || range.peek().functionId() == CSSValueOklch);
    19781984
    19791985    if (!context.cssColor4)
     
    19831989
    19841990    if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
    1985         return parseRelativeLCHParameters(args, context);
    1986     return parseNonRelativeLCHParameters(args, context);
     1991        return parseRelativeLCHParameters<ColorType>(args, context);
     1992    return parseNonRelativeLCHParameters<ColorType>(args, context);
    19871993}
    19881994
     
    22902296    Lab,
    22912297    Lch,
     2298    Oklab,
     2299    Oklch,
    22922300    Srgb,
    22932301    XyzD50,
     
    23132321    case CSSValueLch:
    23142322        return consumeIdentAndComma(args, ColorMixColorSpace::Lch);
     2323    case CSSValueOklab:
     2324        return consumeIdentAndComma(args, ColorMixColorSpace::Oklab);
     2325    case CSSValueOklch:
     2326        return consumeIdentAndComma(args, ColorMixColorSpace::Oklch);
    23152327    case CSSValueSRGB:
    23162328        return consumeIdentAndComma(args, ColorMixColorSpace::Srgb);
     
    24682480    case ColorMixColorSpace::Lch:
    24692481        return mixColorComponentsInColorSpace<LCHA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     2482    case ColorMixColorSpace::Oklab:
     2483        return mixColorComponentsInColorSpace<OKLab<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     2484    case ColorMixColorSpace::Oklch:
     2485        return mixColorComponentsInColorSpace<OKLCHA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    24702486    case ColorMixColorSpace::Srgb:
    24712487        return mixColorComponentsInColorSpace<SRGBA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     
    25752591        break;
    25762592    case CSSValueLab:
    2577         color = parseLabParameters(colorRange, context);
     2593        color = parseLabParameters<Lab<float>>(colorRange, context);
    25782594        break;
    25792595    case CSSValueLch:
    2580         color = parseLCHParameters(colorRange, context);
     2596        color = parseLCHParameters<LCHA<float>>(colorRange, context);
     2597        break;
     2598    case CSSValueOklab:
     2599        color = parseLabParameters<OKLab<float>>(colorRange, context);
     2600        break;
     2601    case CSSValueOklch:
     2602        color = parseLCHParameters<OKLCHA<float>>(colorRange, context);
    25812603        break;
    25822604    case CSSValueColor:
  • trunk/Source/WebCore/platform/graphics/ColorComponents.h

    r279240 r286191  
    136136{
    137137    ColorComponents<T, End - Start> result;
    138     for (std::remove_const_t<decltype(T::Size)> i = Start; i < End; ++i)
     138    for (size_t i = Start; i < End; ++i)
    139139        result[i - Start] = components[i];
    140140    return result;
  • trunk/Source/WebCore/platform/graphics/ColorConversion.cpp

    r286187 r286191  
    3434namespace WebCore {
    3535
     36// MARK: Lab-Like to LCH-Like conversion utilities.
     37
     38template<typename LCHLike, typename LabLike>
     39LCHLike convertToPolarForm(const LabLike& color)
     40{
     41    // https://drafts.csswg.org/css-color/#lab-to-lch
     42    float hue = rad2deg(atan2(color.b, color.a));
     43
     44    return {
     45        color.lightness,
     46        std::hypot(color.a, color.b),
     47        hue >= 0 ? hue : hue + 360,
     48        color.alpha
     49    };
     50}
     51
     52template<typename LabLike, typename LCHLike>
     53LabLike convertToRectangularForm(const LCHLike& color)
     54{
     55    // https://drafts.csswg.org/css-color/#lch-to-lab
     56    float hueAngleRadians = deg2rad(color.hue);
     57
     58    return {
     59        color.lightness,
     60        color.chroma * std::cos(hueAngleRadians),
     61        color.chroma * std::sin(hueAngleRadians),
     62        color.alpha
     63    };
     64}
     65
    3666// MARK: HSL conversions.
    3767
     
    245275}
    246276
    247 
    248277// MARK: LCH conversions.
    249278
    250279LCHA<float> ColorConversion<LCHA<float>, Lab<float>>::convert(const Lab<float>& color)
    251280{
    252     // https://www.w3.org/TR/css-color-4/#lab-to-lch
    253     float hue = rad2deg(atan2(color.b, color.a));
    254 
    255     return {
    256         color.lightness,
    257         std::hypot(color.a, color.b),
    258         hue >= 0 ? hue : hue + 360,
    259         color.alpha
    260     };
     281    return convertToPolarForm<LCHA<float>>(color);
    261282}
    262283
    263284Lab<float> ColorConversion<Lab<float>, LCHA<float>>::convert(const LCHA<float>& color)
    264285{
    265     // https://www.w3.org/TR/css-color-4/#lch-to-lab
    266     float hueAngleRadians = deg2rad(color.hue);
    267 
    268     return {
    269         color.lightness,
    270         color.chroma * std::cos(hueAngleRadians),
    271         color.chroma * std::sin(hueAngleRadians),
    272         color.alpha
    273     };
     286    return convertToRectangularForm<Lab<float>>(color);
     287}
     288
     289// MARK: OKLab conversions.
     290
     291XYZA<float, WhitePoint::D65> ColorConversion<XYZA<float, WhitePoint::D65>, OKLab<float>>::convert(const OKLab<float>& color)
     292{
     293    // FIXME: This could be optimized for when we are not explicitly converting to XYZ-D65 by pre-multiplying the 'LMSToXYZD65'
     294    // matrix with any subsequent matrices in the conversion. This would mean teaching the main conversion about this matrix
     295    // and adding new logic for this transform.
     296
     297    // https://bottosson.github.io/posts/oklab/ with XYZ <-> LMS matrices recalculated for consistent reference white in https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
     298
     299    static constexpr ColorMatrix<3, 3> LinearLMSToXYZD65 {
     300        1.2268798733741557f,  -0.5578149965554813f,  0.28139105017721583f,
     301       -0.04057576262431372f,  1.1122868293970594f, -0.07171106666151701f,
     302       -0.07637294974672142f, -0.4214933239627914f,  1.5869240244272418f
     303    };
     304
     305    static constexpr ColorMatrix<3, 3> OKLabToNonLinearLMS {
     306        0.99999999845051981432f,  0.39633779217376785678f,   0.21580375806075880339f,
     307        1.0000000088817607767f,  -0.1055613423236563494f,   -0.063854174771705903402f,
     308        1.0000000546724109177f,  -0.089484182094965759684f, -1.2914855378640917399f
     309    };
     310
     311    // 1. Transform from precentage lightness to unit lightness.
     312    auto components = asColorComponents(color).subset<0, 3>();
     313    components[0] = components[0] / 100.0f;
     314
     315    // 2. Transform from Lab-coordinates into non-linear LMS "approximate cone responses".
     316    auto nonLinearLMS = OKLabToNonLinearLMS.transformedColorComponents(components);
     317
     318    // 3. Apply linearity.
     319    auto linearLMS = nonLinearLMS.map([] (float v) { return v * v * v; });
     320
     321    // 4. Convert to XYZ.
     322    auto [x, y, z] = LinearLMSToXYZD65.transformedColorComponents(linearLMS);
     323
     324    return { x, y, z, color.alpha };
     325}
     326
     327OKLab<float> ColorConversion<OKLab<float>, XYZA<float, WhitePoint::D65>>::convert(const XYZA<float, WhitePoint::D65>& color)
     328{
     329    // FIXME: This could be optimized for when we are not explicitly converting from XYZ-D65 by pre-multiplying the 'XYZD65ToLMS'
     330    // matrix with any previous matrices in the conversion. This would mean teaching the main conversion about this matrix
     331    // and adding new logic for this transform.
     332
     333    // https://bottosson.github.io/posts/oklab/ with XYZ <-> LMS matrices recalculated for consistent reference white in https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484
     334
     335    static constexpr ColorMatrix<3, 3> XYZD65ToLinearLMS {
     336        0.8190224432164319f,   0.3619062562801221f, -0.12887378261216414f,
     337        0.0329836671980271f,   0.9292868468965546f,  0.03614466816999844f,
     338        0.048177199566046255f, 0.26423952494422764f, 0.6335478258136937f
     339    };
     340
     341    static constexpr ColorMatrix<3, 3> NonLinearLMSToOKLab {
     342        0.2104542553f,  0.7936177850f, -0.0040720468f,
     343        1.9779984951f, -2.4285922050f,  0.4505937099f,
     344        0.0259040371f,  0.7827717662f, -0.8086757660f
     345    };
     346
     347    // 1. Convert XYZ into LMS "approximate cone responses".
     348    auto linearLMS = XYZD65ToLinearLMS.transformedColorComponents(asColorComponents(color).subset<0, 3>());
     349
     350    // 2. Apply non-linearity.
     351    auto nonLinearLMS = linearLMS.map([] (float v) { return std::cbrt(v); });
     352
     353    // 3. Transform into Lab-coordinates.
     354    auto [lightness, a, b] = NonLinearLMSToOKLab.transformedColorComponents(nonLinearLMS);
     355
     356    // 4. Transform lightness from unit lightness to percentage lightness.
     357    return { lightness * 100.0f, a, b, color.alpha };
     358}
     359
     360// MARK: OKLCH conversions.
     361
     362OKLCHA<float> ColorConversion<OKLCHA<float>, OKLab<float>>::convert(const OKLab<float>& color)
     363{
     364    return convertToPolarForm<OKLCHA<float>>(color);
     365}
     366
     367OKLab<float> ColorConversion<OKLab<float>, OKLCHA<float>>::convert(const OKLCHA<float>& color)
     368{
     369    return convertToRectangularForm<OKLab<float>>(color);
    274370}
    275371
     
    290386        case ColorSpace::LinearSRGB:
    291387            return asColorComponents(convertColor<LinearSRGBA<float>>(inputColor));
     388        case ColorSpace::OKLCH:
     389            return asColorComponents(convertColor<OKLCHA<float>>(inputColor));
     390        case ColorSpace::OKLab:
     391            return asColorComponents(convertColor<OKLab<float>>(inputColor));
    292392        case ColorSpace::ProPhotoRGB:
    293393            return asColorComponents(convertColor<ProPhotoRGB<float>>(inputColor));
  • trunk/Source/WebCore/platform/graphics/ColorConversion.h

    r286187 r286191  
    115115};
    116116
     117// MARK: OKLCHA
     118template<> struct ColorConversion<OKLab<float>, OKLCHA<float>> {
     119    WEBCORE_EXPORT static OKLab<float> convert(const OKLCHA<float>&);
     120};
     121template<> struct ColorConversion<OKLCHA<float>, OKLab<float>> {
     122    WEBCORE_EXPORT static OKLCHA<float> convert(const OKLab<float>&);
     123};
     124
     125// MARK: OKLab
     126template<> struct ColorConversion<XYZA<float, WhitePoint::D65>, OKLab<float>> {
     127    WEBCORE_EXPORT static XYZA<float, WhitePoint::D65> convert(const OKLab<float>&);
     128};
     129template<> struct ColorConversion<OKLab<float>, XYZA<float, WhitePoint::D65>> {
     130    WEBCORE_EXPORT static OKLab<float> convert(const XYZA<float, WhitePoint::D65>&);
     131};
     132
    117133// Identity conversion.
    118134
     
    132148//                                       └─────▲─────┘│└─────▲─────┘
    133149//                │                            │      │      │                                                                                                                            │
    134 //       ┌─────────────────────────┬───────────┘      │      └───────────┬───────────────────────────────┬───────────────────────────────┬───────────────────────────────
    135 //       │        │                │                  │                  │                               │                               │                               │                │
    136 //       │                         │                  │                  │                               │                               │                               │
    137 //       │        │                │                  │                  │                               │                               │                               │                │
    138 //       │          ProPhotoRGB───────────────────┐   │   SRGB──────────────────────────┐ DisplayP3─────────────────────┐ A98RGB────────────────────────┐ Rec2020───────────────────────┐
    139 //       │        │ │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │
    140 //       │          ││ Linear │ │ LinearExtended ││   │   ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││
    141 //       │        │ │└────────┘ └────────────────┘│   │   │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │
    142 //       │         ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─│─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─
    143 // ┌───────────┐    │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│
    144 // │    Lab    │    ││ Gamma  │ │ GammaExtended  ││   │   ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││
    145 // └─────▲─────┘    │└────────┘ └────────────────┘│   │   │└────▲───┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│
    146 //       │          └─────────────────────────────┘   │   └─────┼───────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘
    147 //       │                                            │      ┌──┴──────────┐
    148 //       │                                            │      │             │
    149 // ┌───────────┐                                      │┌───────────┐ ┌───────────┐
    150 // │    LCH    │                                      ││    HSL    │ │    HWB    │
    151 // └───────────┘                                      │└───────────┘ └───────────┘
     150//       ┌─────────────────────────┬───────────┘      │      └───────────┬───────────────────────────────┬───────────────────────────────┬───────────────────────────────┬─────────────────────────
     151//       │        │                │                  │                  │                               │                               │                               │                │        │
     152//       │                         │                  │                  │                               │                               │                               │                         │
     153//       │        │                │                  │                  │                               │                               │                               │                │        │
     154//       │          ProPhotoRGB───────────────────┐   │   SRGB──────────────────────────┐ DisplayP3─────────────────────┐ A98RGB────────────────────────┐ Rec2020───────────────────────┐          │
     155//       │        │ │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │        │
     156//       │          ││ Linear │ │ LinearExtended ││   │   ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││ ││ Linear │ │ LinearExtended ││          │
     157//       │        │ │└────────┘ └────────────────┘│   │   │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │        │
     158//       │         ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─│─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─         │
     159// ┌───────────┐    │┌────────┐ ┌────────────────┐│   │   │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│ │┌────────┐ ┌────────────────┐│    ┌───────────┐
     160// │    Lab    │    ││ Gamma  │ │ GammaExtended  ││   │   ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││ ││ Gamma  │ │ GammaExtended  ││    │   OKLab   │
     161// └─────▲─────┘    │└────────┘ └────────────────┘│   │   │└────▲───┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│ │└────────┘ └────────────────┘│    └─────▲─────┘
     162//       │          └─────────────────────────────┘   │   └─────┼───────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘ └─────────────────────────────┘          │
     163//       │                                            │      ┌──┴──────────┐                                                                                                                       │
     164//       │                                            │      │             │                                                                                                                       │
     165// ┌───────────┐                                      │┌───────────┐ ┌───────────┐                                                                                                           ┌───────────┐
     166// │    LCH    │                                      ││    HSL    │ │    HWB    │                                                                                                           │   OKLCH   │
     167// └───────────┘                                      │└───────────┘ └───────────┘                                                                                                           └───────────┘
    152168
    153169template<typename Output, typename Input, typename> struct ColorConversion {
  • trunk/Source/WebCore/platform/graphics/ColorMatrix.h

    r275206 r286191  
    4343    }
    4444
    45     constexpr ColorComponents<float, 4> transformedColorComponents(const ColorComponents<float, 4>&) const;
     45    template<size_t NumberOfComponents>
     46    constexpr ColorComponents<float, NumberOfComponents> transformedColorComponents(const ColorComponents<float, NumberOfComponents>&) const;
    4647
    4748    constexpr float at(size_t row, size_t column) const
     
    121122
    122123template<size_t ColumnCount, size_t RowCount>
    123 constexpr ColorComponents<float, 4> ColorMatrix<ColumnCount, RowCount>::transformedColorComponents(const ColorComponents<float, 4>& inputVector) const
     124template<size_t NumberOfComponents>
     125constexpr auto ColorMatrix<ColumnCount, RowCount>::transformedColorComponents(const ColorComponents<float, NumberOfComponents>& inputVector) const -> ColorComponents<float, NumberOfComponents>
    124126{
    125     static_assert(ColorComponents<float, 4>::Size >= RowCount);
     127    static_assert(ColorComponents<float, NumberOfComponents>::Size >= RowCount);
    126128   
    127     ColorComponents<float, 4> result;
     129    ColorComponents<float, NumberOfComponents> result;
    128130    for (size_t row = 0; row < RowCount; ++row) {
    129         if constexpr (ColumnCount <= ColorComponents<float, 4>::Size) {
     131        if constexpr (ColumnCount <= ColorComponents<float, NumberOfComponents>::Size) {
    130132            for (size_t column = 0; column < ColumnCount; ++column)
    131133                result[row] += at(row, column) * inputVector[column];
    132         } else if constexpr (ColumnCount > ColorComponents<float, 4>::Size) {
    133             for (size_t column = 0; column < ColorComponents<float, 4>::Size; ++column)
     134        } else if constexpr (ColumnCount > ColorComponents<float, NumberOfComponents>::Size) {
     135            for (size_t column = 0; column < ColorComponents<float, NumberOfComponents>::Size; ++column)
    134136                result[row] += at(row, column) * inputVector[column];
    135             for (size_t additionalColumn = ColorComponents<float, 4>::Size; additionalColumn < ColumnCount; ++additionalColumn)
     137            for (size_t additionalColumn = ColorComponents<float, NumberOfComponents>::Size; additionalColumn < ColumnCount; ++additionalColumn)
    136138                result[row] += at(row, additionalColumn);
    137139        }
    138140    }
    139     if constexpr (ColorComponents<float, 4>::Size > RowCount) {
    140         for (size_t additionalRow = RowCount; additionalRow < ColorComponents<float, 4>::Size; ++additionalRow)
     141    if constexpr (ColorComponents<float, NumberOfComponents>::Size > RowCount) {
     142        for (size_t additionalRow = RowCount; additionalRow < ColorComponents<float, NumberOfComponents>::Size; ++additionalRow)
    141143            result[additionalRow] = inputVector[additionalRow];
    142144    }
  • trunk/Source/WebCore/platform/graphics/ColorModels.h

    r274947 r286191  
    7373};
    7474
     75template<typename ColorType> inline constexpr bool UsesExtendedRGBModel = std::is_same_v<typename ColorType::Model, ExtendedRGBModel<typename ColorType::ComponentType>>;
     76
    7577template<> struct HSLModel<float> {
    7678    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     
    8183    static constexpr bool isInvertible = false;
    8284};
     85
     86template<typename ColorType> inline constexpr bool UsesHSLModel = std::is_same_v<typename ColorType::Model, HSLModel<typename ColorType::ComponentType>>;
    8387
    8488template<> struct HWBModel<float> {
     
    9195};
    9296
     97template<typename ColorType> inline constexpr bool UsesHWBModel = std::is_same_v<typename ColorType::Model, HWBModel<typename ColorType::ComponentType>>;
     98
    9399template<> struct LabModel<float> {
    94100    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     
    100106};
    101107
     108template<typename ColorType> inline constexpr bool UsesLabModel = std::is_same_v<typename ColorType::Model, LabModel<typename ColorType::ComponentType>>;
     109
    102110template<> struct LCHModel<float> {
    103111    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     
    108116    static constexpr bool isInvertible = false;
    109117};
     118
     119template<typename ColorType> inline constexpr bool UsesLCHModel = std::is_same_v<typename ColorType::Model, LCHModel<typename ColorType::ComponentType>>;
    110120
    111121template<> struct RGBModel<float> {
     
    127137};
    128138
     139template<typename ColorType> inline constexpr bool UsesRGBModel = std::is_same_v<typename ColorType::Model, RGBModel<typename ColorType::ComponentType>>;
     140
    129141template<> struct XYZModel<float> {
    130142    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     
    136148};
    137149
     150template<typename ColorType> inline constexpr bool UsesXYZModel = std::is_same_v<typename ColorType::Model, XYZModel<typename ColorType::ComponentType>>;
     151
    138152}
  • trunk/Source/WebCore/platform/graphics/ColorSerialization.cpp

    r286168 r286191  
    5656static String serializationForRenderTreeAsText(const LinearSRGBA<float>&, bool useColorFunctionSerialization);
    5757
     58static String serializationForCSS(const OKLCHA<float>&, bool useColorFunctionSerialization);
     59static String serializationForHTML(const OKLCHA<float>&, bool useColorFunctionSerialization);
     60static String serializationForRenderTreeAsText(const OKLCHA<float>&, bool useColorFunctionSerialization);
     61
     62static String serializationForCSS(const OKLab<float>&, bool useColorFunctionSerialization);
     63static String serializationForHTML(const OKLab<float>&, bool useColorFunctionSerialization);
     64static String serializationForRenderTreeAsText(const OKLab<float>&, bool useColorFunctionSerialization);
     65
    5866static String serializationForCSS(const ProPhotoRGB<float>&, bool useColorFunctionSerialization);
    5967static String serializationForHTML(const ProPhotoRGB<float>&, bool useColorFunctionSerialization);
     
    115123    case ColorSpace::LinearSRGB:
    116124        return "srgb-linear"_s;
     125    case ColorSpace::OKLCH:
     126        return "oklch"_s;
     127    case ColorSpace::OKLab:
     128        return "oklab"_s;
    117129    case ColorSpace::ProPhotoRGB:
    118130        return "prophoto-rgb"_s;
     
    141153}
    142154
    143 static String serializationUsingColorFunction(const Lab<float>& color)
    144 {
    145     auto [c1, c2, c3, alpha] = color;
    146     if (WTF::areEssentiallyEqual(alpha, 1.0f))
    147         return makeString("color(", serialization(ColorSpaceFor<Lab<float>>), ' ', c1, "% ", c2, ' ', c3, ')');
    148     return makeString("color(", serialization(ColorSpaceFor<Lab<float>>), ' ', c1, "% ", c2, ' ', c3, " / ", alpha, ')');
    149 }
    150 
    151155static String serializationUsingColorFunction(const SRGBA<uint8_t>& color)
    152156{
     
    190194// MARK: LCHA<float> overloads
    191195
    192 String serializationForCSS(const LCHA<float>& color, bool useColorFunctionSerialization)
     196String serializationForCSS(const LCHA<float>& color, bool)
    193197{
    194198    // https://www.w3.org/TR/css-color-4/#serializing-lab-lch
    195     if (useColorFunctionSerialization)
    196         return serializationUsingColorFunction(color);
    197 
    198199    auto [c1, c2, c3, alpha] = color;
    199200    if (WTF::areEssentiallyEqual(alpha, 1.0f))
     
    214215// MARK: Lab<float> overloads
    215216
    216 String serializationForCSS(const Lab<float>& color, bool useColorFunctionSerialization)
     217String serializationForCSS(const Lab<float>& color, bool)
    217218{
    218219    // https://www.w3.org/TR/css-color-4/#serializing-lab-lch
    219     if (useColorFunctionSerialization)
    220         return serializationUsingColorFunction(color);
    221 
    222220    auto [c1, c2, c3, alpha] = color;
    223221    if (WTF::areEssentiallyEqual(alpha, 1.0f))
     
    251249{
    252250    return serializationUsingColorFunction(color);
     251}
     252
     253// MARK: OKLCHA<float> overloads
     254
     255String serializationForCSS(const OKLCHA<float>& color, bool)
     256{
     257    auto [c1, c2, c3, alpha] = color;
     258    if (WTF::areEssentiallyEqual(alpha, 1.0f))
     259        return makeString("oklch(", c1, "% ", c2, ' ', c3, ')');
     260    return makeString("oklch(", c1, "% ", c2, ' ', c3, " / ", alpha, ')');
     261}
     262
     263String serializationForHTML(const OKLCHA<float>& color, bool useColorFunctionSerialization)
     264{
     265    return serializationForCSS(color, useColorFunctionSerialization);
     266}
     267
     268String serializationForRenderTreeAsText(const OKLCHA<float>& color, bool useColorFunctionSerialization)
     269{
     270    return serializationForCSS(color, useColorFunctionSerialization);
     271}
     272
     273// MARK: OKLab<float> overloads
     274
     275String serializationForCSS(const OKLab<float>& color, bool)
     276{
     277    auto [c1, c2, c3, alpha] = color;
     278    if (WTF::areEssentiallyEqual(alpha, 1.0f))
     279        return makeString("oklab(", c1, "% ", c2, ' ', c3, ')');
     280    return makeString("oklab(", c1, "% ", c2, ' ', c3, " / ", alpha, ')');
     281}
     282
     283String serializationForHTML(const OKLab<float>& color, bool useColorFunctionSerialization)
     284{
     285    return serializationForCSS(color, useColorFunctionSerialization);
     286}
     287
     288String serializationForRenderTreeAsText(const OKLab<float>& color, bool useColorFunctionSerialization)
     289{
     290    return serializationForCSS(color, useColorFunctionSerialization);
    253291}
    254292
  • trunk/Source/WebCore/platform/graphics/ColorSpace.cpp

    r286168 r286191  
    3535    switch (colorSpace) {
    3636    case ColorSpace::A98RGB:
    37         ts << "a98-rgb";
     37        ts << "A98-RGB";
    3838        break;
    3939    case ColorSpace::DisplayP3:
     
    4444        break;
    4545    case ColorSpace::Lab:
    46         ts << "L*a*b";
     46        ts << "Lab";
    4747        break;
    4848    case ColorSpace::LinearSRGB:
    4949        ts << "LinearSRGB";
     50        break;
     51    case ColorSpace::OKLCH:
     52        ts << "OKLCH";
     53        break;
     54    case ColorSpace::OKLab:
     55        ts << "OKLab";
    5056        break;
    5157    case ColorSpace::ProPhotoRGB:
  • trunk/Source/WebCore/platform/graphics/ColorSpace.h

    r286168 r286191  
    3939    Lab,
    4040    LinearSRGB,
     41    OKLCH,
     42    OKLab,
    4143    ProPhotoRGB,
    4244    Rec2020,
     
    5557template<typename T> struct ColorSpaceMapping<Lab<T>> { static constexpr auto colorSpace { ColorSpace::Lab }; };
    5658template<typename T> struct ColorSpaceMapping<LinearSRGBA<T>> { static constexpr auto colorSpace { ColorSpace::LinearSRGB }; };
     59template<typename T> struct ColorSpaceMapping<OKLab<T>> { static constexpr auto colorSpace { ColorSpace::OKLab }; };
     60template<typename T> struct ColorSpaceMapping<OKLCHA<T>> { static constexpr auto colorSpace { ColorSpace::OKLCH }; };
    5761template<typename T> struct ColorSpaceMapping<ProPhotoRGB<T>> { static constexpr auto colorSpace { ColorSpace::ProPhotoRGB }; };
    5862template<typename T> struct ColorSpaceMapping<Rec2020<T>> { static constexpr auto colorSpace { ColorSpace::Rec2020 }; };
     
    7781    case ColorSpace::LinearSRGB:
    7882        return std::invoke(std::forward<Functor>(functor), makeFromComponents<LinearSRGBA<T>>(components));
     83    case ColorSpace::OKLCH:
     84        return std::invoke(std::forward<Functor>(functor), makeFromComponents<OKLCHA<T>>(components));
     85    case ColorSpace::OKLab:
     86        return std::invoke(std::forward<Functor>(functor), makeFromComponents<OKLab<T>>(components));
    7987    case ColorSpace::ProPhotoRGB:
    8088        return std::invoke(std::forward<Functor>(functor), makeFromComponents<ProPhotoRGB<T>>(components));
     
    106114        WebCore::ColorSpace::Lab,
    107115        WebCore::ColorSpace::LinearSRGB,
     116        WebCore::ColorSpace::OKLCH,
     117        WebCore::ColorSpace::OKLab,
    108118        WebCore::ColorSpace::ProPhotoRGB,
    109119        WebCore::ColorSpace::Rec2020,
  • trunk/Source/WebCore/platform/graphics/ColorTypes.h

    r278070 r286191  
    4343template<typename> struct LCHA;
    4444template<typename> struct Lab;
    45 template<typename> struct Oklab;
    46 template<typename> struct Oklch;
     45template<typename> struct OKLCHA;
     46template<typename> struct OKLab;
    4747template<typename, WhitePoint> struct XYZA;
    4848
     
    196196    using TransferFunction = TF;
    197197    using Descriptor = D;
    198     static constexpr WhitePoint whitePoint = D::whitePoint;
     198    static constexpr auto whitePoint = D::whitePoint;
    199199
    200200    constexpr RGBAType(T red, T green, T blue, T alpha = AlphaTraits<T>::opaque)
     
    300300struct SRGBADescriptor {
    301301    template<typename T, TransferFunctionMode Mode> using TransferFunction = SRGBTransferFunction<T, Mode>;
    302     static constexpr WhitePoint whitePoint = WhitePoint::D65;
     302    static constexpr auto whitePoint = WhitePoint::D65;
    303303
    304304    // https://drafts.csswg.org/css-color/#color-conversion-code
     
    323323struct A98RGBDescriptor {
    324324    template<typename T, TransferFunctionMode Mode> using TransferFunction = A98RGBTransferFunction<T, Mode>;
    325     static constexpr WhitePoint whitePoint = WhitePoint::D65;
     325    static constexpr auto whitePoint = WhitePoint::D65;
    326326
    327327    // https://drafts.csswg.org/css-color/#color-conversion-code
     
    344344struct DisplayP3Descriptor {
    345345    template<typename T, TransferFunctionMode Mode> using TransferFunction = SRGBTransferFunction<T, Mode>;
    346     static constexpr WhitePoint whitePoint = WhitePoint::D65;
     346    static constexpr auto whitePoint = WhitePoint::D65;
    347347
    348348    // https://drafts.csswg.org/css-color/#color-conversion-code
     
    365365struct ProPhotoRGBDescriptor {
    366366    template<typename T, TransferFunctionMode Mode> using TransferFunction = ProPhotoRGBTransferFunction<T, Mode>;
    367     static constexpr WhitePoint whitePoint = WhitePoint::D50;
     367    static constexpr auto whitePoint = WhitePoint::D50;
    368368
    369369    // https://drafts.csswg.org/css-color/#color-conversion-code
     
    386386struct Rec2020Descriptor {
    387387    template<typename T, TransferFunctionMode Mode> using TransferFunction = Rec2020TransferFunction<T, Mode>;
    388     static constexpr WhitePoint whitePoint = WhitePoint::D65;
     388    static constexpr auto whitePoint = WhitePoint::D65;
    389389
    390390    // https://drafts.csswg.org/css-color/#color-conversion-code
     
    410410    using ComponentType = T;
    411411    using Model = LabModel<T>;
    412     static constexpr WhitePoint whitePoint = WhitePoint::D50;
    413     using Reference =  XYZA<T, whitePoint>;
     412    static constexpr auto whitePoint = WhitePoint::D50;
     413    using Reference = XYZA<T, whitePoint>;
    414414
    415415    constexpr Lab(T lightness, T a, T b, T alpha = AlphaTraits<T>::opaque)
     
    445445    using ComponentType = T;
    446446    using Model = LCHModel<T>;
    447     static constexpr WhitePoint whitePoint = WhitePoint::D50;
     447    static constexpr auto whitePoint = WhitePoint::D50;
    448448    using Reference = Lab<T>;
    449449
     
    475475template<typename ColorType> inline constexpr bool IsLCHA = std::is_same_v<LCHA<typename ColorType::ComponentType>, ColorType>;
    476476
     477// MARK: - OKLab Color Type.
     478
     479template<typename T> struct OKLab : ColorWithAlphaHelper<OKLab<T>> {
     480    using ComponentType = T;
     481    using Model = LabModel<T>;
     482    static constexpr auto whitePoint = WhitePoint::D65;
     483    using Reference = XYZA<T, whitePoint>;
     484
     485    constexpr OKLab(T lightness, T a, T b, T alpha = AlphaTraits<T>::opaque)
     486        : lightness { lightness }
     487        , a { a }
     488        , b { b }
     489        , alpha { alpha }
     490    {
     491        assertInRange(*this);
     492    }
     493
     494    constexpr OKLab()
     495        : OKLab { 0, 0, 0, 0 }
     496    {
     497    }
     498
     499    T lightness;
     500    T a;
     501    T b;
     502    T alpha;
     503};
     504
     505template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const OKLab<T>& c)
     506{
     507    return { c.lightness, c.a, c.b, c.alpha };
     508}
     509
     510template<typename ColorType> inline constexpr bool IsOKLab = std::is_same_v<OKLab<typename ColorType::ComponentType>, ColorType>;
     511
     512// MARK: - OKLCHA Color Type.
     513
     514template<typename T> struct OKLCHA : ColorWithAlphaHelper<OKLCHA<T>> {
     515    using ComponentType = T;
     516    using Model = LCHModel<T>;
     517    static constexpr auto whitePoint = WhitePoint::D65;
     518    using Reference = OKLab<T>;
     519
     520    constexpr OKLCHA(T lightness, T chroma, T hue, T alpha = AlphaTraits<T>::opaque)
     521        : lightness { lightness }
     522        , chroma { chroma }
     523        , hue { hue }
     524        , alpha { alpha }
     525    {
     526        assertInRange(*this);
     527    }
     528
     529    constexpr OKLCHA()
     530        : OKLCHA { 0, 0, 0, 0 }
     531    {
     532    }
     533
     534    T lightness;
     535    T chroma;
     536    T hue;
     537    T alpha;
     538};
     539
     540template<typename T> constexpr ColorComponents<T, 4> asColorComponents(const OKLCHA<T>& c)
     541{
     542    return { c.lightness, c.chroma, c.hue, c.alpha };
     543}
     544
     545template<typename ColorType> inline constexpr bool IsOKLCHA = std::is_same_v<OKLCHA<typename ColorType::ComponentType>, ColorType>;
     546
    477547
    478548// MARK: - HSLA Color Type.
     
    481551    using ComponentType = T;
    482552    using Model = HSLModel<T>;
    483     static constexpr WhitePoint whitePoint = WhitePoint::D65;
     553    static constexpr auto whitePoint = WhitePoint::D65;
    484554    using Reference = SRGBA<T>;
    485555
     
    516586    using ComponentType = T;
    517587    using Model = HWBModel<T>;
    518     static constexpr WhitePoint whitePoint = WhitePoint::D65;
     588    static constexpr auto whitePoint = WhitePoint::D65;
    519589    using Reference = SRGBA<T>;
    520590
     
    552622    using Model = XYZModel<T>;
    553623    using ReferenceXYZ = XYZA<T, W>;
    554     static constexpr WhitePoint whitePoint = W;
     624    static constexpr auto whitePoint = W;
    555625
    556626    constexpr XYZA(T x, T y, T z, T alpha = AlphaTraits<T>::opaque)
  • trunk/Source/WebCore/platform/graphics/ColorUtilities.h

    r274947 r286191  
    5555template<typename ColorType> ColorType invertedColorWithOverriddenAlpha(const ColorType&, float overrideAlpha);
    5656
    57 template<typename ColorType, typename std::enable_if_t<std::is_same_v<typename ColorType::Model, RGBModel<typename ColorType::ComponentType>>>* = nullptr> constexpr bool isBlack(const ColorType&);
     57template<typename ColorType, typename std::enable_if_t<UsesLabModel<ColorType> || UsesLCHModel<ColorType>>* = nullptr> constexpr bool isBlack(const ColorType&);
     58template<typename ColorType, typename std::enable_if_t<UsesRGBModel<ColorType>>* = nullptr> constexpr bool isBlack(const ColorType&);
    5859template<WhitePoint W> constexpr bool isBlack(const XYZA<float, W>&);
    59 constexpr bool isBlack(const LCHA<float>&);
    60 constexpr bool isBlack(const Lab<float>&);
    6160
    62 template<typename ColorType, typename std::enable_if_t<std::is_same_v<typename ColorType::Model, RGBModel<typename ColorType::ComponentType>>>* = nullptr> constexpr bool isWhite(const ColorType&);
     61template<typename ColorType, typename std::enable_if_t<UsesLabModel<ColorType> || UsesLCHModel<ColorType>>* = nullptr> constexpr bool isWhite(const ColorType&);
     62template<typename ColorType, typename std::enable_if_t<UsesRGBModel<ColorType>>* = nullptr> constexpr bool isWhite(const ColorType&);
    6363template<WhitePoint W> constexpr bool isWhite(const XYZA<float, W>&);
    64 constexpr bool isWhite(const LCHA<float>&);
    65 constexpr bool isWhite(const Lab<float>&);
    6664
    6765constexpr uint16_t fastMultiplyBy255(uint16_t);
     
    151149}
    152150
    153 constexpr bool isBlack(const LCHA<float>& color)
     151template<typename ColorType, typename std::enable_if_t<UsesLabModel<ColorType> || UsesLCHModel<ColorType>>*>
     152constexpr bool isBlack(const ColorType& color)
    154153{
    155154    return color.lightness == 0 && color.alpha == AlphaTraits<float>::opaque;
    156155}
    157156
    158 constexpr bool isBlack(const Lab<float>& color)
    159 {
    160     return color.lightness == 0 && color.alpha == AlphaTraits<float>::opaque;
    161 }
    162 
    163 template<typename ColorType, typename std::enable_if_t<std::is_same_v<typename ColorType::Model, RGBModel<typename ColorType::ComponentType>>>*>
     157template<typename ColorType, typename std::enable_if_t<UsesRGBModel<ColorType>>*>
    164158constexpr bool isBlack(const ColorType& color)
    165159{
     
    174168}
    175169
    176 constexpr bool isWhite(const LCHA<float>& color)
     170template<typename ColorType, typename std::enable_if_t<UsesLabModel<ColorType> || UsesLCHModel<ColorType>>*>
     171constexpr bool isWhite(const ColorType& color)
    177172{
    178173    return color.lightness == 100 && color.alpha == AlphaTraits<float>::opaque;
    179174}
    180175
    181 constexpr bool isWhite(const Lab<float>& color)
    182 {
    183     return color.lightness == 100 && color.alpha == AlphaTraits<float>::opaque;
    184 }
    185 
    186 template<typename ColorType, typename std::enable_if_t<std::is_same_v<typename ColorType::Model, RGBModel<typename ColorType::ComponentType>>>*>
     176template<typename ColorType, typename std::enable_if_t<UsesRGBModel<ColorType>>*>
    187177constexpr bool isWhite(const ColorType& color)
    188178{
  • trunk/Source/WebCore/platform/graphics/cg/ColorSpaceCG.h

    r286168 r286191  
    8686        return nullptr;
    8787#endif
    88     case ColorSpace::LCH:
    89         return nullptr;
    9088    case ColorSpace::Lab:
    9189#if HAVE(CORE_GRAPHICS_LAB_COLOR_SPACE)
     
    120118        return nullptr;
    121119#endif
     120
     121    // FIXME: Add support for these once CoreGraphics supports it.
     122    case ColorSpace::LCH:
     123    case ColorSpace::OKLCH:
     124    case ColorSpace::OKLab:
    122125    case ColorSpace::XYZ_D65:
    123         // FIXME: Add support for this once we have figured out how to create the CoreGraphics representation.
    124126        return nullptr;
    125127
Note: See TracChangeset for help on using the changeset viewer.