Closed Bug 1919411 Opened 1 year ago Closed 6 months ago

<a> :hover state gets triggered atomically with the long-press context-menu on Firefox, vs. slightly before the long-press context-menu in Chrome

Categories

(Core :: Panning and Zooming, defect, P3)

Unspecified
Android
defect

Tracking

()

RESOLVED FIXED
145 Branch
Tracking Status
firefox145 --- fixed

People

(Reporter: dholbert, Assigned: hiro)

References

Details

(Keywords: webcompat:platform-bug, Whiteboard: Epic https://mozilla-hub.atlassian.net/browse/FFXP-3024)

User Story

platform-scheduled:2025-06-30

Attachments

(9 files, 1 obsolete file)

541 bytes, text/html
Details
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review
48 bytes, text/x-phabricator-request
Details | Review

STR:

  1. In Firefox for Android, visit https://bugzilla.mozilla.org/attachment.cgi?id=9425357
  2. Touch the "ANCHOR" element (either the text or anywhere in the black box, I don't think it matters), and immediately drag up/down to scroll the page. Release your finger.
  3. If the anchor element got a colorful background, tap elsewhere (e.g. the "DIV") so that ANCHOR loses its background.
  4. Repeat steps 2-3, waiting shorter/longer amounts between touching the screen and when you drag up/down.

ACTUAL RESULTS:
In Firefox, the anchor element only gains a background (a hover-state) when you've long-pressed it (without yet scrolling) for long enough to trigger a context-menu.

EXPECTED RESULTS:
In Chrome, the anchor element gains a background when you've long-pressed it (without yet scrolling) for a short amount of time, which is shorter than the time that it takes to trigger the context-menu.

This ends up meaning that it's possible to trigger the hover-state without triggering a context-menu (and without actually navigating to the link-target) in Chrome, but not in Firefox.

I'm not sure this area (:hover on Android) is well-specced, but it's perhaps worth considering whether Chrome's behavior here makes any sense and is worth aligning on for compat. We do have one webcompat site-report that was filed about this (bug 1907805) though it's not clear the use-case-that-works-in-Chrome-but-not-Firefox there (making :hover preview images appear by touching and scrolling) is particularly robust or by-design.

screencast showing Chrome first, then Firefox Nightly, on my Pixel 8 with Android 14:
https://drive.google.com/file/d/1jFjkkH7aWQZOBJpR4IBPHcb73oUWB2mb/view?usp=sharing

In Chrome, you can see that the anchor is typically treated as hovered after I've touched it without moving for a moment (maybe 100ms? not sure), and its context-menu doesn't appear if I then start scrolling.

In Firefox, the hover-state doesn't get activated until the context-menu appears.

OS: Unspecified → Android

Given the webcompat bug has a S3 severity, I am marking this one as the same.

Severity: -- → S3
Summary: <a> :hover state gets triggered atomically with the long-press context-menu on Firefox, vs. slightly earlier in Chrome → <a> :hover state gets triggered atomically with the long-press context-menu on Firefox, vs. slightly before the long-press context-menu in Chrome

(In reply to Daniel Holbert [:dholbert] from comment #0)

STR:

  1. In Firefox for Android, visit https://bugzilla.mozilla.org/attachment.cgi?id=9425357
  2. Touch the "ANCHOR" element (either the text or anywhere in the black box, I don't think it matters), and immediately drag up/down to scroll the page. Release your finger.
  3. If the anchor element got a colorful background, tap elsewhere (e.g. the "DIV") so that ANCHOR loses its background.
  4. Repeat steps 2-3, waiting shorter/longer amounts between touching the screen and when you drag up/down.

ACTUAL RESULTS:
In Firefox, the anchor element only gains a background (a hover-state) when you've long-pressed it (without yet scrolling) for long enough to trigger a context-menu.

EXPECTED RESULTS:
In Chrome, the anchor element gains a background when you've long-pressed it (without yet scrolling) for a short amount of time, which is shorter than the time that it takes to trigger the context-menu.

This ends up meaning that it's possible to trigger the hover-state without triggering a context-menu (and without actually navigating to the link-target) in Chrome, but not in Firefox.

I'm not sure this area (:hover on Android) is well-specced, but it's perhaps worth considering whether Chrome's behavior here makes any sense and is worth aligning on for compat. We do have one webcompat site-report that was filed about this (bug 1907805) though it's not clear the use-case-that-works-in-Chrome-but-not-Firefox there (making :hover preview images appear by touching and scrolling) is particularly robust or by-design.

Hi Makoto!
Would love to know your thoughts about a path forward. Does it make sense that we align our behavior to Chrome? How big the effort is if we plan to do the change? Thank you.

Flags: needinfo?(m_kato)

It seems to be APZ behavior. Botond, could you look this by APZ team?

Flags: needinfo?(m_kato) → needinfo?(botond)

Sure, will discuss with the team and follow up on this.

For reference, the relevant code for activating elements in response to touch gestures is in ActiveElementManager.cpp and its uses in APZEventState.cpp.

Whiteboard: [apz-needsdiscussion]
Flags: needinfo?(botond)
Flags: needinfo?(botond)
Attached video Behavior Safari on iOS (obsolete) —

I've captured a screen recording on iOS 18.2. Hope this gives a good impression of the behavior, please let me know should I test differently.
Link: https://drive.google.com/file/d/1bZKcfTdZDggH21SIzRy6mFswJ65xLiXr/view?usp=sharing

Discussed this in today's APZ meeting.

(In reply to Hsin-Yi Tsai (she/her) [:hsinyi] from comment #3)

Does it make sense that we align our behavior to Chrome?

We've verified that Safari also has similar behaviour to Chrome, so we think it would make sense to align with this behaviour as well.

How big the effort is if we plan to do the change?

One thing I overlooked when writing comment 5 is that the :hover state is not directly managed by ActiveElementManager (I was thinking of the :active state, I confused the two). However, the activation of the :hover state is still likely to be an indirect result of actions taken to handle the tap gesture in APZEventState.

We're tracking this for further investigation (and hopefully a fix, if we don't run into any major hurdles) in FFXP-3024.

Component: DOM: UI Events & Focus Handling → Panning and Zooming
Flags: needinfo?(botond)
Priority: -- → P3
Attachment #9444462 - Attachment is obsolete: true
Whiteboard: [apz-needsdiscussion]

Have captured this as part of Jira Epic APZ Android Sprint Part V

User Story: (updated)
Whiteboard: Epic https://mozilla-hub.atlassian.net/browse/FFXP-3024

Note for when we start work on this: re-test the affected scenarios once bug 1633450 has landed, in case it has improved some of them.

Here is another test case, which is closer to what the site in bug 1907805 does.

In this test case there's an APZ aware event listener (touchmove) so that calling ActiveElementManager::HandleTouchStart slightly delays.

This test case realized me that changing :hover state needs to be triggered, i.e. needs to start a timer without waiting for the response from the content. As far as I can tell that's what chrome does.

We will use ElementStateManager for :hover state setting.

Assignee: nobody → hikezoe.birchill
Status: NEW → ASSIGNED

There are two differences from :active state.

  1. A setting :hover state task is triggered right after the initial
    touchstart event is dispatched to the content, i.e. unlike :active
    we don't wait for APZStateChange::eStartTouch notification that the
    result comes from an APZC which has started using the touchstart event

  2. ElementStateManager will never unset :hover state explicitely, :hover
    state will be unset implicitly when a new :hover element is set or
    some other events such as mouseout

These :hover behaviors match Chrome (our :active behaviors don't match
Chrome though, the timing when Chrome sets :hover looks same as :active).

There are three test cases for 1),
helper_hover_state_with_touch_action_none.html:
:hover is set on touch-action:none elements
helper_hover_state_with_prevent_default_on_touchmove.html:
:hover is set even if touchmove is preventDefaulted
helper_hover_state_while_scroll.html:
:hover is set even if the content is being scrolled by the touch events

helper_hover_state_while_scroll.html is also for 2), i.e. :hover state
keeps being applied even after scrolling happens.

One caveat here is that on Chrome :hover state is never set if the
initial touchstart event is preventDefaulted. This case is handled in
the next change.

Attachment #9511598 - Attachment description: Bug 1919411 - Rename CancelTasl to CancelSetActiveTask. r?botond → Bug 1919411 - Rename CancelTask to CancelSetActiveTask. r?botond
Pushed by chorotan@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/b9d02bcfbff0 https://hg.mozilla.org/integration/autoland/rev/75f4f681813a Revert "Bug 1919411 - Do not set :hover state if the touchstart event was preventDefault-ed. r=botond" for causing leaks

Backed out for causing leaks

Backout link

Push with failures

Failure log

Flags: needinfo?(hikezoe.birchill)

Otherwise these tasks will leak if the tasks were in the scheduled queue
when the target document is destroyed.

Posted D265039 to fix the failure (a leak).

In short it's kind pre-exising, our :active task has been also leaked there, but there was no test covering the case. I've added a new test covering the :active case as well as :hover case in the patch.

Flags: needinfo?(hikezoe.birchill)
Pushed by hikezoe.birchill@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/8f7bd5a3a74e https://hg.mozilla.org/integration/autoland/rev/f2cd81177ee0 Rename ActiveElementManager to ElementStateManager. r=botond https://github.com/mozilla-firefox/firefox/commit/349ac19f30cd https://hg.mozilla.org/integration/autoland/rev/0b6acaa63fec Factor out the code for scheduling SetActiveTask. r=botond https://github.com/mozilla-firefox/firefox/commit/9adae67b8221 https://hg.mozilla.org/integration/autoland/rev/7964f764cbc2 Rename CancelTask to CancelSetActiveTask. r=botond https://github.com/mozilla-firefox/firefox/commit/e870da71c93e https://hg.mozilla.org/integration/autoland/rev/915417628d26 Drop trailing line-feeds in MOZ_LOG. r=botond https://github.com/mozilla-firefox/firefox/commit/aa5aa0e26dee https://hg.mozilla.org/integration/autoland/rev/4707377b107c Set :hover state on touch events, similar to what we do for :active. r=botond https://github.com/mozilla-firefox/firefox/commit/91f38f0634a6 https://hg.mozilla.org/integration/autoland/rev/a680bac172a6 Do not set :hover state if the touchstart event was preventDefault-ed. r=botond https://github.com/mozilla-firefox/firefox/commit/9967c184c931 https://hg.mozilla.org/integration/autoland/rev/c371349d9191 Cancel scheduled tasks owned by GestureEventListener when it's destroyed. r=botond https://github.com/mozilla-firefox/firefox/commit/9efd319f32ac https://hg.mozilla.org/integration/autoland/rev/60bc16d960fe Cancel scheduled :active and :hover setting tasks. r=botond
Pushed by chorotan@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/a7ceed3292da https://hg.mozilla.org/integration/autoland/rev/f032c4daf9fa Revert "Bug 1919411 - Cancel scheduled :active and :hover setting tasks. r=botond" for causing mochitest failures on test_group_touchevents-6.html

Backed out for causing muchitest failures

Backout link

Push with failures

Failure log

Flags: needinfo?(hikezoe.birchill)

The new tests failed on non-fission runs. (I am a bit surprised there still exist non-fission runs).

We don't need to run the new tests specifically on non-fission runs.

Flags: needinfo?(hikezoe.birchill)
Pushed by hikezoe.birchill@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/49b9e07dbc85 https://hg.mozilla.org/integration/autoland/rev/1a5291c45f7f Rename ActiveElementManager to ElementStateManager. r=botond https://github.com/mozilla-firefox/firefox/commit/d113678d575c https://hg.mozilla.org/integration/autoland/rev/d75d92ae0a25 Factor out the code for scheduling SetActiveTask. r=botond https://github.com/mozilla-firefox/firefox/commit/096aa5eafe35 https://hg.mozilla.org/integration/autoland/rev/3792e90297a0 Rename CancelTask to CancelSetActiveTask. r=botond https://github.com/mozilla-firefox/firefox/commit/4cd19cf0d737 https://hg.mozilla.org/integration/autoland/rev/69c219a16ebc Drop trailing line-feeds in MOZ_LOG. r=botond https://github.com/mozilla-firefox/firefox/commit/ad7d99864389 https://hg.mozilla.org/integration/autoland/rev/e420ba8f1aba Set :hover state on touch events, similar to what we do for :active. r=botond https://github.com/mozilla-firefox/firefox/commit/ece5556018cc https://hg.mozilla.org/integration/autoland/rev/615e00e7d630 Do not set :hover state if the touchstart event was preventDefault-ed. r=botond https://github.com/mozilla-firefox/firefox/commit/807533b4e734 https://hg.mozilla.org/integration/autoland/rev/d269fde7d16f Cancel scheduled tasks owned by GestureEventListener when it's destroyed. r=botond https://github.com/mozilla-firefox/firefox/commit/b93456329305 https://hg.mozilla.org/integration/autoland/rev/34342a576506 Cancel scheduled :active and :hover setting tasks. r=botond
Pushed by imoraru@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/51a45ab9ff9f https://hg.mozilla.org/integration/autoland/rev/2ec92a1807ff Revert "Bug 1919411 - Cancel scheduled :active and :hover setting tasks. r=botond" for causing mochitest-plain failures on test_group_touchevents-6.html.

Revert for causing mochitest-plain failures on test_group_touchevents-6.html.

[task 2025-09-19T06:47:23.987+00:00] 06:47:23     INFO -  TEST-START | gfx/layers/apz/test/mochitest/test_group_touchevents-6.html
[task 2025-09-19T06:53:57.885+00:00] 06:53:57     INFO -  wait for org.mozilla.geckoview.test_runner complete; top activity=org.mozilla.geckoview.test_runner
[task 2025-09-19T06:53:57.886+00:00] 06:53:57     INFO -  org.mozilla.geckoview.test_runner unexpectedly found running. Killing...
[task 2025-09-19T06:54:11.278+00:00] 06:54:11  WARNING -  TEST-UNEXPECTED-FAIL | gfx/layers/apz/test/mochitest/test_group_touchevents-6.html | application timed out after 370 seconds with no output
[task 2025-09-19T06:54:11.278+00:00] 06:54:11     INFO -  runtestsremote.py | Application ran for: 0:08:35.470814
[task 2025-09-19T06:54:11.360+00:00] 06:54:11     INFO -  runtests.py | Running http tests: end. status: 1
[task 2025-09-19T06:54:11.360+00:00] 06:54:11     INFO -  Stopping web server
[task 2025-09-19T06:54:11.362+00:00] 06:54:11     INFO -  Server shut down.
[task 2025-09-19T06:54:11.362+00:00] 06:54:11     INFO -  Web server killed.
[task 2025-09-19T06:54:11.362+00:00] 06:54:11     INFO -  Stopping web socket server
[task 2025-09-19T06:54:11.362+00:00] 06:54:11     INFO -  Stopping ssltunnel
[task 2025-09-19T06:54:11.604+00:00] 06:54:11     INFO -  Buffered messages logged at 06:47:23
[task 2025-09-19T06:54:11.605+00:00] 06:54:11     INFO -  TEST-PASS | gfx/layers/apz/test/mochitest/test_group_touchevents-6.html | Check if TouchEvent is supported (it should be, the test harness forces it on everywhere)
[task 2025-09-19T06:54:11.605+00:00] 06:54:11     INFO -  TEST-PASS | gfx/layers/apz/test/mochitest/test_group_touchevents-6.html | Starting subtest helper_event_during_fast_fling.html
Flags: needinfo?(hikezoe.birchill)

The failure task is M-fis-hv, which is that example.com is not loading out of process.

I've updated D265039 to skip the tests on fis-hv tasks.

I will land these change tomorrow morning.

Flags: needinfo?(hikezoe.birchill)
Pushed by hikezoe.birchill@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/fbd8f8b153aa https://hg.mozilla.org/integration/autoland/rev/23ca6658ec29 Rename ActiveElementManager to ElementStateManager. r=botond https://github.com/mozilla-firefox/firefox/commit/bec72cecdab7 https://hg.mozilla.org/integration/autoland/rev/9a0aeed42532 Factor out the code for scheduling SetActiveTask. r=botond https://github.com/mozilla-firefox/firefox/commit/7c193833319a https://hg.mozilla.org/integration/autoland/rev/7c852a62abad Rename CancelTask to CancelSetActiveTask. r=botond https://github.com/mozilla-firefox/firefox/commit/e0f9fcd122ad https://hg.mozilla.org/integration/autoland/rev/4b4982f8d383 Drop trailing line-feeds in MOZ_LOG. r=botond https://github.com/mozilla-firefox/firefox/commit/cf0f4e6f011e https://hg.mozilla.org/integration/autoland/rev/185e4f6e570d Set :hover state on touch events, similar to what we do for :active. r=botond https://github.com/mozilla-firefox/firefox/commit/a40e9c56bcd4 https://hg.mozilla.org/integration/autoland/rev/2761d187e9dd Do not set :hover state if the touchstart event was preventDefault-ed. r=botond https://github.com/mozilla-firefox/firefox/commit/ea428a68682c https://hg.mozilla.org/integration/autoland/rev/3b54f91fe6a9 Cancel scheduled tasks owned by GestureEventListener when it's destroyed. r=botond https://github.com/mozilla-firefox/firefox/commit/7555a8a5fbbc https://hg.mozilla.org/integration/autoland/rev/19f29c60f99b Cancel scheduled :active and :hover setting tasks. r=botond
QA Whiteboard: [qa-triage-done-c146/b145]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: