- Revision
- 247161
- Author
- wenson_hs...@apple.com
- Date
- 2019-07-05 09:58:06 -0700 (Fri, 05 Jul 2019)
Log Message
Click events on outer page are not being dispatched correctly after touch-zooming within an iframe
https://bugs.webkit.org/show_bug.cgi?id=185001
<rdar://problem/40569615>
Reviewed by Simon Fraser.
Source/WebKit:
Mitigations introduced in r227759 prevent a touch inside a document of origin A to result in a click event being
dispatched on an element inside a document of origin B. It accomplishes this by keeping track of the security
origin of the last touch via m_potentialTapSecurityOrigin on WebPage. However, there exists a corner case in
which m_potentialTapSecurityOrigin, set after touching a document in a subframe, may persist even after the user
has finished interacting, causing taps in subsequent documents to not result in synthetic click events due to
mismatched potential tap origins.
This may happen if the first user gesture happens inside an element in a subframe with touch event handlers, but
no click event handler (and the touch is additionally not over some clickable element). In this case,
m_potentialTapNode is set to null in WebPage::potentialTapAtPosition, and when we consult it in
WebPage::commitPotentialTap, we just end up calling commitPotentialTapFailed(); and return early. This means
that m_potentialTapNode, m_potentialTapLocation, and (importantly) m_potentialTapSecurityOrigin are not reset.
This causes subsequent taps in the top-level document to never dispatch click events, if the security origin
does not match with that of the subframe.
To fix this, we add a new async IPC message from the UI process to the web process to ensure that our current
security origin is reset before attempting to handle a tap.
Test: http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::resetPotentialTapSecurityOrigin):
Reset any stale potential tap security origin if needed.
* UIProcess/WebPageProxy.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _webTouchEventsRecognized:]):
Send the new IPC message when starting a touch.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::resetPotentialTapSecurityOrigin):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
LayoutTests:
Add a new layout test to verify that after interacting with an element with touch event handlers in a cross-
origin subframe, the user is still able to click on elements on the top level document.
* http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https-expected.txt: Added.
* http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html: Added.
* http/tests/events/touch/ios/resources/touch-target.html: Added.
Modified Paths
Added Paths
Diff
Modified: trunk/LayoutTests/ChangeLog (247160 => 247161)
--- trunk/LayoutTests/ChangeLog 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/LayoutTests/ChangeLog 2019-07-05 16:58:06 UTC (rev 247161)
@@ -1,5 +1,20 @@
2019-07-05 Wenson Hsieh <wenson_hs...@apple.com>
+ Click events on outer page are not being dispatched correctly after touch-zooming within an iframe
+ https://bugs.webkit.org/show_bug.cgi?id=185001
+ <rdar://problem/40569615>
+
+ Reviewed by Simon Fraser.
+
+ Add a new layout test to verify that after interacting with an element with touch event handlers in a cross-
+ origin subframe, the user is still able to click on elements on the top level document.
+
+ * http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https-expected.txt: Added.
+ * http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html: Added.
+ * http/tests/events/touch/ios/resources/touch-target.html: Added.
+
+2019-07-05 Wenson Hsieh <wenson_hs...@apple.com>
+
Touching media controls sometimes shows software keyboard
https://bugs.webkit.org/show_bug.cgi?id=199490
<rdar://problem/52076270>
Added: trunk/LayoutTests/http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https-expected.txt (0 => 247161)
--- trunk/LayoutTests/http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https-expected.txt 2019-07-05 16:58:06 UTC (rev 247161)
@@ -0,0 +1,14 @@
+This test verifies that tap in the top document is recognized as a click after touching inside a cross-origin subframe. To manually test, touch anywhere in the top iframe, and then tap the green box on the bottom. The text 'Clicked' should appear.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS touchend
+PASS Clicked
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
+Then click here.
+Clicked
+
Added: trunk/LayoutTests/http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html (0 => 247161)
--- trunk/LayoutTests/http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html (rev 0)
+++ trunk/LayoutTests/http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html 2019-07-05 16:58:06 UTC (rev 247161)
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+ <script src=""
+ <script src=""
+ <style>
+ iframe, #target {
+ width: 300px;
+ height: 150px;
+ }
+
+ #target {
+ background-color: green;
+ color: white;
+ }
+
+ #result {
+ color: green;
+ }
+ </style>
+ <script>
+ jsTestIsAsync = true;
+ progress = 0;
+
+ function checkProgress() {
+ if (++progress == 2)
+ finishJSTest();
+ }
+
+ description("This test verifies that tap in the top document is recognized as a click after touching inside a cross-origin subframe. To manually test, touch anywhere in the top iframe, and then tap the green box on the bottom. The text 'Clicked' should appear.")
+
+ addEventListener("load", async event => {
+ addEventListener("message", message => testPassed(message.data));
+ document.getElementById("target").addEventListener("click", () => {
+ document.getElementById("result").textContent = "Clicked";
+ testPassed("Clicked");
+ checkProgress();
+ });
+
+ if (!window.testRunner)
+ return;
+
+ await UIHelper.activateElement(document.querySelector("iframe"));
+ await UIHelper.activateElement(document.getElementById("target"));
+ checkProgress();
+ });
+ </script>
+</head>
+<body>
+ <p id="description"></p>
+ <iframe src=""
+ <div id="target">Then click here.</div>
+ <pre id="result"></pre>
+ <pre id="console"></pre>
+</body>
+</html>
\ No newline at end of file
Added: trunk/LayoutTests/http/tests/events/touch/ios/resources/touch-target.html (0 => 247161)
--- trunk/LayoutTests/http/tests/events/touch/ios/resources/touch-target.html (rev 0)
+++ trunk/LayoutTests/http/tests/events/touch/ios/resources/touch-target.html 2019-07-05 16:58:06 UTC (rev 247161)
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<style>
+ body {
+ margin: 0;
+ }
+
+ div {
+ width: 100vw;
+ height: 100vh;
+ }
+</style>
+<div id="target">Touch this element.</div>
+<script>
+document.getElementById("target").addEventListener("touchend", () => parent.postMessage("touchend", "*"));
+</script>
Modified: trunk/Source/WebKit/ChangeLog (247160 => 247161)
--- trunk/Source/WebKit/ChangeLog 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/ChangeLog 2019-07-05 16:58:06 UTC (rev 247161)
@@ -1,5 +1,49 @@
2019-07-05 Wenson Hsieh <wenson_hs...@apple.com>
+ Click events on outer page are not being dispatched correctly after touch-zooming within an iframe
+ https://bugs.webkit.org/show_bug.cgi?id=185001
+ <rdar://problem/40569615>
+
+ Reviewed by Simon Fraser.
+
+ Mitigations introduced in r227759 prevent a touch inside a document of origin A to result in a click event being
+ dispatched on an element inside a document of origin B. It accomplishes this by keeping track of the security
+ origin of the last touch via m_potentialTapSecurityOrigin on WebPage. However, there exists a corner case in
+ which m_potentialTapSecurityOrigin, set after touching a document in a subframe, may persist even after the user
+ has finished interacting, causing taps in subsequent documents to not result in synthetic click events due to
+ mismatched potential tap origins.
+
+ This may happen if the first user gesture happens inside an element in a subframe with touch event handlers, but
+ no click event handler (and the touch is additionally not over some clickable element). In this case,
+ m_potentialTapNode is set to null in WebPage::potentialTapAtPosition, and when we consult it in
+ WebPage::commitPotentialTap, we just end up calling commitPotentialTapFailed(); and return early. This means
+ that m_potentialTapNode, m_potentialTapLocation, and (importantly) m_potentialTapSecurityOrigin are not reset.
+ This causes subsequent taps in the top-level document to never dispatch click events, if the security origin
+ does not match with that of the subframe.
+
+ To fix this, we add a new async IPC message from the UI process to the web process to ensure that our current
+ security origin is reset before attempting to handle a tap.
+
+ Test: http/tests/events/touch/ios/click-after-handling-touch-in-cross-origin-frame.https.html
+
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::resetPotentialTapSecurityOrigin):
+
+ Reset any stale potential tap security origin if needed.
+
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/ios/WKContentViewInteraction.mm:
+ (-[WKContentView _webTouchEventsRecognized:]):
+
+ Send the new IPC message when starting a touch.
+
+ * WebProcess/WebPage/WebPage.cpp:
+ (WebKit::WebPage::resetPotentialTapSecurityOrigin):
+ * WebProcess/WebPage/WebPage.h:
+ * WebProcess/WebPage/WebPage.messages.in:
+
+2019-07-05 Wenson Hsieh <wenson_hs...@apple.com>
+
Touching media controls sometimes shows software keyboard
https://bugs.webkit.org/show_bug.cgi?id=199490
<rdar://problem/52076270>
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (247160 => 247161)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp 2019-07-05 16:58:06 UTC (rev 247161)
@@ -2657,6 +2657,14 @@
m_touchAndPointerEventTracking.reset();
}
+void WebPageProxy::resetPotentialTapSecurityOrigin()
+{
+ if (!hasRunningProcess())
+ return;
+
+ m_process->send(Messages::WebPage::ResetPotentialTapSecurityOrigin(), m_pageID);
+}
+
void WebPageProxy::handleTouchEventAsynchronously(const NativeWebTouchEvent& event)
{
if (!hasRunningProcess())
Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (247160 => 247161)
--- trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h 2019-07-05 16:58:06 UTC (rev 247161)
@@ -828,6 +828,7 @@
#endif
#if ENABLE(IOS_TOUCH_EVENTS)
+ void resetPotentialTapSecurityOrigin();
void handleTouchEventSynchronously(NativeWebTouchEvent&);
void handleTouchEventAsynchronously(const NativeWebTouchEvent&);
Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (247160 => 247161)
--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm 2019-07-05 16:58:06 UTC (rev 247161)
@@ -1315,6 +1315,10 @@
[self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
_layerTreeTransactionIdAtLastTouchStart = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).lastCommittedLayerTreeTransactionID();
+#if ENABLE(TOUCH_EVENTS)
+ _page->resetPotentialTapSecurityOrigin();
+#endif
+
WebKit::InteractionInformationRequest positionInformationRequest { WebCore::IntPoint(_lastInteractionLocation) };
[self doAfterPositionInformationUpdate:[assistant = WeakObjCPtr<WKActionSheetAssistant>(_actionSheetAssistant.get())] (WebKit::InteractionInformationAtPosition information) {
[assistant interactionDidStartWithPositionInformation:information];
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (247160 => 247161)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp 2019-07-05 16:58:06 UTC (rev 247161)
@@ -2916,6 +2916,11 @@
reply(handled);
}
+void WebPage::resetPotentialTapSecurityOrigin()
+{
+ m_potentialTapSecurityOrigin = nullptr;
+}
+
void WebPage::updatePotentialTapSecurityOrigin(const WebTouchEvent& touchEvent, bool wasHandled)
{
if (wasHandled)
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (247160 => 247161)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h 2019-07-05 16:58:06 UTC (rev 247161)
@@ -1320,6 +1320,7 @@
#if ENABLE(IOS_TOUCH_EVENTS)
void touchEventSync(const WebTouchEvent&, CompletionHandler<void(bool)>&&);
+ void resetPotentialTapSecurityOrigin();
void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled);
#elif ENABLE(TOUCH_EVENTS)
void touchEvent(const WebTouchEvent&);
Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (247160 => 247161)
--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2019-07-05 16:38:40 UTC (rev 247160)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in 2019-07-05 16:58:06 UTC (rev 247161)
@@ -126,6 +126,7 @@
#endif
#if ENABLE(IOS_TOUCH_EVENTS)
+ ResetPotentialTapSecurityOrigin()
TouchEventSync(WebKit::WebTouchEvent event) -> (bool handled) Synchronous
#endif
#if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS)