Record the declared-length fix, and park the rest-with-no-leftover rule
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
324f0f02ef
commit
a128648bd2
1 file changed
+44
-2
+44
-2
@@ -26,8 +26,32 @@ reference renders and the resize render are byte-identical across all of
|
|||||||
it, and the hundred-seed sweep passes. `/home/bob/repos/ai-app-2` is on
|
it, and the hundred-seed sweep passes. `/home/bob/repos/ai-app-2` is on
|
||||||
`rustify`, worktree clean.
|
`rustify`, worktree clean.
|
||||||
|
|
||||||
**A declared `rel` length is applied twice, and it is the one thing to fix
|
**Fixed, 2026-09-15, by `de9ddc0`: a declared length is resolved where the
|
||||||
before #18 lands.** `.width(rel(0.5))` in a 400-wide span puts the `SetSize` at
|
widget is drawn.** `Painter` takes a child's `size_hint` in its own box before
|
||||||
|
drawing it there -- which is what a fraction of a length means, and is the
|
||||||
|
identity for a caller that already reserved the space -- and `SetSize::draw`
|
||||||
|
keeps none of it. `rest` is deliberately not resolved there: a part of what is
|
||||||
|
left over is only a length to the widget dividing one, so it passes up in the
|
||||||
|
size, the way it already passes up out of a span. A declared length is then
|
||||||
|
part of the box its parent decided, so a change to one redraws the parent; the
|
||||||
|
lengths resolved into a box are kept beside it in `ActiveData::declared` and
|
||||||
|
compared. Assuming instead that any dirty widget which declares a length needs
|
||||||
|
its parent costs 17% of a frame that dirties 130 of 260 widgets and buys
|
||||||
|
nothing. All five reference renders, the resize render and the image replay are
|
||||||
|
byte-identical to `upstream/main`, and the 100-seed sweep passes.
|
||||||
|
|
||||||
|
`9644971` is the other half of the cost. Whether the inliner took
|
||||||
|
`DrawLayers::write` into `Painter::glyphs` turned out to depend on unrelated
|
||||||
|
code in `iris-core`: the resolution above pushed it out, and a call per glyph
|
||||||
|
cost 12% of a resize frame with every counter -- widget draws, primitive
|
||||||
|
writes, text renders -- unchanged. `#[inline]` says it directly. The
|
||||||
|
random-tree rig is 12.59B instructions per 500 resize frames where it was
|
||||||
|
13.25B before either change, and the `revision_cost` fixture is 1.286 ms
|
||||||
|
against 1.289.
|
||||||
|
|
||||||
|
The defect it fixed, for the record:
|
||||||
|
|
||||||
|
**A declared `rel` length used to be applied twice.** `.width(rel(0.5))` in a 400-wide span puts the `SetSize` at
|
||||||
0..200 and its child at 0..100: the span sizes the box from the hint, and
|
0..200 and its child at 0..100: the span sizes the box from the hint, and
|
||||||
`c596bf1` then measures the child in the declared length again *inside* that
|
`c596bf1` then measures the child in the declared length again *inside* that
|
||||||
box. `px` is unaffected, since 200 px of a box already 200 px wide is the whole
|
box. `px` is unaffected, since 200 px of a box already 200 px wide is the whole
|
||||||
@@ -45,6 +69,24 @@ its box is its own declared length or the whole of what its parent had.
|
|||||||
Minimal repro: `(inner.width(rel(0.5)), rect()).span(Dir::RIGHT)` at 400 wide,
|
Minimal repro: `(inner.width(rel(0.5)), rect()).span(Dir::RIGHT)` at 400 wide,
|
||||||
asking where `inner` landed.
|
asking where `inner` landed.
|
||||||
|
|
||||||
|
**Parked, and wanted: a `rest` with nothing left over should not draw.** The
|
||||||
|
owner asked for it on 2026-09-15 -- "if it's 0 wide for rest then it shouldn't
|
||||||
|
draw in the first place", with `rel` and `px` continuing to overflow forward as
|
||||||
|
they do now, and only a length that is *nothing but* `rest` skipped. Written
|
||||||
|
and reverted: `Span` needs `painter.px_len(axis)` to know whether anything is
|
||||||
|
left over, since `rel(0.5)` beside 300 px is full at 600 and overfull at 400
|
||||||
|
and the difference is not expressible in fractions, and that makes a span's
|
||||||
|
drawing depend on its own box. Inside a `Scroll`, whose box comes from the
|
||||||
|
content, seed 13 of `adding_and_removing_span_children` then lands warm and
|
||||||
|
cold on different answers: the same span holds the same region in both, and
|
||||||
|
`ActiveData::px` says it drew against 63 px warm and 900 cold, so the leftover
|
||||||
|
question is answered in two different boxes. `Painter::undraw` -- drop a child
|
||||||
|
drawn only to measure it, so it is not one of this widget's children this
|
||||||
|
frame -- is the other half and worked. `Branch` in `iris::random` already makes
|
||||||
|
a pixel-dependent choice about which child to draw and the fuzzer is happy with
|
||||||
|
it, so the shape is supported; what is not settled is which box a span should
|
||||||
|
ask in.
|
||||||
|
|
||||||
**The `tabs` divergence does not reproduce, so nothing waits on the owner.**
|
**The `tabs` divergence does not reproduce, so nothing waits on the owner.**
|
||||||
Re-measured 2026-09-15 at `f61e893` against `upstream/main` built in its own
|
Re-measured 2026-09-15 at `f61e893` against `upstream/main` built in its own
|
||||||
worktree: `tabs` at 1920x1200 is byte-identical, and so are a cold 900x1200 and
|
worktree: `tabs` at 1920x1200 is byte-identical, and so are a cold 900x1200 and
|
||||||
|
|||||||
Reference in new issue
Block a user