AX: "(inverted-colors)" media query only matches on page reload; should match on...
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Nov 2016 02:51:15 +0000 (02:51 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Nov 2016 02:51:15 +0000 (02:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=163564
<rdar://problem/28807350>

Source/WebCore:

Reviewed by Simon Fraser.

Mark some media queries as responding to notifications that
system accessibility settings have changed. When Page gets told
that has happened, check if any of the results have changed.

Tests: fast/media/mq-inverted-colors-live-update.html
       fast/media/mq-monochrome-live-update.html
       fast/media/mq-prefers-reduced-motion-live-update.html

* css/MediaQueryEvaluator.cpp:
(WebCore::isAccessibilitySettingsDependent):
(WebCore::MediaQueryEvaluator::evaluate):
* css/StyleResolver.cpp:
(WebCore::StyleResolver::addAccessibilitySettingsDependentMediaQueryResult):
(WebCore::StyleResolver::hasMediaQueriesAffectedByAccessibilitySettingsChange):
* css/StyleResolver.h:
(WebCore::StyleResolver::hasAccessibilitySettingsDependentMediaQueries):
* page/Page.cpp:
(WebCore::Page::accessibilitySettingsDidChange):
* page/Page.h:

Source/WebKit2:

Reviewed by Simon Fraser.

Listen for the appropriate notifications that accessibility settings
have changed. This is a single notification on macOS, which uses WebViewImpl,
and more fine-grained notifications on iOS, using WKWebView.

When we see the notification, send a message to the WebProcess which will
then tell the WebCore::Page.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _initializeWithConfiguration:]):
(-[WKWebView _accessibilitySettingsDidChange:]):
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(-[WKAccessibilitySettingsObserver initWithImpl:]):
(-[WKAccessibilitySettingsObserver dealloc]):
(-[WKAccessibilitySettingsObserver _settingsDidChange:]):
(WebKit::WebViewImpl::WebViewImpl):
(WebKit::WebViewImpl::accessibilitySettingsDidChange):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::accessibilitySettingsDidChange):
* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::accessibilitySettingsDidChange):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Reviewed by NOBODY (OOPS!).

Add a UIScriptController method that tricks WebKit into thinking
it has received a notification that accessibility settings have
changed. Combined with our forced overrides, this allows us to
test if a page would react to the notifications.

* DumpRenderTree/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
* DumpRenderTree/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
* TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
* TestRunnerShared/UIScriptContext/UIScriptController.cpp:
(WTR::simulateAccessibilitySettingsChangeNotification):
* TestRunnerShared/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
* WebKitTestRunner/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):

LayoutTests:

Reviewed by Simon Fraser.

* fast/media/mq-inverted-colors-live-update-in-subframes-expected.html: Added.
* fast/media/mq-inverted-colors-live-update-in-subframes.html: Added.
* fast/media/mq-inverted-colors-live-update-expected.html: Added.
* fast/media/mq-inverted-colors-live-update.html: Added.
* fast/media/mq-monochrome-live-update-expected.html: Added.
* fast/media/mq-monochrome-live-update.html: Added.
* fast/media/mq-prefers-reduced-motion-live-update-expected.html: Added.
* fast/media/mq-prefers-reduced-motion-live-update.html: Added.

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

35 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/fast/media/mq-inverted-colors-live-update-expected.html [new file with mode: 0644]
LayoutTests/fast/media/mq-inverted-colors-live-update-in-subframes-expected.html [new file with mode: 0644]
LayoutTests/fast/media/mq-inverted-colors-live-update-in-subframes.html [new file with mode: 0644]
LayoutTests/fast/media/mq-inverted-colors-live-update.html [new file with mode: 0644]
LayoutTests/fast/media/mq-monochrome-live-update-expected.html [new file with mode: 0644]
LayoutTests/fast/media/mq-monochrome-live-update.html [new file with mode: 0644]
LayoutTests/fast/media/mq-prefers-reduced-motion-live-update-expected.html [new file with mode: 0644]
LayoutTests/fast/media/mq-prefers-reduced-motion-live-update.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator-wk2/TestExpectations
LayoutTests/platform/mac-wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/css/MediaQueryEvaluator.cpp
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h
Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Tools/ChangeLog
Tools/DumpRenderTree/ios/UIScriptControllerIOS.mm
Tools/DumpRenderTree/mac/UIScriptControllerMac.mm
Tools/TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl
Tools/TestRunnerShared/UIScriptContext/UIScriptController.cpp
Tools/TestRunnerShared/UIScriptContext/UIScriptController.h
Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm
Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm

index 56ba818..d766631 100644 (file)
@@ -1,3 +1,20 @@
+2016-11-18  Dean Jackson  <dino@apple.com>
+
+        AX: "(inverted-colors)" media query only matches on page reload; should match on change
+        https://bugs.webkit.org/show_bug.cgi?id=163564
+        <rdar://problem/28807350>
+
+        Reviewed by Simon Fraser.
+
+        * fast/media/mq-inverted-colors-live-update-in-subframes-expected.html: Added.
+        * fast/media/mq-inverted-colors-live-update-in-subframes.html: Added.
+        * fast/media/mq-inverted-colors-live-update-expected.html: Added.
+        * fast/media/mq-inverted-colors-live-update.html: Added.
+        * fast/media/mq-monochrome-live-update-expected.html: Added.
+        * fast/media/mq-monochrome-live-update.html: Added.
+        * fast/media/mq-prefers-reduced-motion-live-update-expected.html: Added.
+        * fast/media/mq-prefers-reduced-motion-live-update.html: Added.
+
 2016-11-18  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [WebGL2] Implement texStorage2D()
index 7a395bd..12c808d 100644 (file)
@@ -70,6 +70,12 @@ editing/selection/character-granularity-rect.html [ Skip ]
 # This test is for ios-simulator-wk1
 editing/input/focus-change-with-marked-text.html [ Skip ]
 
+# These only run on Mac and iOS WK2
+fast/media/mq-inverted-colors-live-update.html [ Skip ]
+fast/media/mq-inverted-colors-live-update-in-subframes.html [ Skip ]
+fast/media/mq-monochrome-live-update.html [ Skip ]
+fast/media/mq-prefers-reduced-motion-live-update.html [ Skip ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific tests.
 #//////////////////////////////////////////////////////////////////////////////////////////
diff --git a/LayoutTests/fast/media/mq-inverted-colors-live-update-expected.html b/LayoutTests/fast/media/mq-inverted-colors-live-update-expected.html
new file mode 100644 (file)
index 0000000..4ba0554
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+<title>CSS4 media query test: inverted-colors.</title>
+<style type="text/css">
+p { color: black; }
+#a { color: green; }
+</style>
+</head>
+<body>
+  <p id="a"></p>
+  <p>Before was: rgb(0, 0, 0) - should be rgb(0, 0, 0)</p>
+  <p>After was: rgb(0, 128, 0) - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-inverted-colors-live-update-in-subframes-expected.html b/LayoutTests/fast/media/mq-inverted-colors-live-update-in-subframes-expected.html
new file mode 100644 (file)
index 0000000..5060e05
--- /dev/null
@@ -0,0 +1,19 @@
+<html>
+<head>
+<title>CSS4 media query test: inverted-colors.</title>
+</head>
+<body>
+  <iframe srcdoc='
+  <style type="text/css">
+  p { color: black; }
+
+  @media (inverted-colors) {
+      #a { color: green; }
+  }
+  </style>
+  <p id="a"></p>
+  '></iframe>
+  <p>Before was: <span id="before">rgb(0, 0, 0)</span> - should be rgb(0, 0, 0)</p>
+  <p>After was: <span id="after">rgb(0, 128, 0)</span> - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-inverted-colors-live-update-in-subframes.html b/LayoutTests/fast/media/mq-inverted-colors-live-update-in-subframes.html
new file mode 100644 (file)
index 0000000..924b1a7
--- /dev/null
@@ -0,0 +1,77 @@
+<html>
+<head>
+<title>CSS4 media query test: inverted-colors.</title>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.simulateAccessibilitySettingsChangeNotification(function() {
+            uiController.uiScriptComplete("Done");
+        });
+    })();`
+}
+
+function runTest()
+{
+    if (!window.internals)
+        return;
+
+    var frame = document.querySelector("iframe");
+    frame.contentWindow.postMessage({ type: "before" }, "*");
+}
+
+window.addEventListener("load", runTest, false);
+
+window.addEventListener("message", function (event) {
+    if (event.data.type == "beforeResponse") {
+        document.getElementById("before").textContent = event.data.color;
+        window.internals.settings.forcedColorsAreInvertedAccessibilityValue = "on";
+        if (testRunner.runUIScript) {
+            testRunner.runUIScript(getUIScript(), function(result) {
+                var frame = document.querySelector("iframe");
+                frame.contentWindow.postMessage({ type: "after" }, "*");
+            });
+        }
+    } else if (event.data.type == "afterResponse") {
+        document.getElementById("after").textContent = event.data.color;
+        testRunner.notifyDone();
+    }
+}, false);
+
+</script>
+</head>
+<body>
+  <iframe srcdoc='
+  <style type="text/css">
+  p { color: black; }
+
+  @media (inverted-colors) {
+      #a { color: green; }
+  }
+  </style>
+  <script>
+      window.addEventListener("message", function (event) {
+          var element = document.getElementById("a");
+          if (event.data.type == "before") {
+             event.source.postMessage({
+                 type: "beforeResponse",
+                 color: window.getComputedStyle(element).color
+             }, event.origin);
+          } else if (event.data.type == "after") {
+             event.source.postMessage({
+                 type: "afterResponse",
+                 color: window.getComputedStyle(element).color
+             }, event.origin);
+          }
+      }, false);
+  </script>
+  <p id="a"></p>
+  '></iframe>
+  <p>Before was: <span id="before"></span> - should be rgb(0, 0, 0)</p>
+  <p>After was: <span id="after"></span> - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-inverted-colors-live-update.html b/LayoutTests/fast/media/mq-inverted-colors-live-update.html
new file mode 100644 (file)
index 0000000..45dcbe1
--- /dev/null
@@ -0,0 +1,50 @@
+<html>
+<head>
+<title>CSS4 media query test: inverted-colors.</title>
+<style type="text/css">
+p { color: black; }
+
+@media (inverted-colors) {
+    #a { color: green; }
+}
+</style>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.simulateAccessibilitySettingsChangeNotification(function() {
+            uiController.uiScriptComplete("Done");
+        });
+    })();`
+}
+
+function runTest()
+{
+    if (!window.internals)
+        return;
+
+    var element = document.getElementById("a");
+
+    window.internals.settings.forcedColorsAreInvertedAccessibilityValue = "on";
+    document.getElementById("before").textContent = window.getComputedStyle(element).color;
+    if (testRunner.runUIScript) {
+        testRunner.runUIScript(getUIScript(), function(result) {
+            document.getElementById("after").textContent = window.getComputedStyle(element).color;
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.addEventListener("load", runTest, false);
+</script>
+</head>
+<body>
+  <p id="a"></p>
+  <p>Before was: <span id="before"></span> - should be rgb(0, 0, 0)</p>
+  <p>After was: <span id="after"></span> - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-monochrome-live-update-expected.html b/LayoutTests/fast/media/mq-monochrome-live-update-expected.html
new file mode 100644 (file)
index 0000000..9534302
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+<title>CSS4 media query test: monochrome.</title>
+<style type="text/css">
+p { color: black; }
+#a { color: green; }
+</style>
+</head>
+<body>
+  <p id="a"></p>
+  <p>Before was: rgb(0, 0, 0) - should be rgb(0, 0, 0)</p>
+  <p>After was: rgb(0, 128, 0) - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-monochrome-live-update.html b/LayoutTests/fast/media/mq-monochrome-live-update.html
new file mode 100644 (file)
index 0000000..835a728
--- /dev/null
@@ -0,0 +1,50 @@
+<html>
+<head>
+<title>CSS4 media query test: monochrome.</title>
+<style type="text/css">
+p { color: black; }
+
+@media (monochrome) {
+    #a { color: green; }
+}
+</style>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.simulateAccessibilitySettingsChangeNotification(function() {
+            uiController.uiScriptComplete("Done");
+        });
+    })();`
+}
+
+function runTest()
+{
+    if (!window.internals)
+        return;
+
+    var element = document.getElementById("a");
+
+    window.internals.settings.forcedDisplayIsMonochromeAccessibilityValue = "on";
+    document.getElementById("before").textContent = window.getComputedStyle(element).color;
+    if (testRunner.runUIScript) {
+        testRunner.runUIScript(getUIScript(), function(result) {
+            document.getElementById("after").textContent = window.getComputedStyle(element).color;
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.addEventListener("load", runTest, false);
+</script>
+</head>
+<body>
+  <p id="a"></p>
+  <p>Before was: <span id="before"></span> - should be rgb(0, 0, 0)</p>
+  <p>After was: <span id="after"></span> - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-prefers-reduced-motion-live-update-expected.html b/LayoutTests/fast/media/mq-prefers-reduced-motion-live-update-expected.html
new file mode 100644 (file)
index 0000000..a144fe7
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<head>
+<title>CSS4 media query test: prefers-reduced-motion.</title>
+<style type="text/css">
+p { color: black; }
+#a { color: green; }
+</style>
+</head>
+<body>
+  <p id="a"></p>
+  <p>Before was: rgb(0, 0, 0) - should be rgb(0, 0, 0)</p>
+  <p>After was: rgb(0, 128, 0) - should be rgb(0, 128, 0)</p>
+</body>
+</html>
diff --git a/LayoutTests/fast/media/mq-prefers-reduced-motion-live-update.html b/LayoutTests/fast/media/mq-prefers-reduced-motion-live-update.html
new file mode 100644 (file)
index 0000000..6add1dc
--- /dev/null
@@ -0,0 +1,50 @@
+<html>
+<head>
+<title>CSS4 media query test: prefers-reduced-motion.</title>
+<style type="text/css">
+p { color: black; }
+
+@media (prefers-reduced-motion) {
+    #a { color: green; }
+}
+</style>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+function getUIScript()
+{
+    return `
+    (function() {
+        uiController.simulateAccessibilitySettingsChangeNotification(function() {
+            uiController.uiScriptComplete("Done");
+        });
+    })();`
+}
+
+function runTest()
+{
+    if (!window.internals)
+        return;
+
+    var element = document.getElementById("a");
+
+    window.internals.settings.forcedPrefersReducedMotionAccessibilityValue = "on";
+    document.getElementById("before").textContent = window.getComputedStyle(element).color;
+    if (testRunner.runUIScript) {
+        testRunner.runUIScript(getUIScript(), function(result) {
+            document.getElementById("after").textContent = window.getComputedStyle(element).color;
+            testRunner.notifyDone();
+        });
+    }
+}
+
+window.addEventListener("load", runTest, false);
+</script>
+</head>
+<body>
+  <p id="a"></p>
+  <p>Before was: <span id="before"></span> - should be rgb(0, 0, 0)</p>
+  <p>After was: <span id="after"></span> - should be rgb(0, 128, 0)</p>
+</body>
+</html>
index b771e92..f221203 100644 (file)
@@ -11,6 +11,11 @@ fast/viewport/ios [ Pass ]
 scrollingcoordinator/ios [ Pass ]
 editing/selection/character-granularity-rect.html [ Pass ]
 
+fast/media/mq-inverted-colors-live-update.html [ Pass ]
+fast/media/mq-inverted-colors-live-update-in-subframes.html [ Pass ]
+fast/media/mq-monochrome-live-update.html [ Pass ]
+fast/media/mq-prefers-reduced-motion-live-update.html [ Pass ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////
index 3a7fb22..78bdc95 100644 (file)
@@ -14,6 +14,11 @@ fast/events/force-click-link-selection-behavior.html [ Pass ]
 fast/events/force-click-on-link-navigation.html [ Pass ]
 fast/events/force-click-text-selection-behavior.html [ Failure ]
 
+fast/media/mq-inverted-colors-live-update.html [ Pass ]
+fast/media/mq-inverted-colors-live-update-in-subframes.html [ Pass ]
+fast/media/mq-monochrome-live-update.html [ Pass ]
+fast/media/mq-prefers-reduced-motion-live-update.html [ Pass ]
+
 #//////////////////////////////////////////////////////////////////////////////////////////
 # End platform-specific directories.
 #//////////////////////////////////////////////////////////////////////////////////////////
index fd2ad89..27853bd 100644 (file)
@@ -1,3 +1,31 @@
+2016-11-18  Dean Jackson  <dino@apple.com>
+
+        AX: "(inverted-colors)" media query only matches on page reload; should match on change
+        https://bugs.webkit.org/show_bug.cgi?id=163564
+        <rdar://problem/28807350>
+
+        Reviewed by Simon Fraser.
+
+        Mark some media queries as responding to notifications that
+        system accessibility settings have changed. When Page gets told
+        that has happened, check if any of the results have changed.
+
+        Tests: fast/media/mq-inverted-colors-live-update.html
+               fast/media/mq-monochrome-live-update.html
+               fast/media/mq-prefers-reduced-motion-live-update.html
+
+        * css/MediaQueryEvaluator.cpp:
+        (WebCore::isAccessibilitySettingsDependent):
+        (WebCore::MediaQueryEvaluator::evaluate):
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::addAccessibilitySettingsDependentMediaQueryResult):
+        (WebCore::StyleResolver::hasMediaQueriesAffectedByAccessibilitySettingsChange):
+        * css/StyleResolver.h:
+        (WebCore::StyleResolver::hasAccessibilitySettingsDependentMediaQueries):
+        * page/Page.cpp:
+        (WebCore::Page::accessibilitySettingsDidChange):
+        * page/Page.h:
+
 2016-11-18  Anders Carlsson  <andersca@apple.com>
 
         Rename the 'other' Apple Pay Button type to 'donate'
index 2e71901..a860117 100644 (file)
@@ -63,6 +63,15 @@ enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
 typedef bool (*MediaQueryFunction)(CSSValue*, const CSSToLengthConversionData&, Frame&, MediaFeaturePrefix);
 typedef HashMap<AtomicStringImpl*, MediaQueryFunction> MediaQueryFunctionMap;
 
+static bool isAccessibilitySettingsDependent(const AtomicString& mediaFeature)
+{
+    return mediaFeature == MediaFeatureNames::invertedColors
+        || mediaFeature == MediaFeatureNames::maxMonochrome
+        || mediaFeature == MediaFeatureNames::minMonochrome
+        || mediaFeature == MediaFeatureNames::monochrome
+        || mediaFeature == MediaFeatureNames::prefersReducedMotion;
+}
+
 static bool isViewportDependent(const AtomicString& mediaFeature)
 {
     return mediaFeature == MediaFeatureNames::width
@@ -120,9 +129,9 @@ bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, StyleResolver*
 {
     auto& queries = querySet.queryVector();
     if (!queries.size())
-        return true; // empty query list evaluates to true
+        return true; // Empty query list evaluates to true.
 
-    // iterate over queries, stop if any of them eval to true (OR semantics)
+    // Iterate over queries, stop if any of them eval to true (OR semantics).
     bool result = false;
     for (size_t i = 0; i < queries.size() && !result; ++i) {
         auto& query = queries[i];
@@ -132,18 +141,19 @@ bool MediaQueryEvaluator::evaluate(const MediaQuerySet& querySet, StyleResolver*
 
         if (mediaTypeMatch(query.mediaType())) {
             auto& expressions = query.expressions();
-            // iterate through expressions, stop if any of them eval to false (AND semantics)
+            // Iterate through expressions, stop if any of them eval to false (AND semantics).
             size_t j = 0;
             for (; j < expressions.size(); ++j) {
                 bool expressionResult = evaluate(expressions[j]);
                 if (styleResolver && isViewportDependent(expressions[j].mediaFeature()))
                     styleResolver->addViewportDependentMediaQueryResult(expressions[j], expressionResult);
+                if (styleResolver && isAccessibilitySettingsDependent(expressions[j].mediaFeature()))
+                    styleResolver->addAccessibilitySettingsDependentMediaQueryResult(expressions[j], expressionResult);
                 if (!expressionResult)
                     break;
             }
 
-            // assume true if we are at the end of the list,
-            // otherwise assume false
+            // Assume true if we are at the end of the list, otherwise assume false.
             result = applyRestrictor(query.restrictor(), expressions.size() == j);
         } else
             result = applyRestrictor(query.restrictor(), false);
index 19a7037..91363c1 100644 (file)
@@ -1850,6 +1850,20 @@ bool StyleResolver::hasMediaQueriesAffectedByViewportChange() const
     return false;
 }
 
+void StyleResolver::addAccessibilitySettingsDependentMediaQueryResult(const MediaQueryExpression& expression, bool result)
+{
+    m_accessibilitySettingsDependentMediaQueryResults.append(MediaQueryResult { expression, result });
+}
+
+bool StyleResolver::hasMediaQueriesAffectedByAccessibilitySettingsChange() const
+{
+    for (auto& result : m_accessibilitySettingsDependentMediaQueryResults) {
+        if (m_mediaQueryEvaluator.evaluate(result.expression) != result.result)
+            return true;
+    }
+    return false;
+}
+
 static FilterOperation::OperationType filterOperationForType(CSSValueID type)
 {
     switch (type) {
index e91b561..e0d1362 100644 (file)
@@ -207,6 +207,10 @@ public:
     bool hasViewportDependentMediaQueries() const { return !m_viewportDependentMediaQueryResults.isEmpty(); }
     bool hasMediaQueriesAffectedByViewportChange() const;
 
+    void addAccessibilitySettingsDependentMediaQueryResult(const MediaQueryExpression&, bool result);
+    bool hasAccessibilitySettingsDependentMediaQueries() const { return !m_accessibilitySettingsDependentMediaQueryResults.isEmpty(); }
+    bool hasMediaQueriesAffectedByAccessibilitySettingsChange() const;
+
     void addKeyframeStyle(Ref<StyleRuleKeyframes>&&);
 
     bool checkRegionStyle(const Element* regionElement);
@@ -503,6 +507,7 @@ private:
     RenderStyle* m_overrideDocumentElementStyle { nullptr };
 
     Vector<MediaQueryResult> m_viewportDependentMediaQueryResults;
+    Vector<MediaQueryResult> m_accessibilitySettingsDependentMediaQueryResults;
 
 #if ENABLE(CSS_DEVICE_ADAPTATION)
     RefPtr<ViewportStyleResolver> m_viewportStyleResolver;
index f6d9149..ae96608 100644 (file)
@@ -2058,4 +2058,24 @@ void Page::setCaptionUserPreferencesStyleSheet(const String& styleSheet)
     invalidateInjectedStyleSheetCacheInAllFrames();
 }
 
+void Page::accessibilitySettingsDidChange()
+{
+    bool neededRecalc = false;
+
+    for (Frame* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (Document* document = frame->document()) {
+            auto* styleResolver = document->styleScope().resolverIfExists();
+            if (styleResolver && styleResolver->hasMediaQueriesAffectedByAccessibilitySettingsChange()) {
+                document->styleScope().didChangeStyleSheetEnvironment();
+                neededRecalc = true;
+                // FIXME: This instrumentation event is not strictly accurate since cached media query results do not persist across StyleResolver rebuilds.
+                InspectorInstrumentation::mediaQueryResultChanged(*document);
+            }
+        }
+    }
+
+    if (neededRecalc)
+        LOG(Layout, "hasMediaQueriesAffectedByAccessibilitySettingsChange, enqueueing style recalc");
+}
+
 } // namespace WebCore
index 23a359e..40f3cbf 100644 (file)
@@ -317,7 +317,9 @@ public:
 
     WEBCORE_EXPORT void setHorizontalScrollElasticity(ScrollElasticity);
     ScrollElasticity horizontalScrollElasticity() const { return static_cast<ScrollElasticity>(m_horizontalScrollElasticity); }
-    
+
+    WEBCORE_EXPORT void accessibilitySettingsDidChange();
+
     // Page and FrameView both store a Pagination value. Page::pagination() is set only by API,
     // and FrameView::pagination() is set only by CSS. Page::pagination() will affect all
     // FrameViews in the page cache, but FrameView::pagination() only affects the current
index 36b1f1b..444c3c6 100644 (file)
@@ -1,3 +1,37 @@
+2016-11-18  Dean Jackson  <dino@apple.com>
+
+        AX: "(inverted-colors)" media query only matches on page reload; should match on change
+        https://bugs.webkit.org/show_bug.cgi?id=163564
+        <rdar://problem/28807350>
+
+        Reviewed by Simon Fraser.
+
+        Listen for the appropriate notifications that accessibility settings
+        have changed. This is a single notification on macOS, which uses WebViewImpl,
+        and more fine-grained notifications on iOS, using WKWebView.
+
+        When we see the notification, send a message to the WebProcess which will
+        then tell the WebCore::Page.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _initializeWithConfiguration:]):
+        (-[WKWebView _accessibilitySettingsDidChange:]):
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (-[WKAccessibilitySettingsObserver initWithImpl:]):
+        (-[WKAccessibilitySettingsObserver dealloc]):
+        (-[WKAccessibilitySettingsObserver _settingsDidChange:]):
+        (WebKit::WebViewImpl::WebViewImpl):
+        (WebKit::WebViewImpl::accessibilitySettingsDidChange):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::accessibilitySettingsDidChange):
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::accessibilitySettingsDidChange):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2016-11-18  Jeremy Jones  <jeremyj@apple.com>
 
         USE WK_MAC_TBA for version number in _webViewRequestPointerLock:(WKWebView *)webView WK_API_AVAILABLE(macosx(10.12))
index 7f976fb..d74d42c 100644 (file)
@@ -540,6 +540,10 @@ static uint32_t convertSystemLayoutDirection(NSUserInterfaceLayoutDirection dire
     [center addObserver:self selector:@selector(_contentSizeCategoryDidChange:) name:UIContentSizeCategoryDidChangeNotification object:nil];
     _page->contentSizeCategoryDidChange([self _contentSizeCategory]);
 
+    [center addObserver:self selector:@selector(_accessibilitySettingsDidChange:) name:UIAccessibilityGrayscaleStatusDidChangeNotification object:nil];
+    [center addObserver:self selector:@selector(_accessibilitySettingsDidChange:) name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil];
+    [center addObserver:self selector:@selector(_accessibilitySettingsDidChange:) name:UIAccessibilityReduceMotionStatusDidChangeNotification object:nil];
+
     [[_configuration _contentProviderRegistry] addPage:*_page];
     _page->setForceAlwaysUserScalable([_configuration ignoresViewportScaleLimits]);
 #endif
@@ -2248,6 +2252,11 @@ static bool scrollViewCanScroll(UIScrollView *scrollView)
     return [[UIApplication sharedApplication] preferredContentSizeCategory];
 }
 
+- (void)_accessibilitySettingsDidChange:(NSNotification *)notification
+{
+    _page->accessibilitySettingsDidChange();
+}
+
 - (void)setAllowsBackForwardNavigationGestures:(BOOL)allowsBackForwardNavigationGestures
 {
     if (_allowsBackForwardNavigationGestures == allowsBackForwardNavigationGestures)
index ba79936..f7744cf 100644 (file)
@@ -43,6 +43,7 @@
 OBJC_CLASS NSImmediateActionGestureRecognizer;
 OBJC_CLASS NSTextInputContext;
 OBJC_CLASS NSView;
+OBJC_CLASS WKAccessibilitySettingsObserver;
 OBJC_CLASS WKBrowsingContextController;
 OBJC_CLASS WKEditorUndoTargetObjC;
 OBJC_CLASS WKFullScreenWindowController;
@@ -208,6 +209,8 @@ public:
     bool shouldDelayWindowOrderingForEvent(NSEvent *);
     bool windowResizeMouseLocationIsInVisibleScrollerThumb(CGPoint);
 
+    void accessibilitySettingsDidChange();
+
     // -[NSView mouseDownCanMoveWindow] returns YES when the NSView is transparent,
     // but we don't want a drag in the NSView to move the window, even if it's transparent.
     static bool mouseDownCanMoveWindow() { return false; }
@@ -631,6 +634,7 @@ private:
 #endif
 
     RetainPtr<WKWindowVisibilityObserver> m_windowVisibilityObserver;
+    RetainPtr<WKAccessibilitySettingsObserver> m_accessibilitySettingsObserver;
 
     bool m_shouldDeferViewInWindowChanges { false };
     bool m_viewInWindowChangeWasDeferred { false };
index 8202e32..971f72c 100644 (file)
@@ -122,6 +122,46 @@ SOFT_LINK_CONSTANT_MAY_FAIL(Lookup, LUNotificationPopoverWillClose, NSString *)
 - (BOOL)handleEventByKeyboardLayout:(NSEvent *)event;
 @end
 
+@interface WKAccessibilitySettingsObserver : NSObject {
+    WebKit::WebViewImpl *_impl;
+}
+
+- (instancetype)initWithImpl:(WebKit::WebViewImpl&)impl;
+@end
+
+@implementation WKAccessibilitySettingsObserver
+
+- (instancetype)initWithImpl:(WebKit::WebViewImpl&)impl
+{
+    self = [super init];
+    if (!self)
+        return nil;
+
+    _impl = &impl;
+
+    NSNotificationCenter* workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
+    [workspaceNotificationCenter addObserver:self selector:@selector(_settingsDidChange:) name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:nil];
+
+    return self;
+}
+
+- (void)dealloc
+{
+    NSNotificationCenter *workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
+    [workspaceNotificationCenter removeObserver:self name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:nil];
+
+    [super dealloc];
+}
+
+- (void)_settingsDidChange:(NSNotification *)notification
+{
+    WTFLogAlways("received notification");
+
+    _impl->accessibilitySettingsDidChange();
+}
+
+@end
+
 @interface WKWindowVisibilityObserver : NSObject {
     NSView *_view;
     WebKit::WebViewImpl *_impl;
@@ -134,7 +174,6 @@ SOFT_LINK_CONSTANT_MAY_FAIL(Lookup, LUNotificationPopoverWillClose, NSString *)
 - (void)startObservingLookupDismissal;
 @end
 
-
 @implementation WKWindowVisibilityObserver
 
 - (instancetype)initWithView:(NSView *)view impl:(WebKit::WebViewImpl&)impl
@@ -1180,6 +1219,7 @@ WebViewImpl::WebViewImpl(NSView <WebViewImplDelegate> *view, WKWebView *outerWeb
     , m_layoutStrategy([WKViewLayoutStrategy layoutStrategyWithPage:m_page view:m_view viewImpl:*this mode:kWKLayoutModeViewSize])
     , m_undoTarget(adoptNS([[WKEditorUndoTargetObjC alloc] init]))
     , m_windowVisibilityObserver(adoptNS([[WKWindowVisibilityObserver alloc] initWithView:view impl:*this]))
+    , m_accessibilitySettingsObserver(adoptNS([[WKAccessibilitySettingsObserver alloc] initWithImpl:*this]))
     , m_primaryTrackingArea(adoptNS([[NSTrackingArea alloc] initWithRect:m_view.frame options:trackingAreaOptions() owner:m_view userInfo:nil]))
 {
     static_cast<PageClientImpl&>(*m_pageClient).setImpl(*this);
@@ -1839,6 +1879,11 @@ bool WebViewImpl::mightBeginScrollWhileInactive()
     return false;
 }
 
+void WebViewImpl::accessibilitySettingsDidChange()
+{
+    m_page->accessibilitySettingsDidChange();
+}
+
 bool WebViewImpl::acceptsFirstMouse(NSEvent *event)
 {
     if (!mightBeginDragWhileInactive() && !mightBeginScrollWhileInactive())
index d812dd4..5adda01 100644 (file)
@@ -2603,6 +2603,14 @@ void WebPageProxy::setCustomDeviceScaleFactor(float customScaleFactor)
         m_drawingArea->deviceScaleFactorDidChange();
 }
 
+void WebPageProxy::accessibilitySettingsDidChange()
+{
+    if (!isValid())
+        return;
+
+    m_process->send(Messages::WebPage::AccessibilitySettingsDidChange(), m_pageID);
+}
+
 void WebPageProxy::setUseFixedLayout(bool fixed)
 {
     if (!isValid())
index 945220a..1ec8df1 100644 (file)
@@ -684,6 +684,7 @@ public:
     void setIntrinsicDeviceScaleFactor(float);
     void setCustomDeviceScaleFactor(float);
     void windowScreenDidChange(WebCore::PlatformDisplayID);
+    void accessibilitySettingsDidChange();
 
     void setUseFixedLayout(bool);
     void setFixedLayoutSize(const WebCore::IntSize&);
index f1f431e..fc988d0 100644 (file)
@@ -1674,6 +1674,11 @@ float WebPage::deviceScaleFactor() const
     return m_page->deviceScaleFactor();
 }
 
+void WebPage::accessibilitySettingsDidChange()
+{
+    m_page->accessibilitySettingsDidChange();
+}
+
 void WebPage::setUseFixedLayout(bool fixed)
 {
     // Do not overwrite current settings if initially setting it to false.
index 938e89e..dce6b0b 100644 (file)
@@ -391,6 +391,8 @@ public:
     void setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor);
     void windowScreenDidChange(uint32_t);
 
+    void accessibilitySettingsDidChange();
+
     void scalePage(double scale, const WebCore::IntPoint& origin);
     void scalePageInViewCoordinates(double scale, WebCore::IntPoint centerInViewCoordinates);
     double pageScaleFactor() const;
index 069bec6..9fcb8e3 100644 (file)
@@ -201,6 +201,8 @@ messages -> WebPage LegacyReceiver {
     SetTextZoomFactor(double zoomFactor)
     WindowScreenDidChange(uint32_t displayID)
 
+    AccessibilitySettingsDidChange()
+
     ScalePage(double scale, WebCore::IntPoint origin)
     ScalePageInViewCoordinates(double scale, WebCore::IntPoint centerInViewCoordinates)
     ScaleView(double scale)
index 549ca39..ff714af 100644 (file)
@@ -1,3 +1,29 @@
+2016-11-18  Dean Jackson  <dino@apple.com>
+
+        AX: "(inverted-colors)" media query only matches on page reload; should match on change
+        https://bugs.webkit.org/show_bug.cgi?id=163564
+        <rdar://problem/28807350>
+
+        Reviewed by Simon Fraser.
+
+        Add a UIScriptController method that tricks WebKit into thinking
+        it has received a notification that accessibility settings have
+        changed. Combined with our forced overrides, this allows us to
+        test if a page would react to the notifications.
+
+        * DumpRenderTree/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
+        * DumpRenderTree/mac/UIScriptControllerMac.mm:
+        (WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
+        * TestRunnerShared/UIScriptContext/Bindings/UIScriptController.idl:
+        * TestRunnerShared/UIScriptContext/UIScriptController.cpp:
+        (WTR::simulateAccessibilitySettingsChangeNotification):
+        * TestRunnerShared/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
+        * WebKitTestRunner/mac/UIScriptControllerMac.mm:
+        (WTR::UIScriptController::simulateAccessibilitySettingsChangeNotification):
+
 2016-11-18  Alex Christensen  <achristensen@webkit.org>
 
         Fix API test after r208902
index dfd87d2..3fcfe49 100644 (file)
@@ -63,6 +63,10 @@ void UIScriptController::zoomToScale(double scale, JSValueRef callback)
     });
 }
 
+void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef)
+{
+}
+
 double UIScriptController::zoomScale() const
 {
     return gWebScrollView.zoomScale;
index b7828e1..55db4ee 100644 (file)
@@ -64,6 +64,10 @@ void UIScriptController::zoomToScale(double scale, JSValueRef callback)
     });
 }
 
+void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef)
+{
+}
+
 JSObjectRef UIScriptController::contentsOfUserInterfaceItem(JSStringRef interfaceItem) const
 {
     return nullptr;
index 5106924..0ed40c0 100644 (file)
@@ -29,6 +29,8 @@ interface UIScriptController {
 
     void zoomToScale(double scale, object callback);
 
+    void simulateAccessibilitySettingsChangeNotification(object callback);
+
     // Interaction.
     // These functions post events asynchronously. The callback is fired when the events have been dispatched, but any
     // resulting behavior may also be asynchronous.
index dc942b1..27df59e 100644 (file)
@@ -56,6 +56,10 @@ JSClassRef UIScriptController::wrapperClass()
 void UIScriptController::doAsyncTask(JSValueRef)
 {
 }
+
+void simulateAccessibilitySettingsChangeNotification(JSValueRef)
+{
+}
 #endif
 
 void UIScriptController::setDidStartFormControlInteractionCallback(JSValueRef callback)
@@ -162,6 +166,10 @@ void UIScriptController::zoomToScale(double, JSValueRef)
 {
 }
 
+void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef)
+{
+}
+
 JSObjectRef UIScriptController::contentsOfUserInterfaceItem(JSStringRef interfaceItem) const
 {
     return nullptr;
index 820bcc2..e8d0f8c 100644 (file)
@@ -52,6 +52,8 @@ public:
     void doAsyncTask(JSValueRef callback);
     void zoomToScale(double scale, JSValueRef callback);
 
+    void simulateAccessibilitySettingsChangeNotification(JSValueRef callback);
+
     void touchDownAtPoint(long x, long y, long touchCount, JSValueRef callback);
     void liftUpAtPoint(long x, long y, long touchCount, JSValueRef callback);
     void singleTapAtPoint(long x, long y, JSValueRef callback);
index 8184b6d..994b6da 100644 (file)
@@ -68,6 +68,21 @@ void UIScriptController::zoomToScale(double scale, JSValueRef callback)
     }];
 }
 
+void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef callback)
+{
+    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
+
+    auto* webView = TestController::singleton().mainWebView()->platformView();
+    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+    [center postNotificationName:UIAccessibilityInvertColorsStatusDidChangeNotification object:webView];
+
+    [webView _doAfterNextPresentationUpdate: ^{
+        if (!m_context)
+            return;
+        m_context->asyncTaskComplete(callbackID);
+    }];
+}
+
 double UIScriptController::zoomScale() const
 {
     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()->platformView();
index a23b270..79be0c2 100644 (file)
@@ -90,6 +90,25 @@ void UIScriptController::zoomToScale(double scale, JSValueRef callback)
 #endif
 }
 
+void UIScriptController::simulateAccessibilitySettingsChangeNotification(JSValueRef callback)
+{
+#if WK_API_ENABLED
+    unsigned callbackID = m_context->prepareForAsyncTask(callback, CallbackTypeNonPersistent);
+
+    auto* webView = TestController::singleton().mainWebView()->platformView();
+    NSNotificationCenter *center = [[NSWorkspace sharedWorkspace] notificationCenter];
+    [center postNotificationName:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:webView];
+
+    [webView _doAfterNextPresentationUpdate: ^{
+        if (!m_context)
+            return;
+        m_context->asyncTaskComplete(callbackID);
+    }];
+#else
+    UNUSED_PARAM(callback);
+#endif
+}
+
 JSObjectRef UIScriptController::contentsOfUserInterfaceItem(JSStringRef interfaceItem) const
 {
 #if WK_API_ENABLED