Skip to content

0016 — Layout may draw ahead, and return

Status: Accepted

Context

Planning must not change anything: the engine plans speculatively, often more than once, and discards what it does not use. Most layout honours that by asking each child once, but some layout can only know where content ends by laying it out. A story flowing through columns does not know where the second column starts until the first has been drawn; balancing those columns means trying one height after another. Content composed page by page has the same need in another form: it must say what it would draw without having drawn it.

Blocks keep their progress in their own fields — how many lines of a paragraph are drawn, how many rows of a table, which items of a stack — and ResetOwnState already clears it for a new pass.

Decision

Every block that remembers progress can also save and restore it: SaveOwnProgress returns a copy of what ResetOwnState would clear, and RestoreOwnProgress puts it back. Block.SaveProgress gathers the copies of a whole tree and RestoreProgress returns every block to them.

Layout that must see ahead saves the progress of its content, draws it onto a surface that keeps nothing, notes where it ended, and restores it before returning — so planning still changes nothing.

Content composed page by page does not keep progress in fields at all: each composition is handed the state it got to and returns the state after it, and only drawing advances.

Consequences

  • Flowing columns and balancing are exact: they use the same layout that draws, not an estimate.
  • Every new stateful block must override the pair alongside ResetOwnState; a round-trip test over every kind of stateful content guards them.
  • Drawing ahead costs a layout per trial. Balancing narrows in by halves, a fixed number of trials a page.