Title: [167684] trunk
Revision
167684
Author
[email protected]
Date
2014-04-22 14:55:59 -0700 (Tue, 22 Apr 2014)

Log Message

REGRESSION (r151839): Subframe keeps getting mousemove events with the same coordinates after hiding a hovered element.
<https://webkit.org/b/131974>
<rdar://problem/15907469>

Source/WebCore:
When the currently hovered element disappears as a result of style recalc,
we send a fake mousemove event to the page, to see if anything newly added
should become hovered.

The faking mechanism lives in EventHandler and simply synthesizes a new
mousemove event using the last seen mouse location.

The problem here is that we were sending this fake mousemove event to the
subframe where the hovered element lived. Since subframes aren't kept up
to date on recent mouse locations, this could cause some strange behavior
where a subframe would dispatch mousemove events with stale coordinates.

The solution is to always dispatch fake mousemove events from the main
frame's event handler. This is how real event delivery happens, and hit
testing will then find the appropriate subframe, if any.

Reviewed by Benjamin Poulain.

Test: fast/events/ghostly-mousemoves-in-subframe.html

* dom/Document.cpp:
(WebCore::Document::recalcStyle):

LayoutTests:
Add a test that triggers the weirdness where removing the renderer from
a hovered element in a subframe would leave the subframe's EventHandler
in a state where it could dispatch fake mousemove events with stale
coordinates in response to style recalc.

Note that the final 500ms delay is because fake mousemove events are
sent on 250ms delay timers so we need to give it some time to catch up.

Reviewed by Benjamin Poulain.

* fast/events/ghostly-mousemoves-in-subframe-expected.txt: Added.
* fast/events/ghostly-mousemoves-in-subframe.html: Added.
* platform/mac-wk2/fast/events/resources/ghostly-mousemoves-in-subframe-the-actual-subframe.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (167683 => 167684)


--- trunk/LayoutTests/ChangeLog	2014-04-22 21:07:11 UTC (rev 167683)
+++ trunk/LayoutTests/ChangeLog	2014-04-22 21:55:59 UTC (rev 167684)
@@ -1,3 +1,23 @@
+2014-04-22  Andreas Kling  <[email protected]>
+
+        REGRESSION (r151839): Subframe keeps getting mousemove events with the same coordinates after hiding a hovered element.
+        <https://webkit.org/b/131974>
+        <rdar://problem/15907469>
+
+        Add a test that triggers the weirdness where removing the renderer from
+        a hovered element in a subframe would leave the subframe's EventHandler
+        in a state where it could dispatch fake mousemove events with stale
+        coordinates in response to style recalc.
+
+        Note that the final 500ms delay is because fake mousemove events are
+        sent on 250ms delay timers so we need to give it some time to catch up.
+
+        Reviewed by Benjamin Poulain.
+
+        * fast/events/ghostly-mousemoves-in-subframe-expected.txt: Added.
+        * fast/events/ghostly-mousemoves-in-subframe.html: Added.
+        * platform/mac-wk2/fast/events/resources/ghostly-mousemoves-in-subframe-the-actual-subframe.html: Added.
+
 2014-04-22  Tim Horton  <[email protected]>
 
         REGRESSION: JSRegress's js/slow-stress/new-spread.html fails sometimes

Added: trunk/LayoutTests/fast/events/ghostly-mousemoves-in-subframe.html (0 => 167684)


--- trunk/LayoutTests/fast/events/ghostly-mousemoves-in-subframe.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/ghostly-mousemoves-in-subframe.html	2014-04-22 21:55:59 UTC (rev 167684)
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html id="main_frame">
+<head>
+<meta charset="utf-8">
+<script src=""
+<style>
+#subframe {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 200px;
+    height: 200px;
+    background: white;
+}
+
+#overlapping_div_in_main_frame {
+    position: absolute;
+    background: black;
+    top: 0;
+    left: 0;
+    height: 50px;
+    width: 50px;
+    display: none;
+    z-index: 10;
+}
+</style>
+</head>
+<body>
+<iframe id="subframe" src=""
+<div id="overlapping_div_in_main_frame"></div>
+<script>
+
+description("Test for http://webkit.org/b/131974 REGRESSION (r151839): Subframe keeps getting mousemove events with the same coordinates after hiding a hovered element.");
+var jsTestIsAsync = true;
+
+function logEvent(e) {
+    debug(e.target.id + " got " + event.type + " at " + event.x + "," + event.y);
+}
+
+window._onload_ = function() {
+    window._onclick_ = function(event) {
+        logEvent(event);
+
+        var clickable_div_in_subframe = document.querySelector("iframe").contentDocument.querySelector("#clickable_div_in_subframe");
+        clickable_div_in_subframe.style.display = "none";
+        clickable_div_in_subframe.clientHeight;
+        clickable_div_in_subframe.style.display = "block";
+        clickable_div_in_subframe.clientHeight;
+    };
+
+    if (!window.eventSender) {
+        debug("This test requires eventSender from the WebKit layout test internals.");
+        return;
+    }
+
+    // Move the mouse over clickable_div_in_subframe so it becomes the subframe document's hovered element.
+    eventSender.mouseMoveTo(15, 15);
+    setTimeout(function() {
+        // Fire the subframe's clickable_div_in_subframe.onclick handler.
+        // This will cause a overlapping_div_in_main_frame to overlap the currently hovered element in the subframe.
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+        setTimeout(function() {
+            // Jiggle the mouse inside the newly hovered element a bit.
+            eventSender.mouseMoveTo(16, 16);
+            setTimeout(function() {
+                eventSender.mouseMoveTo(400, 400);
+                setTimeout(function() {
+                    // Cause a click in the main frame, so the above window.onclick handler will run,
+                    // killing and then recreating clickable_div_in_subframe's renderer.
+                    eventSender.mouseDown();
+                    eventSender.mouseUp();
+                    setTimeout(function() {
+                        finishJSTest();
+                    }, 500);
+                }, 0);
+            }, 0);
+        }, 0);
+    }, 0);
+};
+
+window._onmousemove_ = function(event) {
+    logEvent(event);
+};
+
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/fast/events/resources/ghostly-mousemoves-in-subframe-the-actual-subframe.html (0 => 167684)


--- trunk/LayoutTests/fast/events/resources/ghostly-mousemoves-in-subframe-the-actual-subframe.html	                        (rev 0)
+++ trunk/LayoutTests/fast/events/resources/ghostly-mousemoves-in-subframe-the-actual-subframe.html	2014-04-22 21:55:59 UTC (rev 167684)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <div id="clickable_div_in_subframe">beautiful brown eyes</div>
+</body>
+<head>
+    <script>
+        function debug(s) {
+            top.document.querySelector("#console").innerText += s + "\n";
+        }
+
+        function logEvent(e) {
+            debug(e.target.id + " got " + event.type + " at " + event.x + "," + event.y);
+        }
+
+        window._onload_ = function() {
+            var clickable_div_in_subframe = document.querySelector("#clickable_div_in_subframe");
+
+            clickable_div_in_subframe._onmousemove_ = function(event) {
+                logEvent(event);
+            };
+
+            clickable_div_in_subframe._onmouseover_= function(event) {
+                logEvent(event);
+            };
+
+            clickable_div_in_subframe._onclick_ = function(event) {
+                logEvent(event);
+
+                var overlapping_div_in_main_frame = top.document.querySelector("#overlapping_div_in_main_frame");
+
+                // Give overlapping_div_in_main_frame a renderer. It should now be right under the cursor.
+                overlapping_div_in_main_frame.style.display = "block";
+
+                // Force clickable_div_in_subframe to lose its renderer.
+                this.style.display = "none";
+                this.clientHeight;
+
+                // Force clickable_div_in_subframe to gain a new renderer.
+                this.style.display = "block";
+                this.clientHeight;
+            };
+        };
+    </script>
+</head>
+</html>

Added: trunk/LayoutTests/platform/mac-wk2/fast/events/ghostly-mousemoves-in-subframe-expected.txt (0 => 167684)


--- trunk/LayoutTests/platform/mac-wk2/fast/events/ghostly-mousemoves-in-subframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac-wk2/fast/events/ghostly-mousemoves-in-subframe-expected.txt	2014-04-22 21:55:59 UTC (rev 167684)
@@ -0,0 +1,17 @@
+Test for http://webkit.org/b/131974 REGRESSION (r151839): Subframe keeps getting mousemove events with the same coordinates after hiding a hovered element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+clickable_div_in_subframe got mouseover at 13,13
+clickable_div_in_subframe got mousemove at 13,13
+clickable_div_in_subframe got click at 13,13
+clickable_div_in_subframe got mousemove at 14,14
+overlapping_div_in_main_frame got mousemove at 16,16
+main_frame got mousemove at 400,400
+main_frame got click at 400,400
+main_frame got mousemove at 400,400
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Modified: trunk/Source/WebCore/ChangeLog (167683 => 167684)


--- trunk/Source/WebCore/ChangeLog	2014-04-22 21:07:11 UTC (rev 167683)
+++ trunk/Source/WebCore/ChangeLog	2014-04-22 21:55:59 UTC (rev 167684)
@@ -1,3 +1,32 @@
+2014-04-22  Andreas Kling  <[email protected]>
+
+        REGRESSION (r151839): Subframe keeps getting mousemove events with the same coordinates after hiding a hovered element.
+        <https://webkit.org/b/131974>
+        <rdar://problem/15907469>
+
+        When the currently hovered element disappears as a result of style recalc,
+        we send a fake mousemove event to the page, to see if anything newly added
+        should become hovered.
+
+        The faking mechanism lives in EventHandler and simply synthesizes a new
+        mousemove event using the last seen mouse location.
+
+        The problem here is that we were sending this fake mousemove event to the
+        subframe where the hovered element lived. Since subframes aren't kept up
+        to date on recent mouse locations, this could cause some strange behavior
+        where a subframe would dispatch mousemove events with stale coordinates.
+
+        The solution is to always dispatch fake mousemove events from the main
+        frame's event handler. This is how real event delivery happens, and hit
+        testing will then find the appropriate subframe, if any.
+
+        Reviewed by Benjamin Poulain.
+
+        Test: fast/events/ghostly-mousemoves-in-subframe.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::recalcStyle):
+
 2014-04-22  Myles C. Maxfield  <[email protected]>
 
         [OS X] Glyph spacing for system fonts may be incorrect

Modified: trunk/Source/WebCore/dom/Document.cpp (167683 => 167684)


--- trunk/Source/WebCore/dom/Document.cpp	2014-04-22 21:07:11 UTC (rev 167683)
+++ trunk/Source/WebCore/dom/Document.cpp	2014-04-22 21:55:59 UTC (rev 167684)
@@ -1794,7 +1794,7 @@
     // detached (for example, by setting display:none in the :hover style), schedule another mouseMove event
     // to check if any other elements ended up under the mouse pointer due to re-layout.
     if (m_hoveredElement && !m_hoveredElement->renderer())
-        frameView.frame().eventHandler().dispatchFakeMouseMoveEventSoon();
+        frameView.frame().mainFrame().eventHandler().dispatchFakeMouseMoveEventSoon();
 
     // Style change may reset the focus, e.g. display: none, visibility: hidden.
     resetHiddenFocusElementSoon();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to