Diff
Modified: trunk/LayoutTests/ChangeLog (273243 => 273244)
--- trunk/LayoutTests/ChangeLog 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/LayoutTests/ChangeLog 2021-02-22 17:52:13 UTC (rev 273244)
@@ -1,5 +1,16 @@
2021-02-22 Sam Weinig <wei...@apple.com>
+ Add experimental support for CSS Color 5 color-mix()
+ https://bugs.webkit.org/show_bug.cgi?id=222258
+
+ Reviewed by Antti Koivisto.
+
+ * fast/css/parsing-color-mix-expected.txt: Added.
+ * fast/css/parsing-color-mix.html: Added.
+ Add parsing and computed style computation tests for color-mix().
+
+2021-02-22 Sam Weinig <wei...@apple.com>
+
Update web-platform-tests/css/css-color
https://bugs.webkit.org/show_bug.cgi?id=222235
Added: trunk/LayoutTests/fast/css/parsing-color-mix-expected.txt (0 => 273244)
--- trunk/LayoutTests/fast/css/parsing-color-mix-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/css/parsing-color-mix-expected.txt 2021-02-22 17:52:13 UTC (rev 273244)
@@ -0,0 +1,204 @@
+Test the parsing of CSS Color 5 color-mix().
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+color-mix(hsl, ...)
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))") is "rgb(84, 92, 61)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))") is "rgb(112, 106, 67)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)") is "rgb(61, 73, 54)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)") is "rgb(112, 106, 67)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)") is "rgb(112, 106, 67)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)") is "rgb(112, 106, 67)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 50%)") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) hue 50%)") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 100%, hsl(30deg 30% 40%))") is "rgb(46, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100% alpha 100%, hsl(30deg 30% 40%))") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0%)") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0%)") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0% alpha 0%)") is "rgb(53, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75%, hsl(30deg 30% 40%))") is "rgb(55, 59, 43)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15%, hsl(30deg 30% 40%))") is "rgb(101, 108, 80)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15% alpha 10%, hsl(30deg 30% 40%))") is "rgb(101, 108, 80)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%))") is "rgb(52, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 40%)") is "rgb(52, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%) hue 40%)") is "rgb(52, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 60% hue 40%, hsl(30deg 30% 40%))") is "rgb(55, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 40%, hsl(30deg 30% 40%))") is "rgb(55, 56, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))") is "rgb(133, 102, 71)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue -10%, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
+PASS computedStyle("background-color", "color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))") is "rgb(56, 51, 46)"
+
+color-mix(hwb, ...)
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%))") is "rgb(147, 179, 52)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%))") is "rgb(166, 153, 64)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)") is "rgb(96, 191, 39)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)") is "rgb(166, 153, 64)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)") is "rgb(166, 153, 64)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)") is "rgb(166, 153, 64)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 50%)") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) hue 50%)") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 100%, hwb(30deg 30% 40%))") is "rgb(26, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100% alpha 100%, hwb(30deg 30% 40%))") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0%)") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0%)") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0% alpha 0%)") is "rgb(160, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75%, hwb(30deg 30% 40%))") is "rgb(163, 204, 39)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15%, hwb(30deg 30% 40%))") is "rgb(130, 161, 39)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15% alpha 10%, hwb(30deg 30% 40%))") is "rgb(130, 161, 39)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%))") is "rgb(133, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 40%)") is "rgb(133, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%) hue 40%)") is "rgb(133, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 75% 25%) whiteness 100%, hwb(120deg 25% 75%) blackness 100%)") is "rgb(128, 128, 128)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 60% hue 40%, hwb(30deg 30% 40%))") is "rgb(186, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 40%, hwb(30deg 30% 40%))") is "rgb(186, 204, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))") is "rgb(153, 115, 77)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue -10%, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
+PASS computedStyle("background-color", "color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))") is "rgb(204, 115, 26)"
+
+color-mix(lch, ...)
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))") is "lch(30% 40 50 / 0.6)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8))") is "lch(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) 25%)") is "lch(20% 30 40 / 0.5)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8) 75%)") is "lch(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 50%, lch(50% 60 70deg / .8) 150%)") is "lch(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 12.5%, lch(50% 60 70deg / .8) 37.5%)") is "lch(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 50%)") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) lightness 50%)") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 100%, lch(50% 60 70deg / .8))") is "lch(10% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100% alpha 100%, lch(50% 60 70deg / .8))") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0%)") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0%)") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0% alpha 0%)") is "lch(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75%, lch(50% 60 70deg / .8))") is "lch(30% 30 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15%, lch(50% 60 70deg / .8))") is "lch(30% 30 64 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15% alpha 10%, lch(50% 60 70deg / .8))") is "lch(30% 30 64 / 0.76)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8))") is "lch(26% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 40%)") is "lch(26% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8) lightness 40%)") is "lch(26% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 60% lightness 40%, lch(50% 60 70deg / .8))") is "lch(34% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 40%, lch(50% 60 70deg / .8))") is "lch(34% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))") is "lch(50% 60 70 / 0.8)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness -10%, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))") is "lch(50% 20 30 / 0.4)"
+
+color-mix(lab, ...)
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))") is "lab(30% 40 50 / 0.6)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8))") is "lab(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) 25%)") is "lab(20% 30 40 / 0.5)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8) 75%)") is "lab(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 50%, lab(50% 60 70 / .8) 150%)") is "lab(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 12.5%, lab(50% 60 70 / .8) 37.5%)") is "lab(40% 50 60 / 0.7)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8))") is "lab(50% 60 70 / 0.8)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 50%)") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) lightness 50%)") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 100%, lab(50% 60 70 / .8))") is "lab(10% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100% alpha 100%, lab(50% 60 70 / .8))") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0%)") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0%)") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0% alpha 0%)") is "lab(30% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75%, lab(50% 60 70 / .8))") is "lab(30% 30 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15%, lab(50% 60 70 / .8))") is "lab(30% 30 64 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15% alpha 10%, lab(50% 60 70 / .8))") is "lab(30% 30 64 / 0.76)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8))") is "lab(26% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 40%)") is "lab(26% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8) lightness 40%)") is "lab(26% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 60% lightness 40%, lab(50% 60 70 / .8))") is "lab(34% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness, lab(50% 60 70 / .8))") is "lab(50% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness 0%, lab(50% 60 70 / .8))") is "lab(50% 20 30 / 0.4)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))") is "lab(50% 60 70 / 0.8)"
+PASS computedStyle("background-color", "color-mix(lab, lab(10% 20 30 / .4) lightness -10%, lab(50% 60 70 / .8))") is "lab(50% 20 30 / 0.4)"
+
+color-mix(srgb, ...)
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.4 0.5 / 0.6)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) 25%)") is "color(srgb 0.2 0.3 0.4 / 0.5)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8) 75%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 50%, color(srgb .5 .6 .7 / .8) 150%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 12.5%, color(srgb .5 .6 .7 / .8) 37.5%)") is "color(srgb 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.6 0.7 / 0.8)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 50%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) red 50%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.1 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100% alpha 100%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0% alpha 0%)") is "color(srgb 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.3 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.3 0.64 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15% alpha 10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.3 0.3 0.64 / 0.76)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.26 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 40%)") is "color(srgb 0.26 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8) red 40%)") is "color(srgb 0.26 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60% red 40%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.34 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red 0%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.6 0.7 / 0.8)"
+PASS computedStyle("background-color", "color-mix(srgb, color(srgb .1 .2 .3 / .4) red -10%, color(srgb .5 .6 .7 / .8))") is "color(srgb 0.5 0.2 0.3 / 0.4)"
+
+color-mix(xyz, ...)
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.4 0.5 / 0.6)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) 25%)") is "color(xyz 0.2 0.3 0.4 / 0.5)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 12.5%, color(xyz .5 .6 .7 / .8) 37.5%)") is "color(xyz 0.4 0.5 0.6 / 0.7)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.6 0.7 / 0.8)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 50%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) x 50%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.1 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100% alpha 100%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0% alpha 0%)") is "color(xyz 0.3 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.3 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.3 0.64 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15% alpha 10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.3 0.3 0.64 / 0.76)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.26 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 40%)") is "color(xyz 0.26 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8) x 40%)") is "color(xyz 0.26 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60% x 40%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.34 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x 0%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.6 0.7 / 0.8)"
+PASS computedStyle("background-color", "color-mix(xyz, color(xyz .1 .2 .3 / .4) x -10%, color(xyz .5 .6 .7 / .8))") is "color(xyz 0.5 0.2 0.3 / 0.4)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/css/parsing-color-mix.html (0 => 273244)
--- trunk/LayoutTests/fast/css/parsing-color-mix.html (rev 0)
+++ trunk/LayoutTests/fast/css/parsing-color-mix.html 2021-02-22 17:52:13 UTC (rev 273244)
@@ -0,0 +1,330 @@
+<!DOCTYPE html><!-- webkit-test-runner [ CSSColorMixEnabled=true ] -->
+<html>
+ <script src=""
+</head>
+<body>
+<script>
+ description("Test the parsing of CSS Color 5 color-mix().");
+
+ function computedStyle(property, value)
+ {
+ var div = document.createElement("div");
+ document.body.appendChild(div);
+ div.style.setProperty(property, value);
+ var computedValue = getComputedStyle(div).getPropertyValue(property);
+ document.body.removeChild(div);
+ return computedValue;
+ }
+
+ function testComputedProperty(property, value, expected)
+ {
+ shouldBeEqualToString('computedStyle("' + property + '", "' + value + '")', expected);
+ }
+
+ function testComputed(value, expected)
+ {
+ testComputedProperty("background-color", value, expected);
+ }
+
+ debug('color-mix(hsl, ...)');
+
+ // Special case no adjusters or percentage is split 50-50.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%))`, `rgb(84, 92, 61)`); // hsl(75deg 20% 30%)
+
+ // Test precentage without adjusters.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%))`, `rgb(112, 106, 67)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) 25%)`, `rgb(61, 73, 54)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 25%, hsl(30deg 30% 40%) 75%)`, `rgb(112, 106, 67)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 50%, hsl(30deg 30% 40%) 150%)`, `rgb(112, 106, 67)`); // Scale down > 100% sum.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 12.5%, hsl(30deg 30% 40%) 37.5%)`, `rgb(112, 106, 67)`); // Scale up < 100% sum.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
+
+ // Test per-channel adjusters.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 50%)`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) hue 50%)`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 100%, hsl(30deg 30% 40%))`, `rgb(46, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 100% lightness 100% alpha 100%, hsl(30deg 30% 40%))`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0%)`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0%)`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50%, hsl(30deg 30% 40%) saturation 0% lightness 0% alpha 0%)`, `rgb(53, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75%, hsl(30deg 30% 40%))`, `rgb(55, 59, 43)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15%, hsl(30deg 30% 40%))`, `rgb(101, 108, 80)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 50% saturation 75% lightness 15% alpha 10%, hsl(30deg 30% 40%))`, `rgb(101, 108, 80)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%))`, `rgb(52, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%), hsl(30deg 30% 40%) hue 40%)`, `rgb(52, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 60%, hsl(30deg 30% 40%) hue 40%)`, `rgb(52, 56, 46)`);
+
+ // FIXME: Test hue mixes with modifiers.
+
+ // Open questions.
+
+ // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 60% hue 40%, hsl(30deg 30% 40%))`, `rgb(55, 56, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 40%, hsl(30deg 30% 40%))`, `rgb(55, 56, 46)`);
+
+ // What should happen if you provide an adjuster without a paihue percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
+
+ // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) -10%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%))`, `rgb(133, 102, 71)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue -10%, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
+ testComputed(`color-mix(hsl, hsl(120deg 10% 20%) hue 0%, hsl(30deg 30% 40%))`, `rgb(56, 51, 46)`);
+
+
+ debug('');
+ debug('color-mix(hwb, ...)');
+
+ // Special case no adjusters or percentage is split 50-50.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%))`, `rgb(147, 179, 52)`); // hwb(75deg 20% 30%)
+
+ // Test precentage without adjusters.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%))`, `rgb(166, 153, 64)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) 25%)`, `rgb(96, 191, 39)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 25%, hwb(30deg 30% 40%) 75%)`, `rgb(166, 153, 64)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 50%, hwb(30deg 30% 40%) 150%)`, `rgb(166, 153, 64)`); // Scale down > 100% sum.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 12.5%, hwb(30deg 30% 40%) 37.5%)`, `rgb(166, 153, 64)`); // Scale up < 100% sum.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
+
+ // Test per-channel adjusters.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 50%)`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) hue 50%)`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 100%, hwb(30deg 30% 40%))`, `rgb(26, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 100% blackness 100% alpha 100%, hwb(30deg 30% 40%))`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0%)`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0%)`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50%, hwb(30deg 30% 40%) whiteness 0% blackness 0% alpha 0%)`, `rgb(160, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75%, hwb(30deg 30% 40%))`, `rgb(163, 204, 39)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15%, hwb(30deg 30% 40%))`, `rgb(130, 161, 39)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 50% whiteness 75% blackness 15% alpha 10%, hwb(30deg 30% 40%))`, `rgb(130, 161, 39)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%))`, `rgb(133, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%), hwb(30deg 30% 40%) hue 40%)`, `rgb(133, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 60%, hwb(30deg 30% 40%) hue 40%)`, `rgb(133, 204, 26)`);
+
+ // Test mix that creates whiteness + blackness > 100%.
+ testComputed(`color-mix(hwb, hwb(120deg 75% 25%) whiteness 100%, hwb(120deg 25% 75%) blackness 100%)`, `rgb(128, 128, 128)`);
+
+ // FIXME: Test hue mixes with modifiers.
+
+
+ // Open questions.
+
+ // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 60% hue 40%, hwb(30deg 30% 40%))`, `rgb(186, 204, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 40%, hwb(30deg 30% 40%))`, `rgb(186, 204, 26)`);
+
+ // What should happen if you provide an adjuster without a paihue percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
+
+ // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) -10%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) 0%, hwb(30deg 30% 40%))`, `rgb(153, 115, 77)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue -10%, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
+ testComputed(`color-mix(hwb, hwb(120deg 10% 20%) hue 0%, hwb(30deg 30% 40%))`, `rgb(204, 115, 26)`);
+
+
+ debug('');
+ debug('color-mix(lch, ...)');
+
+ // Special case no adjusters or percentage is split 50-50.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8))`, `lch(30% 40 50 / 0.6)`);
+
+ // Test precentage without adjusters.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8))`, `lch(40% 50 60 / 0.7)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) 25%)`, `lch(20% 30 40 / 0.5)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 25%, lch(50% 60 70deg / .8) 75%)`, `lch(40% 50 60 / 0.7)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 50%, lch(50% 60 70deg / .8) 150%)`, `lch(40% 50 60 / 0.7)`); // Scale down > 100% sum.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 12.5%, lch(50% 60 70deg / .8) 37.5%)`, `lch(40% 50 60 / 0.7)`); // Scale up < 100% sum.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
+
+ // Test per-channel adjusters.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 50%)`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) lightness 50%)`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 100%, lch(50% 60 70deg / .8))`, `lch(10% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 100% hue 100% alpha 100%, lch(50% 60 70deg / .8))`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0%)`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0%)`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50%, lch(50% 60 70deg / .8) chroma 0% hue 0% alpha 0%)`, `lch(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75%, lch(50% 60 70deg / .8))`, `lch(30% 30 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15%, lch(50% 60 70deg / .8))`, `lch(30% 30 64 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 50% chroma 75% hue 15% alpha 10%, lch(50% 60 70deg / .8))`, `lch(30% 30 64 / 0.76)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8))`, `lch(26% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4), lch(50% 60 70deg / .8) lightness 40%)`, `lch(26% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 60%, lch(50% 60 70deg / .8) lightness 40%)`, `lch(26% 20 30 / 0.4)`);
+
+ // FIXME: Test hue mixes with modifiers.
+
+ // Open questions.
+
+ // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 60% lightness 40%, lch(50% 60 70deg / .8))`, `lch(34% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 40%, lch(50% 60 70deg / .8))`, `lch(34% 20 30 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a pailightness percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) -10%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) 0%, lch(50% 60 70deg / .8))`, `lch(50% 60 70 / 0.8)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness -10%, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
+ testComputed(`color-mix(lch, lch(10% 20 30deg / .4) lightness 0%, lch(50% 60 70deg / .8))`, `lch(50% 20 30 / 0.4)`);
+
+
+ debug('');
+ debug('color-mix(lab, ...)');
+
+ // Special case no adjusters or percentage is split 50-50.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8))`, `lab(30% 40 50 / 0.6)`);
+
+ // Test precentage without adjusters.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8))`, `lab(40% 50 60 / 0.7)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) 25%)`, `lab(20% 30 40 / 0.5)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) 25%, lab(50% 60 70 / .8) 75%)`, `lab(40% 50 60 / 0.7)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) 50%, lab(50% 60 70 / .8) 150%)`, `lab(40% 50 60 / 0.7)`); // Scale down > 100% sum.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) 12.5%, lab(50% 60 70 / .8) 37.5%)`, `lab(40% 50 60 / 0.7)`); // Scale up < 100% sum.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) 0%, lab(50% 60 70 / .8))`, `lab(50% 60 70 / 0.8)`);
+
+ // Test per-channel adjusters.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 50%)`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) lightness 50%)`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 100%, lab(50% 60 70 / .8))`, `lab(10% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 100% b 100% alpha 100%, lab(50% 60 70 / .8))`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0%)`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0%)`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50%, lab(50% 60 70 / .8) a 0% b 0% alpha 0%)`, `lab(30% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75%, lab(50% 60 70 / .8))`, `lab(30% 30 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15%, lab(50% 60 70 / .8))`, `lab(30% 30 64 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 50% a 75% b 15% alpha 10%, lab(50% 60 70 / .8))`, `lab(30% 30 64 / 0.76)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8))`, `lab(26% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4), lab(50% 60 70 / .8) lightness 40%)`, `lab(26% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 60%, lab(50% 60 70 / .8) lightness 40%)`, `lab(26% 20 30 / 0.4)`);
+
+ // Open questions.
+
+ // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 60% lightness 40%, lab(50% 60 70 / .8))`, `lab(34% 20 30 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a pailightness percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness, lab(50% 60 70 / .8))`, `lab(50% 20 30 / 0.4)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness 0%, lab(50% 60 70 / .8))`, `lab(50% 20 30 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) -10%, lab(50% 60 70 / .8))`, `lab(50% 60 70 / 0.8)`);
+ testComputed(`color-mix(lab, lab(10% 20 30 / .4) lightness -10%, lab(50% 60 70 / .8))`, `lab(50% 20 30 / 0.4)`);
+
+ debug('');
+ debug('color-mix(srgb, ...)');
+
+ // Special case no adjusters or percentage is split 50-50.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.4 0.5 / 0.6)`);
+
+ // Test precentage without adjusters.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.4 0.5 0.6 / 0.7)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) 25%)`, `color(srgb 0.2 0.3 0.4 / 0.5)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 25%, color(srgb .5 .6 .7 / .8) 75%)`, `color(srgb 0.4 0.5 0.6 / 0.7)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 50%, color(srgb .5 .6 .7 / .8) 150%)`, `color(srgb 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 12.5%, color(srgb .5 .6 .7 / .8) 37.5%)`, `color(srgb 0.4 0.5 0.6 / 0.7)`); // Scale up < 100% sum.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) 0%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.6 0.7 / 0.8)`);
+
+ // Test per-channel adjusters.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 50%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) red 50%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.1 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 100% blue 100% alpha 100%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50%, color(srgb .5 .6 .7 / .8) green 0% blue 0% alpha 0%)`, `color(srgb 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.3 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.3 0.64 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 50% green 75% blue 15% alpha 10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.3 0.3 0.64 / 0.76)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.26 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4), color(srgb .5 .6 .7 / .8) red 40%)`, `color(srgb 0.26 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60%, color(srgb .5 .6 .7 / .8) red 40%)`, `color(srgb 0.26 0.2 0.3 / 0.4)`);
+
+ // Open questions.
+
+ // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 60% red 40%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.34 0.2 0.3 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a paired percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red 0%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.2 0.3 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) -10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.6 0.7 / 0.8)`);
+ testComputed(`color-mix(srgb, color(srgb .1 .2 .3 / .4) red -10%, color(srgb .5 .6 .7 / .8))`, `color(srgb 0.5 0.2 0.3 / 0.4)`);
+
+
+ debug('');
+ debug('color-mix(xyz, ...)');
+
+ // Special case no adjusters or percentage is split 50-50.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.4 0.5 / 0.6)`);
+
+ // Test precentage without adjusters.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) 25%)`, `color(xyz 0.2 0.3 0.4 / 0.5)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 25%, color(xyz .5 .6 .7 / .8) 75%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 50%, color(xyz .5 .6 .7 / .8) 150%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`); // Scale down > 100% sum.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 12.5%, color(xyz .5 .6 .7 / .8) 37.5%)`, `color(xyz 0.4 0.5 0.6 / 0.7)`); // Scale up < 100% sum.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) 0%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.6 0.7 / 0.8)`);
+
+ // Test per-channel adjusters.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 50%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) x 50%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.1 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 100% z 100% alpha 100%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50%, color(xyz .5 .6 .7 / .8) y 0% z 0% alpha 0%)`, `color(xyz 0.3 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.3 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.3 0.64 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 50% y 75% z 15% alpha 10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.3 0.3 0.64 / 0.76)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.26 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4), color(xyz .5 .6 .7 / .8) x 40%)`, `color(xyz 0.26 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60%, color(xyz .5 .6 .7 / .8) x 40%)`, `color(xyz 0.26 0.2 0.3 / 0.4)`);
+
+ // Open questions.
+
+ // What should happen if you provide the same adjuster more than once? Currently, we do last one wins.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 60% x 40%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.34 0.2 0.3 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a paix percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.2 0.3 / 0.4)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x 0%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.2 0.3 / 0.4)`);
+
+ // What should happen if you provide an adjuster without a negative percent? Currently, we treat that like having 0% for that adjuster.
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) -10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.6 0.7 / 0.8)`);
+ testComputed(`color-mix(xyz, color(xyz .1 .2 .3 / .4) x -10%, color(xyz .5 .6 .7 / .8))`, `color(xyz 0.5 0.2 0.3 / 0.4)`);
+</script>
+
+<script src=""
+</body>
+</html>
Modified: trunk/Source/WTF/ChangeLog (273243 => 273244)
--- trunk/Source/WTF/ChangeLog 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WTF/ChangeLog 2021-02-22 17:52:13 UTC (rev 273244)
@@ -1,3 +1,14 @@
+2021-02-22 Sam Weinig <wei...@apple.com>
+
+ Add experimental support for CSS Color 5 color-mix()
+ https://bugs.webkit.org/show_bug.cgi?id=222258
+
+ Reviewed by Antti Koivisto.
+
+ * Scripts/Preferences/WebPreferencesExperimental.yaml:
+ Add new experimental preference for CSS Color 5 color-mix()
+ which is off by default.
+
2021-02-22 Carlos Garcia Campos <cgar...@igalia.com>
[SOUP] Add support for libsoup3
Modified: trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml (273243 => 273244)
--- trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml 2021-02-22 17:52:13 UTC (rev 273244)
@@ -113,6 +113,18 @@
WebKit:
default: false
+CSSColorMixEnabled:
+ type: bool
+ humanReadableName: "CSS color-mix()"
+ humanReadableDescription: "Enable support for CSS color-mix() defined in CSS Color 5"
+ defaultValue:
+ WebKitLegacy:
+ default: false
+ WebKit:
+ default: false
+ WebCore:
+ default: false
+
CSSCustomPropertiesAndValuesEnabled:
type: bool
humanReadableName: "CSS Custom Properties and Values API"
Modified: trunk/Source/WebCore/ChangeLog (273243 => 273244)
--- trunk/Source/WebCore/ChangeLog 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WebCore/ChangeLog 2021-02-22 17:52:13 UTC (rev 273244)
@@ -1,3 +1,75 @@
+2021-02-22 Sam Weinig <wei...@apple.com>
+
+ Add experimental support for CSS Color 5 color-mix()
+ https://bugs.webkit.org/show_bug.cgi?id=222258
+
+ Reviewed by Antti Koivisto.
+
+ Adds initial support for CSS Color 5 color-mix() - https://drafts.csswg.org/css-color-5/#color-mix
+
+ This feature is off by default and can be enabled via the CSSColorMixEnabled
+ experimental preference flag.
+
+ This implementation has the same restriction on it that the recently landed
+ Relative Color Syntax does in that it does support system colors or currentColor
+ as input, since those can't be resolved at parse time. Ultimately, we will need
+ to add a late binding version of this for those cases.
+
+ Test: fast/css/parsing-color-mix.html
+
+ * css/CSSValueKeywords.in:
+ Add new keywords needed for color-mix().
+
+ * css/parser/CSSParserContext.cpp:
+ (WebCore::operator==):
+ * css/parser/CSSParserContext.h:
+ (WebCore::CSSParserContextHash::hash):
+ Add new setting for color-mix().
+
+ * css/parser/CSSPropertyParserHelpers.cpp:
+ (WebCore::CSSPropertyParserHelpers::HueColorAdjuster::fixupAnglesForInterpolation):
+ (WebCore::CSSPropertyParserHelpers::HueColorAdjuster::HueColorAdjuster):
+ (WebCore::CSSPropertyParserHelpers::ColorAdjuster::ColorAdjuster):
+ (WebCore::CSSPropertyParserHelpers::consumeAdjuster):
+ (WebCore::CSSPropertyParserHelpers::consumeAndUpdateAdjusterAtIndex):
+ (WebCore::CSSPropertyParserHelpers::consumeAndUpdateAdjuster):
+ (WebCore::CSSPropertyParserHelpers::consumeAdjusters):
+ (WebCore::CSSPropertyParserHelpers::consumeMixComponents):
+ (WebCore::CSSPropertyParserHelpers::normalizeAdjusterValues):
+ (WebCore::CSSPropertyParserHelpers::remainingAdjustment):
+ (WebCore::CSSPropertyParserHelpers::mixComponent):
+ (WebCore::CSSPropertyParserHelpers::mixComponentAtIndex):
+ (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix):
+ (WebCore::CSSPropertyParserHelpers::makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>):
+ (WebCore::CSSPropertyParserHelpers::mix):
+ (WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParametersUsingAdjusters):
+ (WebCore::CSSPropertyParserHelpers::parseColorMixFunctionParameters):
+ (WebCore::CSSPropertyParserHelpers::parseColorFunction):
+ The implementation uses a templatized ColorAdjuster struct to declartively map the
+ various mixing color spaces to their allowed adjusters and what type those adjusters
+ operate on (either double or the hue specific HueColorAdjuster). For example, for
+ LCHA we have:
+
+ using LCHColorAdjuster = ColorAdjuster<LCHA<float>, CSSValueLightness, double, CSSValueChroma, HueColorAdjuster, CSSValueHue, double, CSSValueAlpha, double>;
+
+ which indicates:
+
+ - it creates a LCHA<float> and will operate on LCHA<float> values
+ - its first channel is called "lightness" and is a double
+ - its second channel is called "chroma" and is a double
+ - its third channel is called "hue" and is a HueColorAdjuster
+ - its fourth channel is called "alpha" and is a double
+
+ This data is then used by the parsing and mixing functions to implement mixing without
+ having to write specific implementations for each mixing color space and can be expanded
+ to more spaces if needed.
+
+ * platform/graphics/Color.h:
+ (WebCore::Color::Color):
+ Add new overloaded constructor for a generic Optional<ColorType<float>> which parallels the existing
+ Optional<SRGBA<uint8_t>> allowing callers to convert WTF::nullopt to an invalid Color without checking
+ for nullopt themselves.
+
2021-02-19 Sergio Villar Senin <svil...@igalia.com>
[css-flex] Refactoring of code retrieving main/cross size lengths from children
Modified: trunk/Source/WebCore/css/CSSValueKeywords.in (273243 => 273244)
--- trunk/Source/WebCore/css/CSSValueKeywords.in 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WebCore/css/CSSValueKeywords.in 2021-02-22 17:52:13 UTC (rev 273244)
@@ -1434,6 +1434,18 @@
// sRGB
xyz
+// color-mix()
+color-mix
+shorter
+longer
+increasing
+decreasing
+specified
+lightness
+chroma
+whiteness
+blackness
+
// prefers-default-appearance
prefers
// no-preference
Modified: trunk/Source/WebCore/css/parser/CSSParserContext.cpp (273243 => 273244)
--- trunk/Source/WebCore/css/parser/CSSParserContext.cpp 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WebCore/css/parser/CSSParserContext.cpp 2021-02-22 17:52:13 UTC (rev 273244)
@@ -69,6 +69,7 @@
, useSystemAppearance { document.page() ? document.page()->useSystemAppearance() : false }
, aspectRatioEnabled { document.settings().aspectRatioEnabled() }
, colorFilterEnabled { document.settings().colorFilterEnabled() }
+ , colorMixEnabled { document.settings().cssColorMixEnabled() }
, constantPropertiesEnabled { document.settings().constantPropertiesEnabled() }
, deferredCSSParserEnabled { document.settings().deferredCSSParserEnabled() }
, enforcesCSSMIMETypeInNoQuirksMode { document.settings().enforceCSSMIMETypeInNoQuirksMode() }
@@ -106,6 +107,7 @@
&& a.useSystemAppearance == b.useSystemAppearance
&& a.aspectRatioEnabled == b.aspectRatioEnabled
&& a.colorFilterEnabled == b.colorFilterEnabled
+ && a.colorMixEnabled == b.colorMixEnabled
&& a.constantPropertiesEnabled == b.constantPropertiesEnabled
&& a.deferredCSSParserEnabled == b.deferredCSSParserEnabled
&& a.enforcesCSSMIMETypeInNoQuirksMode == b.enforcesCSSMIMETypeInNoQuirksMode
Modified: trunk/Source/WebCore/css/parser/CSSParserContext.h (273243 => 273244)
--- trunk/Source/WebCore/css/parser/CSSParserContext.h 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WebCore/css/parser/CSSParserContext.h 2021-02-22 17:52:13 UTC (rev 273244)
@@ -59,6 +59,7 @@
// Settings.
bool aspectRatioEnabled { false };
bool colorFilterEnabled { false };
+ bool colorMixEnabled { false };
bool constantPropertiesEnabled { false };
bool deferredCSSParserEnabled { false };
bool enforcesCSSMIMETypeInNoQuirksMode { true };
@@ -102,6 +103,7 @@
hash ^= WTF::URLHash::hash(key.baseURL);
if (!key.charset.isEmpty())
hash ^= StringHash::hash(key.charset);
+
unsigned bits = key.isHTMLDocument << 0
& key.hasDocumentSecurityOrigin << 1
& key.isContentOpaque << 2
@@ -108,29 +110,30 @@
& key.useSystemAppearance << 3
& key.aspectRatioEnabled << 4
& key.colorFilterEnabled << 5
- & key.constantPropertiesEnabled << 6
- & key.deferredCSSParserEnabled << 7
- & key.enforcesCSSMIMETypeInNoQuirksMode << 8
- & key.individualTransformPropertiesEnabled << 9
+ & key.colorMixEnabled << 6
+ & key.constantPropertiesEnabled << 7
+ & key.deferredCSSParserEnabled << 8
+ & key.enforcesCSSMIMETypeInNoQuirksMode << 9
+ & key.individualTransformPropertiesEnabled << 10
#if ENABLE(OVERFLOW_SCROLLING_TOUCH)
- & key.legacyOverflowScrollingTouchEnabled << 10
+ & key.legacyOverflowScrollingTouchEnabled << 11
#endif
- & key.overscrollBehaviorEnabled << 11
- & key.relativeColorSyntaxEnabled << 12
- & key.scrollBehaviorEnabled << 13
- & key.springTimingFunctionEnabled << 14
+ & key.overscrollBehaviorEnabled << 12
+ & key.relativeColorSyntaxEnabled << 13
+ & key.scrollBehaviorEnabled << 14
+ & key.springTimingFunctionEnabled << 15
#if ENABLE(TEXT_AUTOSIZING)
- & key.textAutosizingEnabled << 15
+ & key.textAutosizingEnabled << 16
#endif
#if ENABLE(CSS_TRANSFORM_STYLE_OPTIMIZED_3D)
- & key.transformStyleOptimized3DEnabled << 16
+ & key.transformStyleOptimized3DEnabled << 17
#endif
- & key.useLegacyBackgroundSizeShorthandBehavior << 17
- & key.focusVisibleEnabled << 18
+ & key.useLegacyBackgroundSizeShorthandBehavior << 18
+ & key.focusVisibleEnabled << 19
#if ENABLE(ATTACHMENT_ELEMENT)
- & key.attachmentEnabled << 19
+ & key.attachmentEnabled << 20
#endif
- & key.mode << 20; // Keep this last.
+ & key.mode << 21; // Keep this last.
hash ^= WTF::intHash(bits);
return hash;
}
Modified: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (273243 => 273244)
--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp 2021-02-22 17:52:13 UTC (rev 273244)
@@ -1480,6 +1480,380 @@
return color;
}
+struct HueColorAdjuster {
+ enum class Type {
+ Shorter,
+ Longer,
+ Increasing,
+ Decreasing,
+ Specified
+ };
+
+ static std::pair<double, double> fixupAnglesForInterpolation(double theta1, double theta2, Type type)
+ {
+ ASSERT(theta1 >= 0.0);
+ ASSERT(theta1 <= 360.0);
+ ASSERT(theta2 >= 0.0);
+ ASSERT(theta2 <= 360.0);
+
+ switch (type) {
+ case Type::Shorter: {
+ auto difference = theta2 - theta1;
+ if (difference > 180.0)
+ return { theta1 + 360.0, theta2 };
+ if (difference < -180.0)
+ return { theta1, theta2 + 360.0 };
+ return { theta1, theta2 };
+ }
+ case Type::Longer: {
+ auto difference = theta2 - theta1;
+ if (difference >= 0.0 && difference < 180.0)
+ return { theta1 + 360.0, theta2 };
+ if (difference >= -180.0 && difference < 0)
+ return { theta1, theta2 + 360.0 };
+ return { theta1, theta2 };
+ }
+ case Type::Increasing: {
+ if (theta2 < theta1)
+ return { theta1, theta2 + 360.0 };
+ return { theta1, theta2 };
+ }
+ case Type::Decreasing: {
+ if (theta1 < theta2)
+ return { theta1 + 360.0, theta2 };
+ return { theta1, theta2 };
+ }
+ case Type::Specified:
+ return { theta1, theta2 };
+ }
+ }
+
+ HueColorAdjuster(double value = 0.0, Type type = Type::Shorter)
+ : type { type }
+ , value { value }
+ {
+ }
+
+ Type type;
+ double value;
+};
+
+template<typename C, CSSValueID ID0, typename Channel0, CSSValueID ID1, typename Channel1, CSSValueID ID2, typename Channel2, CSSValueID ID3, typename Channel3>
+struct ColorAdjuster {
+ using ColorType = C;
+ static constexpr auto channelCSSValueIDs = std::make_tuple(ID0, ID1, ID2, ID3);
+
+ ColorAdjuster() = default;
+ explicit ColorAdjuster(double percentage)
+ : channels { percentage, percentage, percentage, percentage }
+ {
+ }
+
+ std::tuple<Optional<Channel0>, Optional<Channel1>, Optional<Channel2>, Optional<Channel3>> channels;
+};
+
+using HSLColorAdjuster = ColorAdjuster<HSLA<float>, CSSValueHue, HueColorAdjuster, CSSValueSaturation, double, CSSValueLightness, double, CSSValueAlpha, double>;
+using HWBColorAdjuster = ColorAdjuster<HWBA<float>, CSSValueHue, HueColorAdjuster, CSSValueWhiteness, double, CSSValueBlackness, double, CSSValueAlpha, double>;
+using LCHColorAdjuster = ColorAdjuster<LCHA<float>, CSSValueLightness, double, CSSValueChroma, HueColorAdjuster, CSSValueHue, double, CSSValueAlpha, double>;
+using LabColorAdjuster = ColorAdjuster<Lab<float>, CSSValueLightness, double, CSSValueA, double, CSSValueB, double, CSSValueAlpha, double>;
+using SRGBColorAdjuster = ColorAdjuster<SRGBA<float>, CSSValueRed, double, CSSValueGreen, double, CSSValueBlue, double, CSSValueAlpha, double>;
+using XYZColorAdjuster = ColorAdjuster<XYZA<float, WhitePoint::D50>, CSSValueX, double, CSSValueY, double, CSSValueZ, double, CSSValueAlpha, double>;
+
+template<typename Adjuster> struct ColorMixComponent {
+ Color color;
+ Adjuster adjuster;
+};
+
+template<CSSValueID Ident, typename T> struct AdjusterConsumer;
+
+template<CSSValueID Ident> struct AdjusterConsumer<Ident, HueColorAdjuster> {
+ static Optional<HueColorAdjuster> consume(CSSParserTokenRange& args)
+ {
+ if (!consumeIdentRaw<Ident>(args))
+ return WTF::nullopt;
+
+ HueColorAdjuster result;
+ if (auto hueAdjustmentType = consumeHueAdjustmentType(args))
+ result.type = *hueAdjustmentType;
+
+ // FIXME: Is clamping to 0 for negative percentages the right thing to do?
+ if (auto percentage = consumePercentRaw(args))
+ result.value = std::max(0.0, *percentage);
+
+ // FIXME: Should an adjuster without a percetange be allowed?
+ // e.g color-mix(hsl, teal hue, red);
+
+ return result;
+ }
+
+ static Optional<HueColorAdjuster::Type> consumeHueAdjustmentType(CSSParserTokenRange& args)
+ {
+ switch (args.peek().id()) {
+ case CSSValueShorter:
+ consumeIdentRaw(args);
+ return HueColorAdjuster::Type::Shorter;
+ case CSSValueLonger:
+ consumeIdentRaw(args);
+ return HueColorAdjuster::Type::Longer;
+ case CSSValueIncreasing:
+ consumeIdentRaw(args);
+ return HueColorAdjuster::Type::Increasing;
+ case CSSValueDecreasing:
+ consumeIdentRaw(args);
+ return HueColorAdjuster::Type::Decreasing;
+ case CSSValueSpecified:
+ consumeIdentRaw(args);
+ return HueColorAdjuster::Type::Specified;
+ default:
+ return WTF::nullopt;
+ }
+ }
+};
+
+template<CSSValueID Ident> struct AdjusterConsumer<Ident, double> {
+ static Optional<double> consume(CSSParserTokenRange& args)
+ {
+ if (!consumeIdentRaw<Ident>(args))
+ return WTF::nullopt;
+
+ // FIXME: Is clamping to 0 for negative percentages the right thing to do?
+ if (auto percentage = consumePercentRaw(args))
+ return std::max(0.0, *percentage);
+
+ // FIXME: Should an adjuster without a percetange be allowed?
+ // e.g color-mix(hsl, teal saturation, red);
+
+ return 0;
+ }
+};
+
+template<CSSValueID Ident, typename T> inline decltype(auto) consumeAdjuster(CSSParserTokenRange& args)
+{
+ return AdjusterConsumer<Ident, T>::consume(args);
+}
+
+template<std::size_t I, typename Adjuster> static bool consumeAndUpdateAdjusterAtIndex(CSSParserTokenRange& args, Adjuster& adjuster)
+{
+ using AdjusterType = std::decay_t<decltype(std::get<I>(adjuster.channels).value())>;
+ static constexpr CSSValueID Ident = std::get<I>(Adjuster::channelCSSValueIDs);
+
+ if (auto adjustment = consumeAdjuster<Ident, AdjusterType>(args)) {
+ std::get<I>(adjuster.channels) = *adjustment;
+ return true;
+ }
+ return false;
+}
+
+template<typename Adjuster> static bool consumeAndUpdateAdjuster(CSSParserTokenRange& args, Adjuster& adjuster)
+{
+ if (consumeAndUpdateAdjusterAtIndex<0>(args, adjuster))
+ return true;
+ if (consumeAndUpdateAdjusterAtIndex<1>(args, adjuster))
+ return true;
+ if (consumeAndUpdateAdjusterAtIndex<2>(args, adjuster))
+ return true;
+ if (consumeAndUpdateAdjusterAtIndex<3>(args, adjuster))
+ return true;
+ return false;
+}
+
+template<typename Adjuster> static Adjuster consumeAdjusters(CSSParserTokenRange& args)
+{
+ Adjuster adjuster;
+ while (consumeAndUpdateAdjuster(args, adjuster)) {
+ // Keep consuming until there are no more adjusters.
+ }
+
+ return adjuster;
+}
+
+template<typename Adjuster> static Optional<ColorMixComponent<Adjuster>> consumeMixComponents(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+ auto originColor = consumeOriginColor(args, context);
+ if (!originColor.isValid())
+ return WTF::nullopt;
+
+ // FIXME: Is clamping to 0 for negative percentages the right thing to do?
+ if (auto percentage = consumePercentRaw(args))
+ return { { WTFMove(originColor), Adjuster { std::max(0.0, *percentage) } } };
+
+ return { { WTFMove(originColor), consumeAdjusters<Adjuster>(args) } };
+}
+
+static std::pair<HueColorAdjuster, HueColorAdjuster> normalizeAdjusterValues(HueColorAdjuster adjuster1, HueColorAdjuster adjuster2)
+{
+ if (auto sum = adjuster1.value + adjuster2.value; sum != 100.0) {
+ adjuster1.value *= 100.0 / sum;
+ adjuster2.value *= 100.0 / sum;
+ }
+
+ return { adjuster1, adjuster2 };
+}
+
+static std::pair<double, double> normalizeAdjusterValues(double adjuster1, double adjuster2)
+{
+ if (auto sum = adjuster1 + adjuster2; sum != 100.0) {
+ adjuster1 *= 100.0 / sum;
+ adjuster2 *= 100.0 / sum;
+ }
+
+ return { adjuster1, adjuster2 };
+}
+
+static HueColorAdjuster remainingAdjustment(HueColorAdjuster adjuster)
+{
+ return { 100.0 - adjuster.value, adjuster.type };
+}
+
+static double remainingAdjustment(double adjuster)
+{
+ return 100.0 - adjuster;
+}
+
+template<typename AdjusterType> static auto normalizeAdjusterValues(Optional<AdjusterType> adjuster1, Optional<AdjusterType> adjuster2) -> std::pair<AdjusterType, AdjusterType>
+{
+ if (adjuster1 && adjuster2)
+ return normalizeAdjusterValues(*adjuster1, *adjuster2);
+ if (!adjuster1 && adjuster2)
+ return { remainingAdjustment(*adjuster2), *adjuster2 };
+ if (adjuster1 && !adjuster2)
+ return { *adjuster1, remainingAdjustment(*adjuster1) };
+ // When neigher mix component provides an adjuster, the result is the non-modified
+ // channel from from the first color.
+ ASSERT(!adjuster1 && !adjuster2);
+ return { 100.0, 0.0 };
+}
+
+static double mixComponent(float component1, HueColorAdjuster adjustment1, float component2, HueColorAdjuster adjustment2)
+{
+ // FIXME: The spec does not indicate what to do if two different hue types are specified. We always use the first one for now,
+ // though we probably should take into account whether it was actually specified or is the default value. That normalization
+ // should happen in normalizeAdjusterValues().
+
+ auto [fixedUpComponent1, fixedUpComponent2] = HueColorAdjuster::fixupAnglesForInterpolation(component1, component2, adjustment1.type);
+ auto result = (fixedUpComponent1 * (adjustment1.value / 100.0)) + (fixedUpComponent2 * (adjustment2.value / 100.0));
+ // FIXME: Check if this full normalization is needed.
+ return normalizeHue(result);
+}
+
+static double mixComponent(float component1, double adjustment1, float component2, double adjustment2)
+{
+ return (component1 * (adjustment1 / 100.0)) + (component2 * (adjustment2 / 100.0));
+}
+
+template<std::size_t I, typename Adjuster> static double mixComponentAtIndex(const ColorComponents<float>& color1, const Adjuster& adjuster1, const ColorComponents<float>& color2, const Adjuster& adjuster2)
+{
+ auto [normalizedAdjuster1Value, normalizedAdjuster2Value] = normalizeAdjusterValues(std::get<I>(adjuster1.channels), std::get<I>(adjuster2.channels));
+ return mixComponent(color1[I], normalizedAdjuster1Value, color2[I], normalizedAdjuster2Value);
+}
+
+template<typename ColorType> inline ColorType makeColorTypeByNormalizingComponentsAfterMix(double channel0, double channel1, double channel2, double channel3)
+{
+ return { static_cast<float>(channel0), static_cast<float>(channel1), static_cast<float>(channel2), static_cast<float>(channel3) };
+}
+
+template<> inline HWBA<float> makeColorTypeByNormalizingComponentsAfterMix<HWBA<float>>(double hue, double whiteness, double blackness, double alpha)
+{
+ auto [normalizedWhitness, normalizedBlackness] = normalizeWhitenessBlackness(whiteness, blackness);
+ return { static_cast<float>(hue), static_cast<float>(normalizedWhitness), static_cast<float>(normalizedBlackness), static_cast<float>(alpha) };
+}
+
+template<typename Adjuster> static typename Adjuster::ColorType mix(const ColorMixComponent<Adjuster>& mixComponents1, const ColorMixComponent<Adjuster>& mixComponents2)
+{
+ using ColorType = typename Adjuster::ColorType;
+
+ auto color1 = asColorComponents(mixComponents1.color.template toColorTypeLossy<ColorType>());
+ auto color2 = asColorComponents(mixComponents2.color.template toColorTypeLossy<ColorType>());
+
+ auto adjuster1 = mixComponents1.adjuster;
+ auto adjuster2 = mixComponents2.adjuster;
+
+ if (!std::get<0>(adjuster1.channels) && !std::get<1>(adjuster1.channels) && !std::get<2>(adjuster1.channels) && !std::get<3>(adjuster1.channels) && !std::get<0>(adjuster2.channels) && !std::get<1>(adjuster2.channels) && !std::get<2>(adjuster2.channels) && !std::get<3>(adjuster2.channels)) {
+ // No adjusters being specified at all is special cased to mean mix 50-50.
+ adjuster1 = Adjuster { 50.0 };
+ adjuster2 = Adjuster { 50.0 };
+ }
+
+ auto channel0 = mixComponentAtIndex<0>(color1, adjuster1, color2, adjuster2);
+ auto channel1 = mixComponentAtIndex<1>(color1, adjuster1, color2, adjuster2);
+ auto channel2 = mixComponentAtIndex<2>(color1, adjuster1, color2, adjuster2);
+ auto channel3 = mixComponentAtIndex<3>(color1, adjuster1, color2, adjuster2);
+
+ return makeColorTypeByNormalizingComponentsAfterMix<ColorType>(channel0, channel1, channel2, channel3);
+}
+
+template<typename Adjuster> static Optional<typename Adjuster::ColorType> parseColorMixFunctionParametersUsingAdjusters(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+ auto mixComponents1 = consumeMixComponents<Adjuster>(args, context);
+ if (!mixComponents1)
+ return WTF::nullopt;
+
+ // FIXME: This comma is not in the grammar, but is in all the examples.
+ if (!consumeCommaIncludingWhitespace(args))
+ return WTF::nullopt;
+
+ auto mixComponents2 = consumeMixComponents<Adjuster>(args, context);
+ if (!mixComponents2)
+ return WTF::nullopt;
+
+ return mix(*mixComponents1, *mixComponents2);
+}
+
+static Color parseColorMixFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+ ASSERT(range.peek().functionId() == CSSValueColorMix);
+
+ if (!context.colorMixEnabled)
+ return { };
+
+ auto args = consumeFunction(range);
+
+ auto consumeIdentAndComma = [](CSSParserTokenRange& args) {
+ consumeIdentRaw(args);
+ // FIXME: This comma is not in the grammar, but is in all the examples.
+ return consumeCommaIncludingWhitespace(args);
+ };
+
+ switch (args.peek().id()) {
+ case CSSValueHsl: {
+ if (!consumeIdentAndComma(args))
+ return { };
+ auto hsl = parseColorMixFunctionParametersUsingAdjusters<HSLColorAdjuster>(args, context);
+ if (!hsl)
+ return { };
+ return convertColor<SRGBA<uint8_t>>(*hsl);
+ }
+ case CSSValueHwb: {
+ if (!consumeIdentAndComma(args))
+ return { };
+ auto hwb = parseColorMixFunctionParametersUsingAdjusters<HWBColorAdjuster>(args, context);
+ if (!hwb)
+ return { };
+ return convertColor<SRGBA<uint8_t>>(*hwb);
+ }
+ case CSSValueLch:
+ if (!consumeIdentAndComma(args))
+ return { };
+ return parseColorMixFunctionParametersUsingAdjusters<LCHColorAdjuster>(args, context);
+ case CSSValueLab:
+ if (!consumeIdentAndComma(args))
+ return { };
+ return parseColorMixFunctionParametersUsingAdjusters<LabColorAdjuster>(args, context);
+ case CSSValueXyz:
+ if (!consumeIdentAndComma(args))
+ return { };
+ return parseColorMixFunctionParametersUsingAdjusters<XYZColorAdjuster>(args, context);
+ case CSSValueSRGB:
+ if (!consumeIdentAndComma(args))
+ return { };
+ return parseColorMixFunctionParametersUsingAdjusters<SRGBColorAdjuster>(args, context);
+ default:
+ // Default to using LCH if no color space is provided as per the spec.
+ // FIXME: This behavior is unnecessarily confusing, we should remove the default from the spec.
+ return parseColorMixFunctionParametersUsingAdjusters<LCHColorAdjuster>(args, context);
+ }
+}
+
static Optional<SRGBA<uint8_t>> parseHexColor(CSSParserTokenRange& range, bool acceptQuirkyColors)
{
String string;
@@ -1547,6 +1921,9 @@
case CSSValueColor:
color = parseColorFunctionParameters(colorRange);
break;
+ case CSSValueColorMix:
+ color = parseColorMixFunctionParameters(colorRange, context);
+ break;
default:
return { };
}
Modified: trunk/Source/WebCore/platform/graphics/Color.h (273243 => 273244)
--- trunk/Source/WebCore/platform/graphics/Color.h 2021-02-22 17:33:21 UTC (rev 273243)
+++ trunk/Source/WebCore/platform/graphics/Color.h 2021-02-22 17:52:13 UTC (rev 273244)
@@ -73,8 +73,12 @@
Color(Optional<SRGBA<uint8_t>>, OptionSet<Flags> = { });
Color(ColorComponents<float>, ColorSpace, OptionSet<Flags> = { });
+
template<typename ColorType, typename std::enable_if_t<IsColorTypeWithComponentType<ColorType, float>>* = nullptr>
Color(const ColorType&, OptionSet<Flags> = { });
+
+ template<typename ColorType, typename std::enable_if_t<IsColorTypeWithComponentType<ColorType, float>>* = nullptr>
+ Color(const Optional<ColorType>&, OptionSet<Flags> = { });
explicit Color(WTF::HashTableEmptyValueType);
explicit Color(WTF::HashTableDeletedValueType);
@@ -300,6 +304,13 @@
setExtendedColor(ExtendedColor::create(color), toFlagsIncludingPrivate(flags));
}
+template<typename ColorType, typename std::enable_if_t<IsColorTypeWithComponentType<ColorType, float>>*>
+inline Color::Color(const Optional<ColorType>& color, OptionSet<Flags> flags)
+{
+ if (color)
+ setExtendedColor(ExtendedColor::create(*color), toFlagsIncludingPrivate(flags));
+}
+
inline Color::Color(Ref<ExtendedColor>&& extendedColor, OptionSet<Flags> flags)
{
setExtendedColor(WTFMove(extendedColor), toFlagsIncludingPrivate(flags));