<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.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@167684
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2014-04-22 Andreas Kling <akling@apple.com>
+
+ 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 <timothy_horton@apple.com>
REGRESSION: JSRegress's js/slow-stress/new-spread.html fails sometimes
--- /dev/null
+<!DOCTYPE html>
+<html id="main_frame">
+<head>
+<meta charset="utf-8">
+<script src="../../resources/js-test-pre.js"></script>
+<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="resources/ghostly-mousemoves-in-subframe-the-actual-subframe.html"></iframe>
+<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="../../resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+<!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>
--- /dev/null
+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
+
+2014-04-22 Andreas Kling <akling@apple.com>
+
+ 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 <mmaxfield@apple.com>
[OS X] Glyph spacing for system fonts may be incorrect
// 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();