Bug 323851
| Summary: | [QUIRK] google.com: clicking a provider link in the "Where to watch" panel closes the panel instead of navigating | ||
|---|---|---|---|
| Product: | WebKit | Reporter: | Karl Dubost <karlcow> |
| Component: | WebKit Misc. | Assignee: | Karl Dubost <karlcow> |
| Status: | RESOLVED FIXED | ||
| Severity: | Normal | CC: | webkit-bug-importer |
| Priority: | P2 | Keywords: | InRadar |
| Version: | Safari 26 | ||
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
| See Also: | https://bugs.webkit.org/show_bug.cgi?id=18425 | ||
| Bug Depends on: | 229895 | ||
| Bug Blocks: | |||
Karl Dubost
On a Google search result page for a film, the "Where to watch" card expands into a panel of provider rows. Each row is a plain `<a href>`. In Safari, pressing one closes the panel and nothing navigates. Chrome and Firefox navigate on the first press.
**Steps to reproduce**
1. Search Google for a film with several streaming providers. "soylent green" works.
2. Click the "Where to watch" header, or the "+N more" chip, to expand the panel.
3. Click any provider row.
Result: the panel collapses and the page stays where it is.
Expected: the browser navigates to the provider, as it does in Chrome and Firefox.
**Root cause**
WebKit does not give focus to a plain link when it is pressed. `HTMLAnchorElement::isMouseFocusable()` returns `HTMLElement::supportsFocus()` for a link, which is false unless the link carries `tabindex` or `contenteditable`.
Google's panel closes itself when focus leaves it. Its container carries `jsaction="...;blur:.CLIENT"`, and that handler branches on `relatedTarget`. Measured on the live page:
mousedown on a provider link activeElement before: the panel header
activeElement after: body
+1 ms blur and focusout on the header, relatedTarget null
+3 ms the reveal class is removed and the panel collapses
+263 ms mouseup lands on a different element, the panel having shrunk
the click is therefore retargeted to a common ancestor
The link never receives a click, so nothing navigates. The visible symptom is the panel closing, but the closing is the cause rather than a second effect.
The contrasting case in the same session shows the handler is doing what it was written to do. The "+N more" chip is `role="button" tabindex="0"`, so it takes focus, `relatedTarget` stays inside the panel, and the panel stays open. Only the bare links fall out.
Confirmed by adding `tabindex="0"` to the six provider links in the page: they become mouse focusable and the very next press navigates.
**Why a quirk rather than a behaviour change**
WebKit is not violating the specification. HTML leaves this to the user agent:
> A focusable area is said to be click focusable if the user agent determines that it is click focusable.
https://html.spec.whatwg.org/multipage/interaction.html#focus
The specification only says user agents should treat focusable areas with a non-null tabindex as click focusable, which WebKit already does. So this is a divergence from the other engines, not a defect, and changing WebKit's default focus-on-press behaviour is a much larger change than this site needs.
**Proposed fix**
A new quirk, `needsExpandablePanelAnchorToBeMouseFocusableQuirk`, narrower than the existing `needsAnchorToBeMouseFocusableQuirk` that covers dictionary.com and thesaurus.com for the same root cause:
URL scope anyTopLevelDomain("google") and pathIs("/search")
element scope only anchors with an ancestor carrying data-expc
So only links inside the expandable panel become mouse focusable. Every other link on a Google results page is unaffected, and no other Google property is touched. `anyTopLevelDomain` is needed because the panel is locale-dependent and the reproduction is easiest on a ccTLD.
The element check is affordable because `isMouseFocusable()` runs on mouse press, not during style resolution or painting. The ancestor walk is bounded at 12 levels.
Known weakness, stated up front: `data-expc` is Google's markup. If they rename it the quirk stops matching and the bug returns silently. The alternative is a domain-wide quirk, which changes focus behaviour for every link on the domain. This patch takes the narrower scope; widening it later is a one-line change.
**Test coverage**
`fast/quirks/active-quirks-by-domain.html` gains three URLs covering the scoping: the results page, a deeper path under /search that must not match, and a ccTLD results page. Six expected files updated, since the quirk is cocoa-only and glib must show no change.
**Console output**
No new logging is needed. `Quirks::logQuirksToConsoleIfNecessary()`, called from `FrameLoader.cpp` on main-frame load, already lists every quirk enabled for the URL. On a Google search page the Web Inspector console will show a warning of the form:
<url> has active WebKit quirks: MaybeBypassBackForwardCache, NeedsExpandablePanelAnchorToBeMouseFocusableQuirk. Visit https://docs.webkit.org/Infrastructure/Quirks.html for more information.
Note this reports quirks enabled for the URL, not quirks that changed behaviour on a given interaction, which is how every table-driven quirk reports.
**Reproducing the bug after the quirk lands**
The quirk hides the bug, so to see the original behaviour again, turn site-specific quirks off:
MiniBrowser Settings menu, uncheck "Enable site-specific quirks"
Safari Develop menu, the compatibility setting that disables site-specific hacks
With quirks disabled, steps 1 to 3 above fail exactly as reported. With quirks enabled, the provider link navigates. That difference is the check that this patch is doing what it claims.
For a layout test the equivalent switch is `internals.setTopDocumentURLForQuirks(url)`, which turns `needsSiteSpecificQuirks` on and sets the URL used for matching, plus `internals.activeQuirks()` to read back what is enabled.
| Attachments | ||
|---|---|---|
| Add attachment proposed patch, testcase, etc. |
Karl Dubost
<rdar://181740296>
Karl Dubost
Pull request: https://github.com/WebKit/WebKit/pull/73658
EWS
Committed 320889@main (e27850ecf367): <https://commits.webkit.org/320889@main>
Reviewed commits have been landed. Closing PR #73658 and removing active labels.