Skip to content

Prevent stale selection dismissal from replacing newer selections - #209

Merged
Renakoni merged 1 commit into
mainfrom
fix/selection-dismissal-race
Aug 13, 2026
Merged

Prevent stale selection dismissal from replacing newer selections#209
Renakoni merged 1 commit into
mainfrom
fix/selection-dismissal-race

Conversation

@Renakoni

Copy link
Copy Markdown
Owner

Summary

  • defer outside-tap ActionMode cleanup until the current touch and synthesized mouse sequence settles
  • bind each dismissal to the caret it created and cancel it when Blink upgrades that gesture to a newer word or paragraph selection
  • keep selection ownership monitoring alive through the frame after the native bridge resolves
  • use a generation counter so an older dismissal cannot overwrite a later tap
  • invalidate pending dismissals when the native listener is uninstalled

Root cause

A rapid third tap was consumed by two asynchronous paths. Blink upgraded it to a triple-click paragraph selection, while the selection toolbar treated the same gesture as an outside-tap dismissal. The native ActionMode.finish() round trip then restored the dismissal's older collapsed caret over the newer paragraph selection, producing a visible paragraph-selection flash followed by collapse.

Checking only after the native promise resolves is too late because ActionMode.finish() can itself clear Chromium's selection. The fix therefore confirms ownership before entering native code, observes replacement selections while the bridge is in flight, and waits one additional animation frame after the bridge resolves before deciding whether the original caret is still safe to restore.

Behavior

  • ordinary outside taps still place their caret immediately; only hidden ActionMode cleanup is deferred
  • double/triple-tap selection upgrades keep their newer selection and the custom toolbar re-anchors normally
  • overlapping outside taps allow only the newest request to finish
  • toolbar button taps and non-editor screens retain their existing guards

Verification

  • selection lifecycle tests: 16/16
  • Web unit tests: 83 files / 705 tests
  • selection toolbar mobile WebView E2E: 23/23
  • pnpm typecheck
  • pnpm build
  • focused ESLint
  • git diff --check

Closes #205

@Renakoni
Renakoni merged commit 8060c90 into main Aug 13, 2026
6 checks passed
@Renakoni
Renakoni deleted the fix/selection-dismissal-race branch August 13, 2026 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Selection toolbar outside-tap dismissal races multi-tap selection: triple-tap paragraph selection flashes, then collapses

1 participant