Make it possible to compute a region for elements on the page that have wheel event...
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Mar 2015 23:42:31 +0000 (23:42 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Mar 2015 23:42:31 +0000 (23:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142807

Reviewed by David Hyatt.

Source/WebCore:

Make it possible to compute a region that covers the elements on the page that have
a wheel event handler. This region may overestimate, but must not underestimate the area.

Elements with wheel handlers are registered on the document, and when a document gains
its first wheel handler, it registers the ownerElement in the parent document. Thus, on
the main frame, the region encompasses elements with handlers, and iframes whose subdocuments
have handlers.

Element gains some functions that allow it to return a rect which is the bounds of the element's
renderer, and renders for its descendant elements, which is the size or larger than the event
handling region for that element. Some configurations (e.g. position:fixed) require special
treatment.

Document::absoluteRegionForEventTargets() can then iterate over all elements in the given set,
and build a Region for those (short-circuiting if the document itself has a handler).

The new code is exercised for the debug MouseWheelRegionOverlay, and also added to the
non-fast scrollable region, used by threaded scrolling.

Tests: platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html
       platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html

* dom/ContainerNode.h:
(WebCore::ContainerNode::absoluteEventHandlerBounds): Base class implementation; returns empty rect.
* dom/Document.cpp:
(WebCore::Document::prepareForDestruction): Unregister from the parent document.
(WebCore::Document::didAddWheelEventHandler): Add to the wheel handler set. Tell the parent
document if we are adding wheel handlers for the first time. Eventually the wheelEventHandlerCountChanged()
code will be removed, now we have the set. Tell debug overlays that we changed.
(WebCore::Document::didRemoveWheelEventHandler): Remove from the set, and unregister with the parent
document if necessary. Tell debug overlays that we changed.
(WebCore::Document::didAddTouchEventHandler): Minor cleanup.
(WebCore::Document::didRemoveTouchEventHandler): Ditto.
(WebCore::Document::didRemoveEventTargetNode): Remove from wheel targets.
(WebCore::Document::absoluteEventHandlerBounds): Implementation of the ContainerNode
function, just return the document bounds.
(WebCore::Document::absoluteRegionForEventTargets): Iterate over the given event targets,
and call absoluteEventHandlerBounds() on each.
* dom/Document.h:
(WebCore::Document::wheelEventTargets):
* dom/Element.cpp:
(WebCore::layoutOverflowRectContainsAllDescendants): Return true if we can determine that the
layoutOverflow bounds of the given renderer contains the renderers of all descendant elements.
(WebCore::Element::eventBounds): Get the "event handling" bounds of this element (excluding
descendants), and while doing so, compute whether any descendants are position:fixed, and whether
these bounds are known to include descendants.
(WebCore::Element::eventBoundsOfElementAndDescendants): Recursive function that short-circuits
if it can determine that descendants are enclosed by the bounds.
(WebCore::Element::absoluteEventHandlerBounds):
* dom/Element.h:
* page/DebugPageOverlays.cpp:
(WebCore::MouseWheelRegionOverlay::updateRegion): Ask the document for the region of wheel
event handlers.
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::ScrollingCoordinator::computeNonFastScrollableRegion): Add the wheel handler region
to the non-fast scrollable region.
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::scrollTo): Overflow scrolling needs to dirty event regions.
* rendering/RenderObject.cpp:
(WebCore::RenderObject::absoluteBoundingBoxRect): Need to pass the "wasFixed" flag out
of this function.
(WebCore::RenderObject::localToAbsolute): Ditto.
* rendering/RenderObject.h:

LayoutTests:

Tests that dump the non-fast-scrollable region, for various rendering configurations.

* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/gain-wheel-handler.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/lose-wheel-handler.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/wheel-handler-region-helper.js: Added.
(rectsAsString):
(dumpRegion):
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic-expected.txt: Added.
* platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html: Added.

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

33 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/gain-wheel-handler.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/lose-wheel-handler.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/wheel-handler-region-helper.js [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-overflow-scroll-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-overflow-scroll.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/ContainerNode.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/page/DebugPageOverlays.cpp
Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h

index 3ec8f14..bfcfc3b 100644 (file)
@@ -1,3 +1,32 @@
+2015-03-31  Simon Fraser  <simon.fraser@apple.com>
+
+        Make it possible to compute a region for elements on the page that have wheel event handlers
+        https://bugs.webkit.org/show_bug.cgi?id=142807
+
+        Reviewed by David Hyatt.
+        
+        Tests that dump the non-fast-scrollable region, for various rendering configurations.
+
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/gain-wheel-handler.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/lose-wheel-handler.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/wheel-handler-region-helper.js: Added.
+        (rectsAsString):
+        (dumpRegion):
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic-expected.txt: Added.
+        * platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html: Added.
+
 2015-03-31  Dean Jackson  <dino@apple.com>
 
         accessibility/aria-hidden-hides-all-elements.html fails on Windows
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes-expected.txt
new file mode 100644 (file)
index 0000000..85ac96d
--- /dev/null
@@ -0,0 +1,2 @@
+
+20, 12 - 320, 162
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html
new file mode 100644 (file)
index 0000000..97cbd77
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        iframe {
+            display: block;
+            margin: 10px;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        var notificationsPending = 3;
+
+        // Called from subframes.
+        function frameChanged()
+        {
+            receivedNotification();
+        }
+        
+        function mainFrameLoaded()
+        {
+            receivedNotification();
+        }
+        
+        function receivedNotification()
+        {
+            if (!--notificationsPending) {
+                dumpRegion();
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }
+        }
+        
+        window.addEventListener('load', mainFrameLoaded, false);
+    </script>
+</head>
+<body>
+
+<iframe src="resources/gain-wheel-handler.html"></iframe>
+<iframe src="resources/lose-wheel-handler.html"></iframe>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/gain-wheel-handler.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/gain-wheel-handler.html
new file mode 100644 (file)
index 0000000..6f79687
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .box {
+            width: 100px;
+            height: 100px;
+            border: 4px solid black;
+        }
+    </style>
+    <script>
+        function addHandler()
+        {
+            window.setTimeout(function() {
+                var target = document.getElementById('target');
+                target.addEventListener('mousewheel', function(e) { });
+                parent.frameChanged();
+            }, 0);
+        }
+        
+        window.addEventListener('load', addHandler, false);
+    </script>
+</head>
+<body>
+
+<div id="target" class="box">
+</div>
+
+<pre id="output"></pre>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/lose-wheel-handler.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/lose-wheel-handler.html
new file mode 100644 (file)
index 0000000..89213e9
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .box {
+            width: 100px;
+            height: 100px;
+            border: 4px solid black;
+        }
+    </style>
+    <script>
+        function wheelHandler(e)
+        {
+        }
+
+        function removeHandler()
+        {
+            window.setTimeout(function() {
+                var target = document.getElementById('target');
+                target.removeEventListener('mousewheel', wheelHandler);
+                parent.frameChanged();
+            }, 0);
+        }
+        
+        window.addEventListener('load', removeHandler, false);
+    </script>
+</head>
+<body>
+
+<div id="target" class="box">
+</div>
+
+<pre id="output"></pre>
+
+<script>
+var target = document.getElementById('target');
+target.addEventListener('mousewheel', wheelHandler);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/wheel-handler-region-helper.js b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/resources/wheel-handler-region-helper.js
new file mode 100644 (file)
index 0000000..8390a1f
--- /dev/null
@@ -0,0 +1,22 @@
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+function rectsAsString(rects)
+{
+    var result = "";
+    for (var i = 0; i < rects.length; ++i) {
+        var rect = rects[i];
+        if (i)
+            result += '\n';
+        result += rect.left + ', ' + rect.top + ' - ' + rect.right + ', ' + rect.bottom;
+    }
+    return result;
+}
+
+function dumpRegion()
+{
+    if (window.internals) {
+        var rects = window.internals.nonFastScrollableRects();
+        document.getElementById('output').textContent = rectsAsString(rects);
+    }
+}
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child-expected.txt
new file mode 100644 (file)
index 0000000..1cb255d
--- /dev/null
@@ -0,0 +1 @@
+50, 50 - 150, 150
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html
new file mode 100644 (file)
index 0000000..d444899
--- /dev/null
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .fixed {
+            position: fixed;
+            top: 50px;
+            left: 50px;
+        }
+        
+        .box {
+            height: 100px;
+            width: 100px;
+            background-color: blue;
+        }
+        
+        .child {
+            position: relative;
+            left: 50px;
+            top: 50px;
+        }
+        #output {
+            margin-top: 520px;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        function dumpRegion()
+        {
+            if (window.internals) {
+                var rects = window.internals.nonFastScrollableRects();
+                document.getElementById('output').textContent = rectsAsString(rects);
+            }
+        }
+
+        window.addEventListener('load', dumpRegion, false);
+    </script>
+</head>
+<body>
+
+<div class="box">
+    <div class="fixed box" onmousewheel="(void)0">
+    </div>
+</div>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns-expected.txt
new file mode 100644 (file)
index 0000000..2a7634b
--- /dev/null
@@ -0,0 +1,7 @@
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+28, 20 - 567, 380
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html
new file mode 100644 (file)
index 0000000..bef12e2
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .columns {
+            margin: 20px;
+            width: 400px;
+            height: 360px;
+            column-width: 120px;
+        }
+        .target {
+            color: blue;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        function doTest()
+        {
+            dumpRegion();
+        }
+
+        window.addEventListener('load', doTest);
+    </script>
+</head>
+<body>
+
+<div class="columns">
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+    <p class="target" onmousewheel="(void)0">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
+</div>
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-overflow-scroll-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-overflow-scroll-expected.txt
new file mode 100644 (file)
index 0000000..bbf28b5
--- /dev/null
@@ -0,0 +1,9 @@
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+8, 8 - 310, 310
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-overflow-scroll.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-overflow-scroll.html
new file mode 100644 (file)
index 0000000..fc39390
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        #container {
+            width: 300px;
+            height: 300px;
+            overflow: scroll;
+            border: 1px solid black;
+        }
+        .target {
+            color: blue;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        function doTest()
+        {
+            window.setTimeout(function() {
+                var scroller = document.getElementById('container');
+                scroller.scrollTop = 200;
+                dumpRegion();
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, 0)
+        }
+
+        window.addEventListener('load', doTest);
+    </script>
+</head>
+<body>
+
+<div id="container">
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+    <p class="target" onmousewheel="(void)0">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
+</div>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region-expected.txt
new file mode 100644 (file)
index 0000000..a280d39
--- /dev/null
@@ -0,0 +1,7 @@
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
+
+39, 151 - 609, 401
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html
new file mode 100644 (file)
index 0000000..6518ee8
--- /dev/null
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        #content {
+            -webkit-flow-into: flow1;
+        }
+
+        #region1, #region2 {
+            margin: 10px;
+            border: 1px solid black;
+            -webkit-flow-from: flow1;
+        }
+
+        #region1 {
+            margin-left: 30px;
+            width: 300px;
+            height: 200px;
+        }
+
+        #region2 {
+            margin-top: 80px;
+            margin-left: 200px;
+            width: 400px;
+            height: 90px;
+        }
+
+        .target {
+            color: blue;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        function doTest()
+        {
+            dumpRegion();
+        }
+
+        window.addEventListener('load', doTest);
+    </script>
+</head>
+<body>
+
+<div id="content">
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
+    <p class="target" onmousewheel="(void)0">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
+</div>
+
+<div id="container">
+    <div id="region1"></div>
+    <div id="region2"></div>
+</div>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed-expected.txt
new file mode 100644 (file)
index 0000000..7fa4fc0
--- /dev/null
@@ -0,0 +1 @@
+60, 60 - 160, 160
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html
new file mode 100644 (file)
index 0000000..16c2c30
--- /dev/null
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .fixed {
+            position: fixed;
+            top: 10px;
+            left: 10px;
+        }
+        
+        .box {
+            height: 100px;
+            width: 100px;
+            background-color: blue;
+        }
+        
+        .child {
+            position: relative;
+            left: 50px;
+            top: 50px;
+        }
+        #output {
+            margin-top: 520px;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        window.addEventListener('load', dumpRegion, false);
+    </script>
+</head>
+<body>
+
+<div class="fixed box">
+    <div class="child box" onmousewheel="(void)0">
+    </div>
+</div>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document-expected.txt
new file mode 100644 (file)
index 0000000..0cb4d3b
--- /dev/null
@@ -0,0 +1 @@
+0, 0 - 800, 600
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html
new file mode 100644 (file)
index 0000000..3660c0e
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        function doTest()
+        {
+            document.addEventListener('mousewheel', function() { });
+            dumpRegion();
+        }
+
+        window.addEventListener('load', doTest);
+    </script>
+</head>
+<body>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed-expected.txt
new file mode 100644 (file)
index 0000000..d8439fa
--- /dev/null
@@ -0,0 +1 @@
+10, 10 - 110, 110
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html
new file mode 100644 (file)
index 0000000..ce9ef5c
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .fixed {
+            position: fixed;
+            top: 10px;
+            left: 10px;
+        }
+        
+        .box {
+            height: 100px;
+            width: 100px;
+            background-color: blue;
+        }
+        #output {
+            margin-top: 520px;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        window.addEventListener('load', dumpRegion, false);
+    </script>
+</head>
+<body>
+
+<div class="fixed box" onmousewheel="(void)0">
+</div>
+
+<pre id="output"></pre>
+
+</body>
+</html>
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic-expected.txt b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic-expected.txt
new file mode 100644 (file)
index 0000000..a8de68c
--- /dev/null
@@ -0,0 +1,10 @@
+Some text
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. here Container
+Intermediate
+Child
+Container
+Intermediate
+Child
+8, 8 - 777, 329
+9, 369 - 290, 425
+9, 501 - 290, 601
diff --git a/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html b/LayoutTests/platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html
new file mode 100644 (file)
index 0000000..b84ddc1
--- /dev/null
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .box {
+            width: 100px;
+            height: 100px;
+            border: 4px solid black;
+            position: relative;
+        }
+        
+        .overflowing-transformed {
+            position: absolute;
+            top: 100px;
+            left: 300px;
+            width: 200px;
+            height: 100px;
+            border: 1px solid green;
+            -webkit-transform: rotate(30deg);
+        }
+        
+        .container {
+            position: absolute;
+            top: 350px;
+            height: 100px;
+            border: 1px solid green;
+        }
+        
+        .inner {
+            position: relative;
+            top: 20px;
+            left: 200px;
+            background-color: orange;
+        }
+        
+        #output {
+            margin-top: 520px;
+        }
+    </style>
+    <script src="resources/wheel-handler-region-helper.js"></script>
+    <script>
+        window.addEventListener('load', dumpRegion, false);
+    </script>
+</head>
+<body>
+
+<span id="target" onmousewheel="(void)0">Some text
+    <div class="box">
+        <div class="overflowing-transformed">
+            Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+        </div>
+    </div>
+here</span>
+
+<!-- Handler on skipped containing block -->
+<div class="container" onmousewheel="(void)0" style="top: 500px;">
+    Container
+    <div class="intermediate">
+        Intermediate
+        <div class="inner">
+            Child
+        </div>
+    </div>
+</div>
+
+<div class="container">
+    Container
+    <!-- Handler on skipped containing block -->
+    <div class="intermediate" onmousewheel="(void)0">
+        Intermediate
+        <div class="inner">
+            Child
+        </div>
+    </div>
+</div>
+
+<pre id="output"></pre>
+
+</body>
+</html>
index 83036ed..8cbd03b 100644 (file)
@@ -1,3 +1,80 @@
+2015-03-31  Simon Fraser  <simon.fraser@apple.com>
+
+        Make it possible to compute a region for elements on the page that have wheel event handlers
+        https://bugs.webkit.org/show_bug.cgi?id=142807
+
+        Reviewed by David Hyatt.
+        
+        Make it possible to compute a region that covers the elements on the page that have
+        a wheel event handler. This region may overestimate, but must not underestimate the area.
+        
+        Elements with wheel handlers are registered on the document, and when a document gains
+        its first wheel handler, it registers the ownerElement in the parent document. Thus, on 
+        the main frame, the region encompasses elements with handlers, and iframes whose subdocuments
+        have handlers.
+        
+        Element gains some functions that allow it to return a rect which is the bounds of the element's
+        renderer, and renders for its descendant elements, which is the size or larger than the event
+        handling region for that element. Some configurations (e.g. position:fixed) require special
+        treatment.
+        
+        Document::absoluteRegionForEventTargets() can then iterate over all elements in the given set,
+        and build a Region for those (short-circuiting if the document itself has a handler).
+        
+        The new code is exercised for the debug MouseWheelRegionOverlay, and also added to the
+        non-fast scrollable region, used by threaded scrolling.
+
+        Tests: platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/handlers-in-iframes.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-fixed-child.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-columns.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-in-region.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-inside-fixed.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-document.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-on-fixed.html
+               platform/mac-wk2/tiled-drawing/scrolling/non-fast-region/wheel-handler-region-basic.html
+
+        * dom/ContainerNode.h:
+        (WebCore::ContainerNode::absoluteEventHandlerBounds): Base class implementation; returns empty rect.
+        * dom/Document.cpp:
+        (WebCore::Document::prepareForDestruction): Unregister from the parent document.
+        (WebCore::Document::didAddWheelEventHandler): Add to the wheel handler set. Tell the parent
+        document if we are adding wheel handlers for the first time. Eventually the wheelEventHandlerCountChanged()
+        code will be removed, now we have the set. Tell debug overlays that we changed.
+        (WebCore::Document::didRemoveWheelEventHandler): Remove from the set, and unregister with the parent
+        document if necessary. Tell debug overlays that we changed.
+        (WebCore::Document::didAddTouchEventHandler): Minor cleanup.
+        (WebCore::Document::didRemoveTouchEventHandler): Ditto.
+        (WebCore::Document::didRemoveEventTargetNode): Remove from wheel targets.
+        (WebCore::Document::absoluteEventHandlerBounds): Implementation of the ContainerNode
+        function, just return the document bounds.
+        (WebCore::Document::absoluteRegionForEventTargets): Iterate over the given event targets,
+        and call absoluteEventHandlerBounds() on each.
+        * dom/Document.h:
+        (WebCore::Document::wheelEventTargets):
+        * dom/Element.cpp:
+        (WebCore::layoutOverflowRectContainsAllDescendants): Return true if we can determine that the
+        layoutOverflow bounds of the given renderer contains the renderers of all descendant elements.
+        (WebCore::Element::eventBounds): Get the "event handling" bounds of this element (excluding
+        descendants), and while doing so, compute whether any descendants are position:fixed, and whether
+        these bounds are known to include descendants.
+        (WebCore::Element::eventBoundsOfElementAndDescendants): Recursive function that short-circuits
+        if it can determine that descendants are enclosed by the bounds.
+        (WebCore::Element::absoluteEventHandlerBounds):
+        * dom/Element.h:
+        * page/DebugPageOverlays.cpp:
+        (WebCore::MouseWheelRegionOverlay::updateRegion): Ask the document for the region of wheel
+        event handlers.
+        * page/scrolling/ScrollingCoordinator.cpp:
+        (WebCore::ScrollingCoordinator::computeNonFastScrollableRegion): Add the wheel handler region
+        to the non-fast scrollable region.
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::scrollTo): Overflow scrolling needs to dirty event regions.
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::absoluteBoundingBoxRect): Need to pass the "wasFixed" flag out
+        of this function.
+        (WebCore::RenderObject::localToAbsolute): Ditto.
+        * rendering/RenderObject.h:
+
 2015-03-31  Alexey Proskuryakov  <ap@apple.com>
 
         Fix bindings tests results after <http://trac.webkit.org/changeset/182205>.
index d50b604..ca2ac66 100644 (file)
@@ -136,6 +136,10 @@ public:
 
     RenderElement* renderer() const;
 
+    // Return a bounding box in absolute coordinates enclosing this node and all its descendants.
+    // This gives the area within which events may get handled by a hander registered on this node.
+    virtual LayoutRect absoluteEventHandlerBounds(bool& /* includesFixedPositionElements */) { return LayoutRect(); }
+
     Element* querySelector(const String& selectors, ExceptionCode&);
     RefPtr<NodeList> querySelectorAll(const String& selectors, ExceptionCode&);
 
index 30cd2dc..e8a7f14 100644 (file)
@@ -47,6 +47,7 @@
 #include "DOMNamedFlowCollection.h"
 #include "DOMWindow.h"
 #include "DateComponents.h"
+#include "DebugPageOverlays.h"
 #include "Dictionary.h"
 #include "DocumentLoader.h"
 #include "DocumentMarkerController.h"
@@ -2245,6 +2246,9 @@ void Document::prepareForDestruction()
         parentDocument()->didRemoveEventTargetNode(*this);
 #endif
 
+    if (m_wheelEventTargets && m_wheelEventTargets->size() && parentDocument())
+        parentDocument()->didRemoveEventTargetNode(*this);
+
     if (m_mediaQueryMatcher)
         m_mediaQueryMatcher->documentDestroyed();
 
@@ -5998,29 +6002,61 @@ static void wheelEventHandlerCountChanged(Document* document)
     scrollingCoordinator->frameViewWheelEventHandlerCountChanged(*frameView);
 }
 
-void Document::didAddWheelEventHandler(Node&)
+void Document::didAddWheelEventHandler(Node& node)
 {
     ++m_wheelEventHandlerCount;
+
+    if (!m_wheelEventTargets)
+        m_wheelEventTargets = std::make_unique<EventTargetSet>();
+
+    m_wheelEventTargets->add(&node);
+
+    if (Document* parent = parentDocument()) {
+        parent->didAddWheelEventHandler(*this);
+        return;
+    }
+
     wheelEventHandlerCountChanged(this);
+
+    if (Frame* frame = this->frame())
+        DebugPageOverlays::didChangeEventHandlers(*frame);
 }
 
-void Document::didRemoveWheelEventHandler(Node&)
+void Document::didRemoveWheelEventHandler(Node& node)
 {
     ASSERT(m_wheelEventHandlerCount > 0);
     --m_wheelEventHandlerCount;
+
+    if (!m_wheelEventTargets)
+        return;
+
+    ASSERT(m_wheelEventTargets->contains(&node));
+    m_wheelEventTargets->remove(&node);
+
+    if (Document* parent = parentDocument()) {
+        parent->didRemoveWheelEventHandler(*this);
+        return;
+    }
+
     wheelEventHandlerCountChanged(this);
+
+    if (Frame* frame = this->frame())
+        DebugPageOverlays::didChangeEventHandlers(*frame);
 }
 
 void Document::didAddTouchEventHandler(Node& handler)
 {
 #if ENABLE(TOUCH_EVENTS)
-    if (!m_touchEventTargets.get())
+    if (!m_touchEventTargets)
         m_touchEventTargets = std::make_unique<EventTargetSet>();
+
     m_touchEventTargets->add(&handler);
+
     if (Document* parent = parentDocument()) {
         parent->didAddTouchEventHandler(*this);
         return;
     }
+
     if (Page* page = this->page()) {
         if (m_touchEventTargets->size() == 1)
             page->chrome().client().needTouchEvents(true);
@@ -6033,10 +6069,12 @@ void Document::didAddTouchEventHandler(Node& handler)
 void Document::didRemoveTouchEventHandler(Node& handler)
 {
 #if ENABLE(TOUCH_EVENTS)
-    if (!m_touchEventTargets.get())
+    if (!m_touchEventTargets)
         return;
+
     ASSERT(m_touchEventTargets->contains(&handler));
     m_touchEventTargets->remove(&handler);
+
     if (Document* parent = parentDocument()) {
         parent->didRemoveTouchEventHandler(*this);
         return;
@@ -6047,6 +6085,8 @@ void Document::didRemoveTouchEventHandler(Node& handler)
         return;
     if (m_touchEventTargets->size())
         return;
+
+    // FIXME: why can't we trust m_touchEventTargets?
     for (const Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
         if (frame->document() && frame->document()->hasTouchEventHandlers())
             return;
@@ -6065,9 +6105,51 @@ void Document::didRemoveEventTargetNode(Node& handler)
         if ((&handler == this || m_touchEventTargets->isEmpty()) && parentDocument())
             parentDocument()->didRemoveEventTargetNode(*this);
     }
-#else
-    UNUSED_PARAM(handler);
 #endif
+
+    if (m_wheelEventTargets) {
+        m_wheelEventTargets->removeAll(&handler);
+        if ((&handler == this || m_wheelEventTargets->isEmpty()) && parentDocument())
+            parentDocument()->didRemoveEventTargetNode(*this);
+    }
+}
+
+LayoutRect Document::absoluteEventHandlerBounds(bool& includesFixedPositionElements)
+{
+    includesFixedPositionElements = false;
+    if (RenderView* renderView = this->renderView())
+        return renderView->documentRect();
+    
+    return LayoutRect();
+}
+
+Region Document::absoluteRegionForEventTargets(const EventTargetSet* targets)
+{
+    if (!targets)
+        return Region();
+
+    Region targetRegion;
+    bool insideFixedPosition = false;
+
+    for (auto it : *targets) {
+        LayoutRect rootRelativeBounds;
+        
+        if (is<Document>(it.key)) {
+            Document* document = downcast<Document>(it.key);
+            if (document == this)
+                rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
+            else if (Element* element = document->ownerElement())
+                rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
+        } else if (is<Element>(it.key)) {
+            Element* element = downcast<Element>(it.key);
+            rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
+        }
+        
+        if (!rootRelativeBounds.isEmpty())
+            targetRegion.unite(Region(enclosingIntRect(rootRelativeBounds)));
+    }
+
+    return targetRegion;
 }
 
 void Document::updateLastHandledUserGestureTimestamp()
index e0a4279..8a612ad 100644 (file)
@@ -41,6 +41,7 @@
 #include "PageVisibilityState.h"
 #include "PlatformScreen.h"
 #include "ReferrerPolicy.h"
+#include "Region.h"
 #include "RenderPtr.h"
 #include "ScriptExecutionContext.h"
 #include "StringWithDirection.h"
@@ -1148,6 +1149,12 @@ public:
 #endif
     }
 
+    const EventTargetSet* wheelEventTargets() const { return m_wheelEventTargets.get(); }
+
+    Region absoluteRegionForEventTargets(const EventTargetSet*);
+
+    LayoutRect absoluteEventHandlerBounds(bool&) override final;
+
     bool visualUpdatesAllowed() const { return m_visualUpdatesAllowed; }
 
     bool isInDocumentWrite() { return m_writeRecursionDepth > 0; }
@@ -1561,6 +1568,7 @@ private:
 #if ENABLE(TOUCH_EVENTS)
     std::unique_ptr<EventTargetSet> m_touchEventTargets;
 #endif
+    std::unique_ptr<EventTargetSet> m_wheelEventTargets;
 
     double m_lastHandledUserGestureTimestamp;
 
index 1ed7360..14038fe 100644 (file)
@@ -63,6 +63,7 @@
 #include "NodeRenderStyle.h"
 #include "PlatformWheelEvent.h"
 #include "PointerLockController.h"
+#include "RenderFlowThread.h"
 #include "RenderLayer.h"
 #include "RenderNamedFlowFragment.h"
 #include "RenderRegion.h"
@@ -925,6 +926,126 @@ IntRect Element::boundsInRootViewSpace()
     return result;
 }
 
+static bool layoutOverflowRectContainsAllDescendants(const RenderElement& renderer)
+{
+    if (renderer.isRenderView())
+        return true;
+
+    if (!renderer.element())
+        return false;
+
+    // If there are any position:fixed inside of us, game over.
+    if (auto viewPositionedObjects = renderer.view().positionedObjects()) {
+        for (RenderBox* it : *viewPositionedObjects) {
+            if (it != &renderer && it->style().position() == FixedPosition && renderer.element()->contains(it->element()))
+                return false;
+        }
+    }
+
+    if (renderer.canContainAbsolutelyPositionedObjects()) {
+        // Our layout overflow will include all descendant positioned elements.
+        return true;
+    }
+
+    // This renderer may have positioned descendants whose containing block is some ancestor.
+    if (auto containingBlock = renderer.containingBlockForAbsolutePosition()) {
+        if (auto positionedObjects = containingBlock->positionedObjects()) {
+            for (RenderBox* it : *positionedObjects) {
+                if (it != &renderer && renderer.element()->contains(it->element()))
+                    return false;
+            }
+        }
+    }
+    
+    return false;
+}
+
+LayoutRect Element::absoluteEventBounds(bool& boundsIncludeAllDescendantElements, bool& includesFixedPositionElements)
+{
+    boundsIncludeAllDescendantElements = false;
+    includesFixedPositionElements = false;
+
+    if (!renderer())
+        return LayoutRect();
+
+    LayoutRect result;
+    if (isSVGElement()) {
+        // Get the bounding rectangle from the SVG model.
+        SVGElement& svgElement = downcast<SVGElement>(*this);
+        FloatRect localRect;
+        if (svgElement.getBoundingBox(localRect))
+            result = LayoutRect(renderer()->localToAbsoluteQuad(localRect, UseTransforms, &includesFixedPositionElements).boundingBox());
+    } else {
+        if (is<RenderBox>(renderer())) {
+            RenderBox& box = *downcast<RenderBox>(renderer());
+
+            bool computedBounds = false;
+            
+            if (RenderFlowThread* flowThread = box.flowThreadContainingBlock()) {
+                bool wasFixed = false;
+                Vector<FloatQuad> quads;
+                FloatRect localRect(0, 0, box.width(), box.height());
+                if (flowThread->absoluteQuadsForBox(quads, &wasFixed, &box, localRect.y(), localRect.maxY())) {
+                    FloatRect quadBounds = quads[0].boundingBox();
+                    for (size_t i = 1; i < quads.size(); ++i)
+                        quadBounds.unite(quads[i].boundingBox());
+                    
+                    result = LayoutRect(quadBounds);
+                    computedBounds = true;
+                } else {
+                    // Probably columns. Just return the bounds of the multicol block for now.
+                    // FIXME: this doesn't handle nested columns.
+                    RenderElement* multicolContainer = flowThread->parent();
+                    if (multicolContainer && is<RenderBox>(multicolContainer)) {
+                        LayoutRect overflowRect = downcast<RenderBox>(multicolContainer)->layoutOverflowRect();
+                        result = LayoutRect(multicolContainer->localToAbsoluteQuad(FloatRect(overflowRect), UseTransforms, &includesFixedPositionElements).boundingBox());
+                        computedBounds = true;
+                    }
+                }
+            }
+
+            if (!computedBounds) {
+                LayoutRect overflowRect = box.layoutOverflowRect();
+                result = LayoutRect(box.localToAbsoluteQuad(FloatRect(overflowRect), UseTransforms, &includesFixedPositionElements).boundingBox());
+                boundsIncludeAllDescendantElements = layoutOverflowRectContainsAllDescendants(box);
+            }
+        } else
+            result = LayoutRect(renderer()->absoluteBoundingBoxRect(true /* useTransforms */, &includesFixedPositionElements));
+    }
+
+    return result;
+}
+
+LayoutRect Element::absoluteEventBoundsOfElementAndDescendants(bool& includesFixedPositionElements)
+{
+    bool boundsIncludeDescendants;
+    LayoutRect result = absoluteEventBounds(boundsIncludeDescendants, includesFixedPositionElements);
+    if (boundsIncludeDescendants)
+        return result;
+
+    for (auto& child : childrenOfType<Element>(*this)) {
+        bool includesFixedPosition = false;
+        LayoutRect childBounds = child.absoluteEventBoundsOfElementAndDescendants(includesFixedPosition);
+        includesFixedPositionElements |= includesFixedPosition;
+        result.unite(childBounds);
+    }
+
+    return result;
+}
+
+LayoutRect Element::absoluteEventHandlerBounds(bool& includesFixedPositionElements)
+{
+    // This is not web-exposed, so don't call the FOUC-inducing updateLayoutIgnorePendingStylesheets().
+    FrameView* frameView = document().view();
+    if (!frameView)
+        return LayoutRect();
+
+    if (frameView->needsLayout())
+        frameView->layout();
+
+    return absoluteEventBoundsOfElementAndDescendants(includesFixedPositionElements);
+}
+
 Ref<ClientRectList> Element::getClientRects()
 {
     document().updateLayoutIgnorePendingStylesheets();
index b79f439..c900960 100644 (file)
@@ -484,6 +484,8 @@ public:
     virtual void didDetachRenderers();
     virtual RefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle);
 
+    LayoutRect absoluteEventHandlerBounds(bool& includesFixedPositionElements) override;
+
     void setBeforePseudoElement(Ref<PseudoElement>&&);
     void setAfterPseudoElement(Ref<PseudoElement>&&);
     void clearBeforePseudoElement();
@@ -562,6 +564,9 @@ private:
     void addAttributeInternal(const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
     void removeAttributeInternal(unsigned index, SynchronizationOfLazyAttribute);
 
+    LayoutRect absoluteEventBounds(bool& boundsIncludeAllDescendantElements, bool& includesFixedPositionElements);
+    LayoutRect absoluteEventBoundsOfElementAndDescendants(bool& includesFixedPositionElements);
+    
 #if ENABLE(TREE_DEBUGGING)
     virtual void formatForDebugger(char* buffer, unsigned length) const override;
 #endif
index 0fa784b..b2621ce 100644 (file)
@@ -90,15 +90,7 @@ private:
 
 bool MouseWheelRegionOverlay::updateRegion()
 {
-    std::unique_ptr<Region> region = std::make_unique<Region>();
-
-    for (auto& element : descendantsOfType<Element>(*m_frame.document())) {
-        if (element.hasEventListeners(eventNames().mousewheelEvent) || element.hasEventListeners(eventNames().wheelEvent)) {
-            IntRect elementRect = element.boundsInRootViewSpace();
-            elementRect = m_frame.view()->rootViewToContents(elementRect);
-            region->unite(Region(elementRect));
-        }
-    }
+    std::unique_ptr<Region> region = std::make_unique<Region>(m_frame.document()->absoluteRegionForEventTargets(m_frame.document()->wheelEventTargets()));
 
     bool regionChanged = !m_region || !(*m_region == *region);
     m_region = WTF::move(region);
index a641b65..69fdc2b 100644 (file)
@@ -98,6 +98,10 @@ bool ScrollingCoordinator::coordinatesScrollingForFrameView(const FrameView& fra
 
 Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame& frame, const IntPoint& frameLocation) const
 {
+    RenderView* renderView = frame.contentRenderer();
+    if (!renderView || renderView->documentBeingDestroyed())
+        return Region();
+
 #if ENABLE(IOS_TOUCH_EVENTS)
     // On iOS, we use nonFastScrollableRegion to represent the region covered by elements with touch event handlers.
     ASSERT(frame.isMainFrame());
@@ -114,6 +118,7 @@ Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame& frame,
     for (const auto& rect : touchRects)
         touchRegion.unite(rect);
 
+    // FIXME: use absoluteRegionForEventTargets().
     return touchRegion;
 #else
     Region nonFastScrollableRegion;
@@ -148,6 +153,11 @@ Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame& frame,
     for (Frame* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling())
         nonFastScrollableRegion.unite(computeNonFastScrollableRegion(*subframe, offset));
 
+    // Include wheel event handler region for the main frame.
+    Region wheelHandlerRegion = frame.document()->absoluteRegionForEventTargets(frame.document()->wheelEventTargets());
+    wheelHandlerRegion.translate(toIntSize(offset));
+    nonFastScrollableRegion.unite(wheelHandlerRegion);
+
     return nonFastScrollableRegion;
 #endif
 }
index bd77af0..12980c9 100644 (file)
@@ -48,6 +48,7 @@
 #include "BoxShape.h"
 #include "CSSPropertyNames.h"
 #include "Chrome.h"
+#include "DebugPageOverlays.h"
 #include "Document.h"
 #include "DocumentEventQueue.h"
 #include "Element.h"
@@ -2391,6 +2392,7 @@ void RenderLayer::scrollTo(int x, int y)
 #if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
         renderer().document().dirtyTouchEventRects();
 #endif
+        DebugPageOverlays::didLayout(renderer().frame());
     }
 
     Frame& frame = renderer().frame();
index 98617d5..bfbf9e7 100644 (file)
@@ -1085,11 +1085,11 @@ void RenderObject::collectSelectionRects(Vector<SelectionRect>& rects, unsigned
 }
 #endif
 
-IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const
+IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms, bool* wasFixed) const
 {
     if (useTransforms) {
         Vector<FloatQuad> quads;
-        absoluteQuads(quads);
+        absoluteQuads(quads, wasFixed);
 
         size_t n = quads.size();
         if (!n)
@@ -1101,7 +1101,7 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const
         return result;
     }
 
-    FloatPoint absPos = localToAbsolute();
+    FloatPoint absPos = localToAbsolute(FloatPoint(), 0 /* ignore transforms */, wasFixed);
     Vector<IntRect> rects;
     absoluteRects(rects, flooredLayoutPoint(absPos));
 
@@ -1579,10 +1579,10 @@ void RenderObject::selectionStartEnd(int& spos, int& epos) const
     selectionRoot().selectionData().selectionStartEndPositions(spos, epos);
 }
 
-FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode) const
+FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode, bool* wasFixed) const
 {
     TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
-    mapLocalToContainer(nullptr, transformState, mode | ApplyContainerFlip);
+    mapLocalToContainer(nullptr, transformState, mode | ApplyContainerFlip, wasFixed);
     transformState.flatten();
     
     return transformState.lastPlanarPoint();
index c9a96e7..b1f1895 100644 (file)
@@ -652,7 +652,7 @@ public:
     RenderBlock* containingBlock() const;
 
     // Convert the given local point to absolute coordinates. If MapCoordinatesFlags includes UseTransforms, take transforms into account.
-    WEBCORE_EXPORT FloatPoint localToAbsolute(const FloatPoint& localPoint = FloatPoint(), MapCoordinatesFlags = 0) const;
+    WEBCORE_EXPORT FloatPoint localToAbsolute(const FloatPoint& localPoint = FloatPoint(), MapCoordinatesFlags = 0, bool* wasFixed = nullptr) const;
     FloatPoint absoluteToLocal(const FloatPoint&, MapCoordinatesFlags = 0) const;
 
     // Convert a local quad to absolute coordinates, taking transforms into account.
@@ -681,7 +681,7 @@ public:
     virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint&) const { }
 
     // FIXME: useTransforms should go away eventually
-    WEBCORE_EXPORT IntRect absoluteBoundingBoxRect(bool useTransform = true) const;
+    WEBCORE_EXPORT IntRect absoluteBoundingBoxRect(bool useTransform = true, bool* wasFixed = nullptr) const;
     IntRect absoluteBoundingBoxRectIgnoringTransforms() const { return absoluteBoundingBoxRect(false); }
 
     // Build an array of quads in absolute coords for line boxes