add_child invalidated the canvas but left _draw bound to it, and the draw property only rebuilt when _draw was None. Callers therefore got a context pointing at a discarded image while page._canvas stayed None. table_layouter reads page._canvas directly, so every image inside a table cell laid out after any other content silently degraded to a grey [Image: WxH] placeholder. The property now rebuilds when either half is missing. On its own that would make layout allocate a full-page RGBA canvas per line, because layout measures text through the page - so measurement moves to page.measurement_draw, a 1x1 scratch context that is never invalidated. Its mode matches the render canvas so that Text's width cache does not hold two entries per word. Children built against the scratch context are re-bound to the live canvas by render_children, which already synchronised _draw and _canvas; that behaviour was incidental and is now load-bearing and documented as such. Regenerating the examples shows table images rendering as images rather than placeholders. The empty header row in the second table of example 05 is unrelated and pre-existing - row height ignores cell padding, so text is clipped as padding grows - recorded as evidence under S6.
98 KiB
1360x640px
98 KiB
1360x640px