- 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();