Skip to content

perf: first edit re-measures the whole document — measure cache is keyed by a document-wide font signature #3841

Description

@hitpopdimestop

Summary

On a large document, the first formatting edit that introduces a new font face (e.g. the first Bold) blocks for ~2 s while every block is re-measured, even though almost none of them changed. Later edits are fast.

Evidence

Fixture: a 482-page / ~3,200-block DOCX. With SD_DEBUG_LAYOUT=1, bolding a few characters:

edit incrementalLayout measure all blocks
1st bold ~2260 ms 1894 ms (3201 measured, 0 cached)
2nd bold ~395 ms 6 ms (3200 cached)
3rd bold ~558 ms 5 ms (3201 cached)

The cache never fully clears — the misses come from a font-signature change. The measure-cache key is blockId@WxH:contentHash#fontSignature, where fontSignature is the document-wide set of used faces:

  • initial full-doc layout measures under {aptos-display-400, arial-400}
  • the first bold introduces aptos-display-700 → the document-wide signature becomes {aptos-400, aptos-700, arial-400}every block's key changes → all ~3,200 blocks re-measure

So introducing one new face anywhere invalidates the measurements of every block, including thousands with no bold.

Recommended fix

Key each block's measurement by the faces that block uses, not the whole-document signature — so bolding one paragraph invalidates only that paragraph (and a new font family only invalidates blocks that use it).

Caveats / risks

  • Changes the measure-cache correctness contract: the per-block key must capture everything affecting measurement (the block's resolved physical faces) or risk a silent cache collision.
  • Must interact correctly with the late-font-load reflow (a block measured against a fallback must re-measure once the real font loads).

Reproduction

SD_DEBUG_LAYOUT=1, load a large multi-font DOCX, bold text → [Perf] 4.1 Measure all blocks: ~1900ms (… 0 cached).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions