Changeset 286196 in webkit


Ignore:
Timestamp:
Nov 28, 2021 10:55:05 AM (8 months ago)
Author:
weinig@apple.com
Message:

[CSS Color 5] Update color-mix() to latest spec (again)
https://bugs.webkit.org/show_bug.cgi?id=233527

Reviewed by Dean Jackson.

Source/WebCore:

Updates color-mix() implementation with support for hue interpolation methods and
addresses various other spec changes (detailed below).

  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:

Add ColorInterpolation.h/cpp

  • css/CSSValueKeywords.in:

Add keywords need for the <color-space-interpolation> production. Separated out
from color-mix as these will be used for other CSS properties as well.

  • css/parser/CSSPropertyParserHelpers.cpp:

(WebCore::CSSPropertyParserHelpers::consumeHueInterpolationMethod):
(WebCore::CSSPropertyParserHelpers::consumeColorInterpolationMethod):
(WebCore::CSSPropertyParserHelpers::consumeColorMixComponent):
(WebCore::CSSPropertyParserHelpers::normalizedMixPercentages):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HSLA<float>>):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<LCHA<float>>):
(WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<OKLCHA<float>>):
(WebCore::CSSPropertyParserHelpers::mixColorComponentsUsingColorInterpolationMethod):
(WebCore::CSSPropertyParserHelpers::mixColorComponents):
(WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParameters):
(WebCore::CSSPropertyParserHelpers::consumeColorMixColorSpaceAndComma): Deleted.
(WebCore::CSSPropertyParserHelpers::fixupHueComponentsPriorToMix): Deleted.
(WebCore::CSSPropertyParserHelpers::mixColorComponentsInColorSpace): Deleted.
Rework color-mix to support the hue interpolation method specification for polor color spaces
like lch, oklch, hsl and hwb. Also update implementation to match the current spec by restricting
mix percentages to between 0 and 100 and applying alpha multiplier when the mix percentages add
up to less than 100.

  • platform/graphics/ColorInterpolation.cpp: Added.
  • platform/graphics/ColorInterpolation.h: Added.

Add structures to represent color interpolation methods including optional hue
interpolation parameters for color spaces that require it and provides prenormalization
that fixes up hue angles depending on the method selected. Over time, more aspects of
interpolation should be moved here as we figure out what can be shared.

LayoutTests:

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

Update tests to include testing of hue interpolation methods, new
restrictions on percentage ranges and the new alpha multiplier.

Location:
trunk
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r286194 r286196  
     12021-11-28  Sam Weinig  <weinig@apple.com>
     2
     3        [CSS Color 5] Update color-mix() to latest spec (again)
     4        https://bugs.webkit.org/show_bug.cgi?id=233527
     5
     6        Reviewed by Dean Jackson.
     7
     8        * fast/css/parsing-color-mix-expected.txt:
     9        * fast/css/parsing-color-mix.html:
     10        Update tests to include testing of hue interpolation methods, new
     11        restrictions on percentage ranges and the new alpha multiplier.
     12
    1132021-11-28  Philippe Normand  <pnormand@igalia.com>
    214
  • trunk/LayoutTests/fast/css/parsing-color-mix-expected.txt

    r286191 r286196  
    1111PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)") is "rgb(61, 73, 54)"
    1212PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)") is "rgb(112, 106, 67)"
    13 PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)") is "rgb(112, 106, 67)"
    14 PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)") is "rgb(112, 106, 67)"
     13PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 30%, hsl(30deg 30% 40%) 90%)") 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 "rgba(112, 106, 67, 0.5)"
    1515PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
    16 PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))") is "rgb(142, 97, 72)"
     16-> no hue method specified, defaults to shorter
     17PASS computedStyle("background-color", "color-mix(in hsl, hsl(40deg 50% 50%), hsl(60deg 50% 50%))") is "rgb(191, 170, 64)"
     18PASS computedStyle("background-color", "color-mix(in hsl, hsl(60deg 50% 50%), hsl(40deg 50% 50%))") is "rgb(191, 170, 64)"
     19PASS computedStyle("background-color", "color-mix(in hsl, hsl(50deg 50% 50%), hsl(330deg 50% 50%))") is "rgb(191, 85, 64)"
     20PASS computedStyle("background-color", "color-mix(in hsl, hsl(330deg 50% 50%), hsl(50deg 50% 50%))") is "rgb(191, 85, 64)"
     21PASS computedStyle("background-color", "color-mix(in hsl, hsl(20deg 50% 50%), hsl(320deg 50% 50%))") is "rgb(191, 64, 85)"
     22PASS computedStyle("background-color", "color-mix(in hsl, hsl(320deg 50% 50%), hsl(20deg 50% 50%))") is "rgb(191, 64, 85)"
     23-> shorter hue
     24PASS computedStyle("background-color", "color-mix(in hsl shorter hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))") is "rgb(191, 170, 64)"
     25PASS computedStyle("background-color", "color-mix(in hsl shorter hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))") is "rgb(191, 170, 64)"
     26PASS computedStyle("background-color", "color-mix(in hsl shorter hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))") is "rgb(191, 85, 64)"
     27PASS computedStyle("background-color", "color-mix(in hsl shorter hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))") is "rgb(191, 85, 64)"
     28PASS computedStyle("background-color", "color-mix(in hsl shorter hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))") is "rgb(191, 64, 85)"
     29PASS computedStyle("background-color", "color-mix(in hsl shorter hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))") is "rgb(191, 64, 85)"
     30-> longer hue
     31PASS computedStyle("background-color", "color-mix(in hsl longer hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))") is "rgb(64, 85, 191)"
     32PASS computedStyle("background-color", "color-mix(in hsl longer hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))") is "rgb(64, 85, 191)"
     33PASS computedStyle("background-color", "color-mix(in hsl longer hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))") is "rgb(64, 170, 191)"
     34PASS computedStyle("background-color", "color-mix(in hsl longer hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))") is "rgb(64, 170, 191)"
     35PASS computedStyle("background-color", "color-mix(in hsl longer hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))") is "rgb(64, 191, 170)"
     36PASS computedStyle("background-color", "color-mix(in hsl longer hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))") is "rgb(64, 191, 170)"
     37-> increasing hue
     38PASS computedStyle("background-color", "color-mix(in hsl increasing hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))") is "rgb(191, 170, 64)"
     39PASS computedStyle("background-color", "color-mix(in hsl increasing hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))") is "rgb(64, 85, 191)"
     40PASS computedStyle("background-color", "color-mix(in hsl increasing hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))") is "rgb(64, 170, 191)"
     41PASS computedStyle("background-color", "color-mix(in hsl increasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))") is "rgb(191, 85, 64)"
     42PASS computedStyle("background-color", "color-mix(in hsl increasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))") is "rgb(64, 191, 170)"
     43PASS computedStyle("background-color", "color-mix(in hsl increasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))") is "rgb(191, 64, 85)"
     44-> decreasing hue
     45PASS computedStyle("background-color", "color-mix(in hsl decreasing hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))") is "rgb(64, 85, 191)"
     46PASS computedStyle("background-color", "color-mix(in hsl decreasing hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))") is "rgb(191, 170, 64)"
     47PASS computedStyle("background-color", "color-mix(in hsl decreasing hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))") is "rgb(191, 85, 64)"
     48PASS computedStyle("background-color", "color-mix(in hsl decreasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))") is "rgb(64, 170, 191)"
     49PASS computedStyle("background-color", "color-mix(in hsl decreasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))") is "rgb(191, 64, 85)"
     50PASS computedStyle("background-color", "color-mix(in hsl decreasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))") is "rgb(64, 191, 170)"
     51-> specified hue
     52PASS computedStyle("background-color", "color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))") is "rgb(191, 170, 64)"
     53PASS computedStyle("background-color", "color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))") is "rgb(191, 170, 64)"
     54PASS computedStyle("background-color", "color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))") is "rgb(64, 170, 191)"
     55PASS computedStyle("background-color", "color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))") is "rgb(64, 170, 191)"
     56PASS computedStyle("background-color", "color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))") is "rgb(64, 191, 170)"
     57PASS computedStyle("background-color", "color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))") is "rgb(64, 191, 170)"
     58-> Invalid examples
     59PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))") is "rgba(0, 0, 0, 0)"
     60PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 150%, hsl(30deg 30% 40%))") is "rgba(0, 0, 0, 0)"
     61PASS computedStyle("background-color", "color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%) 0%)") is "rgba(0, 0, 0, 0)"
    1762
    1863color-mix(in hwb, ...)
     
    2368PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)") is "rgb(96, 191, 39)"
    2469PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)") is "rgb(166, 153, 64)"
    25 PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)") is "rgb(166, 153, 64)"
    26 PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)") is "rgb(166, 153, 64)"
     70PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 30%, hwb(30deg 30% 40%) 90%)") is "rgb(166, 153, 64)"
     71PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)") is "rgba(166, 153, 64, 0.5)"
    2772PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
    28 PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))") is "rgb(148, 105, 82)"
     73-> no hue method specified, defaults to shorter
     74PASS computedStyle("background-color", "color-mix(in hwb, hwb(40deg 30% 40%), hwb(60deg 30% 40%))") is "rgb(153, 140, 77)"
     75PASS computedStyle("background-color", "color-mix(in hwb, hwb(60deg 30% 40%), hwb(40deg 30% 40%))") is "rgb(153, 140, 77)"
     76PASS computedStyle("background-color", "color-mix(in hwb, hwb(50deg 30% 40%), hwb(330deg 30% 40%))") is "rgb(153, 89, 77)"
     77PASS computedStyle("background-color", "color-mix(in hwb, hwb(330deg 30% 40%), hwb(50deg 30% 40%))") is "rgb(153, 89, 77)"
     78PASS computedStyle("background-color", "color-mix(in hwb, hwb(20deg 30% 40%), hwb(320deg 30% 40%))") is "rgb(153, 77, 89)"
     79PASS computedStyle("background-color", "color-mix(in hwb, hwb(320deg 30% 40%), hwb(20deg 30% 40%))") is "rgb(153, 77, 89)"
     80-> shorter hue
     81PASS computedStyle("background-color", "color-mix(in hwb shorter hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))") is "rgb(153, 140, 77)"
     82PASS computedStyle("background-color", "color-mix(in hwb shorter hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))") is "rgb(153, 140, 77)"
     83PASS computedStyle("background-color", "color-mix(in hwb shorter hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))") is "rgb(153, 89, 77)"
     84PASS computedStyle("background-color", "color-mix(in hwb shorter hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))") is "rgb(153, 89, 77)"
     85PASS computedStyle("background-color", "color-mix(in hwb shorter hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))") is "rgb(153, 77, 89)"
     86PASS computedStyle("background-color", "color-mix(in hwb shorter hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))") is "rgb(153, 77, 89)"
     87-> longer hue
     88PASS computedStyle("background-color", "color-mix(in hwb longer hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))") is "rgb(77, 89, 153)"
     89PASS computedStyle("background-color", "color-mix(in hwb longer hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))") is "rgb(77, 89, 153)"
     90PASS computedStyle("background-color", "color-mix(in hwb longer hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))") is "rgb(77, 140, 153)"
     91PASS computedStyle("background-color", "color-mix(in hwb longer hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))") is "rgb(77, 140, 153)"
     92PASS computedStyle("background-color", "color-mix(in hwb longer hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))") is "rgb(77, 153, 140)"
     93PASS computedStyle("background-color", "color-mix(in hwb longer hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))") is "rgb(77, 153, 140)"
     94-> increasing hue
     95PASS computedStyle("background-color", "color-mix(in hwb increasing hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))") is "rgb(153, 140, 77)"
     96PASS computedStyle("background-color", "color-mix(in hwb increasing hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))") is "rgb(77, 89, 153)"
     97PASS computedStyle("background-color", "color-mix(in hwb increasing hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))") is "rgb(77, 140, 153)"
     98PASS computedStyle("background-color", "color-mix(in hwb increasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))") is "rgb(153, 89, 77)"
     99PASS computedStyle("background-color", "color-mix(in hwb increasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))") is "rgb(77, 153, 140)"
     100PASS computedStyle("background-color", "color-mix(in hwb increasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))") is "rgb(153, 77, 89)"
     101-> decreasing hue
     102PASS computedStyle("background-color", "color-mix(in hwb decreasing hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))") is "rgb(77, 89, 153)"
     103PASS computedStyle("background-color", "color-mix(in hwb decreasing hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))") is "rgb(153, 140, 77)"
     104PASS computedStyle("background-color", "color-mix(in hwb decreasing hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))") is "rgb(153, 89, 77)"
     105PASS computedStyle("background-color", "color-mix(in hwb decreasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))") is "rgb(77, 140, 153)"
     106PASS computedStyle("background-color", "color-mix(in hwb decreasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))") is "rgb(153, 77, 89)"
     107PASS computedStyle("background-color", "color-mix(in hwb decreasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))") is "rgb(77, 153, 140)"
     108-> specified hue
     109PASS computedStyle("background-color", "color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))") is "rgb(153, 140, 77)"
     110PASS computedStyle("background-color", "color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))") is "rgb(153, 140, 77)"
     111PASS computedStyle("background-color", "color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))") is "rgb(77, 140, 153)"
     112PASS computedStyle("background-color", "color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))") is "rgb(77, 140, 153)"
     113PASS computedStyle("background-color", "color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))") is "rgb(77, 153, 140)"
     114PASS computedStyle("background-color", "color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))") is "rgb(77, 153, 140)"
     115-> Invalid examples
     116PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))") is "rgba(0, 0, 0, 0)"
     117PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 150%, hwb(30deg 30% 40%))") is "rgba(0, 0, 0, 0)"
     118PASS computedStyle("background-color", "color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%) 0%)") is "rgba(0, 0, 0, 0)"
    29119
    30120color-mix(in lch, ...)
     
    35125PASS 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)"
    36126PASS 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)"
    37 PASS 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)"
    38 PASS 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)"
     127PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 30%, lch(50% 60 70deg / .8) 90%)") is "lch(40% 50 60 / 0.7)"
     128PASS 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.35)"
    39129PASS 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)"
    40 PASS 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)"
     130-> no hue method specified, defaults to shorter
     131PASS computedStyle("background-color", "color-mix(in lch, lch(100% 0 40deg), lch(100% 0 60deg))") is "lch(100% 0 50)"
     132PASS computedStyle("background-color", "color-mix(in lch, lch(100% 0 60deg), lch(100% 0 40deg))") is "lch(100% 0 50)"
     133PASS computedStyle("background-color", "color-mix(in lch, lch(100% 0 50deg), lch(100% 0 330deg))") is "lch(100% 0 10)"
     134PASS computedStyle("background-color", "color-mix(in lch, lch(100% 0 330deg), lch(100% 0 50deg))") is "lch(100% 0 10)"
     135PASS computedStyle("background-color", "color-mix(in lch, lch(100% 0 20deg), lch(100% 0 320deg))") is "lch(100% 0 350)"
     136PASS computedStyle("background-color", "color-mix(in lch, lch(100% 0 320deg), lch(100% 0 20deg))") is "lch(100% 0 350)"
     137-> shorter hue
     138PASS computedStyle("background-color", "color-mix(in lch shorter hue, lch(100% 0 40deg), lch(100% 0 60deg))") is "lch(100% 0 50)"
     139PASS computedStyle("background-color", "color-mix(in lch shorter hue, lch(100% 0 60deg), lch(100% 0 40deg))") is "lch(100% 0 50)"
     140PASS computedStyle("background-color", "color-mix(in lch shorter hue, lch(100% 0 50deg), lch(100% 0 330deg))") is "lch(100% 0 10)"
     141PASS computedStyle("background-color", "color-mix(in lch shorter hue, lch(100% 0 330deg), lch(100% 0 50deg))") is "lch(100% 0 10)"
     142PASS computedStyle("background-color", "color-mix(in lch shorter hue, lch(100% 0 20deg), lch(100% 0 320deg))") is "lch(100% 0 350)"
     143PASS computedStyle("background-color", "color-mix(in lch shorter hue, lch(100% 0 320deg), lch(100% 0 20deg))") is "lch(100% 0 350)"
     144-> longer hue
     145PASS computedStyle("background-color", "color-mix(in lch longer hue, lch(100% 0 40deg), lch(100% 0 60deg))") is "lch(100% 0 230)"
     146PASS computedStyle("background-color", "color-mix(in lch longer hue, lch(100% 0 60deg), lch(100% 0 40deg))") is "lch(100% 0 230)"
     147PASS computedStyle("background-color", "color-mix(in lch longer hue, lch(100% 0 50deg), lch(100% 0 330deg))") is "lch(100% 0 190)"
     148PASS computedStyle("background-color", "color-mix(in lch longer hue, lch(100% 0 330deg), lch(100% 0 50deg))") is "lch(100% 0 190)"
     149PASS computedStyle("background-color", "color-mix(in lch longer hue, lch(100% 0 20deg), lch(100% 0 320deg))") is "lch(100% 0 170)"
     150PASS computedStyle("background-color", "color-mix(in lch longer hue, lch(100% 0 320deg), lch(100% 0 20deg))") is "lch(100% 0 170)"
     151-> increasing hue
     152PASS computedStyle("background-color", "color-mix(in lch increasing hue, lch(100% 0 40deg), lch(100% 0 60deg))") is "lch(100% 0 50)"
     153PASS computedStyle("background-color", "color-mix(in lch increasing hue, lch(100% 0 60deg), lch(100% 0 40deg))") is "lch(100% 0 230)"
     154PASS computedStyle("background-color", "color-mix(in lch increasing hue, lch(100% 0 50deg), lch(100% 0 330deg))") is "lch(100% 0 190)"
     155PASS computedStyle("background-color", "color-mix(in lch increasing hue, lch(100% 0 330deg), lch(100% 0 50deg))") is "lch(100% 0 10)"
     156PASS computedStyle("background-color", "color-mix(in lch increasing hue, lch(100% 0 20deg), lch(100% 0 320deg))") is "lch(100% 0 170)"
     157PASS computedStyle("background-color", "color-mix(in lch increasing hue, lch(100% 0 320deg), lch(100% 0 20deg))") is "lch(100% 0 350)"
     158-> decreasing hue
     159PASS computedStyle("background-color", "color-mix(in lch decreasing hue, lch(100% 0 40deg), lch(100% 0 60deg))") is "lch(100% 0 230)"
     160PASS computedStyle("background-color", "color-mix(in lch decreasing hue, lch(100% 0 60deg), lch(100% 0 40deg))") is "lch(100% 0 50)"
     161PASS computedStyle("background-color", "color-mix(in lch decreasing hue, lch(100% 0 50deg), lch(100% 0 330deg))") is "lch(100% 0 10)"
     162PASS computedStyle("background-color", "color-mix(in lch decreasing hue, lch(100% 0 330deg), lch(100% 0 50deg))") is "lch(100% 0 190)"
     163PASS computedStyle("background-color", "color-mix(in lch decreasing hue, lch(100% 0 20deg), lch(100% 0 320deg))") is "lch(100% 0 350)"
     164PASS computedStyle("background-color", "color-mix(in lch decreasing hue, lch(100% 0 320deg), lch(100% 0 20deg))") is "lch(100% 0 170)"
     165-> specified hue
     166PASS computedStyle("background-color", "color-mix(in lch specified hue, lch(100% 0 40deg), lch(100% 0 60deg))") is "lch(100% 0 50)"
     167PASS computedStyle("background-color", "color-mix(in lch specified hue, lch(100% 0 60deg), lch(100% 0 40deg))") is "lch(100% 0 50)"
     168PASS computedStyle("background-color", "color-mix(in lch specified hue, lch(100% 0 50deg), lch(100% 0 330deg))") is "lch(100% 0 190)"
     169PASS computedStyle("background-color", "color-mix(in lch specified hue, lch(100% 0 330deg), lch(100% 0 50deg))") is "lch(100% 0 190)"
     170PASS computedStyle("background-color", "color-mix(in lch specified hue, lch(100% 0 20deg), lch(100% 0 320deg))") is "lch(100% 0 170)"
     171PASS computedStyle("background-color", "color-mix(in lch specified hue, lch(100% 0 320deg), lch(100% 0 20deg))") is "lch(100% 0 170)"
     172-> Invalid examples
     173PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))") is "rgba(0, 0, 0, 0)"
     174PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 150%, lch(50% 60 70deg / .8))") is "rgba(0, 0, 0, 0)"
     175PASS computedStyle("background-color", "color-mix(in lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8) 0%)") is "rgba(0, 0, 0, 0)"
    41176
    42177color-mix(in oklch, ...)
     
    47182PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4), oklch(50% 60 70deg / .8) 25%)") is "oklch(20% 30 40 / 0.5)"
    48183PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 25%, oklch(50% 60 70deg / .8) 75%)") is "oklch(40% 50 60 / 0.7)"
    49 PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 50%, oklch(50% 60 70deg / .8) 150%)") is "oklch(40% 50 60 / 0.7)"
    50 PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 12.5%, oklch(50% 60 70deg / .8) 37.5%)") is "oklch(40% 50 60 / 0.7)"
     184PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 30%, oklch(50% 60 70deg / .8) 90%)") is "oklch(40% 50 60 / 0.7)"
     185PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 12.5%, oklch(50% 60 70deg / .8) 37.5%)") is "oklch(40% 50 60 / 0.35)"
    51186PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 0%, oklch(50% 60 70deg / .8))") is "oklch(50% 60 70 / 0.8)"
    52 PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) -10%, oklch(50% 60 70deg / .8))") is "oklch(54% 64 74 / 0.84000003)"
     187-> no hue method specified, defaults to shorter
     188PASS computedStyle("background-color", "color-mix(in oklch, oklch(100% 0 40deg), oklch(100% 0 60deg))") is "oklch(100% 0 50)"
     189PASS computedStyle("background-color", "color-mix(in oklch, oklch(100% 0 60deg), oklch(100% 0 40deg))") is "oklch(100% 0 50)"
     190PASS computedStyle("background-color", "color-mix(in oklch, oklch(100% 0 50deg), oklch(100% 0 330deg))") is "oklch(100% 0 10)"
     191PASS computedStyle("background-color", "color-mix(in oklch, oklch(100% 0 330deg), oklch(100% 0 50deg))") is "oklch(100% 0 10)"
     192PASS computedStyle("background-color", "color-mix(in oklch, oklch(100% 0 20deg), oklch(100% 0 320deg))") is "oklch(100% 0 350)"
     193PASS computedStyle("background-color", "color-mix(in oklch, oklch(100% 0 320deg), oklch(100% 0 20deg))") is "oklch(100% 0 350)"
     194-> shorter hue
     195PASS computedStyle("background-color", "color-mix(in oklch shorter hue, oklch(100% 0 40deg), oklch(100% 0 60deg))") is "oklch(100% 0 50)"
     196PASS computedStyle("background-color", "color-mix(in oklch shorter hue, oklch(100% 0 60deg), oklch(100% 0 40deg))") is "oklch(100% 0 50)"
     197PASS computedStyle("background-color", "color-mix(in oklch shorter hue, oklch(100% 0 50deg), oklch(100% 0 330deg))") is "oklch(100% 0 10)"
     198PASS computedStyle("background-color", "color-mix(in oklch shorter hue, oklch(100% 0 330deg), oklch(100% 0 50deg))") is "oklch(100% 0 10)"
     199PASS computedStyle("background-color", "color-mix(in oklch shorter hue, oklch(100% 0 20deg), oklch(100% 0 320deg))") is "oklch(100% 0 350)"
     200PASS computedStyle("background-color", "color-mix(in oklch shorter hue, oklch(100% 0 320deg), oklch(100% 0 20deg))") is "oklch(100% 0 350)"
     201-> longer hue
     202PASS computedStyle("background-color", "color-mix(in oklch longer hue, oklch(100% 0 40deg), oklch(100% 0 60deg))") is "oklch(100% 0 230)"
     203PASS computedStyle("background-color", "color-mix(in oklch longer hue, oklch(100% 0 60deg), oklch(100% 0 40deg))") is "oklch(100% 0 230)"
     204PASS computedStyle("background-color", "color-mix(in oklch longer hue, oklch(100% 0 50deg), oklch(100% 0 330deg))") is "oklch(100% 0 190)"
     205PASS computedStyle("background-color", "color-mix(in oklch longer hue, oklch(100% 0 330deg), oklch(100% 0 50deg))") is "oklch(100% 0 190)"
     206PASS computedStyle("background-color", "color-mix(in oklch longer hue, oklch(100% 0 20deg), oklch(100% 0 320deg))") is "oklch(100% 0 170)"
     207PASS computedStyle("background-color", "color-mix(in oklch longer hue, oklch(100% 0 320deg), oklch(100% 0 20deg))") is "oklch(100% 0 170)"
     208-> increasing hue
     209PASS computedStyle("background-color", "color-mix(in oklch increasing hue, oklch(100% 0 40deg), oklch(100% 0 60deg))") is "oklch(100% 0 50)"
     210PASS computedStyle("background-color", "color-mix(in oklch increasing hue, oklch(100% 0 60deg), oklch(100% 0 40deg))") is "oklch(100% 0 230)"
     211PASS computedStyle("background-color", "color-mix(in oklch increasing hue, oklch(100% 0 50deg), oklch(100% 0 330deg))") is "oklch(100% 0 190)"
     212PASS computedStyle("background-color", "color-mix(in oklch increasing hue, oklch(100% 0 330deg), oklch(100% 0 50deg))") is "oklch(100% 0 10)"
     213PASS computedStyle("background-color", "color-mix(in oklch increasing hue, oklch(100% 0 20deg), oklch(100% 0 320deg))") is "oklch(100% 0 170)"
     214PASS computedStyle("background-color", "color-mix(in oklch increasing hue, oklch(100% 0 320deg), oklch(100% 0 20deg))") is "oklch(100% 0 350)"
     215-> decreasing hue
     216PASS computedStyle("background-color", "color-mix(in oklch decreasing hue, oklch(100% 0 40deg), oklch(100% 0 60deg))") is "oklch(100% 0 230)"
     217PASS computedStyle("background-color", "color-mix(in oklch decreasing hue, oklch(100% 0 60deg), oklch(100% 0 40deg))") is "oklch(100% 0 50)"
     218PASS computedStyle("background-color", "color-mix(in oklch decreasing hue, oklch(100% 0 50deg), oklch(100% 0 330deg))") is "oklch(100% 0 10)"
     219PASS computedStyle("background-color", "color-mix(in oklch decreasing hue, oklch(100% 0 330deg), oklch(100% 0 50deg))") is "oklch(100% 0 190)"
     220PASS computedStyle("background-color", "color-mix(in oklch decreasing hue, oklch(100% 0 20deg), oklch(100% 0 320deg))") is "oklch(100% 0 350)"
     221PASS computedStyle("background-color", "color-mix(in oklch decreasing hue, oklch(100% 0 320deg), oklch(100% 0 20deg))") is "oklch(100% 0 170)"
     222-> specified hue
     223PASS computedStyle("background-color", "color-mix(in oklch specified hue, oklch(100% 0 40deg), oklch(100% 0 60deg))") is "oklch(100% 0 50)"
     224PASS computedStyle("background-color", "color-mix(in oklch specified hue, oklch(100% 0 60deg), oklch(100% 0 40deg))") is "oklch(100% 0 50)"
     225PASS computedStyle("background-color", "color-mix(in oklch specified hue, oklch(100% 0 50deg), oklch(100% 0 330deg))") is "oklch(100% 0 190)"
     226PASS computedStyle("background-color", "color-mix(in oklch specified hue, oklch(100% 0 330deg), oklch(100% 0 50deg))") is "oklch(100% 0 190)"
     227PASS computedStyle("background-color", "color-mix(in oklch specified hue, oklch(100% 0 20deg), oklch(100% 0 320deg))") is "oklch(100% 0 170)"
     228PASS computedStyle("background-color", "color-mix(in oklch specified hue, oklch(100% 0 320deg), oklch(100% 0 20deg))") is "oklch(100% 0 170)"
     229-> Invalid examples
     230PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) -10%, oklch(50% 60 70deg / .8))") is "rgba(0, 0, 0, 0)"
     231PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 150%, oklch(50% 60 70deg / .8))") is "rgba(0, 0, 0, 0)"
     232PASS computedStyle("background-color", "color-mix(in oklch, oklch(10% 20 30deg / .4) 0%, oklch(50% 60 70deg / .8) 0%)") is "rgba(0, 0, 0, 0)"
    53233
    54234color-mix(in lab, ...)
     
    59239PASS 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)"
    60240PASS 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)"
    61 PASS 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)"
    62 PASS 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)"
     241PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 30%, lab(50% 60 70 / .8) 90%)") is "lab(40% 50 60 / 0.7)"
     242PASS 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.35)"
    63243PASS 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)"
    64 PASS 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)"
     244-> Invalid examples
     245PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))") is "rgba(0, 0, 0, 0)"
     246PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 150%, lab(50% 60 70 / .8))") is "rgba(0, 0, 0, 0)"
     247PASS computedStyle("background-color", "color-mix(in lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8) 0%)") is "rgba(0, 0, 0, 0)"
    65248
    66249color-mix(in oklab, ...)
     
    71254PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4), oklab(50% 60 70 / .8) 25%)") is "oklab(20% 30 40 / 0.5)"
    72255PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 25%, oklab(50% 60 70 / .8) 75%)") is "oklab(40% 50 60 / 0.7)"
    73 PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 50%, oklab(50% 60 70 / .8) 150%)") is "oklab(40% 50 60 / 0.7)"
    74 PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 12.5%, oklab(50% 60 70 / .8) 37.5%)") is "oklab(40% 50 60 / 0.7)"
     256PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 30%, oklab(50% 60 70 / .8) 90%)") is "oklab(40% 50 60 / 0.7)"
     257PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 12.5%, oklab(50% 60 70 / .8) 37.5%)") is "oklab(40% 50 60 / 0.35)"
    75258PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 0%, oklab(50% 60 70 / .8))") is "oklab(50% 60 70 / 0.8)"
    76 PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) -10%, oklab(50% 60 70 / .8))") is "oklab(54% 64 74 / 0.84000003)"
     259-> Invalid examples
     260PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) -10%, oklab(50% 60 70 / .8))") is "rgba(0, 0, 0, 0)"
     261PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 150%, oklab(50% 60 70 / .8))") is "rgba(0, 0, 0, 0)"
     262PASS computedStyle("background-color", "color-mix(in oklab, oklab(10% 20 30 / .4) 0%, oklab(50% 60 70 / .8) 0%)") is "rgba(0, 0, 0, 0)"
    77263
    78264color-mix(in srgb, ...)
     
    83269PASS 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)"
    84270PASS 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)"
    85 PASS 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)"
    86 PASS 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)"
     271PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 30%, color(srgb .5 .6 .7 / .8) 90%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
     272PASS 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.35)"
    87273PASS 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)"
    88 PASS 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)"
     274-> Invalid examples
     275PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     276PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 150%, color(srgb .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     277PASS computedStyle("background-color", "color-mix(in srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8) 0%)") is "rgba(0, 0, 0, 0)"
    89278
    90279color-mix(in xyz, ...)
     
    95284PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4), 25% color(xyz .5 .6 .7 / .8))") is "color(xyz-d65 0.2 0.3 0.4 / 0.5)"
    96285PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
    97 PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
    98 PASS 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-d65 0.4 0.5 0.6 / 0.7)"
     286PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 30%, color(xyz .5 .6 .7 / .8) 90%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
     287PASS 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-d65 0.4 0.5 0.6 / 0.35)"
    99288PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))") is "color(xyz-d65 0.5 0.6 0.7 / 0.8)"
    100 PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))") is "color(xyz-d65 0.54 0.64000005 0.74 / 0.84000003)"
     289-> Invalid examples
     290PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     291PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 150%, color(xyz .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     292PASS computedStyle("background-color", "color-mix(in xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8) 0%)") is "rgba(0, 0, 0, 0)"
    101293
    102294color-mix(in xyz-d50, ...)
     
    107299PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4), 25% color(xyz-d50 .5 .6 .7 / .8))") is "color(xyz-d50 0.2 0.3 0.4 / 0.5)"
    108300PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 25%, color(xyz-d50 .5 .6 .7 / .8) 75%)") is "color(xyz-d50 0.4 0.5 0.6 / 0.7)"
    109 PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 50%, color(xyz-d50 .5 .6 .7 / .8) 150%)") is "color(xyz-d50 0.4 0.5 0.6 / 0.7)"
    110 PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 12.5%, color(xyz-d50 .5 .6 .7 / .8) 37.5%)") is "color(xyz-d50 0.4 0.5 0.6 / 0.7)"
     301PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 30%, color(xyz-d50 .5 .6 .7 / .8) 90%)") is "color(xyz-d50 0.4 0.5 0.6 / 0.7)"
     302PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 12.5%, color(xyz-d50 .5 .6 .7 / .8) 37.5%)") is "color(xyz-d50 0.4 0.5 0.6 / 0.35)"
    111303PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 0%, color(xyz-d50 .5 .6 .7 / .8))") is "color(xyz-d50 0.5 0.6 0.7 / 0.8)"
    112 PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) -10%, color(xyz-d50 .5 .6 .7 / .8))") is "color(xyz-d50 0.54 0.64000005 0.74 / 0.84000003)"
     304-> Invalid examples
     305PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) -10%, color(xyz-d50 .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     306PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 150%, color(xyz-d50 .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     307PASS computedStyle("background-color", "color-mix(in xyz-d50, color(xyz-d50 .1 .2 .3 / .4) 0%, color(xyz-d50 .5 .6 .7 / .8) 0%)") is "rgba(0, 0, 0, 0)"
    113308
    114309color-mix(in xyz-d65, ...)
     
    119314PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4), 25% color(xyz-d65 .5 .6 .7 / .8))") is "color(xyz-d65 0.2 0.3 0.4 / 0.5)"
    120315PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 25%, color(xyz-d65 .5 .6 .7 / .8) 75%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
    121 PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 50%, color(xyz-d65 .5 .6 .7 / .8) 150%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
    122 PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 12.5%, color(xyz-d65 .5 .6 .7 / .8) 37.5%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
     316PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 30%, color(xyz-d65 .5 .6 .7 / .8) 90%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.7)"
     317PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 12.5%, color(xyz-d65 .5 .6 .7 / .8) 37.5%)") is "color(xyz-d65 0.4 0.5 0.6 / 0.35)"
    123318PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 0%, color(xyz-d65 .5 .6 .7 / .8))") is "color(xyz-d65 0.5 0.6 0.7 / 0.8)"
    124 PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) -10%, color(xyz-d65 .5 .6 .7 / .8))") is "color(xyz-d65 0.54 0.64000005 0.74 / 0.84000003)"
     319-> Invalid examples
     320PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) -10%, color(xyz-d65 .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     321PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 150%, color(xyz-d65 .5 .6 .7 / .8))") is "rgba(0, 0, 0, 0)"
     322PASS computedStyle("background-color", "color-mix(in xyz-d65, color(xyz-d65 .1 .2 .3 / .4) 0%, color(xyz-d65 .5 .6 .7 / .8) 0%)") is "rgba(0, 0, 0, 0)"
    125323PASS successfullyParsed is true
    126324
  • trunk/LayoutTests/fast/css/parsing-color-mix.html

    r286191 r286196  
    2727    }
    2828
     29    function testComputedComputingResult(value, expected)
     30    {
     31        let computedExpected = computedStyle("background-color", expected)
     32        testComputedProperty("background-color", value, computedExpected);
     33    }
     34
    2935    debug('color-mix(in hsl, ...)');
    3036
     
    3541    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)`, `rgb(61, 73, 54)`);
    3642    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.
     43    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 30%, hsl(30deg 30% 40%) 90%)`, `rgb(112, 106, 67)`); // Scale down > 100% sum.
     44    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)`, `rgba(112, 106, 67, 0.5)`); // Scale up < 100% sum, causes alpha multiplication.
    3945    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
    4046
    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)`);
    43 
     47    debug(`-> no hue method specified, defaults to shorter`)
     48    testComputedComputingResult(`color-mix(in hsl, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     49    testComputedComputingResult(`color-mix(in hsl, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     50    testComputedComputingResult(`color-mix(in hsl, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, `hsl(10deg 50% 50%)`);
     51    testComputedComputingResult(`color-mix(in hsl, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, `hsl(10deg 50% 50%)`);
     52    testComputedComputingResult(`color-mix(in hsl, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, `hsl(350deg 50% 50%)`);
     53    testComputedComputingResult(`color-mix(in hsl, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, `hsl(350deg 50% 50%)`);
     54
     55    debug(`-> shorter hue`)
     56    testComputedComputingResult(`color-mix(in hsl shorter hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     57    testComputedComputingResult(`color-mix(in hsl shorter hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     58    testComputedComputingResult(`color-mix(in hsl shorter hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, `hsl(10deg 50% 50%)`);
     59    testComputedComputingResult(`color-mix(in hsl shorter hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, `hsl(10deg 50% 50%)`);
     60    testComputedComputingResult(`color-mix(in hsl shorter hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, `hsl(350deg 50% 50%)`);
     61    testComputedComputingResult(`color-mix(in hsl shorter hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, `hsl(350deg 50% 50%)`);
     62
     63    debug(`-> longer hue`)
     64    testComputedComputingResult(`color-mix(in hsl longer hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, `hsl(230deg 50% 50%)`);
     65    testComputedComputingResult(`color-mix(in hsl longer hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, `hsl(230deg 50% 50%)`);
     66    testComputedComputingResult(`color-mix(in hsl longer hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, `hsl(190deg 50% 50%)`);
     67    testComputedComputingResult(`color-mix(in hsl longer hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, `hsl(190deg 50% 50%)`);
     68    testComputedComputingResult(`color-mix(in hsl longer hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, `hsl(170deg 50% 50%)`);
     69    testComputedComputingResult(`color-mix(in hsl longer hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, `hsl(170deg 50% 50%)`);
     70
     71    debug(`-> increasing hue`)
     72    testComputedComputingResult(`color-mix(in hsl increasing hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     73    testComputedComputingResult(`color-mix(in hsl increasing hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, `hsl(230deg 50% 50%)`);
     74    testComputedComputingResult(`color-mix(in hsl increasing hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, `hsl(190deg 50% 50%)`);
     75    testComputedComputingResult(`color-mix(in hsl increasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, `hsl(10deg 50% 50%)`);
     76    testComputedComputingResult(`color-mix(in hsl increasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, `hsl(170deg 50% 50%)`);
     77    testComputedComputingResult(`color-mix(in hsl increasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, `hsl(350deg 50% 50%)`);
     78
     79    debug(`-> decreasing hue`)
     80    testComputedComputingResult(`color-mix(in hsl decreasing hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, `hsl(230deg 50% 50%)`);
     81    testComputedComputingResult(`color-mix(in hsl decreasing hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     82    testComputedComputingResult(`color-mix(in hsl decreasing hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, `hsl(10deg 50% 50%)`);
     83    testComputedComputingResult(`color-mix(in hsl decreasing hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, `hsl(190deg 50% 50%)`);
     84    testComputedComputingResult(`color-mix(in hsl decreasing hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, `hsl(350deg 50% 50%)`);
     85    testComputedComputingResult(`color-mix(in hsl decreasing hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, `hsl(170deg 50% 50%)`);
     86
     87    debug(`-> specified hue`)
     88    testComputedComputingResult(`color-mix(in hsl specified hue, hsl(40deg 50% 50%), hsl(60deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     89    testComputedComputingResult(`color-mix(in hsl specified hue, hsl(60deg 50% 50%), hsl(40deg 50% 50%))`, `hsl(50deg 50% 50%)`);
     90    testComputedComputingResult(`color-mix(in hsl specified hue, hsl(50deg 50% 50%), hsl(330deg 50% 50%))`, `hsl(190deg 50% 50%)`);
     91    testComputedComputingResult(`color-mix(in hsl specified hue, hsl(330deg 50% 50%), hsl(50deg 50% 50%))`, `hsl(190deg 50% 50%)`);
     92    testComputedComputingResult(`color-mix(in hsl specified hue, hsl(20deg 50% 50%), hsl(320deg 50% 50%))`, `hsl(170deg 50% 50%)`);
     93    testComputedComputingResult(`color-mix(in hsl specified hue, hsl(320deg 50% 50%), hsl(20deg 50% 50%))`, `hsl(170deg 50% 50%)`);
     94
     95    debug('-> Invalid examples');
     96    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))`, `rgba(0, 0, 0, 0)`); // Percentages less than 0 are not valid.
     97    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 150%, hsl(30deg 30% 40%))`, `rgba(0, 0, 0, 0)`); // Percentages greater than 100 are not valid.
     98    testComputed(`color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%) 0%)`, `rgba(0, 0, 0, 0)`); // Sum of percengates cannot be 0%.
    4499
    45100    debug('');
     
    52107    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)`, `rgb(96, 191, 39)`);
    53108    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.
     109    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 30%, hwb(30deg 30% 40%) 90%)`, `rgb(166, 153, 64)`); // Scale down > 100% sum.
     110    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)`, `rgba(166, 153, 64, 0.5)`); // Scale up < 100% sum, causes alpha multiplication.
    56111    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
    57112
    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)`);
     113    debug(`-> no hue method specified, defaults to shorter`)
     114    testComputedComputingResult(`color-mix(in hwb, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     115    testComputedComputingResult(`color-mix(in hwb, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     116    testComputedComputingResult(`color-mix(in hwb, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, `hwb(10deg 30% 40%)`);
     117    testComputedComputingResult(`color-mix(in hwb, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, `hwb(10deg 30% 40%)`);
     118    testComputedComputingResult(`color-mix(in hwb, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, `hwb(350deg 30% 40%)`);
     119    testComputedComputingResult(`color-mix(in hwb, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, `hwb(350deg 30% 40%)`);
     120
     121    debug(`-> shorter hue`)
     122    testComputedComputingResult(`color-mix(in hwb shorter hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     123    testComputedComputingResult(`color-mix(in hwb shorter hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     124    testComputedComputingResult(`color-mix(in hwb shorter hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, `hwb(10deg 30% 40%)`);
     125    testComputedComputingResult(`color-mix(in hwb shorter hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, `hwb(10deg 30% 40%)`);
     126    testComputedComputingResult(`color-mix(in hwb shorter hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, `hwb(350deg 30% 40%)`);
     127    testComputedComputingResult(`color-mix(in hwb shorter hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, `hwb(350deg 30% 40%)`);
     128
     129    debug(`-> longer hue`)
     130    testComputedComputingResult(`color-mix(in hwb longer hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, `hwb(230deg 30% 40%)`);
     131    testComputedComputingResult(`color-mix(in hwb longer hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, `hwb(230deg 30% 40%)`);
     132    testComputedComputingResult(`color-mix(in hwb longer hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, `hwb(190deg 30% 40%)`);
     133    testComputedComputingResult(`color-mix(in hwb longer hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, `hwb(190deg 30% 40%)`);
     134    testComputedComputingResult(`color-mix(in hwb longer hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, `hwb(170deg 30% 40%)`);
     135    testComputedComputingResult(`color-mix(in hwb longer hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, `hwb(170deg 30% 40%)`);
     136
     137    debug(`-> increasing hue`)
     138    testComputedComputingResult(`color-mix(in hwb increasing hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     139    testComputedComputingResult(`color-mix(in hwb increasing hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, `hwb(230deg 30% 40%)`);
     140    testComputedComputingResult(`color-mix(in hwb increasing hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, `hwb(190deg 30% 40%)`);
     141    testComputedComputingResult(`color-mix(in hwb increasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, `hwb(10deg 30% 40%)`);
     142    testComputedComputingResult(`color-mix(in hwb increasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, `hwb(170deg 30% 40%)`);
     143    testComputedComputingResult(`color-mix(in hwb increasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, `hwb(350deg 30% 40%)`);
     144
     145    debug(`-> decreasing hue`)
     146    testComputedComputingResult(`color-mix(in hwb decreasing hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, `hwb(230deg 30% 40%)`);
     147    testComputedComputingResult(`color-mix(in hwb decreasing hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     148    testComputedComputingResult(`color-mix(in hwb decreasing hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, `hwb(10deg 30% 40%)`);
     149    testComputedComputingResult(`color-mix(in hwb decreasing hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, `hwb(190deg 30% 40%)`);
     150    testComputedComputingResult(`color-mix(in hwb decreasing hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, `hwb(350deg 30% 40%)`);
     151    testComputedComputingResult(`color-mix(in hwb decreasing hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, `hwb(170deg 30% 40%)`);
     152
     153    debug(`-> specified hue`)
     154    testComputedComputingResult(`color-mix(in hwb specified hue, hwb(40deg 30% 40%), hwb(60deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     155    testComputedComputingResult(`color-mix(in hwb specified hue, hwb(60deg 30% 40%), hwb(40deg 30% 40%))`, `hwb(50deg 30% 40%)`);
     156    testComputedComputingResult(`color-mix(in hwb specified hue, hwb(50deg 30% 40%), hwb(330deg 30% 40%))`, `hwb(190deg 30% 40%)`);
     157    testComputedComputingResult(`color-mix(in hwb specified hue, hwb(330deg 30% 40%), hwb(50deg 30% 40%))`, `hwb(190deg 30% 40%)`);
     158    testComputedComputingResult(`color-mix(in hwb specified hue, hwb(20deg 30% 40%), hwb(320deg 30% 40%))`, `hwb(170deg 30% 40%)`);
     159    testComputedComputingResult(`color-mix(in hwb specified hue, hwb(320deg 30% 40%), hwb(20deg 30% 40%))`, `hwb(170deg 30% 40%)`);
     160
     161    debug('-> Invalid examples');
     162    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))`, `rgba(0, 0, 0, 0)`); // Percentages less than 0 are not valid.
     163    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 150%, hwb(30deg 30% 40%))`, `rgba(0, 0, 0, 0)`); // Percentages greater than 100 are not valid.
     164    testComputed(`color-mix(in hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%) 0%)`, `rgba(0, 0, 0, 0)`); // Sum of percengates cannot be 0%.
    60165   
    61166    for (const colorSpace of [ "lch", "oklch" ]) {
     
    69174        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4), ${colorSpace}(50% 60 70deg / .8) 25%)`, `${colorSpace}(20% 30 40 / 0.5)`);
    70175        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 25%, ${colorSpace}(50% 60 70deg / .8) 75%)`, `${colorSpace}(40% 50 60 / 0.7)`);
    71         testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 50%, ${colorSpace}(50% 60 70deg / .8) 150%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale down > 100% sum.
    72         testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 12.5%, ${colorSpace}(50% 60 70deg / .8) 37.5%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale up < 100% sum.
     176        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 30%, ${colorSpace}(50% 60 70deg / .8) 90%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale down > 100% sum.
     177        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 12.5%, ${colorSpace}(50% 60 70deg / .8) 37.5%)`, `${colorSpace}(40% 50 60 / 0.35)`); // Scale up < 100% sum
    73178        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 0%, ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(50% 60 70 / 0.8)`);
    74179
    75         // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
    76         testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) -10%, ${colorSpace}(50% 60 70deg / .8))`, `${colorSpace}(54% 64 74 / 0.84000003)`);
     180        debug(`-> no hue method specified, defaults to shorter`)
     181        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(100% 0 40deg), ${colorSpace}(100% 0 60deg))`, `${colorSpace}(100% 0 50)`);
     182        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(100% 0 60deg), ${colorSpace}(100% 0 40deg))`, `${colorSpace}(100% 0 50)`);
     183        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(100% 0 50deg), ${colorSpace}(100% 0 330deg))`, `${colorSpace}(100% 0 10)`);
     184        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(100% 0 330deg), ${colorSpace}(100% 0 50deg))`, `${colorSpace}(100% 0 10)`);
     185        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(100% 0 20deg), ${colorSpace}(100% 0 320deg))`, `${colorSpace}(100% 0 350)`);
     186        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(100% 0 320deg), ${colorSpace}(100% 0 20deg))`, `${colorSpace}(100% 0 350)`);
     187
     188        debug(`-> shorter hue`)
     189        testComputed(`color-mix(in ${colorSpace} shorter hue, ${colorSpace}(100% 0 40deg), ${colorSpace}(100% 0 60deg))`, `${colorSpace}(100% 0 50)`);
     190        testComputed(`color-mix(in ${colorSpace} shorter hue, ${colorSpace}(100% 0 60deg), ${colorSpace}(100% 0 40deg))`, `${colorSpace}(100% 0 50)`);
     191        testComputed(`color-mix(in ${colorSpace} shorter hue, ${colorSpace}(100% 0 50deg), ${colorSpace}(100% 0 330deg))`, `${colorSpace}(100% 0 10)`);
     192        testComputed(`color-mix(in ${colorSpace} shorter hue, ${colorSpace}(100% 0 330deg), ${colorSpace}(100% 0 50deg))`, `${colorSpace}(100% 0 10)`);
     193        testComputed(`color-mix(in ${colorSpace} shorter hue, ${colorSpace}(100% 0 20deg), ${colorSpace}(100% 0 320deg))`, `${colorSpace}(100% 0 350)`);
     194        testComputed(`color-mix(in ${colorSpace} shorter hue, ${colorSpace}(100% 0 320deg), ${colorSpace}(100% 0 20deg))`, `${colorSpace}(100% 0 350)`);
     195
     196        debug(`-> longer hue`)
     197        testComputed(`color-mix(in ${colorSpace} longer hue, ${colorSpace}(100% 0 40deg), ${colorSpace}(100% 0 60deg))`, `${colorSpace}(100% 0 230)`);
     198        testComputed(`color-mix(in ${colorSpace} longer hue, ${colorSpace}(100% 0 60deg), ${colorSpace}(100% 0 40deg))`, `${colorSpace}(100% 0 230)`);
     199        testComputed(`color-mix(in ${colorSpace} longer hue, ${colorSpace}(100% 0 50deg), ${colorSpace}(100% 0 330deg))`, `${colorSpace}(100% 0 190)`);
     200        testComputed(`color-mix(in ${colorSpace} longer hue, ${colorSpace}(100% 0 330deg), ${colorSpace}(100% 0 50deg))`, `${colorSpace}(100% 0 190)`);
     201        testComputed(`color-mix(in ${colorSpace} longer hue, ${colorSpace}(100% 0 20deg), ${colorSpace}(100% 0 320deg))`, `${colorSpace}(100% 0 170)`);
     202        testComputed(`color-mix(in ${colorSpace} longer hue, ${colorSpace}(100% 0 320deg), ${colorSpace}(100% 0 20deg))`, `${colorSpace}(100% 0 170)`);
     203
     204        debug(`-> increasing hue`)
     205        testComputed(`color-mix(in ${colorSpace} increasing hue, ${colorSpace}(100% 0 40deg), ${colorSpace}(100% 0 60deg))`, `${colorSpace}(100% 0 50)`);
     206        testComputed(`color-mix(in ${colorSpace} increasing hue, ${colorSpace}(100% 0 60deg), ${colorSpace}(100% 0 40deg))`, `${colorSpace}(100% 0 230)`);
     207        testComputed(`color-mix(in ${colorSpace} increasing hue, ${colorSpace}(100% 0 50deg), ${colorSpace}(100% 0 330deg))`, `${colorSpace}(100% 0 190)`);
     208        testComputed(`color-mix(in ${colorSpace} increasing hue, ${colorSpace}(100% 0 330deg), ${colorSpace}(100% 0 50deg))`, `${colorSpace}(100% 0 10)`);
     209        testComputed(`color-mix(in ${colorSpace} increasing hue, ${colorSpace}(100% 0 20deg), ${colorSpace}(100% 0 320deg))`, `${colorSpace}(100% 0 170)`);
     210        testComputed(`color-mix(in ${colorSpace} increasing hue, ${colorSpace}(100% 0 320deg), ${colorSpace}(100% 0 20deg))`, `${colorSpace}(100% 0 350)`);
     211
     212        debug(`-> decreasing hue`)
     213        testComputed(`color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100% 0 40deg), ${colorSpace}(100% 0 60deg))`, `${colorSpace}(100% 0 230)`);
     214        testComputed(`color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100% 0 60deg), ${colorSpace}(100% 0 40deg))`, `${colorSpace}(100% 0 50)`);
     215        testComputed(`color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100% 0 50deg), ${colorSpace}(100% 0 330deg))`, `${colorSpace}(100% 0 10)`);
     216        testComputed(`color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100% 0 330deg), ${colorSpace}(100% 0 50deg))`, `${colorSpace}(100% 0 190)`);
     217        testComputed(`color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100% 0 20deg), ${colorSpace}(100% 0 320deg))`, `${colorSpace}(100% 0 350)`);
     218        testComputed(`color-mix(in ${colorSpace} decreasing hue, ${colorSpace}(100% 0 320deg), ${colorSpace}(100% 0 20deg))`, `${colorSpace}(100% 0 170)`);
     219   
     220        debug(`-> specified hue`)
     221        testComputed(`color-mix(in ${colorSpace} specified hue, ${colorSpace}(100% 0 40deg), ${colorSpace}(100% 0 60deg))`, `${colorSpace}(100% 0 50)`);
     222        testComputed(`color-mix(in ${colorSpace} specified hue, ${colorSpace}(100% 0 60deg), ${colorSpace}(100% 0 40deg))`, `${colorSpace}(100% 0 50)`);
     223        testComputed(`color-mix(in ${colorSpace} specified hue, ${colorSpace}(100% 0 50deg), ${colorSpace}(100% 0 330deg))`, `${colorSpace}(100% 0 190)`);
     224        testComputed(`color-mix(in ${colorSpace} specified hue, ${colorSpace}(100% 0 330deg), ${colorSpace}(100% 0 50deg))`, `${colorSpace}(100% 0 190)`);
     225        testComputed(`color-mix(in ${colorSpace} specified hue, ${colorSpace}(100% 0 20deg), ${colorSpace}(100% 0 320deg))`, `${colorSpace}(100% 0 170)`);
     226        testComputed(`color-mix(in ${colorSpace} specified hue, ${colorSpace}(100% 0 320deg), ${colorSpace}(100% 0 20deg))`, `${colorSpace}(100% 0 170)`);
     227
     228        debug('-> Invalid examples');
     229        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) -10%, ${colorSpace}(50% 60 70deg / .8))`, `rgba(0, 0, 0, 0)`); // Percentages less than 0 are not valid.
     230        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 150%, ${colorSpace}(50% 60 70deg / .8))`, `rgba(0, 0, 0, 0)`); // Percentages greater than 100 are not valid.
     231        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30deg / .4) 0%, ${colorSpace}(50% 60 70deg / .8) 0%)`, `rgba(0, 0, 0, 0)`); // Sum of percengates cannot be 0%.
    77232    }
    78233
     
    87242        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4), ${colorSpace}(50% 60 70 / .8) 25%)`, `${colorSpace}(20% 30 40 / 0.5)`);
    88243        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 25%, ${colorSpace}(50% 60 70 / .8) 75%)`, `${colorSpace}(40% 50 60 / 0.7)`);
    89         testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 50%, ${colorSpace}(50% 60 70 / .8) 150%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale down > 100% sum.
    90         testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 12.5%, ${colorSpace}(50% 60 70 / .8) 37.5%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale up < 100% sum.
     244        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 30%, ${colorSpace}(50% 60 70 / .8) 90%)`, `${colorSpace}(40% 50 60 / 0.7)`); // Scale down > 100% sum.
     245        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 12.5%, ${colorSpace}(50% 60 70 / .8) 37.5%)`, `${colorSpace}(40% 50 60 / 0.35)`); // Scale up < 100% sum, causes alpha multiplication.
    91246        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 0%, ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(50% 60 70 / 0.8)`);
    92247
    93         // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
    94         testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) -10%, ${colorSpace}(50% 60 70 / .8))`, `${colorSpace}(54% 64 74 / 0.84000003)`);
    95     }
    96  
     248        debug('-> Invalid examples');
     249        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) -10%, ${colorSpace}(50% 60 70 / .8))`, `rgba(0, 0, 0, 0)`); // Percentages less than 0 are not valid.
     250        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 150%, ${colorSpace}(50% 60 70 / .8))`, `rgba(0, 0, 0, 0)`); // Percentages greater than 100 are not valid.
     251        testComputed(`color-mix(in ${colorSpace}, ${colorSpace}(10% 20 30 / .4) 0%, ${colorSpace}(50% 60 70 / .8) 0%)`, `rgba(0, 0, 0, 0)`); // Sum of percengates cannot be 0%.
     252    }
     253
    97254    for (const colorSpace of [ "srgb", "xyz", "xyz-d50", "xyz-d65" ]) {
    98255        debug('');
    99256        debug(`color-mix(in ${colorSpace}, ...)`);
    100257 
    101                 const resultColorSpace = colorSpace == "xyz" ? "xyz-d65" : colorSpace;
    102 
    103             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4), color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.3 0.4 0.5 / 0.6)`);
    104             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 25%, color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`);
    105             testComputed(`color-mix(in ${colorSpace}, 25% color(${colorSpace} .1 .2 .3 / .4), color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`);
    106             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4), color(${colorSpace} .5 .6 .7 / .8) 25%)`, `color(${resultColorSpace} 0.2 0.3 0.4 / 0.5)`);
    107             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4), 25% color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.2 0.3 0.4 / 0.5)`);
    108             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 25%, color(${colorSpace} .5 .6 .7 / .8) 75%)`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`);
    109             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 50%, color(${colorSpace} .5 .6 .7 / .8) 150%)`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
    110             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 12.5%, color(${colorSpace} .5 .6 .7 / .8) 37.5%)`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`); // Scale up < 100% sum.
    111             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 0%, color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.5 0.6 0.7 / 0.8)`);
    112 
    113             // What should happen if you provide a negative percent? https://github.com/w3c/csswg-drafts/issues/6047
    114             testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) -10%, color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.54 0.64000005 0.74 / 0.84000003)`);
    115         }
     258        const resultColorSpace = colorSpace == "xyz" ? "xyz-d65" : colorSpace;
     259
     260        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4), color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.3 0.4 0.5 / 0.6)`);
     261        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 25%, color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`);
     262        testComputed(`color-mix(in ${colorSpace}, 25% color(${colorSpace} .1 .2 .3 / .4), color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`);
     263        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4), color(${colorSpace} .5 .6 .7 / .8) 25%)`, `color(${resultColorSpace} 0.2 0.3 0.4 / 0.5)`);
     264        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4), 25% color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.2 0.3 0.4 / 0.5)`);
     265        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 25%, color(${colorSpace} .5 .6 .7 / .8) 75%)`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`);
     266        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 30%, color(${colorSpace} .5 .6 .7 / .8) 90%)`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
     267        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 12.5%, color(${colorSpace} .5 .6 .7 / .8) 37.5%)`, `color(${resultColorSpace} 0.4 0.5 0.6 / 0.35)`); // Scale up < 100% sum, causes alpha multiplication.
     268        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 0%, color(${colorSpace} .5 .6 .7 / .8))`, `color(${resultColorSpace} 0.5 0.6 0.7 / 0.8)`);
     269
     270        debug('-> Invalid examples');
     271        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) -10%, color(${colorSpace} .5 .6 .7 / .8))`, `rgba(0, 0, 0, 0)`); // Percentages less than 0 are not valid.
     272        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 150%, color(${colorSpace} .5 .6 .7 / .8))`, `rgba(0, 0, 0, 0)`); // Percentages greater than 100 are not valid.
     273        testComputed(`color-mix(in ${colorSpace}, color(${colorSpace} .1 .2 .3 / .4) 0%, color(${colorSpace} .5 .6 .7 / .8) 0%)`, `rgba(0, 0, 0, 0)`); // Sum of percengates cannot be 0%.
     274    }
    116275</script>
    117276   
  • trunk/Source/WebCore/ChangeLog

    r286195 r286196  
     12021-11-28  Sam Weinig  <weinig@apple.com>
     2
     3        [CSS Color 5] Update color-mix() to latest spec (again)
     4        https://bugs.webkit.org/show_bug.cgi?id=233527
     5
     6        Reviewed by Dean Jackson.
     7
     8        Updates color-mix() implementation with support for hue interpolation methods and
     9        addresses various other spec changes (detailed below).
     10
     11        * Sources.txt:
     12        * WebCore.xcodeproj/project.pbxproj:
     13        Add ColorInterpolation.h/cpp
     14
     15        * css/CSSValueKeywords.in:
     16        Add keywords need for the <color-space-interpolation> production. Separated out
     17        from color-mix as these will be used for other CSS properties as well.
     18
     19        * css/parser/CSSPropertyParserHelpers.cpp:
     20        (WebCore::CSSPropertyParserHelpers::consumeHueInterpolationMethod):
     21        (WebCore::CSSPropertyParserHelpers::consumeColorInterpolationMethod):
     22        (WebCore::CSSPropertyParserHelpers::consumeColorMixComponent):
     23        (WebCore::CSSPropertyParserHelpers::normalizedMixPercentages):
     24        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>):
     25        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HSLA<float>>):
     26        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<LCHA<float>>):
     27        (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<OKLCHA<float>>):
     28        (WebCore::CSSPropertyParserHelpers::mixColorComponentsUsingColorInterpolationMethod):
     29        (WebCore::CSSPropertyParserHelpers::mixColorComponents):
     30        (WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParameters):
     31        (WebCore::CSSPropertyParserHelpers::consumeColorMixColorSpaceAndComma): Deleted.
     32        (WebCore::CSSPropertyParserHelpers::fixupHueComponentsPriorToMix): Deleted.
     33        (WebCore::CSSPropertyParserHelpers::mixColorComponentsInColorSpace): Deleted.
     34        Rework color-mix to support the hue interpolation method specification for polor color spaces
     35        like lch, oklch, hsl and hwb. Also update implementation to match the current spec by restricting
     36        mix percentages to between 0 and 100 and applying alpha multiplier when the mix percentages add
     37        up to less than 100.
     38
     39        * platform/graphics/ColorInterpolation.cpp: Added.
     40        * platform/graphics/ColorInterpolation.h: Added.
     41        Add structures to represent color interpolation methods including optional hue
     42        interpolation parameters for color spaces that require it and provides prenormalization
     43        that fixes up hue angles depending on the method selected. Over time, more aspects of
     44        interpolation should be moved here as we figure out what can be shared.
     45
    1462021-11-28  Alan Bujtas  <zalan@apple.com>
    247
  • trunk/Source/WebCore/Sources.txt

    r286193 r286196  
    19841984platform/graphics/ColorBlending.cpp
    19851985platform/graphics/ColorConversion.cpp
     1986platform/graphics/ColorInterpolation.cpp
    19861987platform/graphics/ColorLuminance.cpp
    19871988platform/graphics/ColorSerialization.cpp
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r286193 r286196  
    1511115111                BCD9C2BE0C17B69E005C90A2 /* JSNodeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSNodeList.cpp; sourceTree = "<group>"; };
    1511215112                BCD9C2BF0C17B69E005C90A2 /* JSNodeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSNodeList.h; sourceTree = "<group>"; };
     15113                BCDC642427517B040038FB39 /* ColorInterpolation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ColorInterpolation.cpp; sourceTree = "<group>"; };
     15114                BCDC642527517B040038FB39 /* ColorInterpolation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColorInterpolation.h; sourceTree = "<group>"; };
    1511315115                BCDD454D1236C95C009A7985 /* ColumnInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColumnInfo.h; sourceTree = "<group>"; };
    1511415116                BCDF317911F8D683003C5BF8 /* UserTypingGestureIndicator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserTypingGestureIndicator.cpp; sourceTree = "<group>"; };
     
    2793527937                                7C514E0024AF80580050710F /* ColorConversion.h */,
    2793627938                                3103B7DE1DB01556008BB890 /* ColorHash.h */,
     27939                                BCDC642427517B040038FB39 /* ColorInterpolation.cpp */,
     27940                                BCDC642527517B040038FB39 /* ColorInterpolation.h */,
    2793727941                                BC6EB84526266B61003225A7 /* ColorLuminance.cpp */,
    2793827942                                BC4A23EB25EC160200AAC630 /* ColorLuminance.h */,
  • trunk/Source/WebCore/css/CSSValueKeywords.in

    r286191 r286196  
    14861486// color-mix()
    14871487color-mix
     1488
     1489// color-space-interpolation
    14881490in
     1491// srgb
     1492// lab
     1493// oklab
     1494// xyz
     1495// xyz-d50
     1496// xyz-d65
     1497// hsl
     1498// hwb
     1499// lch
     1500// oklch
     1501shorter
     1502longer
     1503increasing
     1504decreasing
     1505specified
     1506// hue
    14891507
    14901508// prefers-default-appearance
  • trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp

    r286191 r286196  
    4545#include "CalculationCategory.h"
    4646#include "ColorConversion.h"
     47#include "ColorInterpolation.h"
    4748#include "ColorLuminance.h"
    4849#include "Logging.h"
     
    22912292}
    22922293
    2293 enum class ColorMixColorSpace {
    2294     Hsl,
    2295     Hwb,
    2296     Lab,
    2297     Lch,
    2298     Oklab,
    2299     Oklch,
    2300     Srgb,
    2301     XyzD50,
    2302     XyzD65
    2303 };
    2304 
    2305 static std::optional<ColorMixColorSpace> consumeColorMixColorSpaceAndComma(CSSParserTokenRange& args)
    2306 {
    2307     auto consumeIdentAndComma = [](CSSParserTokenRange& args, ColorMixColorSpace colorSpace) -> std::optional<ColorMixColorSpace> {
    2308         consumeIdentRaw(args);
    2309         if (!consumeCommaIncludingWhitespace(args))
    2310             return std::nullopt;
    2311         return colorSpace;
     2294static std::optional<HueInterpolationMethod> consumeHueInterpolationMethod(CSSParserTokenRange& args)
     2295{
     2296    switch (args.peek().id()) {
     2297    case CSSValueShorter:
     2298        args.consumeIncludingWhitespace();
     2299        return HueInterpolationMethod::Shorter;
     2300    case CSSValueLonger:
     2301        args.consumeIncludingWhitespace();
     2302        return HueInterpolationMethod::Longer;
     2303    case CSSValueIncreasing:
     2304        args.consumeIncludingWhitespace();
     2305        return HueInterpolationMethod::Increasing;
     2306    case CSSValueDecreasing:
     2307        args.consumeIncludingWhitespace();
     2308        return HueInterpolationMethod::Decreasing;
     2309    case CSSValueSpecified:
     2310        args.consumeIncludingWhitespace();
     2311        return HueInterpolationMethod::Specified;
     2312    default:
     2313        return { };
     2314    }
     2315}
     2316
     2317static std::optional<ColorInterpolationMethod> consumeColorInterpolationMethod(CSSParserTokenRange& args)
     2318{
     2319    // <rectangular-color-space> = srgb | lab | oklab | xyz | xyz-d50 | xyz-d65
     2320    // <polar-color-space> = hsl | hwb | lch | oklch
     2321    // <hue-interpolation-method> = [ shorter | longer | increasing | decreasing | specified ] hue
     2322    // <color-interpolation-method> = in [ <rectangular-color-space> | <polar-color-space> <hue-interpolation-method>? ]
     2323
     2324    if (!consumeIdentRaw<CSSValueIn>(args))
     2325        return { };
     2326
     2327    auto consumePolarColorSpace = [](CSSParserTokenRange& args, auto colorInterpolationMethod) -> std::optional<ColorInterpolationMethod> {
     2328        // Consume the color space identifier.
     2329        args.consumeIncludingWhitespace();
     2330
     2331        // <hue-interpolation-method> is optional, so if it is not provided, we just use the default value
     2332        // specified in the passed in 'colorInterpolationMethod' parameter.
     2333        auto hueInterpolationMethod = consumeHueInterpolationMethod(args);
     2334        if (!hueInterpolationMethod)
     2335            return {{ colorInterpolationMethod }};
     2336       
     2337        // If the hue-interpolation-method was provided it must be followed immediately by the 'hue' identifier.
     2338        if (!consumeIdentRaw<CSSValueHue>(args))
     2339            return { };
     2340
     2341        colorInterpolationMethod.hueInterpolationMethod = *hueInterpolationMethod;
     2342
     2343        return {{ colorInterpolationMethod }};
     2344    };
     2345
     2346    auto consumeRectangularColorSpace = [](CSSParserTokenRange& args, auto colorInterpolationMethod) -> std::optional<ColorInterpolationMethod> {
     2347        // Consume the color space identifier.
     2348        args.consumeIncludingWhitespace();
     2349
     2350        return {{ colorInterpolationMethod }};
    23122351    };
    23132352
    23142353    switch (args.peek().id()) {
    23152354    case CSSValueHsl:
    2316         return consumeIdentAndComma(args, ColorMixColorSpace::Hsl);
     2355        return consumePolarColorSpace(args, ColorInterpolationMethod::HSL { });
    23172356    case CSSValueHwb:
    2318         return consumeIdentAndComma(args, ColorMixColorSpace::Hwb);
     2357        return consumePolarColorSpace(args, ColorInterpolationMethod::HWB { });
     2358    case CSSValueLch:
     2359        return consumePolarColorSpace(args, ColorInterpolationMethod::LCH { });
    23192360    case CSSValueLab:
    2320         return consumeIdentAndComma(args, ColorMixColorSpace::Lab);
    2321     case CSSValueLch:
    2322         return consumeIdentAndComma(args, ColorMixColorSpace::Lch);
     2361        return consumeRectangularColorSpace(args, ColorInterpolationMethod::Lab { });
     2362    case CSSValueOklch:
     2363        return consumePolarColorSpace(args, ColorInterpolationMethod::OKLCH { });
    23232364    case CSSValueOklab:
    2324         return consumeIdentAndComma(args, ColorMixColorSpace::Oklab);
    2325     case CSSValueOklch:
    2326         return consumeIdentAndComma(args, ColorMixColorSpace::Oklch);
     2365        return consumeRectangularColorSpace(args, ColorInterpolationMethod::OKLab { });
    23272366    case CSSValueSRGB:
    2328         return consumeIdentAndComma(args, ColorMixColorSpace::Srgb);
     2367        return consumeRectangularColorSpace(args, ColorInterpolationMethod::SRGB { });
    23292368    case CSSValueXyzD50:
    2330         return consumeIdentAndComma(args, ColorMixColorSpace::XyzD50);
     2369        return consumeRectangularColorSpace(args, ColorInterpolationMethod::XYZD50 { });
    23312370    case CSSValueXyz:
    23322371    case CSSValueXyzD65:
    2333         return consumeIdentAndComma(args, ColorMixColorSpace::XyzD65);
     2372        return consumeRectangularColorSpace(args, ColorInterpolationMethod::XYZD65 { });
    23342373    default:
    2335         return std::nullopt;
     2374        return { };
    23362375    }
    23372376}
     
    23462385    ColorMixComponent result;
    23472386
    2348     if (auto percentage = consumePercentRaw(args))
     2387    if (auto percentage = consumePercentRaw(args)) {
     2388        if (*percentage < 0.0 || *percentage > 100.0)
     2389            return { };
    23492390        result.percentage = percentage;
     2391    }
    23502392
    23512393    result.color = consumeOriginColor(args, context);
     
    23542396
    23552397    if (!result.percentage) {
    2356         if (auto percentage = consumePercentRaw(args))
     2398        if (auto percentage = consumePercentRaw(args)) {
     2399            if (*percentage < 0.0 || *percentage > 100.0)
     2400                return { };
    23572401            result.percentage = percentage;
     2402        }
    23582403    }
    23592404
     
    23642409    double p1;
    23652410    double p2;
     2411    std::optional<double> alphaMultiplier = std::nullopt;
    23662412};
    23672413
    2368 static ColorMixPercentages normalizedMixPercentages(const ColorMixComponent& mixComponents1, const ColorMixComponent& mixComponents2)
     2414static std::optional<ColorMixPercentages> normalizedMixPercentages(const ColorMixComponent& mixComponents1, const ColorMixComponent& mixComponents2)
    23692415{
    23702416    // The percentages are normalized as follows:
     
    23742420    // 2. If both percentages are omitted, they each default to 50% (an equal mix of the two colors).
    23752421    if (!mixComponents1.percentage && !mixComponents2.percentage)
    2376         return { 50.0, 50.0 };
     2422        return {{ 50.0, 50.0 }};
    23772423   
    23782424    ColorMixPercentages result;
     
    23932439    auto sum = result.p1 + result.p2;
    23942440
    2395     // 5. If the percentages sum to zero do something, tbd. (FIXME: We just use 50 / 50 for this case for now).
     2441    // 5.If the percentages sum to zero, the function is invalid.
    23962442    if (sum == 0)
    2397         return { 50.0, 50.0 };
    2398 
    2399     if (sum != 100.0) {
     2443        return { };
     2444
     2445    if (sum > 100.0) {
    24002446        // 6. Otherwise, if both are provided but do not add up to 100%, they are scaled accordingly so that they
    2401         //    add up to 100%. This means that p1 becomes p1 / (p1 + p2) and p2 becomes p2 / (p1 + p2).
     2447        //    add up to 100%.
    24022448        result.p1 *= 100.0 / sum;
    24032449        result.p2 *= 100.0 / sum;
     2450    } else if (sum < 100.0) {
     2451        // 7. Otherwise, if both are provided and add up to less than 100%, the sum is saved as an alpha multiplier.
     2452        //    They are then scaled accordingly so that they add up to 100%.
     2453        result.p1 *= 100.0 / sum;
     2454        result.p2 *= 100.0 / sum;
     2455        result.alphaMultiplier = sum;
    24042456    }
    24052457
     
    24072459}
    24082460
    2409 // Normalization is special cased for HWBA, which needs to normalize the whiteness and blackness components and convert to sRGB
    2410 // and HSLA, which just needs to be converted to sRGB. All other color types can go through this non-specialized case.
     2461// Normalization is special cased for for all polar color spaces to renormalize the hue, with additional normalization needed
     2462// for HWBA to normalize the whiteness and blackness components. Furthermore, HWBA and HSLA also get converted to SRGBA which
     2463// is their canonical form.
    24112464
    24122465template<typename ColorType> inline Color makeColorTypeByNormalizingComponentsAfterMix(const ColorComponents<float, 4>& colorComponents)
     
    24192472    auto [hue, whiteness, blackness, alpha] = colorComponents;
    24202473    auto [normalizedWhitness, normalizedBlackness] = normalizeWhitenessBlackness(whiteness, blackness);
    2421 
    2422     return convertColor<SRGBA<uint8_t>>(HWBA<float> { hue, normalizedWhitness, normalizedBlackness, alpha });
     2474    float normalizedHue = normalizeHue(hue);
     2475
     2476    return convertColor<SRGBA<uint8_t>>(HWBA<float> { normalizedHue, normalizedWhitness, normalizedBlackness, alpha });
    24232477}
    24242478
    24252479template<> inline Color makeColorTypeByNormalizingComponentsAfterMix<HSLA<float>>(const ColorComponents<float, 4>& colorComponents)
    24262480{
    2427     return convertColor<SRGBA<uint8_t>>(makeFromComponents<HSLA<float>>(colorComponents));
    2428 }
    2429 
    2430 template<size_t I, typename ComponentType> static void fixupHueComponentsPriorToMix(ColorComponents<ComponentType, 4>& colorComponents1, ColorComponents<ComponentType, 4>& colorComponents2)
    2431 {
    2432     auto normalizeAnglesUsingShorterAlgorithm = [] (auto theta1, auto theta2) -> std::pair<ComponentType, ComponentType> {
    2433         // https://drafts.csswg.org/css-color-4/#hue-shorter
    2434         auto difference = theta2 - theta1;
    2435         if (difference > 180.0)
    2436             return { theta1 + 360.0, theta2 };
    2437         if (difference < -180.0)
    2438             return { theta1, theta2 + 360.0 };
    2439         return { theta1, theta2 };
    2440     };
    2441 
    2442     // As no other interpolation type was specified, all angles should be normalized to use the "shorter" algorithm.
    2443     auto [theta1, theta2] = normalizeAnglesUsingShorterAlgorithm(colorComponents1[I], colorComponents2[I]);
    2444     colorComponents1[I] = theta1;
    2445     colorComponents2[I] = theta2;
    2446 }
    2447 
    2448 template<typename ColorType> static Color mixColorComponentsInColorSpace(ColorMixPercentages mixPercentages, const Color& color1, const Color& color2)
    2449 {
     2481    auto [hue, saturation, lightness, alpha] = colorComponents;
     2482    float normalizedHue = normalizeHue(hue);
     2483
     2484    return convertColor<SRGBA<uint8_t>>(HSLA<float> { normalizedHue, saturation, lightness, alpha });
     2485}
     2486
     2487template<> inline Color makeColorTypeByNormalizingComponentsAfterMix<LCHA<float>>(const ColorComponents<float, 4>& colorComponents)
     2488{
     2489    auto [lightness, chroma, hue, alpha] = colorComponents;
     2490    float normalizedHue = normalizeHue(hue);
     2491
     2492    return LCHA<float> { lightness, chroma, normalizedHue, alpha };
     2493}
     2494
     2495template<> inline Color makeColorTypeByNormalizingComponentsAfterMix<OKLCHA<float>>(const ColorComponents<float, 4>& colorComponents)
     2496{
     2497    auto [lightness, chroma, hue, alpha] = colorComponents;
     2498    float normalizedHue = normalizeHue(hue);
     2499
     2500    return OKLCHA<float> { lightness, chroma, normalizedHue, alpha };
     2501}
     2502
     2503template<typename Method> static Color mixColorComponentsUsingColorInterpolationMethod(Method colorInterpolationMethod, ColorMixPercentages mixPercentages, const Color& color1, const Color& color2)
     2504{
     2505    using ColorType = typename Method::ColorType;
     2506
     2507    // 1. Both colors are converted to the specified <color-space>. If the specified color space has a smaller gamut than
     2508    //    the one in which the color to be adjusted is specified, gamut mapping will occur.
    24502509    auto colorComponents1 = asColorComponents(color1.template toColorTypeLossy<ColorType>());
    24512510    auto colorComponents2 = asColorComponents(color2.template toColorTypeLossy<ColorType>());
    24522511
    2453     // Perform fixups on any hue/angle components.
    2454     constexpr auto componentInfo = ColorType::Model::componentInfo;
    2455     if constexpr (componentInfo[0].type == ColorComponentType::Angle)
    2456         fixupHueComponentsPriorToMix<0>(colorComponents1, colorComponents2);
    2457     if constexpr (componentInfo[1].type == ColorComponentType::Angle)
    2458         fixupHueComponentsPriorToMix<1>(colorComponents1, colorComponents2);
    2459     if constexpr (componentInfo[2].type == ColorComponentType::Angle)
    2460         fixupHueComponentsPriorToMix<2>(colorComponents1, colorComponents2);
    2461 
    2462     auto colorComponentsMixed = mapColorComponents([&] (auto componentFromColor1, auto componentFromColor2) -> float {
     2512    // 2. Colors are then interpolated in the specified color space, as described in CSS Color 4 § 13 Interpolation. [...]
     2513    auto [normalizedColorComponents1, normalizedColorComponents2] = preInterpolationNormalization(colorInterpolationMethod, colorComponents1, colorComponents2);
     2514
     2515    auto mixedColorComponents = mapColorComponents([&] (auto componentFromColor1, auto componentFromColor2) -> float {
    24632516        return (componentFromColor1 * mixPercentages.p1 / 100.0) + (componentFromColor2 * mixPercentages.p2 / 100.0);
    2464     }, colorComponents1, colorComponents2);
    2465 
    2466     return makeColorTypeByNormalizingComponentsAfterMix<ColorType>(colorComponentsMixed);
    2467 }
    2468 
    2469 static Color mixColorComponents(ColorMixColorSpace colorSpace, const ColorMixComponent& mixComponents1, const ColorMixComponent& mixComponents2)
     2517    }, normalizedColorComponents1, normalizedColorComponents2);
     2518
     2519    // 3. If an alpha multiplier was produced during percentage normalization, the alpha component of the interpolated result
     2520    //    is multiplied by the alpha multiplier.
     2521    if (mixPercentages.alphaMultiplier)
     2522        mixedColorComponents[3] *= (*mixPercentages.alphaMultiplier / 100.0);
     2523
     2524    return makeColorTypeByNormalizingComponentsAfterMix<ColorType>(mixedColorComponents);
     2525}
     2526
     2527static Color mixColorComponents(ColorInterpolationMethod colorInterpolationMethod, const ColorMixComponent& mixComponents1, const ColorMixComponent& mixComponents2)
    24702528{
    24712529    auto mixPercentages = normalizedMixPercentages(mixComponents1, mixComponents2);
    2472 
    2473     switch (colorSpace) {
    2474     case ColorMixColorSpace::Hsl:
    2475         return mixColorComponentsInColorSpace<HSLA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2476     case ColorMixColorSpace::Hwb:
    2477         return mixColorComponentsInColorSpace<HWBA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2478     case ColorMixColorSpace::Lab:
    2479         return mixColorComponentsInColorSpace<Lab<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2480     case ColorMixColorSpace::Lch:
    2481         return mixColorComponentsInColorSpace<LCHA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2482     case ColorMixColorSpace::Oklab:
    2483         return mixColorComponentsInColorSpace<OKLab<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2484     case ColorMixColorSpace::Oklch:
    2485         return mixColorComponentsInColorSpace<OKLCHA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2486     case ColorMixColorSpace::Srgb:
    2487         return mixColorComponentsInColorSpace<SRGBA<float>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2488     case ColorMixColorSpace::XyzD50:
    2489         return mixColorComponentsInColorSpace<XYZA<float, WhitePoint::D50>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2490     case ColorMixColorSpace::XyzD65:
    2491         return mixColorComponentsInColorSpace<XYZA<float, WhitePoint::D65>>(mixPercentages, mixComponents1.color, mixComponents2.color);
    2492     }
    2493 
    2494     RELEASE_ASSERT_NOT_REACHED();
     2530    if (!mixPercentages)
     2531        return { };
     2532
     2533    return WTF::switchOn(colorInterpolationMethod.value,
     2534        [&] (auto method) {
     2535            return mixColorComponentsUsingColorInterpolationMethod<decltype(method)>(method, *mixPercentages, mixComponents1.color, mixComponents2.color);
     2536        }
     2537    );
    24952538}
    24962539
    24972540static Color parseColorMixFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
    24982541{
     2542    // color-mix() = color-mix( <color-interpolation-method> , [ <color> && <percentage [0,100]>? ]#{2})
     2543
    24992544    ASSERT(range.peek().functionId() == CSSValueColorMix);
    25002545
     
    25032548
    25042549    auto args = consumeFunction(range);
    2505 
    2506     if (!consumeIdentRaw<CSSValueIn>(args))
    2507         return { };
    25082550   
    2509     auto colorSpace = consumeColorMixColorSpaceAndComma(args);
    2510     if (!colorSpace)
     2551    auto colorInterpolationMethod = consumeColorInterpolationMethod(args);
     2552    if (!colorInterpolationMethod)
     2553        return { };
     2554
     2555    if (!consumeCommaIncludingWhitespace(args))
    25112556        return { };
    25122557
     
    25252570        return { };
    25262571
    2527     return mixColorComponents(*colorSpace, *mixComponent1, *mixComponent2);
     2572    return mixColorComponents(*colorInterpolationMethod, *mixComponent1, *mixComponent2);
    25282573}
    25292574
Note: See TracChangeset for help on using the changeset viewer.