Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: ea5905fd9777612df86ae3b8471c24c60e9935b7
https://github.com/WebKit/WebKit/commit/ea5905fd9777612df86ae3b8471c24c60e9935b7
Author: Wenson Hsieh <[email protected]>
Date: 2024-11-07 (Thu, 07 Nov 2024)
Changed paths:
A
LayoutTests/pointerevents/ios/dispatch-pointerout-after-synthetic-click-quirk-expected.txt
A
LayoutTests/pointerevents/ios/dispatch-pointerout-after-synthetic-click-quirk.html
M Source/WebCore/Headers.cmake
M Source/WebCore/SaferCPPExpectations/NoUncountedMemberCheckerExpectations
M Source/WebCore/WebCore.xcodeproj/project.pbxproj
M Source/WebCore/page/ChromeClient.h
M Source/WebCore/page/PointerCaptureController.cpp
M Source/WebCore/page/PointerCaptureController.h
M Source/WebCore/page/Quirks.cpp
M Source/WebCore/page/Quirks.h
A Source/WebCore/platform/SyntheticClickResult.h
M Source/WebCore/testing/Internals.cpp
M Source/WebCore/testing/Internals.h
M Source/WebCore/testing/Internals.idl
M Source/WebKit/UIProcess/PageClient.h
M Source/WebKit/UIProcess/WebPageProxy.h
M Source/WebKit/UIProcess/WebPageProxy.messages.in
M Source/WebKit/UIProcess/ios/PageClientImplIOS.h
M Source/WebKit/UIProcess/ios/PageClientImplIOS.mm
M Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
M Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
M Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm
M Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
M Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h
M Source/WebKit/WebProcess/WebPage/WebPage.cpp
M Source/WebKit/WebProcess/WebPage/WebPage.h
M Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm
Log Message:
-----------
soylent.com: dropdown menu dismisses when trying to tap on links
https://bugs.webkit.org/show_bug.cgi?id=282476
rdar://113314067
Reviewed by Aditya Keerthi.
On soylent.com, the site navigation dropdown contains a `pointerout` event
listener which dismisses
the entire dropdown when dispatched. This, when combined with synthetic mouse
events and content
observation, makes it impossible to actually navigate to any links in the
header, since we get the
following sequence of events:
a. User begins a touch over a link inside the dropdown menu, dispatching
`pointerdown`
b. User ends the touch, dispatching `pointerup`
c. Because the touch has ended, we immediately dispatch `pointerout`, and the
page closes the menu
d. In parallel, a synthetic click is recognized in the UI process, dispatching
a synthetic click to
the page
e. This synthetic click hits the `body` element (because the dropdown menu has
already closed), and
we don't click the link
To fix this, we add a quirk to ensure that step (c) now happens after the
synthetic click is
dispatched to the page on `soylent.com`; additionally, this quirk *prevents*
the `pointerout` event
from being dispatched after ending the touch, in the case where the synthetic
click resulted in a
nontrivial content observation (such that the synthetic click state remains in
hover state). This
latter adjustment is required in order to prevent the dropdown menu from
immediately closing after
opening the menu, as a result of dispatching `pointerout`.
At a high level, this bug boils down to the fact that when using a
touch-capable device, `pointer*`
events track the user's touch state and follow the life cycle of touch events,
rather than mapping
to the compatibility mouse events (synthetic clicks) that are dispatched in
response to tapping
elements on the page. soylent.com presents an interesting situation where the
webpage relies on
*both* compatibility mouse events (so that the menu opens when tapping on the
dropdown button), as
well as pointer events (for knowing when to dismiss the menu). The behavior
introduced in this quirk
essentially bridges this gap by allowing `pointerout` to honor the synthetic
mouse hover and clicks
dispatched when tapping the screen, but is likely too risky to deploy in the
general case.
*
LayoutTests/pointerevents/ios/dispatch-pointerout-after-synthetic-click-quirk-expected.txt:
Added.
*
LayoutTests/pointerevents/ios/dispatch-pointerout-after-synthetic-click-quirk.html:
Added.
Add a layout test to exercise this quirk.
* Source/WebCore/Headers.cmake:
Add `SyntheticClickResult.h`.
* Source/WebCore/SaferCPPExpectations/NoUncountedMemberCheckerExpectations:
Update Safer C++ expectations, now that `m_page` is a weak pointer.
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/page/ChromeClient.h:
(WebCore::ChromeClient::callAfterPendingSyntheticClick):
Add a chrome client hook to invoke a callback after waiting for a pending
synthetic click completes.
This may be invoked immediately or asynchronously, with the following results:
• `Failed` The gesture was not recognized as a synthetic click
• `Click` The synthetic click was dispatched
• `Hover` The synthetic click stopped at mouse hover state
• `PageInvalid` The page was invalidated (either because the tab was closed,
or we navigated away)
In the case of `Hover` and `PageInvalid`, we avoid dispatching the
`pointer(out|leave)` events.
* Source/WebCore/page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::dispatchOverOrOutEvent):
(WebCore::PointerCaptureController::dispatchEnterOrLeaveEvent):
Pull these two helpers out as private methods on `PointerCaptureController`, so
we can call into
them asynchronously below.
(WebCore::PointerCaptureController::dispatchEventForTouchAtIndex):
Use `callAfterPendingSyntheticClick` to defer the `pointerout` and
`pointerleave` events until after
the synthetic click has completed (and even withhold them altogether, in the
case of synthetic
hover).
(WebCore::PointerCaptureController::cancelPointer):
* Source/WebCore/page/PointerCaptureController.h:
* Source/WebCore/page/Quirks.cpp:
(WebCore::Quirks::isYahooMail const):
(WebCore::Quirks::isDomain const):
(WebCore::Quirks::domainStartsWith const):
(WebCore::Quirks::needsFormControlToBeMouseFocusable const):
(WebCore::Quirks::isTouchBarUpdateSuppressedForHiddenContentEditable const):
(WebCore::Quirks::isNeverRichlyEditableForTouchBar const):
(WebCore::Quirks::shouldSuppressAutocorrectionAndAutocapitalizationInHiddenEditableAreas
const):
(WebCore::Quirks::shouldDisableWritingSuggestionsByDefault const):
(WebCore::Quirks::isAmazon const):
(WebCore::Quirks::isGoogleMaps const):
(WebCore::Quirks::shouldDispatchSimulatedMouseEvents const):
(WebCore::Quirks::shouldPreventDispatchOfTouchEvent const):
(WebCore::Quirks::shouldAvoidResizingWhenInputViewBoundsChange const):
(WebCore::Quirks::needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand
const):
(WebCore::Quirks::shouldBypassBackForwardCache const):
(WebCore::Quirks::shouldBypassAsyncScriptDeferring const):
(WebCore::Quirks::shouldAvoidPastingImagesAsWebContent const):
(WebCore::Quirks::requestStorageAccessAndHandleClick const):
(WebCore::Quirks::requiresUserGestureToPauseInPictureInPicture const):
(WebCore::Quirks::shouldDisableEndFullscreenEventWhenEnteringPictureInPictureFromFullscreenQuirk
const):
(WebCore::Quirks::allowLayeredFullscreenVideos const):
(WebCore::Quirks::shouldPreventOrientationMediaQueryFromEvaluatingToLandscape
const):
(WebCore::Quirks::shouldFlipScreenDimensions const):
(WebCore::Quirks::shouldIgnoreTextAutoSizing const):
(WebCore::Quirks::scriptToEvaluateBeforeRunningScriptFromURL):
(WebCore::Quirks::shouldHideCoarsePointerCharacteristics const):
(WebCore::Quirks::implicitMuteWhenVolumeSetToZero const):
(WebCore::Quirks::shouldDispatchPointerOutAfterHandlingSyntheticClick const):
(WebCore::Quirks::needsMozillaFileTypeForDataTransfer const):
(WebCore::Quirks::setTopDocumentURLForTesting):
(WebCore::Quirks::topDocumentURL const):
Add the quirk, and also add plumbing for a testing-only hook to allow tests
that have access to
`window.internals` to override the top document URL used for deciding quirks.
The new layout test
uses this mechanism.
(WebCore::isYahooMail): Deleted.
Turn this into a method instead, so that we can use `topDocumentURL` which
accounts for the new
override URL for testing.
* Source/WebCore/page/Quirks.h:
* Source/WebCore/platform/SyntheticClickResult.h: Added.
Add a new enum type; see above for more details.
* Source/WebCore/testing/Internals.cpp:
(WebCore::Internals::setTopDocumentURLForQuirks):
* Source/WebCore/testing/Internals.h:
* Source/WebCore/testing/Internals.idl:
Add a new testing hook to simulate top URLs for quirks; see above for more
details.
* Source/WebKit/UIProcess/PageClient.h:
* Source/WebKit/UIProcess/WebPageProxy.h:
* Source/WebKit/UIProcess/WebPageProxy.messages.in:
Add plumbing for an IPC message that returns whether or not a potential tap is
in progress on iOS.
See below for more details.
* Source/WebKit/UIProcess/ios/PageClientImplIOS.h:
* Source/WebKit/UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::isPotentialTapInProgress const):
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.h:
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView isPotentialTapInProgress]):
* Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::isPotentialTapInProgress):
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::callAfterPendingSyntheticClick):
* Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h:
* Source/WebKit/WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::close):
(WebKit::WebPage::didCommitLoad):
Invoke the pending synthetic click callback with `PageInvalid`, if needed.
(WebKit::WebPage::callAfterPendingSyntheticClick):
Add an empty stub for non-iOS platforms.
* Source/WebKit/WebProcess/WebPage/WebPage.h:
* Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::handleSyntheticClick):
(WebKit::WebPage::didHandleTapAsHover):
(WebKit::WebPage::didFinishContentChangeObserving):
(WebKit::WebPage::completeSyntheticClick):
(WebKit::WebPage::potentialTapAtPosition):
(WebKit::WebPage::commitPotentialTapFailed):
Add calls to invoke the pending synthetic click callback throughout the various
checkpoints during
synthetic mouse event dispatch: `Failed` (for when the potential tap node is
rejected), `Hover` (for
when content change observation fires), and `Click` (for when the click is
dispatched).
(WebKit::WebPage::invokePendingSyntheticClickCallback):
(WebKit::WebPage::callAfterPendingSyntheticClick):
Implement a new helper method on `WebPage` that invokes the callback after the
current synthetic
click event has been dispatched. This avoids racing against gesture state in
the UI process, by
round-tripping to `WKContentView` to determine whether or not the single tap
gesture recognizer has
fired before stashing the callback in `m_pendingSyntheticClickCallback` on the
`WebPage`.
Canonical link: https://commits.webkit.org/286270@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes