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).
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:incrementalLayoutThe cache never fully clears — the misses come from a font-signature change. The measure-cache key is
blockId@WxH:contentHash#fontSignature, wherefontSignatureis the document-wide set of used faces:{aptos-display-400, arial-400}aptos-display-700→ the document-wide signature becomes{aptos-400, aptos-700, arial-400}→ every block's key changes → all ~3,200 blocks re-measureSo 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
Reproduction
SD_DEBUG_LAYOUT=1, load a large multi-font DOCX, bold text →[Perf] 4.1 Measure all blocks: ~1900ms (… 0 cached).