Add color filter for transforming colors in Dark Mode
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jul 2018 02:03:33 +0000 (02:03 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Jul 2018 02:03:33 +0000 (02:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=187717
Source/WebCore:

rdar://problem/41146650

Reviewed by Dean Jackson.

Add a new filter function for use in -apple-color-filter for transforming colors
when in Dark Mode. The filter is called apple-invert-lightness(), and takes no parameters.
It's based on a lightness invert in HSL space, with some adjustments to improve the contrast
of some colors on dark backgrounds, so does a much better job that using invert() with hue-rotate().

Test: css3/color-filters/color-filter-apple-invert-lightness.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForFilter):
* css/CSSValueKeywords.in:
* css/StyleResolver.cpp:
(WebCore::filterOperationForType):
(WebCore::StyleResolver::createFilterOperations):
* css/parser/CSSPropertyParser.cpp:
(WebCore::CSSPropertyParser::parseSingleValue):
* css/parser/CSSPropertyParserHelpers.cpp:
(WebCore::CSSPropertyParserHelpers::consumeFilterImage):
(WebCore::CSSPropertyParserHelpers::isPixelFilterFunction):
(WebCore::CSSPropertyParserHelpers::isColorFilterFunction):
(WebCore::CSSPropertyParserHelpers::consumeFilterFunction):
(WebCore::CSSPropertyParserHelpers::consumeFilter):
(WebCore::CSSPropertyParserHelpers::isValidPrimitiveFilterFunction): Deleted.
* css/parser/CSSPropertyParserHelpers.h:
* page/FrameView.cpp:
(WebCore::FrameView::paintContents):
* platform/graphics/Color.cpp:
* platform/graphics/ColorUtilities.cpp:
(WebCore::sRGBToLinearComponents):
(WebCore::linearToSRGBComponents):
(WebCore::sRGBToLinearColorComponentForLuminance):
(WebCore::luminance):
(WebCore::sRGBToHSL):
(WebCore::calcHue):
(WebCore::HSLToSRGB):
(WebCore::ColorMatrix::ColorMatrix):
* platform/graphics/ColorUtilities.h:
* platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm:
(PlatformCAFilters::filterValueForOperation):
(PlatformCAFilters::colorMatrixValueForFilter):
* platform/graphics/filters/FEColorMatrix.cpp:
* platform/graphics/filters/FilterOperation.cpp:
(WebCore::InvertLightnessFilterOperation::operator== const):
(WebCore::InvertLightnessFilterOperation::blend):
(WebCore::InvertLightnessFilterOperation::transformColor const):
(WebCore::operator<<):
* platform/graphics/filters/FilterOperation.h:
* rendering/FilterEffectRenderer.cpp:
(WebCore::FilterEffectRenderer::build):

Source/WebKit:

Reviewed by Dean Jackson.

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<FilterOperation>::encode):
(IPC::decodeFilterOperation):

LayoutTests:

rdar://problem/41146650

Reviewed by Dean Jackson.

* css3/color-filters/color-filter-apple-invert-lightness-expected.html: Added.
* css3/color-filters/color-filter-apple-invert-lightness.html: Added.
* css3/color-filters/color-filter-parsing-expected.txt:
* css3/color-filters/color-filter-parsing.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233877 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/color-filters/color-filter-apple-invert-lightness-expected.html [new file with mode: 0644]
LayoutTests/css3/color-filters/color-filter-apple-invert-lightness.html [new file with mode: 0644]
LayoutTests/css3/color-filters/color-filter-parsing-expected.txt
LayoutTests/css3/color-filters/color-filter-parsing.html
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/parser/CSSPropertyParser.cpp
Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp
Source/WebCore/css/parser/CSSPropertyParserHelpers.h
Source/WebCore/platform/graphics/Color.cpp
Source/WebCore/platform/graphics/ColorUtilities.cpp
Source/WebCore/platform/graphics/ColorUtilities.h
Source/WebCore/platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm
Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp
Source/WebCore/platform/graphics/filters/FilterOperation.cpp
Source/WebCore/platform/graphics/filters/FilterOperation.h
Source/WebCore/rendering/FilterEffectRenderer.cpp
Source/WebKit/ChangeLog
Source/WebKit/Shared/WebCoreArgumentCoders.cpp

index 744c5cf..59d91b4 100644 (file)
@@ -1,3 +1,16 @@
+2018-07-16  Simon Fraser  <simon.fraser@apple.com>
+
+        Add color filter for transforming colors in Dark Mode
+        https://bugs.webkit.org/show_bug.cgi?id=187717
+        rdar://problem/41146650
+
+        Reviewed by Dean Jackson.
+
+        * css3/color-filters/color-filter-apple-invert-lightness-expected.html: Added.
+        * css3/color-filters/color-filter-apple-invert-lightness.html: Added.
+        * css3/color-filters/color-filter-parsing-expected.txt:
+        * css3/color-filters/color-filter-parsing.html:
+
 2018-07-15  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebCrypto] Crypto operations should copy their parameters before hoping to another thread
diff --git a/LayoutTests/css3/color-filters/color-filter-apple-invert-lightness-expected.html b/LayoutTests/css3/color-filters/color-filter-apple-invert-lightness-expected.html
new file mode 100644 (file)
index 0000000..9aeccec
--- /dev/null
@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <style>
+            .sample {
+                width: 500px;
+                height: 400px;
+                background-color: rgb(51,51,51);
+            }
+            
+            .sample > div {
+                height: 30px;
+                width: 30px;
+                margin: 5px;
+                float: left;
+            }
+
+            .test
+            {
+                width: 100px;
+                height: 100px;
+                background-color: blue;
+                border: 50px solid green;
+                margin: 10px;
+                float: left;
+            }
+        </style>
+        <script>
+            const colors = [
+                // Original, Transformed.
+                ["rgb(0, 0, 0)", "rgb(255,255,255)"],
+                ["rgb(255, 255, 255)", "rgb(51,51,51)"],
+                ["rgb(235, 235, 235)", "rgb(67,67,67)"],
+                ["rgb(214, 214, 214)", "rgb(84,84,84)"],
+                ["rgb(192, 192, 192)", "rgb(101,101,101)"],
+                ["rgb(170, 170, 170)", "rgb(119,119,119)"],
+                ["rgb(146, 146, 146)", "rgb(138,138,138)"],
+                ["rgb(122, 122, 122)", "rgb(157,157,157)"],
+                ["rgb(96, 96, 96)", "rgb(178,178,178)"],
+                ["rgb(68, 68, 68)", "rgb(201,201,201)"],
+                ["rgb(35, 35, 35)", "rgb(227,227,227)"],
+                ["rgb(0, 0, 0)", "rgb(255,255,255)"],
+                ["rgb(0, 54, 74)", "rgb(199,242,255)"],
+                ["rgb(0, 30, 87)", "rgb(191,215,255)"],
+                ["rgb(17, 5, 59)", "rgb(222,212,255)"],
+                ["rgb(46, 7, 62)", "rgb(240,209,253)"],
+                ["rgb(60, 8, 27)", "rgb(249,207,222)"],
+                ["rgb(92, 7, 0)", "rgb(252,184,178)"],
+                ["rgb(90, 28, 0)", "rgb(251,201,179)"],
+                ["rgb(88, 52, 0)", "rgb(249,220,179)"],
+                ["rgb(85, 61, 0)", "rgb(249,230,181)"],
+                ["rgb(102, 97, 0)", "rgb(246,242,165)"],
+                ["rgb(79, 85, 3)", "rgb(241,245,180)"],
+                ["rgb(38, 62, 15)", "rgb(220,240,202)"],
+                ["rgb(0, 77, 101)", "rgb(179,240,255)"],
+                ["rgb(0, 46, 122)", "rgb(166,202,255)"],
+                ["rgb(26, 10, 83)", "rgb(207,195,253)"],
+                ["rgb(69, 14, 89)", "rgb(233,189,249)"],
+                ["rgb(86, 16, 41)", "rgb(242,186,206)"],
+                ["rgb(131, 17, 0)", "rgb(250,159,145)"],
+                ["rgb(124, 42, 0)", "rgb(249,183,149)"],
+                ["rgb(122, 74, 0)", "rgb(247,209,149)"],
+                ["rgb(120, 87, 0)", "rgb(246,220,150)"],
+                ["rgb(141, 134, 0)", "rgb(243,237,130)"],
+                ["rgb(111, 118, 8)", "rgb(233,239,151)"],
+                ["rgb(56, 87, 26)", "rgb(205,230,181)"],
+                ["rgb(0, 109, 143)", "rgb(147,234,255)"],
+                ["rgb(0, 66, 170)", "rgb(130,183,255)"],
+                ["rgb(44, 19, 118)", "rgb(189,169,248)"],
+                ["rgb(97, 23, 124)", "rgb(222,163,243)"],
+                ["rgb(121, 26, 62)", "rgb(235,159,187)"],
+                ["rgb(181, 26, 0)", "rgb(248,124,103)"],
+                ["rgb(173, 62, 0)", "rgb(246,157,108)"],
+                ["rgb(169, 104, 0)", "rgb(244,192,108)"],
+                ["rgb(167, 123, 0)", "rgb(243,208,109)"],
+                ["rgb(196, 188, 0)", "rgb(238,232,81)"],
+                ["rgb(154, 166, 14)", "rgb(221,231,109)"],
+                ["rgb(79, 122, 40)", "rgb(183,217,151)"],
+                ["rgb(0, 140, 180)", "rgb(119,231,255)"],
+                ["rgb(0, 86, 214)", "rgb(98,167,255)"],
+                ["rgb(55, 26, 148)", "rgb(170,147,244)"],
+                ["rgb(123, 33, 159)", "rgb(208,136,237)"],
+                ["rgb(154, 36, 79)", "rgb(226,132,166)"],
+                ["rgb(227, 36, 0)", "rgb(246,93,64)"],
+                ["rgb(217, 80, 0)", "rgb(244,134,70)"],
+                ["rgb(213, 132, 0)", "rgb(241,176,70)"],
+                ["rgb(210, 157, 0)", "rgb(239,197,71)"],
+                ["rgb(245, 236, 0)", "rgb(234,227,37)"],
+                ["rgb(195, 209, 23)", "rgb(209,220,71)"],
+                ["rgb(102, 156, 53)", "rgb(162,205,122)"],
+                ["rgb(0, 163, 215)", "rgb(93,223,255)"],
+                ["rgb(0, 97, 255)", "rgb(68,146,255)"],
+                ["rgb(77, 34, 179)", "rgb(158,123,239)"],
+                ["rgb(153, 41, 189)", "rgb(203,114,232)"],
+                ["rgb(185, 45, 93)", "rgb(219,107,145)"],
+                ["rgb(255, 64, 19)", "rgb(230,77,41)"],
+                ["rgb(255, 106, 0)", "rgb(241,122,37)"],
+                ["rgb(255, 170, 0)", "rgb(237,169,33)"],
+                ["rgb(254, 199, 0)", "rgb(236,192,32)"],
+                ["rgb(255, 252, 65)", "rgb(186,184,34)"],
+                ["rgb(217, 235, 55)", "rgb(181,196,51)"],
+                ["rgb(119, 187, 65)", "rgb(140,194,96)"],
+                ["rgb(0, 199, 252)", "rgb(64,223,255)"],
+                ["rgb(58, 136, 254)", "rgb(65,127,221)"],
+                ["rgb(94, 48, 235)", "rgb(119,82,232)"],
+                ["rgb(190, 56, 243)", "rgb(180,73,223)"],
+                ["rgb(230, 59, 122)", "rgb(208,71,122)"],
+                ["rgb(255, 98, 81)", "rgb(184,58,45)"],
+                ["rgb(255, 134, 71)", "rgb(189,92,42)"],
+                ["rgb(255, 180, 63)", "rgb(192,132,38)"],
+                ["rgb(254, 203, 62)", "rgb(191,151,37)"],
+                ["rgb(255, 247, 107)", "rgb(157,150,38)"],
+                ["rgb(228, 239, 101)", "rgb(153,162,52)"],
+                ["rgb(150, 211, 95)", "rgb(122,171,77)"],
+                ["rgb(83, 213, 253)", "rgb(60,164,196)"],
+                ["rgb(116, 167, 254)", "rgb(61,102,171)"],
+                ["rgb(135, 78, 254)", "rgb(111,66,206)"],
+                ["rgb(211, 87, 254)", "rgb(162,63,196)"],
+                ["rgb(237, 113, 158)", "rgb(165,66,101)"],
+                ["rgb(255, 140, 130)", "rgb(147,55,46)"],
+                ["rgb(255, 165, 125)", "rgb(149,77,44)"],
+                ["rgb(255, 198, 119)", "rgb(151,105,42)"],
+                ["rgb(255, 216, 119)", "rgb(150,119,41)"],
+                ["rgb(255, 249, 149)", "rgb(127,122,42)"],
+                ["rgb(235, 243, 143)", "rgb(126,132,52)"],
+                ["rgb(177, 221, 140)", "rgb(102,137,72)"],
+                ["rgb(148, 227, 254)", "rgb(57,120,141)"],
+                ["rgb(168, 198, 254)", "rgb(58,82,126)"],
+                ["rgb(177, 140, 254)", "rgb(90,61,152)"],
+                ["rgb(227, 146, 254)", "rgb(124,59,145)"],
+                ["rgb(244, 164, 192)", "rgb(124,60,82)"],
+                ["rgb(255, 181, 175)", "rgb(112,53,48)"],
+                ["rgb(255, 196, 171)", "rgb(114,67,47)"],
+                ["rgb(255, 217, 168)", "rgb(115,85,45)"],
+                ["rgb(255, 228, 168)", "rgb(114,93,45)"],
+                ["rgb(255, 251, 185)", "rgb(101,98,45)"],
+                ["rgb(242, 247, 183)", "rgb(99,103,52)"],
+                ["rgb(204, 232, 181)", "rgb(84,107,65)"],
+                ["rgb(202, 240, 254)", "rgb(54,85,96)"],
+                ["rgb(212, 227, 254)", "rgb(55,67,88)"],
+                ["rgb(217, 202, 254)", "rgb(68,56,97)"],
+                ["rgb(241, 201, 254)", "rgb(87,55,98)"],
+                ["rgb(249, 211, 224)", "rgb(86,56,66)"],
+                ["rgb(255, 218, 216)", "rgb(81,51,49)"],
+                ["rgb(255, 226, 214)", "rgb(82,59,49)"],
+                ["rgb(255, 236, 213)", "rgb(82,67,48)"],
+                ["rgb(255, 242, 213)", "rgb(82,71,48)"],
+                ["rgb(254, 252, 221)", "rgb(75,74,49)"],
+                ["rgb(248, 250, 219)", "rgb(76,77,52)"],
+                ["rgb(224, 237, 212)", "rgb(73,84,63)"],
+            ];
+
+            function createSwatches(parent)
+            {
+                for (color of colors) {
+                    var child = document.createElement('div');
+                    child.style.backgroundColor = color[1];
+                    parent.appendChild(child);
+                }
+            }
+
+            function doSetup()
+            {
+                var div;
+                for (div of document.querySelectorAll('.sample'))
+                    createSwatches(div);
+            }
+            
+            window.addEventListener('load', doSetup, false);
+            
+        </script>
+    </head>
+    <body>
+        <div class="sample"></div>
+    </body>
+</html>
diff --git a/LayoutTests/css3/color-filters/color-filter-apple-invert-lightness.html b/LayoutTests/css3/color-filters/color-filter-apple-invert-lightness.html
new file mode 100644 (file)
index 0000000..2c64348
--- /dev/null
@@ -0,0 +1,177 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableColorFilter=true ] -->
+<html>
+    <head>
+        <style>
+            .sample {
+                width: 500px;
+                height: 400px;
+                background-color: white;
+                -apple-color-filter: apple-invert-lightness();
+            }
+            
+            .sample > div {
+                height: 30px;
+                width: 30px;
+                margin: 5px;
+                float: left;
+            }
+
+            .test
+            {
+                width: 100px;
+                height: 100px;
+                background-color: blue;
+                border: 50px solid green;
+                margin: 10px;
+                float: left;
+            }
+        </style>
+        <script>
+            const colors = [
+                // Original, Transformed.
+                ["rgb(0, 0, 0)", "rgb(255,255,255)"],
+                ["rgb(255, 255, 255)", "rgb(51,51,51)"],
+                ["rgb(235, 235, 235)", "rgb(67,67,67)"],
+                ["rgb(214, 214, 214)", "rgb(84,84,84)"],
+                ["rgb(192, 192, 192)", "rgb(101,101,101)"],
+                ["rgb(170, 170, 170)", "rgb(119,119,119)"],
+                ["rgb(146, 146, 146)", "rgb(138,138,138)"],
+                ["rgb(122, 122, 122)", "rgb(157,157,157)"],
+                ["rgb(96, 96, 96)", "rgb(178,178,178)"],
+                ["rgb(68, 68, 68)", "rgb(201,201,201)"],
+                ["rgb(35, 35, 35)", "rgb(227,227,227)"],
+                ["rgb(0, 0, 0)", "rgb(255,255,255)"],
+                ["rgb(0, 54, 74)", "rgb(199,242,255)"],
+                ["rgb(0, 30, 87)", "rgb(191,215,255)"],
+                ["rgb(17, 5, 59)", "rgb(222,212,255)"],
+                ["rgb(46, 7, 62)", "rgb(240,209,253)"],
+                ["rgb(60, 8, 27)", "rgb(249,207,222)"],
+                ["rgb(92, 7, 0)", "rgb(252,184,178)"],
+                ["rgb(90, 28, 0)", "rgb(251,201,179)"],
+                ["rgb(88, 52, 0)", "rgb(249,220,179)"],
+                ["rgb(85, 61, 0)", "rgb(249,230,181)"],
+                ["rgb(102, 97, 0)", "rgb(246,242,165)"],
+                ["rgb(79, 85, 3)", "rgb(241,245,180)"],
+                ["rgb(38, 62, 15)", "rgb(220,240,202)"],
+                ["rgb(0, 77, 101)", "rgb(179,240,255)"],
+                ["rgb(0, 46, 122)", "rgb(166,202,255)"],
+                ["rgb(26, 10, 83)", "rgb(207,195,253)"],
+                ["rgb(69, 14, 89)", "rgb(233,189,249)"],
+                ["rgb(86, 16, 41)", "rgb(242,186,206)"],
+                ["rgb(131, 17, 0)", "rgb(250,159,145)"],
+                ["rgb(124, 42, 0)", "rgb(249,183,149)"],
+                ["rgb(122, 74, 0)", "rgb(247,209,149)"],
+                ["rgb(120, 87, 0)", "rgb(246,220,150)"],
+                ["rgb(141, 134, 0)", "rgb(243,237,130)"],
+                ["rgb(111, 118, 8)", "rgb(233,239,151)"],
+                ["rgb(56, 87, 26)", "rgb(205,230,181)"],
+                ["rgb(0, 109, 143)", "rgb(147,234,255)"],
+                ["rgb(0, 66, 170)", "rgb(130,183,255)"],
+                ["rgb(44, 19, 118)", "rgb(189,169,248)"],
+                ["rgb(97, 23, 124)", "rgb(222,163,243)"],
+                ["rgb(121, 26, 62)", "rgb(235,159,187)"],
+                ["rgb(181, 26, 0)", "rgb(248,124,103)"],
+                ["rgb(173, 62, 0)", "rgb(246,157,108)"],
+                ["rgb(169, 104, 0)", "rgb(244,192,108)"],
+                ["rgb(167, 123, 0)", "rgb(243,208,109)"],
+                ["rgb(196, 188, 0)", "rgb(238,232,81)"],
+                ["rgb(154, 166, 14)", "rgb(221,231,109)"],
+                ["rgb(79, 122, 40)", "rgb(183,217,151)"],
+                ["rgb(0, 140, 180)", "rgb(119,231,255)"],
+                ["rgb(0, 86, 214)", "rgb(98,167,255)"],
+                ["rgb(55, 26, 148)", "rgb(170,147,244)"],
+                ["rgb(123, 33, 159)", "rgb(208,136,237)"],
+                ["rgb(154, 36, 79)", "rgb(226,132,166)"],
+                ["rgb(227, 36, 0)", "rgb(246,93,64)"],
+                ["rgb(217, 80, 0)", "rgb(244,134,70)"],
+                ["rgb(213, 132, 0)", "rgb(241,176,70)"],
+                ["rgb(210, 157, 0)", "rgb(239,197,71)"],
+                ["rgb(245, 236, 0)", "rgb(234,227,37)"],
+                ["rgb(195, 209, 23)", "rgb(209,220,71)"],
+                ["rgb(102, 156, 53)", "rgb(162,205,122)"],
+                ["rgb(0, 163, 215)", "rgb(93,223,255)"],
+                ["rgb(0, 97, 255)", "rgb(68,146,255)"],
+                ["rgb(77, 34, 179)", "rgb(158,123,239)"],
+                ["rgb(153, 41, 189)", "rgb(203,114,232)"],
+                ["rgb(185, 45, 93)", "rgb(219,107,145)"],
+                ["rgb(255, 64, 19)", "rgb(230,77,41)"],
+                ["rgb(255, 106, 0)", "rgb(241,122,37)"],
+                ["rgb(255, 170, 0)", "rgb(237,169,33)"],
+                ["rgb(254, 199, 0)", "rgb(236,192,32)"],
+                ["rgb(255, 252, 65)", "rgb(186,184,34)"],
+                ["rgb(217, 235, 55)", "rgb(181,196,51)"],
+                ["rgb(119, 187, 65)", "rgb(140,194,96)"],
+                ["rgb(0, 199, 252)", "rgb(64,223,255)"],
+                ["rgb(58, 136, 254)", "rgb(65,127,221)"],
+                ["rgb(94, 48, 235)", "rgb(119,82,232)"],
+                ["rgb(190, 56, 243)", "rgb(180,73,223)"],
+                ["rgb(230, 59, 122)", "rgb(208,71,122)"],
+                ["rgb(255, 98, 81)", "rgb(184,58,45)"],
+                ["rgb(255, 134, 71)", "rgb(189,92,42)"],
+                ["rgb(255, 180, 63)", "rgb(192,132,38)"],
+                ["rgb(254, 203, 62)", "rgb(191,151,37)"],
+                ["rgb(255, 247, 107)", "rgb(157,150,38)"],
+                ["rgb(228, 239, 101)", "rgb(153,162,52)"],
+                ["rgb(150, 211, 95)", "rgb(122,171,77)"],
+                ["rgb(83, 213, 253)", "rgb(60,164,196)"],
+                ["rgb(116, 167, 254)", "rgb(61,102,171)"],
+                ["rgb(135, 78, 254)", "rgb(111,66,206)"],
+                ["rgb(211, 87, 254)", "rgb(162,63,196)"],
+                ["rgb(237, 113, 158)", "rgb(165,66,101)"],
+                ["rgb(255, 140, 130)", "rgb(147,55,46)"],
+                ["rgb(255, 165, 125)", "rgb(149,77,44)"],
+                ["rgb(255, 198, 119)", "rgb(151,105,42)"],
+                ["rgb(255, 216, 119)", "rgb(150,119,41)"],
+                ["rgb(255, 249, 149)", "rgb(127,122,42)"],
+                ["rgb(235, 243, 143)", "rgb(126,132,52)"],
+                ["rgb(177, 221, 140)", "rgb(102,137,72)"],
+                ["rgb(148, 227, 254)", "rgb(57,120,141)"],
+                ["rgb(168, 198, 254)", "rgb(58,82,126)"],
+                ["rgb(177, 140, 254)", "rgb(90,61,152)"],
+                ["rgb(227, 146, 254)", "rgb(124,59,145)"],
+                ["rgb(244, 164, 192)", "rgb(124,60,82)"],
+                ["rgb(255, 181, 175)", "rgb(112,53,48)"],
+                ["rgb(255, 196, 171)", "rgb(114,67,47)"],
+                ["rgb(255, 217, 168)", "rgb(115,85,45)"],
+                ["rgb(255, 228, 168)", "rgb(114,93,45)"],
+                ["rgb(255, 251, 185)", "rgb(101,98,45)"],
+                ["rgb(242, 247, 183)", "rgb(99,103,52)"],
+                ["rgb(204, 232, 181)", "rgb(84,107,65)"],
+                ["rgb(202, 240, 254)", "rgb(54,85,96)"],
+                ["rgb(212, 227, 254)", "rgb(55,67,88)"],
+                ["rgb(217, 202, 254)", "rgb(68,56,97)"],
+                ["rgb(241, 201, 254)", "rgb(87,55,98)"],
+                ["rgb(249, 211, 224)", "rgb(86,56,66)"],
+                ["rgb(255, 218, 216)", "rgb(81,51,49)"],
+                ["rgb(255, 226, 214)", "rgb(82,59,49)"],
+                ["rgb(255, 236, 213)", "rgb(82,67,48)"],
+                ["rgb(255, 242, 213)", "rgb(82,71,48)"],
+                ["rgb(254, 252, 221)", "rgb(75,74,49)"],
+                ["rgb(248, 250, 219)", "rgb(76,77,52)"],
+                ["rgb(224, 237, 212)", "rgb(73,84,63)"],
+            ];
+
+            function createSwatches(parent)
+            {
+                for (color of colors) {
+                    var child = document.createElement('div');
+                    child.style.backgroundColor = color[0];
+                    parent.appendChild(child);
+                }
+            }
+
+            function doSetup()
+            {
+                var div;
+                for (div of document.querySelectorAll('.sample'))
+                    createSwatches(div);
+            }
+            
+            window.addEventListener('load', doSetup, false);
+            
+        </script>
+    </head>
+    <body>
+        <div class="sample"></div>
+    </body>
+</html>
index 9cb81af..de6f11c 100644 (file)
@@ -33,4 +33,6 @@ PASS saturate(): values of amount over 100% are allowed, providing super-saturat
 PASS sepia(): values of amount over 100% are allowed but UAs must clamp the values to 1 
 PASS Parse filter list 
 PASS Filter list with blur is invalid 
+PASS Parse apple-invert-lightness() 
+PASS apple-invert-lightness() takes no arguments 
 
index e9e05a8..04bdfbc 100644 (file)
@@ -67,6 +67,10 @@ testColorFilterParsing("sepia(5.3)", "sepia(1)", "sepia(): values of amount over
 testColorFilterParsing("grayscale(50%) hue-rotate(45deg) opacity(0.5)", "grayscale(0.5) hue-rotate(45deg) opacity(0.5)", "Parse filter list");
 testColorFilterParsing("grayscale(50%) blur(10px) opacity(0.5)", "none", "Filter list with blur is invalid");
 
+// apple-invert-lightness
+testColorFilterParsing("apple-invert-lightness()", "apple-invert-lightness()", "Parse apple-invert-lightness()");
+testColorFilterParsing("apple-invert-lightness(0.5)", "none", "apple-invert-lightness() takes no arguments");
+
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>
index 652b776..1e53fac 100644 (file)
@@ -1,3 +1,60 @@
+2018-07-16  Simon Fraser  <simon.fraser@apple.com>
+
+        Add color filter for transforming colors in Dark Mode
+        https://bugs.webkit.org/show_bug.cgi?id=187717
+        rdar://problem/41146650
+
+        Reviewed by Dean Jackson.
+        
+        Add a new filter function for use in -apple-color-filter for transforming colors
+        when in Dark Mode. The filter is called apple-invert-lightness(), and takes no parameters.
+        It's based on a lightness invert in HSL space, with some adjustments to improve the contrast
+        of some colors on dark backgrounds, so does a much better job that using invert() with hue-rotate().
+
+        Test: css3/color-filters/color-filter-apple-invert-lightness.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::valueForFilter):
+        * css/CSSValueKeywords.in:
+        * css/StyleResolver.cpp:
+        (WebCore::filterOperationForType):
+        (WebCore::StyleResolver::createFilterOperations):
+        * css/parser/CSSPropertyParser.cpp:
+        (WebCore::CSSPropertyParser::parseSingleValue):
+        * css/parser/CSSPropertyParserHelpers.cpp:
+        (WebCore::CSSPropertyParserHelpers::consumeFilterImage):
+        (WebCore::CSSPropertyParserHelpers::isPixelFilterFunction):
+        (WebCore::CSSPropertyParserHelpers::isColorFilterFunction):
+        (WebCore::CSSPropertyParserHelpers::consumeFilterFunction):
+        (WebCore::CSSPropertyParserHelpers::consumeFilter):
+        (WebCore::CSSPropertyParserHelpers::isValidPrimitiveFilterFunction): Deleted.
+        * css/parser/CSSPropertyParserHelpers.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::paintContents):
+        * platform/graphics/Color.cpp:
+        * platform/graphics/ColorUtilities.cpp:
+        (WebCore::sRGBToLinearComponents):
+        (WebCore::linearToSRGBComponents):
+        (WebCore::sRGBToLinearColorComponentForLuminance):
+        (WebCore::luminance):
+        (WebCore::sRGBToHSL):
+        (WebCore::calcHue):
+        (WebCore::HSLToSRGB):
+        (WebCore::ColorMatrix::ColorMatrix):
+        * platform/graphics/ColorUtilities.h:
+        * platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm:
+        (PlatformCAFilters::filterValueForOperation):
+        (PlatformCAFilters::colorMatrixValueForFilter):
+        * platform/graphics/filters/FEColorMatrix.cpp:
+        * platform/graphics/filters/FilterOperation.cpp:
+        (WebCore::InvertLightnessFilterOperation::operator== const):
+        (WebCore::InvertLightnessFilterOperation::blend):
+        (WebCore::InvertLightnessFilterOperation::transformColor const):
+        (WebCore::operator<<):
+        * platform/graphics/filters/FilterOperation.h:
+        * rendering/FilterEffectRenderer.cpp:
+        (WebCore::FilterEffectRenderer::build):
+
 2018-07-16  Jiewen Tan  <jiewen_tan@apple.com>
 
         Unreviewed, build fix for r233873.
index 78695c4..feac687 100644 (file)
@@ -1013,6 +1013,10 @@ Ref<CSSValue> ComputedStyleExtractor::valueForFilter(const RenderStyle& style, c
                 filterValue->append(cssValuePool.createValue(downcast<BasicComponentTransferFilterOperation>(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER));
                 break;
             }
+            case FilterOperation::APPLE_INVERT_LIGHTNESS: {
+                filterValue = CSSFunctionValue::create(CSSValueAppleInvertLightness);
+                break;
+            }
             case FilterOperation::OPACITY: {
                 filterValue = CSSFunctionValue::create(CSSValueOpacity);
                 filterValue->append(cssValuePool.createValue(downcast<BasicComponentTransferFilterOperation>(filterOperation).amount(), CSSPrimitiveValue::CSS_NUMBER));
index 03b5ffa..02047b5 100644 (file)
@@ -1232,6 +1232,7 @@ cubic-bezier
 spring
 steps
 frames
+apple-invert-lightness
 
 // colors
 rgb
index 1ba6730..7ce3dbd 100644 (file)
@@ -1885,6 +1885,8 @@ static FilterOperation::OperationType filterOperationForType(CSSValueID type)
         return FilterOperation::HUE_ROTATE;
     case CSSValueInvert:
         return FilterOperation::INVERT;
+    case CSSValueAppleInvertLightness:
+        return FilterOperation::APPLE_INVERT_LIGHTNESS;
     case CSSValueOpacity:
         return FilterOperation::OPACITY;
     case CSSValueBrightness:
@@ -1991,6 +1993,10 @@ bool StyleResolver::createFilterOperations(const CSSValue& inValue, FilterOperat
             operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
             break;
         }
+        case FilterOperation::APPLE_INVERT_LIGHTNESS: {
+            operations.operations().append(InvertLightnessFilterOperation::create());
+            break;
+        }
         case FilterOperation::BLUR: {
             Length stdDeviation = Length(0, Fixed);
             if (filterValue.length() >= 1)
index e566964..bd27d63 100644 (file)
@@ -4133,11 +4133,11 @@ RefPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID property, CSS
 #if ENABLE(FILTERS_LEVEL_2)
     case CSSPropertyWebkitBackdropFilter:
 #endif
-        return consumeFilter(m_range, m_context, AllowedFilterFunctions::All);
+        return consumeFilter(m_range, m_context, AllowedFilterFunctions::PixelFilters);
     case CSSPropertyAppleColorFilter:
         if (!m_context.colorFilterEnabled)
             return nullptr;
-        return consumeFilter(m_range, m_context, AllowedFilterFunctions::Color);
+        return consumeFilter(m_range, m_context, AllowedFilterFunctions::ColorFilters);
     case CSSPropertyTextDecoration:
     case CSSPropertyWebkitTextDecorationsInEffect:
     case CSSPropertyWebkitTextDecorationLine:
index ab62b08..a44a526 100644 (file)
@@ -1286,7 +1286,7 @@ static RefPtr<CSSValue> consumeFilterImage(CSSParserTokenRange& args, const CSSP
     if (!imageValue || !consumeCommaIncludingWhitespace(args))
         return nullptr;
 
-    auto filterValue = consumeFilter(args, context);
+    auto filterValue = consumeFilter(args, context, AllowedFilterFunctions::PixelFilters);
 
     if (!filterValue)
         return nullptr;
@@ -1390,7 +1390,7 @@ static bool isGeneratedImage(CSSValueID id)
         || id == CSSValueFilter;
 }
     
-static bool isValidPrimitiveFilterFunction(CSSValueID filterFunction)
+static bool isPixelFilterFunction(CSSValueID filterFunction)
 {
     switch (filterFunction) {
     case CSSValueBlur:
@@ -1420,6 +1420,7 @@ static bool isColorFilterFunction(CSSValueID filterFunction)
     case CSSValueOpacity:
     case CSSValueSaturate:
     case CSSValueSepia:
+    case CSSValueAppleInvertLightness:
         return true;
     default:
         return false;
@@ -1441,14 +1442,26 @@ static bool allowsValuesGreaterThanOne(CSSValueID filterFunction)
 static RefPtr<CSSFunctionValue> consumeFilterFunction(CSSParserTokenRange& range, const CSSParserContext& context, AllowedFilterFunctions allowedFunctions)
 {
     CSSValueID filterType = range.peek().functionId();
-    if (!isValidPrimitiveFilterFunction(filterType))
-        return nullptr;
-
-    if (allowedFunctions == AllowedFilterFunctions::Color && !isColorFilterFunction(filterType))
-        return nullptr;
+    switch (allowedFunctions) {
+    case AllowedFilterFunctions::PixelFilters:
+        if (!isPixelFilterFunction(filterType))
+            return nullptr;
+        break;
+    case AllowedFilterFunctions::ColorFilters:
+        if (!isColorFilterFunction(filterType))
+            return nullptr;
+        break;
+    }
 
     CSSParserTokenRange args = consumeFunction(range);
     RefPtr<CSSFunctionValue> filterValue = CSSFunctionValue::create(filterType);
+
+    if (filterType == CSSValueAppleInvertLightness) {
+        if (!args.atEnd())
+            return nullptr;
+        return filterValue;
+    }
+
     RefPtr<CSSValue> parsedValue;
 
     if (filterType == CSSValueDropShadow)
@@ -1484,7 +1497,7 @@ RefPtr<CSSValue> consumeFilter(CSSParserTokenRange& range, const CSSParserContex
     if (range.peek().id() == CSSValueNone)
         return consumeIdent(range);
 
-    bool referenceFiltersAllowed = allowedFunctions == AllowedFilterFunctions::All;
+    bool referenceFiltersAllowed = allowedFunctions == AllowedFilterFunctions::PixelFilters;
     auto list = CSSValueList::createSpaceSeparated();
     do {
         RefPtr<CSSValue> filterValue = referenceFiltersAllowed ? consumeUrl(range) : nullptr;
index a078107..e630027 100644 (file)
@@ -94,11 +94,11 @@ RefPtr<CSSValue> consumeImage(CSSParserTokenRange&, CSSParserContext, ConsumeGen
 RefPtr<CSSValue> consumeImageOrNone(CSSParserTokenRange&, CSSParserContext);
 
 enum class AllowedFilterFunctions {
-    All,
-    Color
+    PixelFilters,
+    ColorFilters
 };
 
-RefPtr<CSSValue> consumeFilter(CSSParserTokenRange&, const CSSParserContext&, AllowedFilterFunctions = AllowedFilterFunctions::All);
+RefPtr<CSSValue> consumeFilter(CSSParserTokenRange&, const CSSParserContext&, AllowedFilterFunctions);
 RefPtr<CSSShadowValue> consumeSingleShadow(CSSParserTokenRange&, CSSParserMode, bool allowInset, bool allowSpread);
 
 // Template implementations are at the bottom of the file for readability.
index 5dd150f..3170103 100644 (file)
@@ -117,6 +117,7 @@ static double calcHue(double temp1, double temp2, double hueVal)
 // further explanation available at http://en.wikipedia.org/wiki/HSL_color_space
 
 // Hue is in the range of 0 to 6.0, the remainder are in the range 0 to 1.0
+// FIXME: Use HSLToSRGB().
 RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha)
 {
     const double scaleFactor = nextafter(256.0, 0.0);
@@ -533,6 +534,7 @@ void Color::getRGBA(double& r, double& g, double& b, double& a) const
     a = alpha() / 255.0;
 }
 
+// FIXME: Use sRGBToHSL().
 void Color::getHSL(double& hue, double& saturation, double& lightness) const
 {
     // http://en.wikipedia.org/wiki/HSL_color_space. This is a direct copy of
index 17299a2..60ae004 100644 (file)
@@ -73,12 +73,167 @@ FloatComponents sRGBColorToLinearComponents(const Color& color)
     };
 }
 
+FloatComponents sRGBToLinearComponents(const FloatComponents& sRGBColor)
+{
+    return {
+        sRGBToLinearColorComponent(sRGBColor.components[0]),
+        sRGBToLinearColorComponent(sRGBColor.components[1]),
+        sRGBToLinearColorComponent(sRGBColor.components[2]),
+        sRGBColor.components[3]
+    };
+}
+
+FloatComponents linearToSRGBComponents(const FloatComponents& linearRGB)
+{
+    return {
+        linearToSRGBColorComponent(linearRGB.components[0]),
+        linearToSRGBColorComponent(linearRGB.components[1]),
+        linearToSRGBColorComponent(linearRGB.components[2]),
+        linearRGB.components[3]
+    };
+}
+
+// This is similar to sRGBToLinearColorComponent but for some reason
+// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+// doesn't use the standard sRGB -> linearRGB threshold of 0.04045.
+static float sRGBToLinearColorComponentForLuminance(float c)
+{
+    if (c <= 0.03928f)
+        return c / 12.92f;
+
+    return clampTo<float>(std::pow((c + 0.055f) / 1.055f, 2.4f), 0, 1);
+}
+
+float luminance(const FloatComponents& sRGBCompontents)
+{
+    // Values from https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+    return 0.2126f * sRGBToLinearColorComponentForLuminance(sRGBCompontents.components[0])
+        + 0.7152f * sRGBToLinearColorComponentForLuminance(sRGBCompontents.components[1])
+        + 0.0722f * sRGBToLinearColorComponentForLuminance(sRGBCompontents.components[2]);
+}
+
+FloatComponents sRGBToHSL(const FloatComponents& sRGBColor)
+{
+    // http://en.wikipedia.org/wiki/HSL_color_space.
+    float r = sRGBColor.components[0];
+    float g = sRGBColor.components[1];
+    float b = sRGBColor.components[2];
+
+    float max = std::max(std::max(r, g), b);
+    float min = std::min(std::min(r, g), b);
+    float chroma = max - min;
+
+    float hue;
+    if (!chroma)
+        hue = 0;
+    else if (max == r)
+        hue = (60.0f * ((g - b) / chroma)) + 360.0f;
+    else if (max == g)
+        hue = (60.0f * ((b - r) / chroma)) + 120.0f;
+    else
+        hue = (60.0f * ((r - g) / chroma)) + 240.0f;
+
+    if (hue >= 360.0f)
+        hue -= 360.0f;
+
+    hue /= 360.0f;
+
+    float lightness = 0.5f * (max + min);
+    float saturation;
+    if (!chroma)
+        saturation = 0;
+    else if (lightness <= 0.5f)
+        saturation = (chroma / (max + min));
+    else
+        saturation = (chroma / (2.0f - (max + min)));
+
+    return {
+        hue,
+        saturation,
+        lightness,
+        sRGBColor.components[3]
+    };
+}
+
+// Hue is in the range 0-6, other args in 0-1.
+static float calcHue(float temp1, float temp2, float hueVal)
+{
+    if (hueVal < 0.0f)
+        hueVal += 6.0f;
+    else if (hueVal >= 6.0f)
+        hueVal -= 6.0f;
+    if (hueVal < 1.0f)
+        return temp1 + (temp2 - temp1) * hueVal;
+    if (hueVal < 3.0f)
+        return temp2;
+    if (hueVal < 4.0f)
+        return temp1 + (temp2 - temp1) * (4.0f - hueVal);
+    return temp1;
+}
+
+// Explanation of this algorithm can be found in the CSS Color 4 Module
+// specification at https://drafts.csswg.org/css-color-4/#hsl-to-rgb with
+// further explanation available at http://en.wikipedia.org/wiki/HSL_color_space
+FloatComponents HSLToSRGB(const FloatComponents& hslColor)
+{
+    float hue = hslColor.components[0];
+    float saturation = hslColor.components[1];
+    float lightness = hslColor.components[2];
+
+    // Convert back to RGB.
+    if (!saturation) {
+        return {
+            lightness,
+            lightness,
+            lightness,
+            hslColor.components[3]
+        };
+    }
+    
+    float temp2 = lightness <= 0.5f ? lightness * (1.0f + saturation) : lightness + saturation - lightness * saturation;
+    float temp1 = 2.0f * lightness - temp2;
+    
+    hue *= 6.0f; // calcHue() wants hue in the 0-6 range.
+    return {
+        calcHue(temp1, temp2, hue + 2.0f),
+        calcHue(temp1, temp2, hue),
+        calcHue(temp1, temp2, hue - 2.0f),
+        hslColor.components[3]
+    };
+}
 
 ColorMatrix::ColorMatrix()
 {
     makeIdentity();
 }
 
+ColorMatrix::ColorMatrix(float values[20])
+{
+    m_matrix[0][0] = values[0];
+    m_matrix[0][1] = values[1];
+    m_matrix[0][2] = values[2];
+    m_matrix[0][3] = values[3];
+    m_matrix[0][4] = values[4];
+
+    m_matrix[1][0] = values[5];
+    m_matrix[1][1] = values[6];
+    m_matrix[1][2] = values[7];
+    m_matrix[1][3] = values[8];
+    m_matrix[1][4] = values[9];
+
+    m_matrix[2][0] = values[10];
+    m_matrix[2][1] = values[11];
+    m_matrix[2][2] = values[12];
+    m_matrix[2][3] = values[13];
+    m_matrix[2][4] = values[14];
+
+    m_matrix[3][0] = values[15];
+    m_matrix[3][1] = values[16];
+    m_matrix[3][2] = values[17];
+    m_matrix[3][3] = values[18];
+    m_matrix[3][4] = values[19];
+}
+
 void ColorMatrix::makeIdentity()
 {
     memset(m_matrix, 0, sizeof(m_matrix));
index 6f9242e..766ffb2 100644 (file)
@@ -155,6 +155,13 @@ float linearToSRGBColorComponent(float);
 float sRGBToLinearColorComponent(float);
 
 FloatComponents sRGBColorToLinearComponents(const Color&);
+FloatComponents sRGBToLinearComponents(const FloatComponents&);
+FloatComponents linearToSRGBComponents(const FloatComponents&);
+
+FloatComponents sRGBToHSL(const FloatComponents&);
+FloatComponents HSLToSRGB(const FloatComponents&);
+
+float luminance(const FloatComponents& sRGBCompontents);
 
 class ColorMatrix {
 public:
@@ -164,6 +171,7 @@ public:
     static ColorMatrix sepiaMatrix(float);
 
     ColorMatrix();
+    ColorMatrix(float[20]);
     
     void transformColorComponents(FloatComponents&) const;
 
index 475dfd3..890d65e 100644 (file)
@@ -129,6 +129,9 @@ void PlatformCAFilters::setFiltersOnLayer(PlatformLayer* layer, const FilterOper
             [array.get() addObject:filter];
             break;
         }
+        case FilterOperation::APPLE_INVERT_LIGHTNESS:
+            ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+            break;
         case FilterOperation::OPACITY: {
             RetainPtr<NSValue> colorMatrixValue = PlatformCAFilters::colorMatrixValueForFilter(filterOperation.type(), &filterOperation);
             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMatrix];
@@ -233,6 +236,9 @@ void PlatformCAFilters::setFiltersOnLayer(PlatformLayer* layer, const FilterOper
             [array.get() addObject:filter];
             break;
         }
+        case FilterOperation::APPLE_INVERT_LIGHTNESS:
+            ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+            break;
         case FilterOperation::OPACITY: {
             const auto& componentTransferOperation = downcast<BasicComponentTransferFilterOperation>(filterOperation);
             CIFilter* filter = [CIFilter filterWithName:@"CIColorMatrix"];
@@ -397,6 +403,9 @@ RetainPtr<NSValue> PlatformCAFilters::filterValueForOperation(const FilterOperat
 #endif
         break;
     }
+    case FilterOperation::APPLE_INVERT_LIGHTNESS:
+            ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+        break;
     case FilterOperation::OPACITY: {
 #if USE_CA_FILTERS
         // Opacity CAFilter: inputColorMatrix
@@ -498,6 +507,9 @@ RetainPtr<NSValue> PlatformCAFilters::colorMatrixValueForFilter(FilterOperation:
         };
         return [NSValue valueWithCAColorMatrix:colorMatrix];
     }
+    case FilterOperation::APPLE_INVERT_LIGHTNESS:
+        ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+        return nullptr;
     case FilterOperation::OPACITY: {
         float amount = filterOperation ? downcast<BasicComponentTransferFilterOperation>(filterOperation)->amount() : 1;
         CAColorMatrix colorMatrix = {
index cb2c0fd..e6141bd 100644 (file)
@@ -87,6 +87,7 @@ inline void saturateAndHueRotate(float& red, float& green, float& blue, const fl
     blue    = r * components[6] + g * components[7] + b * components[8];
 }
 
+// FIXME: this should use luminance(const FloatComponents& sRGBCompontents).
 inline void luminance(float& red, float& green, float& blue, float& alpha)
 {
     alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue;
index 79f60e1..d5368b2 100644 (file)
@@ -213,6 +213,46 @@ double BasicComponentTransferFilterOperation::passthroughAmount() const
     }
 }
     
+bool InvertLightnessFilterOperation::operator==(const FilterOperation& operation) const
+{
+    if (!isSameType(operation))
+        return false;
+
+    return true;
+}
+    
+RefPtr<FilterOperation> InvertLightnessFilterOperation::blend(const FilterOperation* from, double, bool)
+{
+    if (from && !from->isSameType(*this))
+        return this;
+
+    // This filter is not currently blendable.
+    return InvertLightnessFilterOperation::create();
+}
+
+bool InvertLightnessFilterOperation::transformColor(FloatComponents& sRGBColorComponents) const
+{
+    FloatComponents hslComponents = sRGBToHSL(sRGBColorComponents);
+    
+    // Rotate the hue 180deg.
+    hslComponents.components[0] = fmod(hslComponents.components[0] + 0.5f, 1.0f);
+    
+    // Convert back to RGB.
+    sRGBColorComponents = HSLToSRGB(hslComponents);
+    
+    // Apply the matrix. See rdar://problem/41146650 for how this matrix was derived.
+    float matrixValues[20] = {
+       -0.770,  0.059, -0.089, 0, 1,
+        0.030, -0.741, -0.089, 0, 1,
+        0.030,  0.059, -0.890, 0, 1,
+        0,      0,      0,     1, 0
+    };
+
+    ColorMatrix toDarkModeMatrix(matrixValues);
+    toDarkModeMatrix.transformColorComponents(sRGBColorComponents);
+    return true;
+}
+
 bool BlurFilterOperation::operator==(const FilterOperation& operation) const
 {
     if (!isSameType(operation))
@@ -297,6 +337,10 @@ TextStream& operator<<(TextStream& ts, const FilterOperation& filter)
         ts << "invert(" << componentTransferFilter.amount() << ")";
         break;
     }
+    case FilterOperation::APPLE_INVERT_LIGHTNESS: {
+        ts << "apple-invert-lightness()";
+        break;
+    }
     case FilterOperation::OPACITY: {
         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
         ts << "opacity(" << componentTransferFilter.amount() << ")";
index 4bd8e27..7b62e0e 100644 (file)
@@ -56,6 +56,7 @@ public:
         SATURATE,
         HUE_ROTATE,
         INVERT,
+        APPLE_INVERT_LIGHTNESS,
         OPACITY,
         BRIGHTNESS,
         CONTRAST,
@@ -270,6 +271,31 @@ private:
     double m_amount;
 };
 
+class WEBCORE_EXPORT InvertLightnessFilterOperation : public FilterOperation {
+public:
+    static Ref<InvertLightnessFilterOperation> create()
+    {
+        return adoptRef(*new InvertLightnessFilterOperation());
+    }
+
+    Ref<FilterOperation> clone() const override
+    {
+        return adoptRef(*new InvertLightnessFilterOperation());
+    }
+
+    RefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false) override;
+
+private:
+    bool operator==(const FilterOperation&) const override;
+
+    InvertLightnessFilterOperation()
+        : FilterOperation(APPLE_INVERT_LIGHTNESS)
+    {
+    }
+
+    bool transformColor(FloatComponents&) const override;
+};
+
 class WEBCORE_EXPORT BlurFilterOperation : public FilterOperation {
 public:
     static Ref<BlurFilterOperation> create(Length stdDeviation)
@@ -354,6 +380,7 @@ SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(PassthroughFilterOperation, type() == Web
 SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(ReferenceFilterOperation, type() == WebCore::FilterOperation::REFERENCE)
 SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(BasicColorMatrixFilterOperation, isBasicColorMatrixFilterOperation())
 SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(BasicComponentTransferFilterOperation, isBasicComponentTransferFilterOperation())
+SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(InvertLightnessFilterOperation, type() == WebCore::FilterOperation::APPLE_INVERT_LIGHTNESS)
 SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(BlurFilterOperation, type() == WebCore::FilterOperation::BLUR)
 SPECIALIZE_TYPE_TRAITS_FILTEROPERATION(DropShadowFilterOperation, type() == WebCore::FilterOperation::DROP_SHADOW)
 
index e316c2d..d6fa995 100644 (file)
@@ -229,6 +229,9 @@ bool FilterEffectRenderer::build(RenderElement& renderer, const FilterOperations
             effect = FEComponentTransfer::create(*this, transferFunction, transferFunction, transferFunction, nullFunction);
             break;
         }
+        case FilterOperation::APPLE_INVERT_LIGHTNESS:
+            ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+            break;
         case FilterOperation::OPACITY: {
             auto& componentTransferOperation = downcast<BasicComponentTransferFilterOperation>(filterOperation);
             ComponentTransferFunction transferFunction;
index 19b681f..b647dcb 100644 (file)
@@ -1,3 +1,14 @@
+2018-07-16  Simon Fraser  <simon.fraser@apple.com>
+
+        Add color filter for transforming colors in Dark Mode
+        https://bugs.webkit.org/show_bug.cgi?id=187717
+
+        Reviewed by Dean Jackson.
+
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<FilterOperation>::encode):
+        (IPC::decodeFilterOperation):
+
 2018-07-16  Tim Horton  <timothy_horton@apple.com>
 
         Black flash in content area when returning to Mail
index bc1b6cc..c0dfb29 100644 (file)
@@ -2242,6 +2242,9 @@ void ArgumentCoder<FilterOperation>::encode(Encoder& encoder, const FilterOperat
     case FilterOperation::CONTRAST:
         encoder << downcast<BasicComponentTransferFilterOperation>(filter).amount();
         break;
+    case FilterOperation::APPLE_INVERT_LIGHTNESS:
+        ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+        break;
     case FilterOperation::BLUR:
         encoder << downcast<BlurFilterOperation>(filter).stdDeviation();
         break;
@@ -2292,6 +2295,9 @@ bool decodeFilterOperation(Decoder& decoder, RefPtr<FilterOperation>& filter)
         filter = BasicComponentTransferFilterOperation::create(amount, type);
         break;
     }
+    case FilterOperation::APPLE_INVERT_LIGHTNESS:
+        ASSERT_NOT_REACHED(); // APPLE_INVERT_LIGHTNESS is only used in -apple-color-filter.
+        break;
     case FilterOperation::BLUR: {
         Length stdDeviation;
         if (!decoder.decode(stdDeviation))