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)