fix(focus): keys typed right after a reopen wait until the restored page has loaded, then reach it in order (dogfood port of #32633)

Draft
LA
4d ago
+208-17

Summary

Dogfood port of #32633 (P0 reopen-browser-plain-keys, cycle B; journey kit cp/reopen-video-kit@4ff1d5e5ce6). After Cmd-Q (keep) and reopen, plain keys typed at once into a restored web page were lost. Lawrence's rule: a key typed before the restored content is ready is held and delivered in order, never dropped.

Cause (as on feat, REOPEN VIDEO 7493, 7660, 7710, 7801): the window key hold awaited a restored Chromium tab only until its pane showed the content. The tab shows before Chromium creates its browser, and its first loads are an empty document and documents that the same load replaces. Keys sent on at any of those points were lost.

Fix, same rule as #32633:

  • A shown Chromium tab is awaited until its page is ready for keys (AwaitedContent.Pane.shownPageReady, BrowserTab.pageReady). It is ready when Chromium created its browser and stopped loading (.loadingState(loading: false)) with a real (not blank) document loaded, or with an error page. An aborted load is no page, and a new commit forgets the document loaded before it (Chrome's DidStopLoading).
  • CEFTab.onReadyForKeys reports it once per browser and writes ready-for-keys to the lifecycle trace. TabContentCache forwards it to onBrowserReady. On this line onBrowserReady did not end a page hold (only a focus settle did), so it now calls the new CreationInputCoordinator.pageArrived, which flushes the holds that await that tab, each key once, in order.
  • Bound and end for a page that never gets ready: the hold ends at holdLimit (2 s) and its keys go on in order. This line lacked feat's CreationHoldLog.pageExpired (#32030), so with the new readiness rule the next key would open a new 2 s hold for the same page. This PR ports it: a page whose hold ended at its bound is not held again until it is ready.
  • Paid back the 5 app lines (arch ratchet) by folding two one-line if blocks in TabContentCache and the onBrowserReady line.

Cost: none per key. One flag check when a hold decides what it awaits; one callback per browser.

Testing

Fleet, 5 runs each, proof-step.py (step ids follow in a comment when done):

  • Red 0ec5dee1a9f (the same tests, behavior stubbed): AwaitedContentTests (aShownBrowserTabIsAwaitedUntilItsPageIsReady, aTabExcludedAfterItsBoundIsHeldAgainOnceItsPageArrived), CEFTabHostFocusTests.aTabIsReadyForKeysOnlyOnceLoadingStoppedOnARealDocument.
  • Green b8acefff35d (this head): those suites 5x, plus CreationInputHoldTests (with twoReadySignalsWithKeysHeldBetweenThemDeliverEachKeyOnceInOrder, a guard that is green before and after), ColdBrowserFocusKeysTests, PageFirstKeysTests.
  • Journeys (REOPEN VIDEO, real keys on a mini, kit 4ff1d5e5ce6): reopen-browser-plain-keys (both cycles) and browser-click-then-type, 3 rounds each on a dogfood proof build of this PR + #32579 (link hints) + #32654 (ChildPageFocus grant guard: the dogfood cycle A miss in STATUS 7801).

Observed / Not run

  • Observed on feat: #32633 on proof build 3d14c646 passed both journeys 3/3 (STATUS 7828); held keys went on 3-11 ms after ready-for-keys in every cycle B round.
  • Not run yet on this line: the 5x runs and the journeys; results follow in a comment.

Changelog

Fixed: Keys you type at once into a web page that a reopen restores reach the page, in order

Proof

No capture: key routing; the proof is the tests and the journeys.


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Fixes lost keystrokes after a reopen: keys typed right after Cmd-Q (keep) and reopen now wait until the restored Chromium page has actually loaded, then reach it in order.

After a reopen, a restored Chromium tab showed in its pane before Chromium created its browser, and its first loads were an empty document or documents the same load replaced, so keys sent immediately never reached the page.

  • A shown Chromium tab is awaited until its page is ready for keys: Chromium created its browser and stopped loading with a real document or an error page loaded; an aborted load is no page, and a new commit forgets the previously loaded document.
  • A page asked to show something waits for that document, so a reopen by address no longer sends keys to the empty document before its navigation; a page with nothing to load takes keys once Chromium creates it, and a blank target counts its blank document.
  • Cmd-L passes an empty page hold once the page exists, so the address bar does not wait for the restored document.
  • CEFTab.onReadyForKeys reports once per browser, and the hold's keys are flushed once each, in order, when the page arrives.
  • A page that never gets ready ends the hold at its 2 s bound, and is not held again until its page arrives (ports pageExpired from #32030).
  • Tests cover the readiness rule, the bound, the blank-tab and fresh-page cases, and that no held key is delivered twice or out of order.