Skip to content

fix(text): keep SDF font waiters across a failed load so a retry wakes them#109

Merged
chiefcll merged 2 commits into
mainfrom
fix/sdf-font-failed-load-retry
Jun 22, 2026
Merged

fix(text): keep SDF font waiters across a failed load so a retry wakes them#109
chiefcll merged 2 commits into
mainfrom
fix/sdf-font-failed-load-retry

Conversation

@chiefcll

Copy link
Copy Markdown
Contributor

What

Fixes two related defects in the SDF font loader (src/core/text-rendering/SdfFontHandler.ts) around the atlas-load-failure path.

1. fontCache Map deleted via bracket access

The 'failed' handler did delete fontCache[fontFamily], but fontCache is a Map — bracket access deletes a plain property that never existed and leaves any real entry untouched. Switched to fontCache.delete(fontFamily).

2. Text nodes stranded after a failed-then-retried load

loadFont overwrote nodesWaitingForFont[fontFamily] with a fresh [] on every call. The sequence that breaks:

  1. loadFont(F) creates the waiter list; a text node parks itself there while the atlas loads.
  2. The atlas fails — the list is left populated (nodes still want the font), promise rejects.
  3. App calls loadFont(F) again (retry). The old code overwrote the list with [], discarding the parked node.
  4. Retry succeeds → the success path walks the (now empty) list → the parked node is never woken and stays blank forever.

The fix reuses an existing waiter list instead of overwriting it, so a successful retry still wakes nodes parked before the failure. The list is consumed and deleted on the next successful load, and shrinks as nodes self-remove via stopWaitingForFont on destroy.

Why

A font-load failure currently produces a silent permanent blank for any text node already waiting on that font, and a retry can't recover those nodes. There's no canvas fallback in single-engine setups, so this is the only recovery path.

Reviewer notes

  • No new behavior or events — a font that fails and is never retried still ends up blank. This PR only makes a successful retry recover the parked nodes, plus the Map-API correctness fix.
  • Deliberate non-deletion on failure: the 'failed' handler intentionally keeps nodesWaitingForFont[fontFamily] (commented in code). Deleting it there would re-introduce the stranding bug, since parked nodes are dormant (_waitingForFont === true) and only a successful retry walking the preserved list can wake them.
  • Test: SdfFontHandler.test.ts gains a regression test that parks a node → fails the first load → retries → succeeds, asserting the node is woken. Verified it fails against the old overwrite (spy called 0 times) and passes with the fix.

Verification

  • pnpm exec vitest run src/core/text-rendering/ → 29/29 pass
  • pnpm exec tsc --build → clean

🤖 Generated with Claude Code

chiefcll and others added 2 commits June 22, 2026 14:41
…s them

When an SDF font's atlas fails to load, the `'failed'` handler did two
things wrong, and `loadFont` had a related stranding bug:

1. `delete fontCache[fontFamily]` used bracket access on a Map, deleting a
   plain property that never existed and leaving any real cache entry
   untouched. Switch to `fontCache.delete(fontFamily)`.

2. `loadFont` overwrote `nodesWaitingForFont[fontFamily]` with a fresh `[]`
   on every call. After a failed attempt left nodes parked in that list, a
   retry discarded them — so even a successful retry never woke the parked
   text nodes (they stayed blank forever). Reuse the existing list instead;
   it is consumed and deleted on the next successful load, and shrinks as
   nodes self-remove via `stopWaitingForFont` on destroy.

No behavior/events were added: a font that fails and is never retried still
ends up blank (there is no canvas fallback in single-engine setups).

Adds a regression test that parks a node, fails the first load, retries,
and asserts the node is woken (verified to fail against the old overwrite).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chiefcll chiefcll merged commit 3a4acff into main Jun 22, 2026
1 check passed
@chiefcll chiefcll deleted the fix/sdf-font-failed-load-retry branch June 22, 2026 20:17
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.

1 participant