Title: [188920] trunk
Revision
188920
Author
[email protected]
Date
2015-08-25 11:03:00 -0700 (Tue, 25 Aug 2015)

Log Message

Wheel events stop propagating when target element is removed from DOM
https://bugs.webkit.org/show_bug.cgi?id=148384
<rdar://problem/19732211>

Reviewed by David Hyatt.

Source/WebCore:

Tested by tiled-drawing/scrolling/latched-to-deleted-node.html

We need to reset our latching state if the targeted node is removed from the DOM.
Add a check in 'platformPrepareForWheelEvents' that checks if the expected latching
target node was already removed from the DOM. If it was, we should not send events
to it, and should reset latching state so we can attach to the next relevant node.

* dom/Element.cpp:
(WebCore::Element::removedFrom): Remove any latched wheel event state objects that
match the current element.
* page/MainFrame.cpp:
(WebCore::MainFrame::removeLatchingStateForTarget): Remove any latched wheel event
state structures that match the passed wheel event target.
* page/MainFrame.h:

LayoutTests:

* tiled-drawing/scrolling/latched-to-deleted-node-expected.txt: Added.
* tiled-drawing/scrolling/latched-to-deleted-node.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (188919 => 188920)


--- trunk/LayoutTests/ChangeLog	2015-08-25 18:01:58 UTC (rev 188919)
+++ trunk/LayoutTests/ChangeLog	2015-08-25 18:03:00 UTC (rev 188920)
@@ -1,3 +1,14 @@
+2015-08-24  Brent Fulgham  <[email protected]>
+
+        Wheel events stop propagating when target element is removed from DOM
+        https://bugs.webkit.org/show_bug.cgi?id=148384
+        <rdar://problem/19732211>
+
+        Reviewed by David Hyatt.
+
+        * tiled-drawing/scrolling/latched-to-deleted-node-expected.txt: Added.
+        * tiled-drawing/scrolling/latched-to-deleted-node.html: Added.
+
 2015-08-25  Chris Dumez  <[email protected]>
 
         compareDocumentPosition() should report PRECEDING or FOLLOWING information even if nodes are disconnected

Added: trunk/LayoutTests/tiled-drawing/scrolling/latched-to-deleted-node-expected.txt (0 => 188920)


--- trunk/LayoutTests/tiled-drawing/scrolling/latched-to-deleted-node-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/latched-to-deleted-node-expected.txt	2015-08-25 18:03:00 UTC (rev 188920)
@@ -0,0 +1,18 @@
+Container
+
+After moving 40px up or down we remove the initial target element of wheel event from
+the dom. In safari this causes the wheel event to stop firing on the current frame, but it
+then starts firing on the parent frame.
+
+Tests that iframe doesn't consume wheel events when scrolling a select in an iframe.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Removed the target element
+PASS Page did not scroll
+PASS div continued scrolling after target element was deleted.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/tiled-drawing/scrolling/latched-to-deleted-node.html (0 => 188920)


--- trunk/LayoutTests/tiled-drawing/scrolling/latched-to-deleted-node.html	                        (rev 0)
+++ trunk/LayoutTests/tiled-drawing/scrolling/latched-to-deleted-node.html	2015-08-25 18:03:00 UTC (rev 188920)
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<style>
+	#pane {
+      display:inline-block;
+	  width:200px;
+	  height:500px;
+	}
+	#boxup {
+	  position: absolute;
+	  top:0px;
+	  width:200px;
+	  height:230px;
+	  background-color: #000;
+	  opacity:.4;
+	}
+	#boxdown {
+	  position: absolute;
+	  top:270px;
+	  width:200px;
+	  height:230px;
+	  background-color: #000;
+	  opacity:.4;
+	}
+	#objectBack {
+	  position: absolute;
+	  top:200px;
+	  width:200px;
+	  height:100px;
+	  background-color: #6c6;
+	}
+	#targetElement {
+	  position: absolute;
+	  top:30px;
+	  width:200px;
+	  height:40px;
+	  background-color: #c66;
+	}
+	</style>
+<script src=""
+</head>
+<body _onload_="setupTopLevel();">
+<script>
+window.jsTestIsAsync = true;
+
+var pageScrollPositionBeforeGesture;
+var divElement;
+var divScrollPositionBeforeGesture;
+
+var deleteThreshhold = 40;
+
+function locationInWindowCoordinates(element)
+{
+    var position = {};
+    position.x = element.offsetLeft;
+    position.y = element.offsetTop;
+
+    while (element.offsetParent) {
+        position.x = position.x + element.offsetParent.offsetLeft;
+        position.y = position.y + element.offsetParent.offsetTop;
+        if (element == document.getElementsByTagName("body")[0])
+            break;
+
+        element = element.offsetParent;
+    }
+
+    return position;
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+	var objectBack = document.getElementById("objectBack");
+	var targetElement = document.getElementById("targetElement");
+	var inIFrame = window.parent !== window;
+	var pos = 0;
+	
+	
+	document.addEventListener("wheel", function(event) {
+		pos = pos - event.deltaY ;
+		move(objectBack, pos);
+		if (Math.abs(pos) > deleteThreshhold) {
+			// don't remove it twice
+			if (targetElement.parentNode) {
+				var parent = targetElement.parentNode;
+				parent.removeChild(targetElement);
+                testPassed("Removed the target element");
+			}
+		}
+		event.preventDefault();
+	});
+	
+	// Setup
+    targetElement.innerHTML = "Put cursor here. Scroll up/down";
+
+	function move(element, pos) {
+		element.style.transform = "translateY(" + pos + "px)";
+    }
+});	
+
+function checkForScroll()
+{
+    var pageScrollPositionAfterGesture = document.body.scrollTop;
+
+    // The page should not have scrolled
+    if (pageScrollPositionBeforeGesture != pageScrollPositionAfterGesture)
+        testFailed("Page received scroll events, when it should not have. Expected " + pageScrollPositionBeforeGesture + ", but got " + pageScrollPositionAfterGesture);
+    else
+        testPassed("Page did not scroll");
+
+    var divScrollPositionAfterGesture = divElement.getBoundingClientRect().top;
+
+    // The div should have continued moving after the element was deleted
+    if (divScrollPositionAfterGesture > (divScrollPositionBeforeGesture - deleteThreshhold - 10))
+        testFailed("div did not scroll to proper location. Expected " + divScrollPositionBeforeGesture + ", but got " + divScrollPositionAfterGesture);
+    else
+        testPassed("div continued scrolling after target element was deleted.");
+
+    finishJSTest();
+}
+
+function scrollTest()
+{
+    pageScrollPositionBeforeGesture = document.body.scrollTop;
+
+    divElement = document.getElementById('objectBack');
+
+    divScrollPositionBeforeGesture = divElement.getBoundingClientRect().top;
+
+    var windowPosition = locationInWindowCoordinates(divElement);
+
+    var startPosX = windowPosition.x + 0.5 * divElement.clientWidth;
+    var startPosY = windowPosition.y + 0.5 * divElement.clientHeight;
+    
+    eventSender.mouseMoveTo(startPosX, startPosY);
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'began', 'none');
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -5, 'changed', 'none');
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -5, 'changed', 'none');
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'ended', 'none');
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'none', 'begin');
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'none', 'continue');
+    eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'none', 'end');
+    eventSender.callAfterScrollingCompletes(checkForScroll);
+}
+
+function setupTopLevel()
+{
+    if (window.eventSender) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+
+        eventSender.monitorWheelEvents();
+        setTimeout(scrollTest, 0);
+    } else {
+        var messageLocation = document.getElementById('parent');
+        var message = document.createElement('div');
+        message.innerHTML = "<p>This test is better run under DumpRenderTree. To manually test it, place the mouse pointer<br/>"
+            + "at the top of the page, and then use the mouse wheel or a two-finger swipe to scroll the<br/>"
+            + "down past the iframe.<br/><br/>"
+            + "The iframe should not scroll.</p>";
+        messageLocation.appendChild(message);
+    }
+}
+</script>
+<div id="parent" style="height: 2000px;">
+    <div id="pane">
+    	<h3>Container</h3>
+    	<div id="objectBack"><div id="targetElement"></div></div>
+    	<div id="boxup"></div>
+    	<div id="boxdown"></div>
+    </div>
+    <p class="description">After moving 40px up or down we remove the initial target element of wheel event from<br/>
+        the dom. In safari this causes the wheel event to stop firing on the current frame, but it<br/>
+        then starts firing on the parent frame.</p>
+</div>
+<div id="console"></div>
+<script>
+description("Tests that iframe doesn't consume wheel events when scrolling a select in an iframe.");
+</script>
+<script src=""
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (188919 => 188920)


--- trunk/Source/WebCore/ChangeLog	2015-08-25 18:01:58 UTC (rev 188919)
+++ trunk/Source/WebCore/ChangeLog	2015-08-25 18:03:00 UTC (rev 188920)
@@ -1,3 +1,26 @@
+2015-08-24  Brent Fulgham  <[email protected]>
+
+        Wheel events stop propagating when target element is removed from DOM
+        https://bugs.webkit.org/show_bug.cgi?id=148384
+        <rdar://problem/19732211>
+
+        Reviewed by David Hyatt.
+
+        Tested by tiled-drawing/scrolling/latched-to-deleted-node.html
+
+        We need to reset our latching state if the targeted node is removed from the DOM.
+        Add a check in 'platformPrepareForWheelEvents' that checks if the expected latching
+        target node was already removed from the DOM. If it was, we should not send events
+        to it, and should reset latching state so we can attach to the next relevant node.
+
+        * dom/Element.cpp:
+        (WebCore::Element::removedFrom): Remove any latched wheel event state objects that
+        match the current element.
+        * page/MainFrame.cpp:
+        (WebCore::MainFrame::removeLatchingStateForTarget): Remove any latched wheel event
+        state structures that match the passed wheel event target.
+        * page/MainFrame.h:
+
 2015-08-25  Wenson Hsieh  <[email protected]>
 
         Fix crash due to search field disappearing when showing results menu

Modified: trunk/Source/WebCore/dom/Element.cpp (188919 => 188920)


--- trunk/Source/WebCore/dom/Element.cpp	2015-08-25 18:01:58 UTC (rev 188919)
+++ trunk/Source/WebCore/dom/Element.cpp	2015-08-25 18:03:00 UTC (rev 188920)
@@ -56,6 +56,7 @@
 #include "IdTargetObserverRegistry.h"
 #include "InsertionPoint.h"
 #include "KeyboardEvent.h"
+#include "MainFrame.h"
 #include "MutationObserverInterestGroup.h"
 #include "MutationRecord.h"
 #include "NodeRenderStyle.h"
@@ -71,6 +72,7 @@
 #include "SVGDocumentExtensions.h"
 #include "SVGElement.h"
 #include "SVGNames.h"
+#include "ScrollLatchingState.h"
 #include "SelectorQuery.h"
 #include "Settings.h"
 #include "StyleProperties.h"
@@ -1591,6 +1593,12 @@
 
     if (hasPendingResources())
         document().accessSVGExtensions().removeElementFromPendingResources(this);
+
+
+#if PLATFORM(MAC)
+    if (Frame* frame = document().frame())
+        frame->mainFrame().removeLatchingStateForTarget(*this);
+#endif
 }
 
 void Element::unregisterNamedFlowContentElement()

Modified: trunk/Source/WebCore/page/MainFrame.cpp (188919 => 188920)


--- trunk/Source/WebCore/page/MainFrame.cpp	2015-08-25 18:01:58 UTC (rev 188919)
+++ trunk/Source/WebCore/page/MainFrame.cpp	2015-08-25 18:03:00 UTC (rev 188920)
@@ -124,6 +124,20 @@
 {
     m_latchingState.removeLast();
 }
+
+void MainFrame::removeLatchingStateForTarget(Element& targetNode)
+{
+    if (m_latchingState.isEmpty())
+        return;
+
+    m_latchingState.removeAllMatching([&targetNode] (ScrollLatchingState& state) {
+        auto* wheelElement = state.wheelEventElement();
+        if (!wheelElement)
+            return false;
+
+        return targetNode.isEqualNode(wheelElement);
+    });
+}
 #endif
 
 }

Modified: trunk/Source/WebCore/page/MainFrame.h (188919 => 188920)


--- trunk/Source/WebCore/page/MainFrame.h	2015-08-25 18:01:58 UTC (rev 188919)
+++ trunk/Source/WebCore/page/MainFrame.h	2015-08-25 18:03:00 UTC (rev 188920)
@@ -59,6 +59,7 @@
     void pushNewLatchingState();
     void popLatchingState();
     void resetLatchingState();
+    void removeLatchingStateForTarget(Element&);
 #endif // PLATFORM(MAC)
 
     WEBCORE_EXPORT DiagnosticLoggingClient& diagnosticLoggingClient() const;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to