Title: [227833] branches/safari-605-branch

Diff

Modified: branches/safari-605-branch/LayoutTests/ChangeLog (227832 => 227833)


--- branches/safari-605-branch/LayoutTests/ChangeLog	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/LayoutTests/ChangeLog	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,22 @@
 2018-01-30  Jason Marcell  <[email protected]>
 
+        Cherry-pick r227759. rdar://problem/37019477
+
+    2018-01-29  Andy Estes  <[email protected]>
+
+            [iOS] Restrict synthetic clicks to the origin that handled the underlying touch event
+            https://bugs.webkit.org/show_bug.cgi?id=182252
+            <rdar://problem/21555881>
+
+            Reviewed by Tim Horton.
+
+            * TestExpectations:
+            * http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https-expected.txt: Added.
+            * http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https.html: Added.
+            * http/tests/events/touch/ios/resources/click-target.html: Added.
+
+2018-01-30  Jason Marcell  <[email protected]>
+
         Cherry-pick r227712. rdar://problem/37019428
 
     2018-01-26  Chris Dumez  <[email protected]>

Modified: branches/safari-605-branch/LayoutTests/TestExpectations (227832 => 227833)


--- branches/safari-605-branch/LayoutTests/TestExpectations	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/LayoutTests/TestExpectations	2018-01-30 18:51:45 UTC (rev 227833)
@@ -36,6 +36,7 @@
 media/controls/ipad [ Skip ]
 fast/text-autosizing [ Skip ]
 fast/css/variables/env/ios [ Skip ]
+http/tests/events/touch/ios [ Skip ]
 http/tests/preload/viewport [ Skip ]
 http/tests/gzip-content-encoding [ Skip ]
 

Added: branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https-expected.txt (0 => 227833)


--- branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https-expected.txt	                        (rev 0)
+++ branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https-expected.txt	2018-01-30 18:51:45 UTC (rev 227833)
@@ -0,0 +1,21 @@
+Test that a synthesized mouse event is restricted to the origin that handled its underlying touch event.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Clicks are dispatched to a frame in the same origin as the touch event handler.
+PASS () => frameWasClicked is true
+PASS () => alternateWasClicked is false
+
+Clicks are dispatched to a frame in a different origin when the touch event target frame has no touch event handlers.
+PASS () => frameWasClicked is true
+PASS () => alternateWasClicked is false
+
+Clicks are not dispatched to a frame in a different origin than the touch event handler.
+PASS () => frameWasClicked is false
+PASS () => alternateWasClicked is true
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https.html (0 => 227833)


--- branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https.html	                        (rev 0)
+++ branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https.html	2018-01-30 18:51:45 UTC (rev 227833)
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<head>
+<script src=""
+<script src=""
+<style>
+    body {
+        margin: 0;
+    }
+
+    .target {
+        position: absolute;
+        width: 14px;
+        height: 15px;
+        right: 0px;
+        border: 0;
+    }
+
+    .hidden {
+        visibility: hidden;
+    }
+
+    #touch-target {
+        position: relative;
+        width: 30px;
+        height: 30px;
+    }
+
+    #alternate-click-target {
+        bottom: 0px;
+    }
+
+    #finish-target {
+        width: 30px;
+        height: 30px;
+    }
+</style>
+</head>
+<body>
+<div id="touch-target">
+    <iframe id="click-target" class="target hidden"></iframe>
+    <div id="alternate-click-target" class="target"></div>
+</div>
+<div id="finish-target"></div>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+    description("Test that a synthesized mouse event is restricted to the origin that handled its underlying touch event.");
+    window.jsTestIsAsync = true;
+
+    (async () => {
+        const runTest = async (description, clickTargetSrc, shouldHandleTouchEvents, frameWasClickedExpected, alternateWasClickedExpected) => {
+            debug(description);
+
+            const clickTarget = document.querySelector("#click-target");
+            const alternateClickTarget = document.querySelector("#alternate-click-target");
+            const touchTarget = document.querySelector("#touch-target");
+
+            var frameWasClicked = false;
+            window._onmessage_ = () => frameWasClicked = true;
+
+            var alternateWasClicked = false;
+            alternateClickTarget._onclick_ = () => alternateWasClicked = true;
+
+            if (shouldHandleTouchEvents)
+                touchTarget._ontouchstart_ = () => { clickTarget.classList.toggle("hidden") };
+            else
+                clickTarget.classList.toggle("hidden");
+
+            await new Promise((resolve) => {
+                clickTarget._onload_ = () => resolve();
+                clickTarget.src = ""
+            });
+
+            await UIHelper.activateElement(touchTarget);
+
+            await new Promise((resolve) => {
+                const finishTarget = document.querySelector("#finish-target");
+                finishTarget._onclick_ = () => resolve();
+                UIHelper.activateElement(finishTarget);
+            });
+
+            shouldBe(() => frameWasClicked, () => frameWasClickedExpected);
+            shouldBe(() => alternateWasClicked, () => alternateWasClickedExpected);
+
+            clickTarget.classList.toggle("hidden");
+            touchTarget._ontouchstart_ = null;
+            debug('');
+        };
+
+        await runTest("Clicks are dispatched to a frame in the same origin as the touch event handler.", "resources/click-target.html", true, true, false);
+        await runTest("Clicks are dispatched to a frame in a different origin when the touch event target frame has no touch event handlers.", "https://localhost:8443/events/touch/ios/resources/click-target.html", false, true, false);
+        await runTest("Clicks are not dispatched to a frame in a different origin than the touch event handler.", "https://localhost:8443/events/touch/ios/resources/click-target.html", true, false, true);
+        finishJSTest();
+    })();
+</script>
+<script src=""
+</body>

Added: branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/resources/click-target.html (0 => 227833)


--- branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/resources/click-target.html	                        (rev 0)
+++ branches/safari-605-branch/LayoutTests/http/tests/events/touch/ios/resources/click-target.html	2018-01-30 18:51:45 UTC (rev 227833)
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<style>
+    body {
+        margin: 0;
+    }
+
+    div {
+        width: 100vw;
+        height: 100vh;
+    }
+</style>
+<div _onclick_="window.parent.postMessage('clicked', '*')"></div>

Modified: branches/safari-605-branch/Source/WebCore/ChangeLog (227832 => 227833)


--- branches/safari-605-branch/Source/WebCore/ChangeLog	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebCore/ChangeLog	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,52 @@
 2018-01-30  Jason Marcell  <[email protected]>
 
+        Cherry-pick r227759. rdar://problem/37019477
+
+    2018-01-29  Andy Estes  <[email protected]>
+
+            [iOS] Restrict synthetic clicks to the origin that handled the underlying touch event
+            https://bugs.webkit.org/show_bug.cgi?id=182252
+            <rdar://problem/21555881>
+
+            Reviewed by Tim Horton.
+
+            Test: http/tests/events/touch/ios/cross-frame-single-tap-same-origin.https.html
+
+            * dom/Document.h:
+            (WebCore::Document::handlingTouchEvent const):
+            * page/EventHandler.h:
+            (WebCore::EventHandler::touchEventTargetSubframe const):
+            (WebCore::EventHandler::touches const):
+
+            Exposed some information needed by WebPage::updatePotentialTapSecurityOrigin().
+
+            * page/Frame.h:
+            * page/ios/FrameIOS.mm:
+            (WebCore::Frame::betterApproximateNode):
+            (WebCore::Frame::qualifyingNodeAtViewportLocation):
+
+            Changed NodeQualifier from a function pointer to a WTF::Function.
+
+            (WebCore::Frame::nodeRespondingToClickEvents):
+
+            Turned ancestorRespondingToClickEvents() into a lambda that captures originRestriction. In
+            the lambda, if there is an origin restriction, return nullptr if the hit test result's inner
+            Node is not in the restricted origin.
+
+            (WebCore::Frame::nodeRespondingToScrollWheelEvents):
+
+            Turned ancestorRespondingToScrollWheelEvents() into a lambda.
+
+            (WebCore::ancestorRespondingToScrollWheelEvents):
+
+            Moved to lambda in nodeRespondingToScrollWheelEvents().
+
+            (WebCore::ancestorRespondingToClickEvents):
+
+            Moved to lambda in nodeRespondingToClickEvents().
+
+2018-01-30  Jason Marcell  <[email protected]>
+
         Cherry-pick r227753. rdar://problem/37019534
 
     2018-01-29  Antti Koivisto  <[email protected]>

Modified: branches/safari-605-branch/Source/WebCore/dom/Document.h (227832 => 227833)


--- branches/safari-605-branch/Source/WebCore/dom/Document.h	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebCore/dom/Document.h	2018-01-30 18:51:45 UTC (rev 227833)
@@ -3,7 +3,7 @@
  *           (C) 1999 Antti Koivisto ([email protected])
  *           (C) 2001 Dirk Mueller ([email protected])
  *           (C) 2006 Alexey Proskuryakov ([email protected])
- * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2018 Apple Inc. All rights reserved.
  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
  * Copyright (C) 2011 Google Inc. All rights reserved.
@@ -1405,6 +1405,10 @@
     void removeApplicationStateChangeListener(ApplicationStateChangeListener&);
     void forEachApplicationStateChangeListener(const Function<void(ApplicationStateChangeListener&)>&);
 
+#if ENABLE(IOS_TOUCH_EVENTS)
+    bool handlingTouchEvent() const { return m_handlingTouchEvent; }
+#endif
+
 protected:
     enum ConstructionFlags { Synthesized = 1, NonRenderedPlaceholder = 1 << 1 };
     Document(Frame*, const URL&, unsigned = DefaultDocumentClass, unsigned constructionFlags = 0);

Modified: branches/safari-605-branch/Source/WebCore/page/EventHandler.h (227832 => 227833)


--- branches/safari-605-branch/Source/WebCore/page/EventHandler.h	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebCore/page/EventHandler.h	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -233,6 +233,8 @@
 #if ENABLE(IOS_TOUCH_EVENTS)
     bool dispatchTouchEvent(const PlatformTouchEvent&, const AtomicString&, const EventTargetTouchMap&, float, float);
     bool dispatchSimulatedTouchEvent(IntPoint location);
+    Frame* touchEventTargetSubframe() const { return m_touchEventTargetSubframe.get(); }
+    const TouchArray& touches() const { return m_touches; }
 #endif
 
 #if ENABLE(IOS_GESTURE_EVENTS)

Modified: branches/safari-605-branch/Source/WebCore/page/Frame.h (227832 => 227833)


--- branches/safari-605-branch/Source/WebCore/page/Frame.h	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebCore/page/Frame.h	2018-01-30 18:51:45 UTC (rev 227833)
@@ -5,7 +5,7 @@
  *                     2000-2001 Simon Hausmann <[email protected]>
  *                     2000-2001 Dirk Mueller <[email protected]>
  *                     2000 Stefan Schimanski <[email protected]>
- * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2018 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
  * Copyright (C) 2008 Eric Seidel <[email protected]>
  *
@@ -87,6 +87,7 @@
 class RenderView;
 class RenderWidget;
 class ScriptController;
+class SecurityOrigin;
 class Settings;
 class URL;
 class VisiblePosition;
@@ -102,7 +103,7 @@
 };
 
 enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll };
-typedef Node* (*NodeQualifier)(const HitTestResult&, Node* terminationNode, IntRect* nodeBounds);
+using NodeQualifier = Function<Node* (const HitTestResult&, Node* terminationNode, IntRect* nodeBounds)>;
 #endif
 
 enum {
@@ -207,7 +208,7 @@
     WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&);
 
     WEBCORE_EXPORT Node* deepestNodeAtLocation(const FloatPoint& viewportLocation);
-    WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation);
+    WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* = nullptr);
     WEBCORE_EXPORT Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation);
 
     WEBCORE_EXPORT NSArray *wordsInCurrentParagraph() const;
@@ -308,9 +309,9 @@
     RetainPtr<NSArray> m_dataDetectionResults;
 #endif
 #if PLATFORM(IOS)
-    void betterApproximateNode(const IntPoint& testPoint, NodeQualifier, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect);
+    void betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect);
     bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center);
-    Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, NodeQualifier, bool shouldApproximate);
+    Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier&, bool shouldApproximate);
 
     void overflowAutoScrollTimerFired();
     void startOverflowAutoScroll(const IntPoint&);

Modified: branches/safari-605-branch/Source/WebCore/page/ios/FrameIOS.mm (227832 => 227833)


--- branches/safari-605-branch/Source/WebCore/page/ios/FrameIOS.mm	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebCore/page/ios/FrameIOS.mm	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -224,88 +224,8 @@
     return CGRectZero;
 }
 
-static Node* ancestorRespondingToScrollWheelEvents(const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds)
+void Frame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect)
 {
-    if (nodeBounds)
-        *nodeBounds = IntRect();
-
-    Node* scrollingAncestor = nullptr;
-    for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) {
-        RenderObject* renderer = node->renderer();
-        if (!renderer)
-            continue;
-
-        if ((renderer->isTextField() || renderer->isTextArea()) && downcast<RenderTextControl>(*renderer).canScroll()) {
-            scrollingAncestor = node;
-            continue;
-        }
-
-        auto& style = renderer->style();
-
-        if (renderer->hasOverflowClip() &&
-            (style.overflowY() == OAUTO || style.overflowY() == OSCROLL || style.overflowY() == OOVERLAY ||
-             style.overflowX() == OAUTO || style.overflowX() == OSCROLL || style.overflowX() == OOVERLAY))
-            scrollingAncestor = node;
-    }
-
-    return scrollingAncestor;
-}
-
-static Node* ancestorRespondingToClickEvents(const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds)
-{
-    bool bodyHasBeenReached = false;
-    bool pointerCursorStillValid = true;
-
-    if (nodeBounds)
-        *nodeBounds = IntRect();
-
-    Node* pointerCursorNode = nullptr;
-    for (Node* node = hitTestResult.innerNode(); node && node != terminationNode; node = node->parentInComposedTree()) {
-        // We only accept pointer nodes before reaching the body tag.
-        if (node->hasTagName(HTMLNames::bodyTag)) {
-#if USE(UIKIT_EDITING)
-            // Make sure we cover the case of an empty editable body.
-            if (!pointerCursorNode && node->isContentEditable())
-                pointerCursorNode = node;
-#endif
-            bodyHasBeenReached = true;
-            pointerCursorStillValid = false;
-        }
-
-        // If we already have a pointer, and we reach a table, don't accept it.
-        if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag)))
-            pointerCursorStillValid = false;
-
-        // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor...
-        if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CursorPointer)
-            pointerCursorNode = node;
-        // We want the lowest unbroken chain of pointer cursors.
-        else if (pointerCursorNode)
-            pointerCursorStillValid = false;
-
-        if (node->willRespondToMouseClickEvents() || node->willRespondToMouseMoveEvents() || (is<Element>(*node) && downcast<Element>(*node).isMouseFocusable())) {
-            // If we're at the body or higher, use the pointer cursor node (which may be null).
-            if (bodyHasBeenReached)
-                node = pointerCursorNode;
-
-            // If we are interested about the frame, use it.
-            if (nodeBounds) {
-                // This is a check to see whether this node is an area element.  The only way this can happen is if this is the first check.
-                if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is<HTMLAreaElement>(*node))
-                    *nodeBounds = snappedIntRect(downcast<HTMLAreaElement>(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer()));
-                else if (node && node->renderer())
-                    *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true);
-            }
-
-            return node;
-        }
-    }
-
-    return nullptr;
-}
-
-void Frame::betterApproximateNode(const IntPoint& testPoint, NodeQualifier nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect)
-{
     IntRect candidateRect;
     Node* candidate = nodeQualifierFunction(eventHandler().hitTestResultAtPoint(testPoint), failedNode, &candidateRect);
 
@@ -346,7 +266,7 @@
     return true;
 }
 
-Node* Frame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, NodeQualifier nodeQualifierFunction, bool shouldApproximate)
+Node* Frame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, bool shouldApproximate)
 {
     adjustedViewportLocation = viewportLocation;
 
@@ -468,15 +388,98 @@
     return hitTestResult.innerNode();
 }
 
-Node* Frame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation)
+Node* Frame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin)
 {
-    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, &ancestorRespondingToClickEvents, true);
+    auto&& ancestorRespondingToClickEvents = [securityOrigin](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* {
+        bool bodyHasBeenReached = false;
+        bool pointerCursorStillValid = true;
+
+        if (nodeBounds)
+            *nodeBounds = IntRect();
+
+        auto node = hitTestResult.innerNode();
+        if (!node || (securityOrigin && !securityOrigin->isSameOriginAs(node->document().securityOrigin())))
+            return nullptr;
+
+        Node* pointerCursorNode = nullptr;
+        for (; node && node != terminationNode; node = node->parentInComposedTree()) {
+            // We only accept pointer nodes before reaching the body tag.
+            if (node->hasTagName(HTMLNames::bodyTag)) {
+#if USE(UIKIT_EDITING)
+                // Make sure we cover the case of an empty editable body.
+                if (!pointerCursorNode && node->isContentEditable())
+                    pointerCursorNode = node;
+#endif
+                bodyHasBeenReached = true;
+                pointerCursorStillValid = false;
+            }
+
+            // If we already have a pointer, and we reach a table, don't accept it.
+            if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag)))
+                pointerCursorStillValid = false;
+
+            // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor...
+            if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CursorPointer)
+                pointerCursorNode = node;
+            // We want the lowest unbroken chain of pointer cursors.
+            else if (pointerCursorNode)
+                pointerCursorStillValid = false;
+
+            if (node->willRespondToMouseClickEvents() || node->willRespondToMouseMoveEvents() || (is<Element>(*node) && downcast<Element>(*node).isMouseFocusable())) {
+                // If we're at the body or higher, use the pointer cursor node (which may be null).
+                if (bodyHasBeenReached)
+                    node = pointerCursorNode;
+
+                // If we are interested about the frame, use it.
+                if (nodeBounds) {
+                    // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check.
+                    if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is<HTMLAreaElement>(*node))
+                        *nodeBounds = snappedIntRect(downcast<HTMLAreaElement>(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer()));
+                    else if (node && node->renderer())
+                        *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true);
+                }
+
+                return node;
+            }
+        }
+
+        return nullptr;
+    };
+
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToClickEvents), true);
 }
 
 Node* Frame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation)
 {
+    auto&& ancestorRespondingToScrollWheelEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* {
+        if (nodeBounds)
+            *nodeBounds = IntRect();
+
+        Node* scrollingAncestor = nullptr;
+        for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) {
+            RenderObject* renderer = node->renderer();
+            if (!renderer)
+                continue;
+
+            if ((renderer->isTextField() || renderer->isTextArea()) && downcast<RenderTextControl>(*renderer).canScroll()) {
+                scrollingAncestor = node;
+                continue;
+            }
+
+            auto& style = renderer->style();
+
+            if (renderer->hasOverflowClip()
+                && (style.overflowY() == OAUTO || style.overflowY() == OSCROLL || style.overflowY() == OOVERLAY
+                || style.overflowX() == OAUTO || style.overflowX() == OSCROLL || style.overflowX() == OOVERLAY)) {
+                scrollingAncestor = node;
+            }
+        }
+
+        return scrollingAncestor;
+    };
+
     FloatPoint adjustedViewportLocation;
-    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, &ancestorRespondingToScrollWheelEvents, false);
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToScrollWheelEvents), false);
 }
 
 int Frame::preferredHeight() const

Modified: branches/safari-605-branch/Source/WebKit/ChangeLog (227832 => 227833)


--- branches/safari-605-branch/Source/WebKit/ChangeLog	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebKit/ChangeLog	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,33 @@
 2018-01-30  Jason Marcell  <[email protected]>
 
+        Cherry-pick r227759. rdar://problem/37019477
+
+    2018-01-29  Andy Estes  <[email protected]>
+
+            [iOS] Restrict synthetic clicks to the origin that handled the underlying touch event
+            https://bugs.webkit.org/show_bug.cgi?id=182252
+            <rdar://problem/21555881>
+
+            Reviewed by Tim Horton.
+
+            * WebProcess/WebPage/WebPage.cpp:
+            (WebKit::WebPage::dispatchTouchEvent):
+            (WebKit::WebPage::updatePotentialTapSecurityOrigin):
+
+            Record the target frame origin of touch events that are potential taps, are
+            TouchStart events, are targeted in frames that have touch event listeners, and are not
+            handled by those listeners.
+
+            * WebProcess/WebPage/WebPage.h:
+            * WebProcess/WebPage/ios/WebPageIOS.mm:
+            (WebKit::WebPage::potentialTapAtPosition):
+            (WebKit::WebPage::commitPotentialTap):
+            (WebKit::WebPage::cancelPotentialTapInFrame):
+
+            Passed the target frame origin to Frame::nodeRespondingToClickEvents() then cleared it.
+
+2018-01-30  Jason Marcell  <[email protected]>
+
         Cherry-pick r227758. rdar://problem/37019506
 
     2018-01-29  Alex Christensen  <[email protected]>

Modified: branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/WebPage.cpp (227832 => 227833)


--- branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-01-30 18:51:45 UTC (rev 227833)
@@ -2503,6 +2503,7 @@
     m_lastInteractionLocation = touchEvent.position();
     CurrentEvent currentEvent(touchEvent);
     handled = handleTouchEvent(touchEvent, m_page.get());
+    updatePotentialTapSecurityOrigin(touchEvent, handled);
 }
 
 void WebPage::touchEventSync(const WebTouchEvent& touchEvent, bool& handled)
@@ -2513,6 +2514,39 @@
 
     dispatchTouchEvent(touchEvent, handled);
 }
+
+void WebPage::updatePotentialTapSecurityOrigin(const WebTouchEvent& touchEvent, bool wasHandled)
+{
+    if (wasHandled)
+        return;
+
+    if (!touchEvent.isPotentialTap())
+        return;
+
+    if (touchEvent.type() != WebEvent::TouchStart)
+        return;
+
+    auto& mainFrame = m_page->mainFrame();
+    auto document = mainFrame.document();
+    if (!document)
+        return;
+
+    if (!document->handlingTouchEvent())
+        return;
+
+    Frame* touchEventTargetFrame = &mainFrame;
+    while (auto subframe = touchEventTargetFrame->eventHandler().touchEventTargetSubframe())
+        touchEventTargetFrame = subframe;
+
+    auto& touches = touchEventTargetFrame->eventHandler().touches();
+    if (touches.isEmpty())
+        return;
+
+    ASSERT(touches.size() == 1);
+
+    if (auto targetDocument = touchEventTargetFrame->document())
+        m_potentialTapSecurityOrigin = &targetDocument->securityOrigin();
+}
 #elif ENABLE(TOUCH_EVENTS)
 void WebPage::touchEvent(const WebTouchEvent& touchEvent)
 {

Modified: branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/WebPage.h (227832 => 227833)


--- branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/WebPage.h	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/WebPage.h	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1159,6 +1159,7 @@
 
 #if ENABLE(IOS_TOUCH_EVENTS)
     void touchEventSync(const WebTouchEvent&, bool& handled);
+    void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled);
 #elif ENABLE(TOUCH_EVENTS)
     void touchEvent(const WebTouchEvent&);
 #endif
@@ -1599,6 +1600,7 @@
 
     RefPtr<WebCore::Node> m_potentialTapNode;
     WebCore::FloatPoint m_potentialTapLocation;
+    RefPtr<WebCore::SecurityOrigin> m_potentialTapSecurityOrigin;
 
     WebCore::ViewportConfiguration m_viewportConfiguration;
     bool m_hasReceivedVisibleContentRectsAfterDidCommitLoad { false };

Modified: branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (227832 => 227833)


--- branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-01-30 18:51:39 UTC (rev 227832)
+++ branches/safari-605-branch/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2018-01-30 18:51:45 UTC (rev 227833)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -755,7 +755,7 @@
 
 void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position)
 {
-    m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation);
+    m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation, m_potentialTapSecurityOrigin.get());
     sendTapHighlightForNodeIfNecessary(requestID, m_potentialTapNode.get());
 #if ENABLE(TOUCH_EVENTS)
     if (m_potentialTapNode && !m_potentialTapNode->allowsDoubleTapGesture())
@@ -771,7 +771,7 @@
     }
 
     FloatPoint adjustedPoint;
-    Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(m_potentialTapLocation, adjustedPoint);
+    Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(m_potentialTapLocation, adjustedPoint, m_potentialTapSecurityOrigin.get());
     Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr;
 
     if (!frameRespondingToClick || lastLayerTreeTransactionId < WebFrame::fromCoreFrame(*frameRespondingToClick)->firstLayerTreeTransactionIDAfterDidCommitLoad()) {
@@ -793,6 +793,7 @@
 
     m_potentialTapNode = nullptr;
     m_potentialTapLocation = FloatPoint();
+    m_potentialTapSecurityOrigin = nullptr;
 }
 
 void WebPage::commitPotentialTapFailed()
@@ -816,6 +817,7 @@
 
     m_potentialTapNode = nullptr;
     m_potentialTapLocation = FloatPoint();
+    m_potentialTapSecurityOrigin = nullptr;
 }
 
 void WebPage::tapHighlightAtPosition(uint64_t requestID, const FloatPoint& position)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to