[iOS] DOM click event may not be dispatched when page has :active style and <input...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Dec 2015 18:07:19 +0000 (18:07 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Dec 2015 18:07:19 +0000 (18:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144451
<rdar://problem/23099482>

Patch by Daniel Bates <dabates@apple.com> on 2015-12-14
Reviewed by Simon Fraser.

Source/WebCore:

Fixes an issue where a DOM click event is not dispatched to an element in a subframe on a page
that has a <input type="search"> and defines a CSS :active pseudo-class for the HTML body element.

On iOS we only dispatch a DOM click event if the content of the page does not change as part of
dispatching a DOM mousemove event at the tapped element as a means of providing a good user
experience on web pages that reveal or hide content based on mouse hover. Currently we consider
the content of the page to have changed if the visibility of any element on the page changes.
In particular we consider the content of the page to have changed if the visibility of a user
agent shadow DOM element changes (e.g. the search field cancel button). Instead we should only
consider visibility changes to the actual web page content and ignore visibility changes to
user agent shadow DOM elements.

Tests: fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html
       fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html
       fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html
       fast/forms/search/search-cancel-in-formerly-invisible-element.html
       fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html
       fast/forms/search/search-cancel-toggle-visibility-initially-visible.html

* style/StyleResolveTree.cpp:
(WebCore::Style::CheckForVisibilityChangeOnRecalcStyle::~CheckForVisibilityChangeOnRecalcStyle):
Ignore visibility changes to user agent shadow DOM elements.

LayoutTests:

Add a test to ensure that a DOM click event is dispatched to an element in a subframe on a page
with a search field and that specifies a CSS :active pseudo-class that changes the tap highlight
color.

Additionally, add tests to ensure we update the cancel button visibility whenever the visibility
of the search field changes.

* fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field-expected.txt: Added.
* fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html: Added.
* fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled-expected.html: Added.
* fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html: Added.
* fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly-expected.html: Added.
* fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html: Added.
* fast/forms/search/search-cancel-in-formerly-invisible-element-expected.html: Added.
* fast/forms/search/search-cancel-in-formerly-invisible-element.html: Added.
* fast/forms/search/search-cancel-toggle-visibility-initially-hidden-expected.html: Added.
* fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html: Added.
* fast/forms/search/search-cancel-toggle-visibility-initially-visible-expected.html: Added.
* fast/forms/search/search-cancel-toggle-visibility-initially-visible.html: Added.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled-expected.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly-expected.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-in-formerly-invisible-element-expected.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-in-formerly-invisible-element.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-hidden-expected.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-visible-expected.html [new file with mode: 0644]
LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-visible.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/style/StyleResolveTree.cpp

index 3dd1cfe..c0d8031 100644 (file)
@@ -1,3 +1,31 @@
+2015-12-14  Daniel Bates  <dabates@apple.com>
+
+        [iOS] DOM click event may not be dispatched when page has :active style and <input type="search">
+        https://bugs.webkit.org/show_bug.cgi?id=144451
+        <rdar://problem/23099482>
+
+        Reviewed by Simon Fraser.
+
+        Add a test to ensure that a DOM click event is dispatched to an element in a subframe on a page
+        with a search field and that specifies a CSS :active pseudo-class that changes the tap highlight
+        color.
+
+        Additionally, add tests to ensure we update the cancel button visibility whenever the visibility
+        of the search field changes.
+
+        * fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field-expected.txt: Added.
+        * fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html: Added.
+        * fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled-expected.html: Added.
+        * fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html: Added.
+        * fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly-expected.html: Added.
+        * fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html: Added.
+        * fast/forms/search/search-cancel-in-formerly-invisible-element-expected.html: Added.
+        * fast/forms/search/search-cancel-in-formerly-invisible-element.html: Added.
+        * fast/forms/search/search-cancel-toggle-visibility-initially-hidden-expected.html: Added.
+        * fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html: Added.
+        * fast/forms/search/search-cancel-toggle-visibility-initially-visible-expected.html: Added.
+        * fast/forms/search/search-cancel-toggle-visibility-initially-visible.html: Added.
+
 2015-12-14  Chris Dumez  <cdumez@apple.com>
 
         Roll out r193974 and follow-up fixes as it caused JSC crashes
diff --git a/LayoutTests/fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field-expected.txt b/LayoutTests/fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field-expected.txt
new file mode 100644 (file)
index 0000000..05e8e6a
--- /dev/null
@@ -0,0 +1,9 @@
+Test that an element, with an onclick handler and an empty ontouchstart attribute, in an <iframe> on a page with a search field and specifies an :active pseudo-class for <body> receives a DOM click event when tapped. To run this test by hand, click the blue square below.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS clicked blue square
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html b/LayoutTests/fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html
new file mode 100644 (file)
index 0000000..4661781
--- /dev/null
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+<style>
+body:active {
+    /* Must be non-empty. */
+    -webkit-tap-highlight-color: yellow;
+}
+</style>
+<script>
+window.jsTestIsAsync = true;
+
+function notifyPass()
+{
+    testPassed("clicked blue square");
+
+    var testContainer = document.getElementById("test-container");
+    testContainer.parentNode.removeChild(testContainer);
+    finishJSTest();
+}
+
+function runTest()
+{
+    if (!window.testRunner)
+        return;
+    var iframe = document.getElementById("iframe");
+    var square = iframe.contentDocument.getElementById("square");
+    var x = iframe.offsetLeft + square.offsetLeft + Math.floor(square.offsetWidth / 2);
+    var y = iframe.offsetTop + square.offsetTop + Math.floor(square.offsetHeight / 2);
+    if (testRunner.runUIScript && window.TouchEvent)
+        testRunner.runUIScript("(function() { uiController.singleTapAtPoint(" + x + ", " + y + "); })()");
+    else if (window.eventSender) {
+        eventSender.mouseMoveTo(x, y);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+}
+</script>
+</head>
+<body>
+<div id="description"></div>
+<div id="test-container">
+    <p><input type="search" placeholder="Do not click me"></p>
+    <iframe id="iframe" width="128" height="128" onload="runTest()" srcdoc='
+        <style>
+            body {
+                margin: 0;
+                padding 0;
+            }
+            #square {
+                -webkit-box-align: center;
+                -webkit-box-pack: center;
+                -webkit-user-select: none;
+                background-color: blue;
+                color: white;
+                cursor: pointer;
+                display: -webkit-box;
+                height: 128px;
+                width: 128px;
+            }
+        </style>
+        <div id="square" ontouchstart="" onclick="window.parent.notifyPass()">Click me</div><!-- Intentionally empty attribute ontouchstart. -->
+    '></iframe>
+</div>
+<div id="console"></div>
+<script>
+description("Test that an element, with an onclick handler and an empty ontouchstart attribute, in an &lt;iframe&gt; on a page with a search field and specifies an <code>:active</code> pseudo-class for &lt;body&gt; receives a DOM click event when tapped. To run this test by hand, click the blue square below.");
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled-expected.html b/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled-expected.html
new file mode 100644 (file)
index 0000000..a39b542
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This tests that the search cancel button renders when the field becomes disabled (no change).</p>
+<input type="search" value="search" disabled>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html b/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html
new file mode 100644 (file)
index 0000000..6dfe5f3
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This tests that the search cancel button renders when the field becomes disabled (no change).</p>
+<input type="search" id="search" value="search">
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+var search = document.getElementById("search");
+
+function makeFieldDisabledAndNotifyDone()
+{
+    search.disabled = true;
+    if (window.internals)
+        internals.updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks();
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+window.setTimeout(makeFieldDisabledAndNotifyDone, 0);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly-expected.html b/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly-expected.html
new file mode 100644 (file)
index 0000000..8053fa2
--- /dev/null
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This tests that the search cancel button renders when the field becomes read only (no change).</p>
+<input type="search" value="search" readonly>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html b/LayoutTests/fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html
new file mode 100644 (file)
index 0000000..072a534
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<body>
+<p>This tests that the search cancel button renders when the field becomes read only (no change).</p>
+<input type="search" id="search" value="search">
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+
+var search = document.getElementById("search");
+
+function makeFieldReadOnlyAndNotifyDone()
+{
+    search.readOnly = true;
+    if (window.internals)
+        internals.updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks();
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+window.setTimeout(makeFieldReadOnlyAndNotifyDone, 0);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-in-formerly-invisible-element-expected.html b/LayoutTests/fast/forms/search/search-cancel-in-formerly-invisible-element-expected.html
new file mode 100644 (file)
index 0000000..9e24e69
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type="search" value="search">
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-in-formerly-invisible-element.html b/LayoutTests/fast/forms/search/search-cancel-in-formerly-invisible-element.html
new file mode 100644 (file)
index 0000000..8ccba3a
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type="search" id="search" value="search" style="visibility: hidden">
+<script>
+document.getElementById("search").style.visibility = "visible";
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-hidden-expected.html b/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-hidden-expected.html
new file mode 100644 (file)
index 0000000..7496b0e
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.width-200px {
+    width: 200px;
+}
+</style>
+<body>
+<p>Tests that the search cancel button is not shown after changing the visibility of &lt;input type=&quot;search&quot;&gt; from hidden to visible to hidden. This test passed if you do not see the search cancel button in the blue outlined box (below).</p>
+<div class="width-200px" style="border: 1px solid blue">
+    <input type="search" value="search" class="width-200px" style="visibility: hidden">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html b/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html
new file mode 100644 (file)
index 0000000..78e16e7
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.width-200px {
+    width: 200px;
+}
+</style>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+</script>
+</head>
+<body>
+<p>Tests that the search cancel button is not shown after changing the visibility of &lt;input type=&quot;search&quot;&gt; from hidden to visible to hidden. This test passed if you do not see the search cancel button in the blue outlined box (below).</p>
+<div class="width-200px" style="border: 1px solid blue">
+    <input type="search" id="search" value="search" class="width-200px" style="visibility: hidden">
+</div>
+<script>
+var search = document.getElementById("search");
+search.style.visibility = "visible";
+function done() {
+    search.style.visibility = "hidden";
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+window.setTimeout(done, 0);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-visible-expected.html b/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-visible-expected.html
new file mode 100644 (file)
index 0000000..83d31e2
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.width-200px {
+    width: 200px;
+}
+</style>
+<body>
+<p>Tests that the search cancel button is not shown after changing the visibility of &lt;input type=&quot;search&quot;&gt; from visible to hidden to visible. This test passed if you see the search cancel button in the blue outlined box (below).</p>
+<div class="width-200px" style="border: 1px solid blue">
+    <input type="search" value="search" class="width-200px">
+</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-visible.html b/LayoutTests/fast/forms/search/search-cancel-toggle-visibility-initially-visible.html
new file mode 100644 (file)
index 0000000..3349b0e
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.width-200px {
+    width: 200px;
+}
+</style>
+<script>
+if (window.testRunner)
+    testRunner.waitUntilDone();
+</script>
+</head>
+<body>
+<p>Tests that the search cancel button is not shown after changing the visibility of &lt;input type=&quot;search&quot;&gt; from visible to hidden to visible. This test passed if you see the search cancel button in the blue outlined box (below).</p>
+<div class="width-200px" style="border: 1px solid blue">
+    <input type="search" id="search" value="search" class="width-200px">
+</div>
+<script>
+var search = document.getElementById("search");
+search.style.visibility = "hidden";
+function done() {
+    search.style.visibility = "visible";
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+window.setTimeout(done, 0);
+</script>
+</body>
+</html>
index 1c734c1..ffe33b2 100644 (file)
@@ -1,3 +1,34 @@
+2015-12-14  Daniel Bates  <dabates@apple.com>
+
+        [iOS] DOM click event may not be dispatched when page has :active style and <input type="search">
+        https://bugs.webkit.org/show_bug.cgi?id=144451
+        <rdar://problem/23099482>
+
+        Reviewed by Simon Fraser.
+
+        Fixes an issue where a DOM click event is not dispatched to an element in a subframe on a page
+        that has a <input type="search"> and defines a CSS :active pseudo-class for the HTML body element.
+
+        On iOS we only dispatch a DOM click event if the content of the page does not change as part of
+        dispatching a DOM mousemove event at the tapped element as a means of providing a good user
+        experience on web pages that reveal or hide content based on mouse hover. Currently we consider
+        the content of the page to have changed if the visibility of any element on the page changes.
+        In particular we consider the content of the page to have changed if the visibility of a user
+        agent shadow DOM element changes (e.g. the search field cancel button). Instead we should only
+        consider visibility changes to the actual web page content and ignore visibility changes to
+        user agent shadow DOM elements.
+
+        Tests: fast/events/can-click-element-on-page-with-active-pseudo-class-and-search-field.html
+               fast/forms/search/search-cancel-button-visible-when-input-becomes-disabled.html
+               fast/forms/search/search-cancel-button-visible-when-input-becomes-readonly.html
+               fast/forms/search/search-cancel-in-formerly-invisible-element.html
+               fast/forms/search/search-cancel-toggle-visibility-initially-hidden.html
+               fast/forms/search/search-cancel-toggle-visibility-initially-visible.html
+
+        * style/StyleResolveTree.cpp:
+        (WebCore::Style::CheckForVisibilityChangeOnRecalcStyle::~CheckForVisibilityChangeOnRecalcStyle):
+        Ignore visibility changes to user agent shadow DOM elements.
+
 2015-12-14  Youenn Fablet  <youenn.fablet@crf.canon.fr>
 
         [Streams API] Directly use @then as much as possible
index e56c211..5c98443 100644 (file)
@@ -757,6 +757,8 @@ public:
     {
         if (!WKObservingContentChanges())
             return;
+        if (m_element->isInUserAgentShadowTree())
+            return;
         RenderStyle* style = m_element->renderStyle();
         if (!style)
             return;