[iOS] Handle hit testing for subframes
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Jan 2019 06:50:49 +0000 (06:50 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Jan 2019 06:50:49 +0000 (06:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192303

Reviewed by Frédéric Wang.

Source/WebCore:

Don't set delegatesScrolling bit for subframes on iOS. It is meant for top level application
controlled scrolling. This fixes coordinate conversions for subframes and makes events work.

Test by Frederic Wang.

Test: fast/scrolling/ios/hit-testing-iframe.html

* platform/ScrollView.cpp:
(WebCore::ScrollView::managesScrollbars const):

Add a function that tells if the scrollview should deal with scrollbars at all
This is always false on iOS and not connected to delegatesScrolling bit.

(WebCore::ScrollView::updateScrollbars):
* platform/ScrollView.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::shouldCompositeOverflowControls const):

Source/WebKit:

* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::transitionToCommittedForNewPage):

Only set delegatesScrolling for the main frame.

LayoutTests:

Test by Frederic Wang.

* fast/scrolling/ios/hit-testing-iframe-expected.html: Added.
* fast/scrolling/ios/hit-testing-iframe.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/scrolling/ios/hit-testing-iframe-expected.html [new file with mode: 0644]
LayoutTests/fast/scrolling/ios/hit-testing-iframe.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/ScrollView.cpp
Source/WebCore/platform/ScrollView.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp

index fcc74f6..0fcf65d 100644 (file)
@@ -1,3 +1,15 @@
+2019-01-21  Antti Koivisto  <antti@apple.com>
+
+        [iOS] Handle hit testing for subframes
+        https://bugs.webkit.org/show_bug.cgi?id=192303
+
+        Reviewed by Frédéric Wang.
+
+        Test by Frederic Wang.
+
+        * fast/scrolling/ios/hit-testing-iframe-expected.html: Added.
+        * fast/scrolling/ios/hit-testing-iframe.html: Added.
+
 2019-01-21  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][Floats] Take float top position into account when computing containing block height.
diff --git a/LayoutTests/fast/scrolling/ios/hit-testing-iframe-expected.html b/LayoutTests/fast/scrolling/ios/hit-testing-iframe-expected.html
new file mode 100644 (file)
index 0000000..5eeaf9e
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html
+  <head>
+    <title>Hit testing of iframe</title>
+  </head>
+  <body>
+    <p>This test passes if you see a green rectangle.</p>
+    <div style="position: absolute; top: 3em; width: 300px; height: 200px; background: green;">
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/scrolling/ios/hit-testing-iframe.html b/LayoutTests/fast/scrolling/ios/hit-testing-iframe.html
new file mode 100644 (file)
index 0000000..ba66e31
--- /dev/null
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Hit testing of iframe</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <script src="../../../resources/basic-gestures.js"></script>
+    <script type="text/javascript">
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+        if (window.internals)
+            internals.settings.setAsyncFrameScrollingEnabled(true);
+
+      function frameBox(id)
+      {
+          return document.getElementById(id).getBoundingClientRect();
+      }
+
+      function waitPromise(delay)
+      {
+          return new Promise((resolve) => { setTimeout(resolve, delay); });
+      }
+
+      async function runTest() {
+         if (!window.testRunner || !testRunner.runUIScript)
+             return;
+
+         // This verifies whether the iframe handles clicks inside or ouside its content box.
+         var p = frameBox("clickInContentBox");
+         await tapAtPoint(p.left + 7, p.top + 7);
+         p = frameBox("clickInPaddingBoxOutOfContentBox");
+         await tapAtPoint(p.left + 3, p.top + 3);
+
+         // This verifies that a click event is consumed by the element on top the frame.
+         p = frameBox("clickElementAboveFrame");
+         await tapAtPoint(p.left + 50, p.top + 50);
+
+         // This verifies that a click event is consumed by an element inside the frame.
+         p = frameBox("clickElementInsideFrame");
+         await tapAtPoint(p.left + 7 + 10, p.top + 7 + 10);
+
+         // This verifies that a click event is consumed by an element inside the frame, after a user scroll.
+         p = frameBox("clickElementInsideFrameAfterUserScroll");
+         await touchAndDragFromPointToPoint(p.left + 7, p.top + 7, p.left + 7, p.top - 150);
+         await liftUpAtPoint(p.left + 7, p.top - 150);
+         await waitPromise(1500); // Wait for scrolling to stabilize and for scrollbars to disappear.
+         await tapAtPoint(p.left + 7 + 10, p.bottom - 7);
+         await waitPromise(100);
+
+         testRunner.notifyDone();
+       }
+
+       var frameToLoadCount = 5;
+       function newFrameLoaded() {
+           frameToLoadCount--;
+           if (frameToLoadCount == 0)
+               runTest();
+       }
+    </script>
+    <style>
+        iframe {
+            position: absolute;
+            height: 90px;
+            width: 90px;
+            overflow: none;
+            margin: 0;
+            border: 0;
+            padding: 5px;
+        }
+    </style>
+  </head>
+  <body>
+    <p>This test passes if you see a green rectangle.</p>
+    <div style="position: absolute; top: 3em; width: 300px; height: 200px; background: green;">
+      <iframe id="clickInContentBox" style="left: 0px; top: 0px;" scrolling="yes" onclick="this.style.background='red'" srcdoc="
+          <body style='margin: 0; width: 200px; height: 200px'>
+              <div style='position: absolute; width: 100px; height: 100px; background: red;'
+                   onclick='this.style.background=&quot;green&quot;'></div>
+          </body>" onload="newFrameLoaded()">
+      </iframe>
+      <iframe id="clickInPaddingBoxOutOfContentBox" style="left: 100px; top: 0px; background: red;" onclick="this.style.background='green'" scrolling="yes" srcdoc="
+          <body style='margin: 0; width: 200px; height: 200px'>
+              <div style='position: absolute; width: 100px; height: 100px; background: green;'
+                   onclick='this.style.background=&quot;red&quot;'></div>
+          </body>" onload="newFrameLoaded()">
+      </iframe>
+      <iframe id="clickElementAboveFrame" style="left: 200px; top: 0px;" scrolling="yes" onclick="this.style.background='red'" srcdoc="
+          <body style='margin: 0; width: 200px; height: 200px; background: green;'>
+              <div style='position: absolute; width: 100px; height: 100px; background: green;'
+                   onclick='this.style.background=&quot;red&quot;'></div>
+          </body>" onload="newFrameLoaded()">
+      </iframe>
+      <div style="position: absolute; width: 50px; height: 50px; left: 225px; top: 25px; background: red" onclick="this.style.background='green';"></div>
+      <iframe id="clickElementInsideFrame" style="left: 0px; top: 100px;" scrolling="yes" onclick="this.style.background='red'" srcdoc="
+          <body style='margin: 0; width: 200px; height: 200px; background: green;'>
+              <div style='position: absolute; left: 10px; top: 10px; width: 50px; height: 50px; background: red;'
+                   onclick='this.style.background=&quot;green&quot;'></div>
+          </body>" onload="newFrameLoaded()">
+      </iframe>
+      <iframe id="clickElementInsideFrameAfterUserScroll" style="left: 100px; top: 100px;" scrolling="yes" onclick="this.style.background='red'" srcdoc="
+          <body style='margin: 0; width: 200px; height: 200px; background: green;'>
+             <div style='position: absolute; width: 75px; height: 75px; background: red;'></div>
+              <div style='position: absolute; left: 0px; top: 150px; width: 50px; height: 50px; background: red;'
+                   onclick='this.style.background=&quot;green&quot;'></div>
+          </body>" onload="newFrameLoaded()">
+      </iframe>
+    </div>
+</body>
+</html>
index 2e4eb3a..3517b06 100644 (file)
@@ -1,3 +1,28 @@
+2019-01-21  Antti Koivisto  <antti@apple.com>
+
+        [iOS] Handle hit testing for subframes
+        https://bugs.webkit.org/show_bug.cgi?id=192303
+
+        Reviewed by Frédéric Wang.
+
+        Don't set delegatesScrolling bit for subframes on iOS. It is meant for top level application
+        controlled scrolling. This fixes coordinate conversions for subframes and makes events work.
+
+        Test by Frederic Wang.
+
+        Test: fast/scrolling/ios/hit-testing-iframe.html
+
+        * platform/ScrollView.cpp:
+        (WebCore::ScrollView::managesScrollbars const):
+
+        Add a function that tells if the scrollview should deal with scrollbars at all
+        This is always false on iOS and not connected to delegatesScrolling bit.
+
+        (WebCore::ScrollView::updateScrollbars):
+        * platform/ScrollView.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::shouldCompositeOverflowControls const):
+
 2019-01-21  Brent Fulgham  <bfulgham@apple.com>
 
         Implement message handlers for NetworkProcess-based ResourceLoadStatistics
index b4d9820..a598947 100644 (file)
@@ -542,6 +542,19 @@ IntSize ScrollView::overhangAmount() const
     return stretch;
 }
 
+bool ScrollView::managesScrollbars() const
+{
+#if PLATFORM(IOS_FAMILY)
+    return false;
+#else
+    if (platformWidget())
+        return false;
+    if (delegatesScrolling())
+        return false;
+    return true;
+#endif
+}
+
 void ScrollView::updateScrollbars(const ScrollPosition& desiredPosition)
 {
     LOG_WITH_STREAM(Scrolling, stream << "ScrollView::updateScrollbars " << desiredPosition);
@@ -549,7 +562,7 @@ void ScrollView::updateScrollbars(const ScrollPosition& desiredPosition)
     if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget())
         return;
     
-    if (delegatesScrolling()) {
+    if (!managesScrollbars()) {
         if (scrollOriginChanged()) {
             ScrollableArea::scrollToOffsetWithoutAnimation(scrollOffsetFromPosition(desiredPosition));
             resetScrollOriginChanged();
index 4ce9bd8..4675ce9 100644 (file)
@@ -378,6 +378,8 @@ public:
     void setAllowsUnclampedScrollPositionForTesting(bool allowsUnclampedScrollPosition) { m_allowsUnclampedScrollPosition = allowsUnclampedScrollPosition; }
     bool allowsUnclampedScrollPosition() const { return m_allowsUnclampedScrollPosition; }
 
+    bool managesScrollbars() const;
+
 protected:
     ScrollView();
 
index 8a14a33..97d7562 100644 (file)
@@ -3007,10 +3007,7 @@ bool RenderLayerCompositor::shouldCompositeOverflowControls() const
 {
     auto& frameView = m_renderView.frameView();
 
-    if (frameView.platformWidget())
-        return false;
-
-    if (frameView.delegatesScrolling())
+    if (!frameView.managesScrollbars())
         return false;
 
     if (documentUsesTiledBacking())
index b4932d3..bc5da36 100644 (file)
@@ -1,3 +1,15 @@
+2019-01-21  Antti Koivisto  <antti@apple.com>
+
+        [iOS] Handle hit testing for subframes
+        https://bugs.webkit.org/show_bug.cgi?id=192303
+
+        Reviewed by Frédéric Wang.
+
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::transitionToCommittedForNewPage):
+
+        Only set delegatesScrolling for the main frame.
+
 2019-01-21  Brent Fulgham  <bfulgham@apple.com>
 
         Unreviewed test fix after r240243
index aacb5b9..df272f1 100644 (file)
@@ -1439,7 +1439,8 @@ void WebFrameLoaderClient::transitionToCommittedForNewPage()
     m_frame->coreFrame()->view()->setViewExposedRect(webPage->drawingArea()->viewExposedRect());
 #endif
 #if PLATFORM(IOS_FAMILY)
-    m_frame->coreFrame()->view()->setDelegatesScrolling(true);
+    if (isMainFrame)
+        m_frame->coreFrame()->view()->setDelegatesScrolling(true);
 #endif
 
     if (webPage->scrollPinningBehavior() != DoNotPin)