Changeset 274947 in webkit


Ignore:
Timestamp:
Mar 24, 2021 10:34:50 AM (16 months ago)
Author:
weinig@apple.com
Message:

Update CSS Color 5 color-mix() implementation to match the latest draft spec
https://bugs.webkit.org/show_bug.cgi?id=223665

Reviewed by Simon Fraser.

Source/WebCore:

Update to the latest draft spec, which dramatically reduces the complexity of color-mix()
by remove per-component adjusters.

  • css/CSSValueKeywords.in:
  • css/parser/CSSPropertyParserHelpers.cpp:

(WebCore::CSSPropertyParserHelpers::normalizeWhitenessBlackness):
(WebCore::CSSPropertyParserHelpers::consumeColorMixColorSpaceAndComma):
(WebCore::CSSPropertyParserHelpers::consumeColorMixComponent):
(WebCore::CSSPropertyParserHelpers::normalizedMixPercentages):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HSLA<float>>):
(WebCore::CSSPropertyParserHelpers::fixupHueComponentsPriorToMix):
(WebCore::CSSPropertyParserHelpers::mixColorComponentsInColorSpace):
(WebCore::CSSPropertyParserHelpers::mixColorComponents):
(WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParameters):
(WebCore::CSSPropertyParserHelpers::HueColorAdjuster::fixupAnglesForInterpolation): Deleted.
(WebCore::CSSPropertyParserHelpers::HueColorAdjuster::HueColorAdjuster): Deleted.
(WebCore::CSSPropertyParserHelpers::ColorAdjuster::ColorAdjuster): Deleted.
(WebCore::CSSPropertyParserHelpers::consumeAdjuster): Deleted.
(WebCore::CSSPropertyParserHelpers::consumeAndUpdateAdjusterAtIndex): Deleted.
(WebCore::CSSPropertyParserHelpers::consumeAndUpdateAdjuster): Deleted.
(WebCore::CSSPropertyParserHelpers::consumeAdjusters): Deleted.
(WebCore::CSSPropertyParserHelpers::consumeMixComponents): Deleted.
(WebCore::CSSPropertyParserHelpers::normalizeAdjusterValues): Deleted.
(WebCore::CSSPropertyParserHelpers::remainingAdjustment): Deleted.
(WebCore::CSSPropertyParserHelpers::mixComponent): Deleted.
(WebCore::CSSPropertyParserHelpers::mixComponentAtIndex): Deleted.
(WebCore::CSSPropertyParserHelpers::mix): Deleted.
(WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParametersUsingAdjusters): Deleted.
Update to the new syntax and remove component adjusters. They may come back for color-adjust()
in the future.

  • platform/graphics/ColorModels.h:
  • platform/graphics/ColorTypes.h:

(WebCore::clampedComponent):
(WebCore::assertInRange):

  • platform/graphics/ColorUtilities.h:

(WebCore::invertedColorWithOverriddenAlpha):
Add support in the color models for annotating more about each component, now including
the type (angle, number or percentage). This allows algorithms generic algorithms to
operate on abstract color type components without specializing for each color type.

LayoutTests:

  • fast/css/parsing-color-mix-expected.txt:
  • fast/css/parsing-color-mix.html:

Update test and results for vastly simplified color-mix().

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r274936 r274947  
     12021-03-24  Sam Weinig  <weinig@apple.com>
     2
     3        Update CSS Color 5 color-mix() implementation to match the latest draft spec
     4        https://bugs.webkit.org/show_bug.cgi?id=223665
     5
     6        Reviewed by Simon Fraser.
     7
     8        * fast/css/parsing-color-mix-expected.txt:
     9        * fast/css/parsing-color-mix.html:
     10        Update test and results for vastly simplified color-mix().
     11
    1122021-03-24  Chris Lord  <clord@igalia.com>
    213
  • trunk/LayoutTests/fast/css/parsing-color-mix-expected.txt

    r273244 r274947  
    55
    66color-mix(hsl, ...)
    7 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))") is "rgb(84, 92, 61)"
    8 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))") is "rgb(112, 106, 67)"
    9 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)") is "rgb(61, 73, 54)"
    10 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)") is "rgb(112, 106, 67)"
    11 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)") is "rgb(112, 106, 67)"
    12 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)") is "rgb(112, 106, 67)"
    13 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
    14 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
    15 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 50%)") is "rgb(53, 56, 46)"
    16 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) hue 50%)") is "rgb(53, 56, 46)"
    17 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 100%, hsl(30deg 30% 40%))") is "rgb(46, 56, 46)"
    18 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
    19 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
    20 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
    21 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100% alpha 100%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
    22 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0%)") is "rgb(53, 56, 46)"
    23 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0%)") is "rgb(53, 56, 46)"
    24 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0% alpha 0%)") is "rgb(53, 56, 46)"
    25 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75%, hsl(30deg 30% 40%))") is "rgb(55, 59, 43)"
    26 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15%, hsl(30deg 30% 40%))") is "rgb(101, 108, 80)"
    27 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15% alpha 10%, hsl(30deg 30% 40%))") is "rgb(101, 108, 80)"
    28 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%))") is "rgb(52, 56, 46)"
    29 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 40%)") is "rgb(52, 56, 46)"
    30 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%) hue 40%)") is "rgb(52, 56, 46)"
    31 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 60% hue 40%, hsl(30deg 30% 40%))") is "rgb(55, 56, 46)"
    32 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 40%, hsl(30deg 30% 40%))") is "rgb(55, 56, 46)"
    33 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
    34 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
    35 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
    36 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
    37 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue -10%, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
    38 PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
     7PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))") is "rgb(84, 92, 61)"
     8PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))") is "rgb(112, 106, 67)"
     9PASS computedStyle("background-color", "color-mix(in hsl, 25% hsl(120deg 10% 20%), hsl(30deg 30% 40%))") is "rgb(112, 106, 67)"
     10PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%), 25% hsl(30deg 30% 40%))") is "rgb(61, 73, 54)"
     11PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)") is "rgb(61, 73, 54)"
     12PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)") is "rgb(112, 106, 67)"
     13PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)") is "rgb(112, 106, 67)"
     14PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)") is "rgb(112, 106, 67)"
     15PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
     16PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))") is "rgb(142, 97, 72)"
    3917
    4018color-mix(hwb, ...)
    41 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%))") is "rgb(147, 179, 52)"
    42 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%))") is "rgb(166, 153, 64)"
    43 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)") is "rgb(96, 191, 39)"
    44 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)") is "rgb(166, 153, 64)"
    45 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)") is "rgb(166, 153, 64)"
    46 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)") is "rgb(166, 153, 64)"
    47 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
    48 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
    49 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 50%)") is "rgb(160, 204, 26)"
    50 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) hue 50%)") is "rgb(160, 204, 26)"
    51 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 100%, hwb(30deg 30% 40%))") is "rgb(26, 204, 26)"
    52 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
    53 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
    54 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
    55 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100% alpha 100%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
    56 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0%)") is "rgb(160, 204, 26)"
    57 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0%)") is "rgb(160, 204, 26)"
    58 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0% alpha 0%)") is "rgb(160, 204, 26)"
    59 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75%, hwb(30deg 30% 40%))") is "rgb(163, 204, 39)"
    60 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15%, hwb(30deg 30% 40%))") is "rgb(130, 161, 39)"
    61 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15% alpha 10%, hwb(30deg 30% 40%))") is "rgb(130, 161, 39)"
    62 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%))") is "rgb(133, 204, 26)"
    63 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 40%)") is "rgb(133, 204, 26)"
    64 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%) hue 40%)") is "rgb(133, 204, 26)"
    65 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 75% 25%) whiteness 100%, hwb(120deg 25% 75%) blackness 100%)") is "rgb(128, 128, 128)"
    66 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 60% hue 40%, hwb(30deg 30% 40%))") is "rgb(186, 204, 26)"
    67 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 40%, hwb(30deg 30% 40%))") is "rgb(186, 204, 26)"
    68 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
    69 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
    70 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
    71 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
    72 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue -10%, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
    73 PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
     19PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%))") is "rgb(147, 179, 52)"
     20PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%))") is "rgb(166, 153, 64)"
     21PASS computedStyle("background-color", "color-mix(in hwb, 25% hwb(120deg 10% 20%), hwb(30deg 30% 40%))") is "rgb(166, 153, 64)"
     22PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%), 25% hwb(30deg 30% 40%))") is "rgb(96, 191, 39)"
     23PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)") is "rgb(96, 191, 39)"
     24PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)") is "rgb(166, 153, 64)"
     25PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)") is "rgb(166, 153, 64)"
     26PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)") is "rgb(166, 153, 64)"
     27PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
     28PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))") is "rgb(148, 105, 82)"
    7429
    7530color-mix(lch, ...)
    76 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))") is "lch(30% 40 50 / 0.6)"
    77 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8))") is "lch(40% 50 60 / 0.7)"
    78 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) 25%)") is "lch(20% 30 40 / 0.5)"
    79 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8) 75%)") is "lch(40% 50 60 / 0.7)"
    80 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 50%, lch(50% 60 70deg / .8) 150%)") is "lch(40% 50 60 / 0.7)"
    81 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 12.5%, lch(50% 60 70deg / .8) 37.5%)") is "lch(40% 50 60 / 0.7)"
    82 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
    83 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
    84 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 50%)") is "lch(30% 20 30 / 0.4)"
    85 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) lightness 50%)") is "lch(30% 20 30 / 0.4)"
    86 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 100%, lch(50% 60 70deg / .8))") is "lch(10% 20 30 / 0.4)"
    87 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
    88 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
    89 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
    90 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100% alpha 100%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
    91 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0%)") is "lch(30% 20 30 / 0.4)"
    92 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0%)") is "lch(30% 20 30 / 0.4)"
    93 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0% alpha 0%)") is "lch(30% 20 30 / 0.4)"
    94 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75%, lch(50% 60 70deg / .8))") is "lch(30% 30 30 / 0.4)"
    95 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15%, lch(50% 60 70deg / .8))") is "lch(30% 30 64 / 0.4)"
    96 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15% alpha 10%, lch(50% 60 70deg / .8))") is "lch(30% 30 64 / 0.76)"
    97 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8))") is "lch(26% 20 30 / 0.4)"
    98 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 40%)") is "lch(26% 20 30 / 0.4)"
    99 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8) lightness 40%)") is "lch(26% 20 30 / 0.4)"
    100 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 60% lightness 40%, lch(50% 60 70deg / .8))") is "lch(34% 20 30 / 0.4)"
    101 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 40%, lch(50% 60 70deg / .8))") is "lch(34% 20 30 / 0.4)"
    102 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
    103 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
    104 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
    105 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
    106 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness -10%, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
    107 PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
     31PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))") is "lch(30% 40 50 / 0.6)"
     32PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8))") is "lch(40% 50 60 / 0.7)"
     33PASS computedStyle("background-color", "color-mix(in lch, 25% lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))") is "lch(40% 50 60 / 0.7)"
     34PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4), 25% lch(50% 60 70deg / .8))") is "lch(20% 30 40 / 0.5)"
     35PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) 25%)") is "lch(20% 30 40 / 0.5)"
     36PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8) 75%)") is "lch(40% 50 60 / 0.7)"
     37PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 50%, lch(50% 60 70deg / .8) 150%)") is "lch(40% 50 60 / 0.7)"
     38PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 12.5%, lch(50% 60 70deg / .8) 37.5%)") is "lch(40% 50 60 / 0.7)"
     39PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
     40PASS 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)"
    10841
    10942color-mix(lab, ...)
    110 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))") is "lab(30% 40 50 / 0.6)"
    111 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8))") is "lab(40% 50 60 / 0.7)"
    112 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) 25%)") is "lab(20% 30 40 / 0.5)"
    113 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8) 75%)") is "lab(40% 50 60 / 0.7)"
    114 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 50%, lab(50% 60 70 / .8) 150%)") is "lab(40% 50 60 / 0.7)"
    115 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 12.5%, lab(50% 60 70 / .8) 37.5%)") is "lab(40% 50 60 / 0.7)"
    116 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8))") is "lab(50% 60 70 / 0.8)"
    117 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
    118 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 50%)") is "lab(30% 20 30 / 0.4)"
    119 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) lightness 50%)") is "lab(30% 20 30 / 0.4)"
    120 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 100%, lab(50% 60 70 / .8))") is "lab(10% 20 30 / 0.4)"
    121 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
    122 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
    123 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
    124 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100% alpha 100%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
    125 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0%)") is "lab(30% 20 30 / 0.4)"
    126 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0%)") is "lab(30% 20 30 / 0.4)"
    127 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0% alpha 0%)") is "lab(30% 20 30 / 0.4)"
    128 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75%, lab(50% 60 70 / .8))") is "lab(30% 30 30 / 0.4)"
    129 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15%, lab(50% 60 70 / .8))") is "lab(30% 30 64 / 0.4)"
    130 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15% alpha 10%, lab(50% 60 70 / .8))") is "lab(30% 30 64 / 0.76)"
    131 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8))") is "lab(26% 20 30 / 0.4)"
    132 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 40%)") is "lab(26% 20 30 / 0.4)"
    133 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8) lightness 40%)") is "lab(26% 20 30 / 0.4)"
    134 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 60% lightness 40%, lab(50% 60 70 / .8))") is "lab(34% 20 30 / 0.4)"
    135 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness, lab(50% 60 70 / .8))") is "lab(50% 20 30 / 0.4)"
    136 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 0%, lab(50% 60 70 / .8))") is "lab(50% 20 30 / 0.4)"
    137 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))") is "lab(50% 60 70 / 0.8)"
    138 PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness -10%, lab(50% 60 70 / .8))") is "lab(50% 20 30 / 0.4)"
     43PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))") is "lab(30% 40 50 / 0.6)"
     44PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8))") is "lab(40% 50 60 / 0.7)"
     45PASS computedStyle("background-color", "color-mix(in lab, 25% lab(10% 20 30 / .4), lab(50% 60 70 / .8))") is "lab(40% 50 60 / 0.7)"
     46PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4), 25% lab(50% 60 70 / .8))") is "lab(20% 30 40 / 0.5)"
     47PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) 25%)") is "lab(20% 30 40 / 0.5)"
     48PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8) 75%)") is "lab(40% 50 60 / 0.7)"
     49PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 50%, lab(50% 60 70 / .8) 150%)") is "lab(40% 50 60 / 0.7)"
     50PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 12.5%, lab(50% 60 70 / .8) 37.5%)") is "lab(40% 50 60 / 0.7)"
     51PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8))") is "lab(50% 60 70 / 0.8)"
     52PASS 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)"
    13953
    14054color-mix(srgb, ...)
    141 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.4 0.5 / 0.6)"
    142 PASS computedStyle("background-color", "color-mix(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)"
    143 PASS computedStyle("background-color", "color-mix(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)"
    144 PASS computedStyle("background-color", "color-mix(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)"
    145 PASS computedStyle("background-color", "color-mix(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)"
    146 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 12.5%, color(srgb .5 .6 .7 / .8) 37.5%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
    147 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.6 0.7 / 0.8)"
    148 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    149 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 50%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    150 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) red 50%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    151 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.1 0.2 0.3 / 0.4)"
    152 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    153 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    154 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    155 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100% alpha 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    156 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    157 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    158 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0% alpha 0%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
    159 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.3 0.3 / 0.4)"
    160 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.3 0.64 / 0.4)"
    161 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15% alpha 10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.3 0.64 / 0.76)"
    162 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.26 0.2 0.3 / 0.4)"
    163 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 40%)") is "color(srgb 0.26 0.2 0.3 / 0.4)"
    164 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8) red 40%)") is "color(srgb 0.26 0.2 0.3 / 0.4)"
    165 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60% red 40%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.34 0.2 0.3 / 0.4)"
    166 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.2 0.3 / 0.4)"
    167 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 0%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.2 0.3 / 0.4)"
    168 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.6 0.7 / 0.8)"
    169 PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red -10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.2 0.3 / 0.4)"
     55PASS 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)"
     56PASS 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)"
     57PASS 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)"
     58PASS 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)"
     59PASS 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)"
     60PASS 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)"
     61PASS 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)"
     62PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 12.5%, color(srgb .5 .6 .7 / .8) 37.5%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
     63PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.6 0.7 / 0.8)"
     64PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.54 0.64000005 0.74 / 0.84000003)"
    17065
    17166color-mix(xyz, ...)
    172 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.4 0.5 / 0.6)"
    173 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.4 0.5 0.6 / 0.7)"
    174 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) 25%)") is "color(xyz 0.2 0.3 0.4 / 0.5)"
    175 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
    176 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
    177 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 12.5%, color(xyz .5 .6 .7 / .8) 37.5%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
    178 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.6 0.7 / 0.8)"
    179 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    180 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 50%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    181 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) x 50%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    182 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.1 0.2 0.3 / 0.4)"
    183 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    184 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    185 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    186 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100% alpha 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    187 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    188 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    189 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0% alpha 0%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
    190 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.3 0.3 / 0.4)"
    191 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.3 0.64 / 0.4)"
    192 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15% alpha 10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.3 0.64 / 0.76)"
    193 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.26 0.2 0.3 / 0.4)"
    194 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 40%)") is "color(xyz 0.26 0.2 0.3 / 0.4)"
    195 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8) x 40%)") is "color(xyz 0.26 0.2 0.3 / 0.4)"
    196 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60% x 40%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.34 0.2 0.3 / 0.4)"
    197 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.2 0.3 / 0.4)"
    198 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 0%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.2 0.3 / 0.4)"
    199 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.6 0.7 / 0.8)"
    200 PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x -10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.2 0.3 / 0.4)"
     67PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.4 0.5 / 0.6)"
     68PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.4 0.5 0.6 / 0.7)"
     69PASS computedStyle("background-color", "color-mix(in xyz, 25% color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))") is "color(xyz 0.4 0.5 0.6 / 0.7)"
     70PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) 25%)") is "color(xyz 0.2 0.3 0.4 / 0.5)"
     71PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4), 25% color(xyz .5 .6 .7 / .8))") is "color(xyz 0.2 0.3 0.4 / 0.5)"
     72PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
     73PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
     74PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 12.5%, color(xyz .5 .6 .7 / .8) 37.5%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
     75PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.6 0.7 / 0.8)"
     76PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.54 0.64000005 0.74 / 0.84000003)"
    20177PASS successfullyParsed is true
    20278
  • trunk/LayoutTests/fast/css/parsing-color-mix.html

    r273244 r274947  
    2929    debug('color-mix(hsl, ...)');
    3030
    31     // Special case no adjusters or percentage is split 50-50.
    32     testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))`, `rgb(84, 92, 61)`); // hsl(75deg 20% 30%)
     31    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))`, `rgb(84, 92, 61)`); // hsl(75deg 20% 30%)
     32    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))`, `rgb(112, 106, 67)`);
     33    testComputed(`color-mix(in hsl, 25% hsl(120deg 10% 20%), hsl(30deg 30% 40%))`, `rgb(112, 106, 67)`);
     34    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%), 25% hsl(30deg 30% 40%))`, `rgb(61, 73, 54)`);
     35    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)`, `rgb(61, 73, 54)`);
     36    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)`, `rgb(112, 106, 67)`);
     37    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)`, `rgb(112, 106, 67)`); // Scale down > 100% sum.
     38    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)`, `rgb(112, 106, 67)`); // Scale up < 100% sum.
     39    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
    3340
    34     // Test precentage without adjusters.
    35     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))`, `rgb(112, 106, 67)`);
    36     testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)`, `rgb(61, 73, 54)`);
    37     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)`, `rgb(112, 106, 67)`);
    38     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)`, `rgb(112, 106, 67)`); // Scale down > 100% sum.
    39     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)`, `rgb(112, 106, 67)`); // Scale up < 100% sum.
    40     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
    41 
    42     // Test per-channel adjusters.
    43     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
    44     testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 50%)`, `rgb(53, 56, 46)`);
    45     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) hue 50%)`, `rgb(53, 56, 46)`);
    46     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 100%, hsl(30deg 30% 40%))`, `rgb(46, 56, 46)`);
    47     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
    48     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
    49     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
    50     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100% alpha 100%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
    51     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0%)`, `rgb(53, 56, 46)`);
    52     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0%)`, `rgb(53, 56, 46)`);
    53     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0% alpha 0%)`, `rgb(53, 56, 46)`);
    54     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75%, hsl(30deg 30% 40%))`, `rgb(55, 59, 43)`);
    55     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15%, hsl(30deg 30% 40%))`, `rgb(101, 108, 80)`);
    56     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15% alpha 10%, hsl(30deg 30% 40%))`, `rgb(101, 108, 80)`);
    57     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%))`, `rgb(52, 56, 46)`);
    58     testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 40%)`, `rgb(52, 56, 46)`);
    59     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%) hue 40%)`, `rgb(52, 56, 46)`);
    60 
    61     // FIXME: Test hue mixes with modifiers.
    62 
    63     // Open questions.
    64 
    65     // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
    66     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 60% hue 40%, hsl(30deg 30% 40%))`, `rgb(55, 56, 46)`);
    67     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 40%, hsl(30deg 30% 40%))`, `rgb(55, 56, 46)`);
    68 
    69     // What should happen if you provide an adjuster without a paihue percent? Currently, we treat that like having 0% for that adjuster.
    70     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
    71     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
    72 
    73     // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
    74     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
    75     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
    76     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue -10%, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
    77     testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
     41    // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
     42    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))`, `rgb(142, 97, 72)`);
    7843
    7944
     
    8146    debug('color-mix(hwb, ...)');
    8247
    83     // Special case no adjusters or percentage is split 50-50.
    84     testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%))`, `rgb(147, 179, 52)`); // hwb(75deg 20% 30%)
     48    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%))`, `rgb(147, 179, 52)`); // hwb(75deg 20% 30%)
     49    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%))`, `rgb(166, 153, 64)`);
     50    testComputed(`color-mix(in hwb, 25% hwb(120deg 10% 20%), hwb(30deg 30% 40%))`, `rgb(166, 153, 64)`);
     51    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%), 25% hwb(30deg 30% 40%))`, `rgb(96, 191, 39)`);
     52    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)`, `rgb(96, 191, 39)`);
     53    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)`, `rgb(166, 153, 64)`);
     54    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)`, `rgb(166, 153, 64)`); // Scale down > 100% sum.
     55    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)`, `rgb(166, 153, 64)`); // Scale up < 100% sum.
     56    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
    8557
    86     // Test precentage without adjusters.
    87     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%))`, `rgb(166, 153, 64)`);
    88     testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)`, `rgb(96, 191, 39)`);
    89     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)`, `rgb(166, 153, 64)`);
    90     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)`, `rgb(166, 153, 64)`); // Scale down > 100% sum.
    91     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)`, `rgb(166, 153, 64)`); // Scale up < 100% sum.
    92     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
    93 
    94     // Test per-channel adjusters.
    95     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
    96     testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 50%)`, `rgb(160, 204, 26)`);
    97     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) hue 50%)`, `rgb(160, 204, 26)`);
    98     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 100%, hwb(30deg 30% 40%))`, `rgb(26, 204, 26)`);
    99     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
    100     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
    101     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
    102     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100% alpha 100%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
    103     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0%)`, `rgb(160, 204, 26)`);
    104     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0%)`, `rgb(160, 204, 26)`);
    105     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0% alpha 0%)`, `rgb(160, 204, 26)`);
    106     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75%, hwb(30deg 30% 40%))`, `rgb(163, 204, 39)`);
    107     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15%, hwb(30deg 30% 40%))`, `rgb(130, 161, 39)`);
    108     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15% alpha 10%, hwb(30deg 30% 40%))`, `rgb(130, 161, 39)`);
    109     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%))`, `rgb(133, 204, 26)`);
    110     testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 40%)`, `rgb(133, 204, 26)`);
    111     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%) hue 40%)`, `rgb(133, 204, 26)`);
    112 
    113     // Test mix that creates whiteness + blackness > 100%.
    114     testComputed(`color-mix(hwb, hwb(120deg 75% 25%) whiteness 100%, hwb(120deg 25% 75%) blackness 100%)`, `rgb(128, 128, 128)`);
    115 
    116     // FIXME: Test hue mixes with modifiers.
    117 
    118 
    119     // Open questions.
    120 
    121     // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
    122     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 60% hue 40%, hwb(30deg 30% 40%))`, `rgb(186, 204, 26)`);
    123     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 40%, hwb(30deg 30% 40%))`, `rgb(186, 204, 26)`);
    124 
    125     // What should happen if you provide an adjuster without a paihue percent? Currently, we treat that like having 0% for that adjuster.
    126     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
    127     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
    128 
    129     // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
    130     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
    131     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
    132     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue -10%, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
    133     testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
     58    // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
     59    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))`, `rgb(148, 105, 82)`);
    13460   
    13561
     
    13763    debug('color-mix(lch, ...)');
    13864
    139     // Special case no adjusters or percentage is split 50-50.
    140     testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))`, `lch(30% 40 50 / 0.6)`);
     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)`);
    14174
    142     // Test precentage without adjusters.
    143     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8))`, `lch(40% 50 60 / 0.7)`);
    144     testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) 25%)`, `lch(20% 30 40 / 0.5)`);
    145     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8) 75%)`, `lch(40% 50 60 / 0.7)`);
    146     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 50%, lch(50% 60 70deg / .8) 150%)`, `lch(40% 50 60 / 0.7)`); // Scale down > 100% sum.
    147     testComputed(`color-mix(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.
    148     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
    149 
    150     // Test per-channel adjusters.
    151     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
    152     testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 50%)`, `lch(30% 20 30 / 0.4)`);
    153     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) lightness 50%)`, `lch(30% 20 30 / 0.4)`);
    154     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 100%, lch(50% 60 70deg / .8))`, `lch(10% 20 30 / 0.4)`);
    155     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
    156     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
    157     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
    158     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100% alpha 100%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
    159     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0%)`, `lch(30% 20 30 / 0.4)`);
    160     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0%)`, `lch(30% 20 30 / 0.4)`);
    161     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0% alpha 0%)`, `lch(30% 20 30 / 0.4)`);
    162     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75%, lch(50% 60 70deg / .8))`, `lch(30% 30 30 / 0.4)`);
    163     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15%, lch(50% 60 70deg / .8))`, `lch(30% 30 64 / 0.4)`);
    164     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15% alpha 10%, lch(50% 60 70deg / .8))`, `lch(30% 30 64 / 0.76)`);
    165     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8))`, `lch(26% 20 30 / 0.4)`);
    166     testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 40%)`, `lch(26% 20 30 / 0.4)`);
    167     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8) lightness 40%)`, `lch(26% 20 30 / 0.4)`);
    168 
    169     // FIXME: Test hue mixes with modifiers.
    170 
    171     // Open questions.
    172 
    173     // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
    174     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 60% lightness 40%, lch(50% 60 70deg / .8))`, `lch(34% 20 30 / 0.4)`);
    175     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 40%, lch(50% 60 70deg / .8))`, `lch(34% 20 30 / 0.4)`);
    176 
    177     // What should happen if you provide an adjuster without a pailightness percent? Currently, we treat that like having 0% for that adjuster.
    178     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
    179     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
    180 
    181     // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
    182     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
    183     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
    184     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness -10%, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
    185     testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
     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)`);
    18677
    18778
     
    18980    debug('color-mix(lab, ...)');
    19081
    191     // Special case no adjusters or percentage is split 50-50.
    192     testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))`, `lab(30% 40 50 / 0.6)`);
     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)`);
    19391
    194     // Test precentage without adjusters.
    195     testComputed(`color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8))`, `lab(40% 50 60 / 0.7)`);
    196     testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) 25%)`, `lab(20% 30 40 / 0.5)`);
    197     testComputed(`color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8) 75%)`, `lab(40% 50 60 / 0.7)`);
    198     testComputed(`color-mix(lab, lab(10% 20 30 / .4) 50%, lab(50% 60 70 / .8) 150%)`, `lab(40% 50 60 / 0.7)`); // Scale down > 100% sum.
    199     testComputed(`color-mix(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.
    200     testComputed(`color-mix(lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8))`, `lab(50% 60 70 / 0.8)`);
    201 
    202     // Test per-channel adjusters.
    203     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
    204     testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 50%)`, `lab(30% 20 30 / 0.4)`);
    205     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) lightness 50%)`, `lab(30% 20 30 / 0.4)`);
    206     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 100%, lab(50% 60 70 / .8))`, `lab(10% 20 30 / 0.4)`);
    207     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
    208     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
    209     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
    210     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100% alpha 100%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
    211     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0%)`, `lab(30% 20 30 / 0.4)`);
    212     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0%)`, `lab(30% 20 30 / 0.4)`);
    213     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0% alpha 0%)`, `lab(30% 20 30 / 0.4)`);
    214     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75%, lab(50% 60 70 / .8))`, `lab(30% 30 30 / 0.4)`);
    215     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15%, lab(50% 60 70 / .8))`, `lab(30% 30 64 / 0.4)`);
    216     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15% alpha 10%, lab(50% 60 70 / .8))`, `lab(30% 30 64 / 0.76)`);
    217     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8))`, `lab(26% 20 30 / 0.4)`);
    218     testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 40%)`, `lab(26% 20 30 / 0.4)`);
    219     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8) lightness 40%)`, `lab(26% 20 30 / 0.4)`);
    220 
    221     // Open questions.
    222 
    223     // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
    224     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 60% lightness 40%, lab(50% 60 70 / .8))`, `lab(34% 20 30 / 0.4)`);
    225 
    226     // What should happen if you provide an adjuster without a pailightness percent? Currently, we treat that like having 0% for that adjuster.
    227     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness, lab(50% 60 70 / .8))`, `lab(50% 20 30 / 0.4)`);
    228     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 0%, lab(50% 60 70 / .8))`, `lab(50% 20 30 / 0.4)`);
    229 
    230     // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
    231     testComputed(`color-mix(lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))`, `lab(50% 60 70 / 0.8)`);
    232     testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness -10%, lab(50% 60 70 / .8))`, `lab(50% 20 30 / 0.4)`);
     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)`);
    23394 
    23495    debug('');
    23596    debug('color-mix(srgb, ...)');
    23697
    237     // Special case no adjusters or percentage is split 50-50.
    238     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.4 0.5 / 0.6)`);
     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)`);
    239107
    240     // Test precentage without adjusters.
    241     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.4 0.5 0.6 / 0.7)`);
    242     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) 25%)`, `color(srgb 0.2 0.3 0.4 / 0.5)`);
    243     testComputed(`color-mix(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)`);
    244     testComputed(`color-mix(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.
    245     testComputed(`color-mix(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.
    246     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.6 0.7 / 0.8)`);
    247 
    248     // Test per-channel adjusters.
    249     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    250     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 50%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    251     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) red 50%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    252     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.1 0.2 0.3 / 0.4)`);
    253     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    254     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    255     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    256     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100% alpha 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    257     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    258     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    259     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0% alpha 0%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
    260     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.3 0.3 / 0.4)`);
    261     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.3 0.64 / 0.4)`);
    262     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15% alpha 10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.3 0.64 / 0.76)`);
    263     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.26 0.2 0.3 / 0.4)`);
    264     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 40%)`, `color(srgb 0.26 0.2 0.3 / 0.4)`);
    265     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8) red 40%)`, `color(srgb 0.26 0.2 0.3 / 0.4)`);
    266 
    267     // Open questions.
    268 
    269     // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
    270     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60% red 40%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.34 0.2 0.3 / 0.4)`);
    271 
    272     // What should happen if you provide an adjuster without a paired percent? Currently, we treat that like having 0% for that adjuster.
    273     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.2 0.3 / 0.4)`);
    274     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 0%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.2 0.3 / 0.4)`);
    275 
    276     // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
    277     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.6 0.7 / 0.8)`);
    278     testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red -10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.2 0.3 / 0.4)`);
     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)`);
    279110
    280111
     
    282113    debug('color-mix(xyz, ...)');
    283114
    284     // Special case no adjusters or percentage is split 50-50.
    285     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.4 0.5 / 0.6)`);
     115    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.4 0.5 / 0.6)`);
     116    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
     117    testComputed(`color-mix(in xyz, 25% color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
     118    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) 25%)`, `color(xyz 0.2 0.3 0.4 / 0.5)`);
     119    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4), 25% color(xyz .5 .6 .7 / .8))`, `color(xyz 0.2 0.3 0.4 / 0.5)`);
     120    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
     121    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
     122    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4) 12.5%, color(xyz .5 .6 .7 / .8) 37.5%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`); // Scale up < 100% sum.
     123    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.6 0.7 / 0.8)`);
    286124
    287     // Test precentage without adjusters.
    288     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
    289     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) 25%)`, `color(xyz 0.2 0.3 0.4 / 0.5)`);
    290     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
    291     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
    292     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 12.5%, color(xyz .5 .6 .7 / .8) 37.5%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`); // Scale up < 100% sum.
    293     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.6 0.7 / 0.8)`);
    294 
    295     // Test per-channel adjusters.
    296     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    297     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 50%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    298     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) x 50%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    299     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.1 0.2 0.3 / 0.4)`);
    300     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    301     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    302     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    303     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100% alpha 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    304     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    305     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    306     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0% alpha 0%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
    307     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.3 0.3 / 0.4)`);
    308     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.3 0.64 / 0.4)`);
    309     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15% alpha 10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.3 0.64 / 0.76)`);
    310     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.26 0.2 0.3 / 0.4)`);
    311     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 40%)`, `color(xyz 0.26 0.2 0.3 / 0.4)`);
    312     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8) x 40%)`, `color(xyz 0.26 0.2 0.3 / 0.4)`);
    313 
    314     // Open questions.
    315 
    316     // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
    317     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60% x 40%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.34 0.2 0.3 / 0.4)`);
    318 
    319     // What should happen if you provide an adjuster without a paix percent? Currently, we treat that like having 0% for that adjuster.
    320     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.2 0.3 / 0.4)`);
    321     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 0%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.2 0.3 / 0.4)`);
    322 
    323     // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
    324     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.6 0.7 / 0.8)`);
    325     testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x -10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.2 0.3 / 0.4)`);
     125    // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
     126    testComputed(`color-mix(in xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.54 0.64000005 0.74 / 0.84000003)`);
    326127</script>
    327128   
  • trunk/Source/WebCore/ChangeLog

    r274943 r274947  
     12021-03-24  Sam Weinig  <weinig@apple.com>
     2
     3        Update CSS Color 5 color-mix() implementation to match the latest draft spec
     4        https://bugs.webkit.org/show_bug.cgi?id=223665
     5
     6        Reviewed by Simon Fraser.
     7
     8        Update to the latest draft spec, which dramatically reduces the complexity of color-mix()
     9        by remove per-component adjusters.
     10
     11        * css/CSSValueKeywords.in:
     12        * css/parser/CSSPropertyParserHelpers.cpp:
     13        (WebCore::CSSPropertyParserHelpers::normalizeWhitenessBlackness):
     14        (WebCore::CSSPropertyParserHelpers::consumeColorMixColorSpaceAndComma):
     15        (WebCore::CSSPropertyParserHelpers::consumeColorMixComponent):
     16        (WebCore::CSSPropertyParserHelpers::normalizedMixPercentages):
     17        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix):
     18        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>):
     19        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HSLA<float>>):
     20        (WebCore::CSSPropertyParserHelpers::fixupHueComponentsPriorToMix):
     21        (WebCore::CSSPropertyParserHelpers::mixColorComponentsInColorSpace):
     22        (WebCore::CSSPropertyParserHelpers::mixColorComponents):
     23        (WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParameters):
     24        (WebCore::CSSPropertyParserHelpers::HueColorAdjuster::fixupAnglesForInterpolation): Deleted.
     25        (WebCore::CSSPropertyParserHelpers::HueColorAdjuster::HueColorAdjuster): Deleted.
     26        (WebCore::CSSPropertyParserHelpers::ColorAdjuster::ColorAdjuster): Deleted.
     27        (WebCore::CSSPropertyParserHelpers::consumeAdjuster): Deleted.
     28        (WebCore::CSSPropertyParserHelpers::consumeAndUpdateAdjusterAtIndex): Deleted.
     29        (WebCore::CSSPropertyParserHelpers::consumeAndUpdateAdjuster): Deleted.
     30        (WebCore::CSSPropertyParserHelpers::consumeAdjusters): Deleted.
     31        (WebCore::CSSPropertyParserHelpers::consumeMixComponents): Deleted.
     32        (WebCore::CSSPropertyParserHelpers::normalizeAdjusterValues): Deleted.
     33        (WebCore::CSSPropertyParserHelpers::remainingAdjustment): Deleted.
     34        (WebCore::CSSPropertyParserHelpers::mixComponent): Deleted.
     35        (WebCore::CSSPropertyParserHelpers::mixComponentAtIndex): Deleted.
     36        (WebCore::CSSPropertyParserHelpers::mix): Deleted.
     37        (WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParametersUsingAdjusters): Deleted.
     38        Update to the new syntax and remove component adjusters. They may come back for color-adjust()
     39        in the future.
     40
     41        * platform/graphics/ColorModels.h:
     42        * platform/graphics/ColorTypes.h:
     43        (WebCore::clampedComponent):
     44        (WebCore::assertInRange):
     45        * platform/graphics/ColorUtilities.h:
     46        (WebCore::invertedColorWithOverriddenAlpha):
     47        Add support in the color models for annotating more about each component, now including
     48        the type (angle, number or percentage). This allows algorithms generic algorithms to
     49        operate on abstract color type components without specializing for each color type.
     50
    1512021-03-24  Zan Dobersek  <zdobersek@igalia.com>
    252
  • trunk/Source/WebCore/css/CSSValueKeywords.in

    r274793 r274947  
    14441444// color-mix()
    14451445color-mix
    1446 shorter
    1447 longer
    1448 increasing
    1449 decreasing
    1450 specified
    1451 lightness
    1452 chroma
    1453 whiteness
    1454 blackness
     1446in
    14551447
    14561448// prefers-default-appearance
  • trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp

    r274053 r274947  
    11051105}
    11061106
     1107template<typename ComponentType>
    11071108struct WhitenessBlackness {
    1108     double whiteness;
    1109     double blackness;
     1109    ComponentType whiteness;
     1110    ComponentType blackness;
    11101111};
    1111 static WhitenessBlackness normalizeWhitenessBlackness(double whiteness, double blackness)
     1112
     1113template<typename ComponentType> static auto normalizeWhitenessBlackness(ComponentType whiteness, ComponentType blackness) -> WhitenessBlackness<ComponentType>
    11121114{
    11131115    //   Values outside of these ranges are not invalid, but are clamped to the
    11141116    //   ranges defined here at computed-value time.
    1115     WhitenessBlackness result {
    1116         clampTo(whiteness, 0.0, 100.0),
    1117         clampTo(blackness, 0.0, 100.0)
     1117    WhitenessBlackness<ComponentType> result {
     1118        clampTo<ComponentType>(whiteness, 0.0, 100.0),
     1119        clampTo<ComponentType>(blackness, 0.0, 100.0)
    11181120    };
    11191121
     
    15521554}
    15531555
    1554 struct HueColorAdjuster {
    1555     enum class Type {
    1556         Shorter,
    1557         Longer,
    1558         Increasing,
    1559         Decreasing,
    1560         Specified
     1556enum class ColorMixColorSpace {
     1557    Srgb,
     1558    Hsl,
     1559    Hwb,
     1560    Xyz,
     1561    Lab,
     1562    Lch
     1563};
     1564
     1565static Optional<ColorMixColorSpace> consumeColorMixColorSpaceAndComma(CSSParserTokenRange& args)
     1566{
     1567    auto consumeIdentAndComma = [](CSSParserTokenRange& args, ColorMixColorSpace colorSpace) -> Optional<ColorMixColorSpace> {
     1568        consumeIdentRaw(args);
     1569        if (!consumeCommaIncludingWhitespace(args))
     1570            return WTF::nullopt;
     1571        return colorSpace;
    15611572    };
    15621573
    1563     static std::pair<double, double> fixupAnglesForInterpolation(double theta1, double theta2, Type type)
    1564     {
    1565         ASSERT(theta1 >= 0.0);
    1566         ASSERT(theta1 <= 360.0);
    1567         ASSERT(theta2 >= 0.0);
    1568         ASSERT(theta2 <= 360.0);
    1569 
    1570         switch (type) {
    1571         case Type::Shorter: {
    1572             auto difference = theta2 - theta1;
    1573             if (difference > 180.0)
    1574                 return { theta1 + 360.0, theta2 };
    1575             if (difference < -180.0)
    1576                 return { theta1, theta2 + 360.0 };
    1577             return { theta1, theta2 };
    1578         }
    1579         case Type::Longer: {
    1580             auto difference = theta2 - theta1;
    1581             if (difference >= 0.0 && difference < 180.0)
    1582                 return { theta1 + 360.0, theta2 };
    1583             if (difference >= -180.0  && difference < 0)
    1584                 return { theta1, theta2 + 360.0 };
    1585             return { theta1, theta2 };
    1586         }
    1587         case Type::Increasing: {
    1588             if (theta2 < theta1)
    1589                 return { theta1, theta2 + 360.0 };
    1590             return { theta1, theta2 };
    1591         }
    1592         case Type::Decreasing: {
    1593             if (theta1 < theta2)
    1594                 return { theta1 + 360.0, theta2 };
    1595             return { theta1, theta2 };
    1596         }
    1597         case Type::Specified:
    1598             return { theta1, theta2 };
    1599         }
    1600 
    1601         RELEASE_ASSERT_NOT_REACHED();
    1602     }
    1603 
    1604     HueColorAdjuster(double value = 0.0, Type type = Type::Shorter)
    1605         : type { type }
    1606         , value { value }
    1607     {
    1608     }
    1609 
    1610     Type type;
    1611     double value;
     1574    switch (args.peek().id()) {
     1575    case CSSValueHsl:
     1576        return consumeIdentAndComma(args, ColorMixColorSpace::Hsl);
     1577    case CSSValueHwb:
     1578        return consumeIdentAndComma(args, ColorMixColorSpace::Hwb);
     1579    case CSSValueLch:
     1580        return consumeIdentAndComma(args, ColorMixColorSpace::Lch);
     1581    case CSSValueLab:
     1582        return consumeIdentAndComma(args, ColorMixColorSpace::Lab);
     1583    case CSSValueXyz:
     1584        return consumeIdentAndComma(args, ColorMixColorSpace::Xyz);
     1585    case CSSValueSRGB:
     1586        return consumeIdentAndComma(args, ColorMixColorSpace::Srgb);
     1587    default:
     1588        return WTF::nullopt;
     1589    }
     1590}
     1591
     1592struct ColorMixComponent {
     1593    Color color;
     1594    Optional<double> percentage;
    16121595};
    16131596
    1614 template<typename C, CSSValueID ID0, typename Channel0, CSSValueID ID1, typename Channel1, CSSValueID ID2, typename Channel2, CSSValueID ID3, typename Channel3>
    1615 struct ColorAdjuster {
    1616     using ColorType = C;
    1617     static constexpr auto channelCSSValueIDs = std::make_tuple(ID0, ID1, ID2, ID3);
    1618 
    1619     ColorAdjuster() = default;
    1620     explicit ColorAdjuster(double percentage)
    1621         : channels { percentage, percentage, percentage, percentage }
    1622     {
    1623     }
    1624 
    1625     std::tuple<Optional<Channel0>, Optional<Channel1>, Optional<Channel2>, Optional<Channel3>> channels;
     1597static Optional<ColorMixComponent> consumeColorMixComponent(CSSParserTokenRange& args, const CSSParserContext& context)
     1598{
     1599    ColorMixComponent result;
     1600
     1601    if (auto percentage = consumePercentRaw(args))
     1602        result.percentage = percentage;
     1603
     1604    result.color = consumeOriginColor(args, context);
     1605    if (!result.color.isValid())
     1606        return WTF::nullopt;
     1607
     1608    if (!result.percentage) {
     1609        if (auto percentage = consumePercentRaw(args))
     1610            result.percentage = percentage;
     1611    }
     1612
     1613    return result;
     1614}
     1615
     1616struct ColorMixPercentages {
     1617    double p1;
     1618    double p2;
    16261619};
    16271620
    1628 using HSLColorAdjuster = ColorAdjuster<HSLA<float>, CSSValueHue, HueColorAdjuster, CSSValueSaturation, double, CSSValueLightness, double, CSSValueAlpha, double>;
    1629 using HWBColorAdjuster = ColorAdjuster<HWBA<float>, CSSValueHue, HueColorAdjuster, CSSValueWhiteness, double, CSSValueBlackness, double, CSSValueAlpha, double>;
    1630 using LCHColorAdjuster = ColorAdjuster<LCHA<float>, CSSValueLightness, double, CSSValueChroma, HueColorAdjuster, CSSValueHue, double, CSSValueAlpha, double>;
    1631 using LabColorAdjuster = ColorAdjuster<Lab<float>, CSSValueLightness, double, CSSValueA, double, CSSValueB, double, CSSValueAlpha, double>;
    1632 using SRGBColorAdjuster = ColorAdjuster<SRGBA<float>, CSSValueRed, double, CSSValueGreen, double, CSSValueBlue, double, CSSValueAlpha, double>;
    1633 using XYZColorAdjuster = ColorAdjuster<XYZA<float, WhitePoint::D50>, CSSValueX, double, CSSValueY, double, CSSValueZ, double, CSSValueAlpha, double>;
    1634 
    1635 template<typename Adjuster> struct ColorMixComponent {
    1636     Color color;
    1637     Adjuster adjuster;
    1638 };
    1639 
    1640 template<CSSValueID Ident, typename T> struct AdjusterConsumer;
    1641 
    1642 template<CSSValueID Ident> struct AdjusterConsumer<Ident, HueColorAdjuster> {
    1643     static Optional<HueColorAdjuster> consume(CSSParserTokenRange& args)
    1644     {
    1645         if (!consumeIdentRaw<Ident>(args))
    1646             return WTF::nullopt;
    1647 
    1648         HueColorAdjuster result;
    1649         if (auto hueAdjustmentType = consumeHueAdjustmentType(args))
    1650             result.type = *hueAdjustmentType;
    1651 
    1652         // FIXME: Is clamping to 0 for negative percentages the right thing to do?
    1653         if (auto percentage = consumePercentRaw(args))
    1654             result.value = std::max(0.0, *percentage);
    1655 
    1656         // FIXME: Should an adjuster without a percetange be allowed?
    1657         //  e.g color-mix(hsl, teal hue, red);
    1658 
    1659         return result;
    1660     }
    1661 
    1662     static Optional<HueColorAdjuster::Type> consumeHueAdjustmentType(CSSParserTokenRange& args)
    1663     {
    1664         switch (args.peek().id()) {
    1665         case CSSValueShorter:
    1666             consumeIdentRaw(args);
    1667             return HueColorAdjuster::Type::Shorter;
    1668         case CSSValueLonger:
    1669             consumeIdentRaw(args);
    1670             return HueColorAdjuster::Type::Longer;
    1671         case CSSValueIncreasing:
    1672             consumeIdentRaw(args);
    1673             return HueColorAdjuster::Type::Increasing;
    1674         case CSSValueDecreasing:
    1675             consumeIdentRaw(args);
    1676             return HueColorAdjuster::Type::Decreasing;
    1677         case CSSValueSpecified:
    1678             consumeIdentRaw(args);
    1679             return HueColorAdjuster::Type::Specified;
    1680         default:
    1681             return WTF::nullopt;
    1682         }
    1683     }
    1684 };
    1685 
    1686 template<CSSValueID Ident> struct AdjusterConsumer<Ident, double> {
    1687     static Optional<double> consume(CSSParserTokenRange& args)
    1688     {
    1689         if (!consumeIdentRaw<Ident>(args))
    1690             return WTF::nullopt;
    1691        
    1692         // FIXME: Is clamping to 0 for negative percentages the right thing to do?
    1693         if (auto percentage = consumePercentRaw(args))
    1694             return std::max(0.0, *percentage);
    1695 
    1696         // FIXME: Should an adjuster without a percetange be allowed?
    1697         //  e.g color-mix(hsl, teal saturation, red);
    1698 
    1699         return 0;
    1700     }
    1701 };
    1702 
    1703 template<CSSValueID Ident, typename T> inline decltype(auto) consumeAdjuster(CSSParserTokenRange& args)
    1704 {
    1705     return AdjusterConsumer<Ident, T>::consume(args);
    1706 }
    1707 
    1708 template<std::size_t I, typename Adjuster> static bool consumeAndUpdateAdjusterAtIndex(CSSParserTokenRange& args, Adjuster& adjuster)
    1709 {
    1710     using AdjusterType = std::decay_t<decltype(std::get<I>(adjuster.channels).value())>;
    1711     static constexpr CSSValueID Ident = std::get<I>(Adjuster::channelCSSValueIDs);
    1712 
    1713     if (auto adjustment = consumeAdjuster<Ident, AdjusterType>(args)) {
    1714         std::get<I>(adjuster.channels) = *adjustment;
    1715         return true;
    1716     }
    1717     return false;
    1718 }
    1719 
    1720 template<typename Adjuster> static bool consumeAndUpdateAdjuster(CSSParserTokenRange& args, Adjuster& adjuster)
    1721 {
    1722     if (consumeAndUpdateAdjusterAtIndex<0>(args, adjuster))
    1723         return true;
    1724     if (consumeAndUpdateAdjusterAtIndex<1>(args, adjuster))
    1725         return true;
    1726     if (consumeAndUpdateAdjusterAtIndex<2>(args, adjuster))
    1727         return true;
    1728     if (consumeAndUpdateAdjusterAtIndex<3>(args, adjuster))
    1729         return true;
    1730     return false;
    1731 }
    1732 
    1733 template<typename Adjuster> static Adjuster consumeAdjusters(CSSParserTokenRange& args)
    1734 {
    1735     Adjuster adjuster;
    1736     while (consumeAndUpdateAdjuster(args, adjuster)) {
    1737         // Keep consuming until there are no more adjusters.
    1738     }
     1621static ColorMixPercentages normalizedMixPercentages(const ColorMixComponent& mixComponents1, const ColorMixComponent& mixComponents2)
     1622{
     1623    // The percentages are normalized as follows:
     1624
     1625    // 1. Let p1 be the first percentage and p2 the second one.
     1626
     1627    // 2. If both percentages are omitted, they each default to 50% (an equal mix of the two colors).
     1628    if (!mixComponents1.percentage && !mixComponents2.percentage)
     1629        return { 50.0, 50.0 };
    17391630   
    1740     return adjuster;
    1741 }
    1742 
    1743 template<typename Adjuster> static Optional<ColorMixComponent<Adjuster>> consumeMixComponents(CSSParserTokenRange& args, const CSSParserContext& context)
    1744 {
    1745     auto originColor = consumeOriginColor(args, context);
    1746     if (!originColor.isValid())
    1747         return WTF::nullopt;
    1748 
    1749     // FIXME: Is clamping to 0 for negative percentages the right thing to do?
    1750     if (auto percentage = consumePercentRaw(args))
    1751         return { { WTFMove(originColor), Adjuster { std::max(0.0, *percentage) } } };
    1752 
    1753     return { { WTFMove(originColor), consumeAdjusters<Adjuster>(args) } };
    1754 }
    1755 
    1756 static std::pair<HueColorAdjuster, HueColorAdjuster> normalizeAdjusterValues(HueColorAdjuster adjuster1, HueColorAdjuster adjuster2)
    1757 {
    1758     if (auto sum = adjuster1.value + adjuster2.value; sum != 100.0) {
    1759         adjuster1.value *= 100.0 / sum;
    1760         adjuster2.value *= 100.0 / sum;
    1761     }
    1762 
    1763     return { adjuster1, adjuster2 };
    1764 }
    1765 
    1766 static std::pair<double, double> normalizeAdjusterValues(double adjuster1, double adjuster2)
    1767 {
    1768     if (auto sum = adjuster1 + adjuster2; sum != 100.0) {
    1769         adjuster1 *= 100.0 / sum;
    1770         adjuster2 *= 100.0 / sum;
    1771     }
    1772 
    1773     return { adjuster1, adjuster2 };
    1774 }
    1775 
    1776 static HueColorAdjuster remainingAdjustment(HueColorAdjuster adjuster)
    1777 {
    1778     return { 100.0 - adjuster.value, adjuster.type };
    1779 }
    1780 
    1781 static double remainingAdjustment(double adjuster)
    1782 {
    1783     return 100.0 - adjuster;
    1784 }
    1785 
    1786 template<typename AdjusterType> static auto normalizeAdjusterValues(Optional<AdjusterType> adjuster1, Optional<AdjusterType> adjuster2) -> std::pair<AdjusterType, AdjusterType>
    1787 {
    1788     if (adjuster1 && adjuster2)
    1789         return normalizeAdjusterValues(*adjuster1, *adjuster2);
    1790     if (!adjuster1 && adjuster2)
    1791         return { remainingAdjustment(*adjuster2), *adjuster2 };
    1792     if (adjuster1 && !adjuster2)
    1793         return { *adjuster1, remainingAdjustment(*adjuster1) };
    1794     // When neigher mix component provides an adjuster, the result is the non-modified
    1795     // channel from from the first color.
    1796     ASSERT(!adjuster1 && !adjuster2);
    1797     return { 100.0, 0.0 };
    1798 }
    1799 
    1800 static double mixComponent(float component1, HueColorAdjuster adjustment1, float component2, HueColorAdjuster adjustment2)
    1801 {
    1802     // FIXME: The spec does not indicate what to do if two different hue types are specified. We always use the first one for now,
    1803     // though we probably should take into account whether it was actually specified or is the default value. That normalization
    1804     // should happen in normalizeAdjusterValues().
    1805 
    1806     auto [fixedUpComponent1, fixedUpComponent2] = HueColorAdjuster::fixupAnglesForInterpolation(component1, component2, adjustment1.type);
    1807     auto result = (fixedUpComponent1 * (adjustment1.value / 100.0)) + (fixedUpComponent2 * (adjustment2.value / 100.0));
    1808     // FIXME: Check if this full normalization is needed.
    1809     return normalizeHue(result);
    1810 }
    1811 
    1812 static double mixComponent(float component1, double adjustment1, float component2, double adjustment2)
    1813 {
    1814     return (component1 * (adjustment1 / 100.0)) + (component2 * (adjustment2 / 100.0));
    1815 }
    1816 
    1817 template<std::size_t I, typename Adjuster> static double mixComponentAtIndex(const ColorComponents<float>& color1, const Adjuster& adjuster1, const ColorComponents<float>& color2, const Adjuster& adjuster2)
    1818 {
    1819     auto [normalizedAdjuster1Value, normalizedAdjuster2Value] = normalizeAdjusterValues(std::get<I>(adjuster1.channels), std::get<I>(adjuster2.channels));
    1820     return mixComponent(color1[I], normalizedAdjuster1Value, color2[I], normalizedAdjuster2Value);
    1821 }
    1822 
    1823 template<typename ColorType> inline ColorType makeColorTypeByNormalizingComponentsAfterMix(double channel0, double channel1, double channel2, double channel3)
    1824 {
    1825     return { static_cast<float>(channel0), static_cast<float>(channel1), static_cast<float>(channel2), static_cast<float>(channel3) };
    1826 }
    1827 
    1828 template<> inline HWBA<float> makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>(double hue, double whiteness, double blackness, double alpha)
    1829 {
     1631    ColorMixPercentages result;
     1632
     1633    if (!mixComponents2.percentage) {
     1634        // 3. Otherwise, if p2 is omitted, it becomes 100% - p1
     1635        result.p1 = *mixComponents1.percentage;
     1636        result.p2 = 100.0 - result.p1;
     1637    } else if (!mixComponents1.percentage) {
     1638        // 4. Otherwise, if p1 is omitted, it becomes 100% - p2
     1639        result.p2 = *mixComponents2.percentage;
     1640        result.p1 = 100.0 - result.p2;
     1641    } else {
     1642        result.p1 = *mixComponents1.percentage;
     1643        result.p2 = *mixComponents2.percentage;
     1644    }
     1645
     1646    auto sum = result.p1 + result.p2;
     1647
     1648    // 5. If the percentages sum to zero do something, tbd. (FIXME: We just use 50 / 50 for this case for now).
     1649    if (sum == 0)
     1650        return { 50.0, 50.0 };
     1651
     1652    if (sum != 100.0) {
     1653        // 6. Otherwise, if both are provided but do not add up to 100%, they are scaled accordingly so that they
     1654        //    add up to 100%. This means that p1 becomes p1 / (p1 + p2) and p2 becomes p2 / (p1 + p2).
     1655        result.p1 *= 100.0 / sum;
     1656        result.p2 *= 100.0 / sum;
     1657    }
     1658
     1659    return result;
     1660}
     1661
     1662// Normalization is special cased for HWBA, which needs to normalize the whiteness and blackness components and convert to sRGB
     1663// and HSLA, which just needs to be converted to sRGB. All other color types can go through this non-specialized case.
     1664
     1665template<typename ColorType> inline Color makeColorTypeByNormalizingComponentsAfterMix(const ColorComponents<float>& colorComponents)
     1666{
     1667    return makeFromComponents<ColorType>(colorComponents);
     1668}
     1669
     1670template<> inline Color makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>(const ColorComponents<float>& colorComponents)
     1671{
     1672    auto [hue, whiteness, blackness, alpha] = colorComponents;
    18301673    auto [normalizedWhitness, normalizedBlackness] = normalizeWhitenessBlackness(whiteness, blackness);
    1831     return { static_cast<float>(hue), static_cast<float>(normalizedWhitness), static_cast<float>(normalizedBlackness), static_cast<float>(alpha) };
    1832 }
    1833 
    1834 template<typename Adjuster> static typename Adjuster::ColorType mix(const ColorMixComponent<Adjuster>& mixComponents1, const ColorMixComponent<Adjuster>& mixComponents2)
    1835 {
    1836     using ColorType = typename Adjuster::ColorType;
    1837 
    1838     auto color1 = asColorComponents(mixComponents1.color.template toColorTypeLossy<ColorType>());
    1839     auto color2 = asColorComponents(mixComponents2.color.template toColorTypeLossy<ColorType>());
    1840 
    1841     auto adjuster1 = mixComponents1.adjuster;
    1842     auto adjuster2 = mixComponents2.adjuster;
    1843 
    1844     if (!std::get<0>(adjuster1.channels) && !std::get<1>(adjuster1.channels) && !std::get<2>(adjuster1.channels) && !std::get<3>(adjuster1.channels) && !std::get<0>(adjuster2.channels) && !std::get<1>(adjuster2.channels) && !std::get<2>(adjuster2.channels) && !std::get<3>(adjuster2.channels)) {
    1845         // No adjusters being specified at all is special cased to mean mix 50-50.
    1846         adjuster1 = Adjuster { 50.0 };
    1847         adjuster2 = Adjuster { 50.0 };
    1848     }
    1849 
    1850     auto channel0 = mixComponentAtIndex<0>(color1, adjuster1, color2, adjuster2);
    1851     auto channel1 = mixComponentAtIndex<1>(color1, adjuster1, color2, adjuster2);
    1852     auto channel2 = mixComponentAtIndex<2>(color1, adjuster1, color2, adjuster2);
    1853     auto channel3 = mixComponentAtIndex<3>(color1, adjuster1, color2, adjuster2);
    1854 
    1855     return makeColorTypeByNormalizingComponentsAfterMix<ColorType>(channel0, channel1, channel2, channel3);
    1856 }
    1857 
    1858 template<typename Adjuster> static Optional<typename Adjuster::ColorType> parseColorMixFunctionParametersUsingAdjusters(CSSParserTokenRange& args, const CSSParserContext& context)
    1859 {
    1860     auto mixComponents1 = consumeMixComponents<Adjuster>(args, context);
    1861     if (!mixComponents1)
    1862         return WTF::nullopt;
    1863 
    1864     // FIXME: This comma is not in the grammar, but is in all the examples.
     1674
     1675    return convertColor<SRGBA<uint8_t>>(HWBA<float> { hue, normalizedWhitness, normalizedBlackness, alpha });
     1676}
     1677
     1678template<> inline Color makeColorTypeByNormalizingComponentsAfterMix<HSLA<float>>(const ColorComponents<float>& colorComponents)
     1679{
     1680    return convertColor<SRGBA<uint8_t>>(makeFromComponents<HSLA<float>>(colorComponents));
     1681}
     1682
     1683template<size_t I, typename ComponentType> static void fixupHueComponentsPriorToMix(ColorComponents<ComponentType>& colorComponents1, ColorComponents<ComponentType>& colorComponents2)
     1684{
     1685    auto normalizeAnglesUsingShorterAlgorithm = [] (auto theta1, auto theta2) -> std::pair<ComponentType, ComponentType> {
     1686        // https://drafts.csswg.org/css-color-4/#hue-shorter
     1687        auto difference = theta2 - theta1;
     1688        if (difference > 180.0)
     1689            return { theta1 + 360.0, theta2 };
     1690        if (difference < -180.0)
     1691            return { theta1, theta2 + 360.0 };
     1692        return { theta1, theta2 };
     1693    };
     1694
     1695    // As no other interpolation type was specified, all angles should be normalized to use the "shorter" algorithm.
     1696    auto [theta1, theta2] = normalizeAnglesUsingShorterAlgorithm(colorComponents1[I], colorComponents2[I]);
     1697    colorComponents1[I] = theta1;
     1698    colorComponents2[I] = theta2;
     1699}
     1700
     1701template<typename ColorType> static Color mixColorComponentsInColorSpace(ColorMixPercentages mixPercentages, const Color& color1, const Color& color2)
     1702{
     1703    auto colorComponents1 = asColorComponents(color1.template toColorTypeLossy<ColorType>());
     1704    auto colorComponents2 = asColorComponents(color2.template toColorTypeLossy<ColorType>());
     1705
     1706    // Perform fixups on any hue/angle components.
     1707    constexpr auto componentInfo = ColorType::Model::componentInfo;
     1708    if constexpr (componentInfo[0].type == ColorComponentType::Angle)
     1709        fixupHueComponentsPriorToMix<0>(colorComponents1, colorComponents2);
     1710    if constexpr (componentInfo[1].type == ColorComponentType::Angle)
     1711        fixupHueComponentsPriorToMix<1>(colorComponents1, colorComponents2);
     1712    if constexpr (componentInfo[2].type == ColorComponentType::Angle)
     1713        fixupHueComponentsPriorToMix<2>(colorComponents1, colorComponents2);
     1714
     1715    auto colorComponentsMixed = mapColorComponents([&] (auto componentFromColor1, auto componentFromColor2) -> float {
     1716        return (componentFromColor1 * mixPercentages.p1 / 100.0) + (componentFromColor2 * mixPercentages.p2 / 100.0);
     1717    }, colorComponents1, colorComponents2);
     1718
     1719    return makeColorTypeByNormalizingComponentsAfterMix<ColorType>(colorComponentsMixed);
     1720}
     1721
     1722static Color mixColorComponents(ColorMixColorSpace colorSpace, const ColorMixComponent& mixComponents1, const ColorMixComponent& mixComponents2)
     1723{
     1724    auto mixPercentages = normalizedMixPercentages(mixComponents1, mixComponents2);
     1725
     1726    switch (colorSpace) {
     1727    case ColorMixColorSpace::Hsl:
     1728        return mixColorComponentsInColorSpace<HSLA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     1729    case ColorMixColorSpace::Hwb:
     1730        return mixColorComponentsInColorSpace<HWBA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     1731    case ColorMixColorSpace::Lch:
     1732        return mixColorComponentsInColorSpace<LCHA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     1733    case ColorMixColorSpace::Lab:
     1734        return mixColorComponentsInColorSpace<Lab<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     1735    case ColorMixColorSpace::Xyz:
     1736        return mixColorComponentsInColorSpace<XYZA<float, WhitePoint::D50>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     1737    case ColorMixColorSpace::Srgb:
     1738        return mixColorComponentsInColorSpace<SRGBA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
     1739    }
     1740}
     1741
     1742static Color parseColorMixFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
     1743{
     1744    ASSERT(range.peek().functionId() == CSSValueColorMix);
     1745
     1746    if (!context.colorMixEnabled)
     1747        return { };
     1748
     1749    auto args = consumeFunction(range);
     1750
     1751    if (!consumeIdentRaw<CSSValueIn>(args))
     1752        return { };
     1753   
     1754    auto colorSpace = consumeColorMixColorSpaceAndComma(args);
     1755    if (!colorSpace)
     1756        return { };
     1757
     1758    auto mixComponent1 = consumeColorMixComponent(args, context);
     1759    if (!mixComponent1)
     1760        return { };
     1761
    18651762    if (!consumeCommaIncludingWhitespace(args))
    1866         return WTF::nullopt;
    1867 
    1868     auto mixComponents2 = consumeMixComponents<Adjuster>(args, context);
    1869     if (!mixComponents2)
    1870         return WTF::nullopt;
    1871 
    1872     return mix(*mixComponents1, *mixComponents2);
    1873 }
    1874 
    1875 static Color parseColorMixFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
    1876 {
    1877     ASSERT(range.peek().functionId() == CSSValueColorMix);
    1878 
    1879     if (!context.colorMixEnabled)
    1880         return { };
    1881 
    1882     auto args = consumeFunction(range);
    1883 
    1884     auto consumeIdentAndComma = [](CSSParserTokenRange& args) {
    1885         consumeIdentRaw(args);
    1886         // FIXME: This comma is not in the grammar, but is in all the examples.
    1887         return consumeCommaIncludingWhitespace(args);
    1888     };
    1889 
    1890     switch (args.peek().id()) {
    1891     case CSSValueHsl: {
    1892         if (!consumeIdentAndComma(args))
    1893             return { };
    1894         auto hsl = parseColorMixFunctionParametersUsingAdjusters<HSLColorAdjuster>(args, context);
    1895         if (!hsl)
    1896             return { };
    1897         return convertColor<SRGBA<uint8_t>>(*hsl);
    1898     }
    1899     case CSSValueHwb: {
    1900         if (!consumeIdentAndComma(args))
    1901             return { };
    1902         auto hwb = parseColorMixFunctionParametersUsingAdjusters<HWBColorAdjuster>(args, context);
    1903         if (!hwb)
    1904             return { };
    1905         return convertColor<SRGBA<uint8_t>>(*hwb);
    1906     }
    1907     case CSSValueLch:
    1908         if (!consumeIdentAndComma(args))
    1909             return { };
    1910         return parseColorMixFunctionParametersUsingAdjusters<LCHColorAdjuster>(args, context);
    1911     case CSSValueLab:
    1912         if (!consumeIdentAndComma(args))
    1913             return { };
    1914         return parseColorMixFunctionParametersUsingAdjusters<LabColorAdjuster>(args, context);
    1915     case CSSValueXyz:
    1916         if (!consumeIdentAndComma(args))
    1917             return { };
    1918         return parseColorMixFunctionParametersUsingAdjusters<XYZColorAdjuster>(args, context);
    1919     case CSSValueSRGB:
    1920         if (!consumeIdentAndComma(args))
    1921             return { };
    1922         return parseColorMixFunctionParametersUsingAdjusters<SRGBColorAdjuster>(args, context);
    1923     default:
    1924         // Default to using LCH if no color space is provided as per the spec.
    1925         // FIXME: This behavior is unnecessarily confusing, we should remove the default from the spec.
    1926         return parseColorMixFunctionParametersUsingAdjusters<LCHColorAdjuster>(args, context);
    1927     }
     1763        return { };
     1764
     1765    auto mixComponent2 = consumeColorMixComponent(args, context);
     1766    if (!mixComponent2)
     1767        return { };
     1768
     1769    if (!args.atEnd())
     1770        return { };
     1771
     1772    return mixColorComponents(*colorSpace, *mixComponent1, *mixComponent2);
    19281773}
    19291774
  • trunk/Source/WebCore/platform/graphics/ColorModels.h

    r272870 r274947  
    3232
    3333template<typename> struct AlphaTraits;
    34 template<typename> struct ColorComponentRange;
     34template<typename> struct ColorComponentInfo;
    3535template<typename> struct ExtendedRGBModel;
    3636template<typename> struct HSLModel;
     
    5252};
    5353
    54 template<typename T> struct ColorComponentRange {
     54enum class ColorComponentType {
     55    Angle,
     56    Number,
     57    Percentage
     58};
     59
     60template<typename T> struct ColorComponentInfo {
    5561    T min;
    5662    T max;
     63    ColorComponentType type;
    5764};
    5865
    5966template<> struct ExtendedRGBModel<float> {
    60     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    61         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() },
    62         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() },
    63         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() }
     67    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     68        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     69        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     70        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number }
    6471    } };
    6572    static constexpr bool isInvertible = false;
     
    6774
    6875template<> struct HSLModel<float> {
    69     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    70         { 0, 360 },
    71         { 0, 100 },
    72         { 0, 100 }
     76    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     77        { 0, 360, ColorComponentType::Angle },
     78        { 0, 100, ColorComponentType::Percentage },
     79        { 0, 100, ColorComponentType::Percentage }
    7380    } };
    7481    static constexpr bool isInvertible = false;
     
    7683
    7784template<> struct HWBModel<float> {
    78     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    79         { 0, 360 },
    80         { 0, 100 },
    81         { 0, 100 }
     85    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     86        { 0, 360, ColorComponentType::Angle },
     87        { 0, 100, ColorComponentType::Percentage },
     88        { 0, 100, ColorComponentType::Percentage }
    8289    } };
    8390    static constexpr bool isInvertible = false;
     
    8592
    8693template<> struct LabModel<float> {
    87     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    88         { 0, std::numeric_limits<float>::infinity() },
    89         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() },
    90         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() }
     94    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     95        { 0, std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     96        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     97        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number }
    9198    } };
    9299    static constexpr bool isInvertible = false;
     
    94101
    95102template<> struct LCHModel<float> {
    96     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    97         { 0, std::numeric_limits<float>::infinity() },
    98         { 0, std::numeric_limits<float>::infinity() },
    99         { 0, 360 }
     103    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     104        { 0, std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     105        { 0, std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     106        { 0, 360, ColorComponentType::Angle }
    100107    } };
    101108    static constexpr bool isInvertible = false;
     
    103110
    104111template<> struct RGBModel<float> {
    105     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    106         { 0, 1 },
    107         { 0, 1 },
    108         { 0, 1 }
     112    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     113        { 0, 1, ColorComponentType::Number },
     114        { 0, 1, ColorComponentType::Number },
     115        { 0, 1, ColorComponentType::Number }
    109116    } };
    110117    static constexpr bool isInvertible = true;
     
    112119
    113120template<> struct RGBModel<uint8_t> {
    114     static constexpr std::array<ColorComponentRange<uint8_t>, 3> ranges { {
    115         { 0, 255 },
    116         { 0, 255 },
    117         { 0, 255 }
     121    static constexpr std::array<ColorComponentInfo<uint8_t>, 3> componentInfo { {
     122        { 0, 255, ColorComponentType::Number },
     123        { 0, 255, ColorComponentType::Number },
     124        { 0, 255, ColorComponentType::Number }
    118125    } };
    119126    static constexpr bool isInvertible = true;
     
    121128
    122129template<> struct XYZModel<float> {
    123     static constexpr std::array<ColorComponentRange<float>, 3> ranges { {
    124         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() },
    125         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() },
    126         { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() }
     130    static constexpr std::array<ColorComponentInfo<float>, 3> componentInfo { {
     131        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     132        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number },
     133        { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), ColorComponentType::Number }
    127134    } };
    128135    static constexpr bool isInvertible = false;
  • trunk/Source/WebCore/platform/graphics/ColorTypes.h

    r272837 r274947  
    5656    static_assert(std::is_integral_v<T>);
    5757
    58     constexpr auto range = ColorType::Model::ranges[Index];
    59     return std::clamp<T>(c, range.min, range.max);
     58    constexpr auto componentInfo = ColorType::Model::componentInfo[Index];
     59    return std::clamp<T>(c, componentInfo.min, componentInfo.max);
    6060}
    6161
    6262template<typename ColorType, unsigned Index> constexpr float clampedComponent(float c)
    6363{
    64     constexpr auto range = ColorType::Model::ranges[Index];
    65 
    66     if constexpr (range.min == -std::numeric_limits<float>::infinity() && range.max == std::numeric_limits<float>::infinity())
     64    constexpr auto componentInfo = ColorType::Model::componentInfo[Index];
     65
     66    if constexpr (componentInfo.min == -std::numeric_limits<float>::infinity() && componentInfo.max == std::numeric_limits<float>::infinity())
    6767        return c;
    6868
    69     if constexpr (range.min == -std::numeric_limits<float>::infinity())
    70         return std::min(c, range.max);
    71 
    72     if constexpr (range.max == std::numeric_limits<float>::infinity())
    73         return std::max(c, range.min);
    74 
    75     return std::clamp(c, range.min, range.max);
     69    if constexpr (componentInfo.min == -std::numeric_limits<float>::infinity())
     70        return std::min(c, componentInfo.max);
     71
     72    if constexpr (componentInfo.max == std::numeric_limits<float>::infinity())
     73        return std::max(c, componentInfo.min);
     74
     75    return std::clamp(c, componentInfo.min, componentInfo.max);
    7676}
    7777
     
    128128        auto components = asColorComponents(color);
    129129        for (unsigned i = 0; i < 3; ++i) {
    130             ASSERT_WITH_MESSAGE(components[i] >= T::Model::ranges[i].min, "Component at index %d is %f and is less than the allowed minimum %f", i,  components[i], T::Model::ranges[i].min);
    131             ASSERT_WITH_MESSAGE(components[i] <= T::Model::ranges[i].max, "Component at index %d is %f and is greater than the allowed maximum %f", i,  components[i], T::Model::ranges[i].max);
     130            ASSERT_WITH_MESSAGE(components[i] >= T::Model::componentInfo[i].min, "Component at index %d is %f and is less than the allowed minimum %f", i,  components[i], T::Model::componentInfo[i].min);
     131            ASSERT_WITH_MESSAGE(components[i] <= T::Model::componentInfo[i].max, "Component at index %d is %f and is greater than the allowed maximum %f", i,  components[i], T::Model::componentInfo[i].max);
    132132        }
    133133        ASSERT_WITH_MESSAGE(color.alpha >= AlphaTraits<typename T::ComponentType>::transparent, "Alpha is %f and is less than the allowed minimum (transparent) %f", color.alpha, AlphaTraits<typename T::ComponentType>::transparent);
  • trunk/Source/WebCore/platform/graphics/ColorUtilities.h

    r273683 r274947  
    126126
    127127    for (unsigned i = 0; i < 3; ++i)
    128         copy[i] = ColorType::Model::ranges[i].max - components[i];
     128        copy[i] = ColorType::Model::componentInfo[i].max - components[i];
    129129    copy[3] = convertByteAlphaTo<typename ColorType::ComponentType>(overrideAlpha);
    130130
     
    140140
    141141    for (unsigned i = 0; i < 3; ++i)
    142         copy[i] = ColorType::Model::ranges[i].max - components[i];
     142        copy[i] = ColorType::Model::componentInfo[i].max - components[i];
    143143    copy[3] = convertFloatAlphaTo<typename ColorType::ComponentType>(overrideAlpha);
    144144
     
    165165{
    166166    auto [c1, c2, c3, alpha] = color;
    167     constexpr auto ranges = ColorType::Model::ranges;
    168     return c1 == ranges[0].min && c2 == ranges[1].min && c3 == ranges[2].min && alpha == AlphaTraits<typename ColorType::ComponentType>::opaque;
     167    constexpr auto componentInfo = ColorType::Model::componentInfo;
     168    return c1 == componentInfo[0].min && c2 == componentInfo[1].min && c3 == componentInfo[2].min && alpha == AlphaTraits<typename ColorType::ComponentType>::opaque;
    169169}
    170170
     
    188188{
    189189    auto [c1, c2, c3, alpha] = color;
    190     constexpr auto ranges = ColorType::Model::ranges;
    191     return c1 == ranges[0].max && c2 == ranges[1].max && c3 == ranges[2].max && alpha == AlphaTraits<typename ColorType::ComponentType>::opaque;
     190    constexpr auto componentInfo = ColorType::Model::componentInfo;
     191    return c1 == componentInfo[0].max && c2 == componentInfo[1].max && c3 == componentInfo[2].max && alpha == AlphaTraits<typename ColorType::ComponentType>::opaque;
    192192}
    193193
Note: See TracChangeset for help on using the changeset viewer.