Record rel_base and the container API, and sweep LAYOUT.md
`frame` is gone from the layout vocabulary in `docs/LAYOUT.md` too, since leaving the design document in the old words defeats the rename; the rendered-frame sense of the word is untouched. The `local == UiRegion::FULL` item is dropped from the handoff: that comment was #18's and is not on the review branch.
This commit is contained in:
1 parent
90400f50ac
commit
93a6830fcd
3 files changed
+70
-60
No files matched your search
+29
-29
@@ -8,7 +8,7 @@ without reading that result does not make the parent's size depend on it.
|
||||
carries those commits whole plus the retained-layout repair built on them. §4 to §6 and the density section
|
||||
retain the rationale of the design but still name types that have since been
|
||||
replaced; they are not an API reference. `docs/HANDOFF.md` is where the work
|
||||
in flight stands. The sections from "Frames, decided boxes and padding"
|
||||
in flight stands. The sections from "Rel bases, decided boxes and padding"
|
||||
onwards are the settled design, the findings that outlived the working log,
|
||||
and the measurement method.
|
||||
|
||||
@@ -302,7 +302,7 @@ physical pixels, unchanged.
|
||||
|
||||
## Masks
|
||||
|
||||
This section and "UI ownership and frame access" describe the app's pinned
|
||||
This section and "UI ownership and rel base access" describe the app's pinned
|
||||
Iris implementation. The upstream #19 review branch still has single
|
||||
rectangular masks and separate `UiData`/`UiRenderState`; adopting it requires
|
||||
integrating the app-side capabilities as well as migrating layout calls.
|
||||
@@ -319,18 +319,18 @@ fragment stage cannot make. Rendering and hit-testing both traverse the full
|
||||
mask chain and use the same rounded-rectangle coverage; `iris/tests/mask_sdf.rs`
|
||||
checks the WGSL implementation against the CPU SDF.
|
||||
|
||||
## Frames, decided boxes and padding
|
||||
## Rel bases, decided boxes and padding
|
||||
|
||||
Containers that only divide room are transparent to fractions. A child frame
|
||||
Containers that only divide room are transparent to fractions. A child rel base
|
||||
is narrowed by a length its parent decided: a declared `px` or `rel` length,
|
||||
or the resolved slot of a `leftover` child. A box a widget reports for itself
|
||||
does not narrow its descendants' frame.
|
||||
does not narrow its descendants' rel base.
|
||||
|
||||
`Pad` is an inset (Bryan, 2026-09-18): it subtracts the padding from both
|
||||
the child's frame and the child's box, and reports the child's size plus the
|
||||
the child's rel base and the child's box, and reports the child's size plus the
|
||||
padding. A `rel(1.0)` child inside padding fills the pad without overflowing
|
||||
it; a wrapping text inside padding wraps at the box the pad was given less
|
||||
the padding. A span's frame never subtracts siblings, so a padded fixed
|
||||
the padding. A span's rel base never subtracts siblings, so a padded fixed
|
||||
child measured after a 24 px sibling in a 900 px row wraps at 844 while a
|
||||
`rel(1.0)` inside it is 868. There is no outset kind and no mixed kind.
|
||||
|
||||
@@ -349,13 +349,13 @@ asserted exactly that and was unsatisfiable.
|
||||
A container that can learn a child's length without drawing it does.
|
||||
`Painter::size_hint` answers from the child's rule, or from
|
||||
`Widget::size_hint` where it implements one, resolved against the asking
|
||||
widget's frame; `Scroll`, `Masked` and a `Stack` without a sizing child hint
|
||||
widget's rel base; `Scroll`, `Masked` and a `Stack` without a sizing child hint
|
||||
`LEFTOVER`, since each always reports the whole of its box. `Span` takes each
|
||||
child's length from its hint where there is one and asks that child exactly
|
||||
once, in the slot it decided; a child with no hint is drawn in the room left
|
||||
from the cursor, because a text has to wrap at the width actually there, and
|
||||
its drawing is moved to its slot with `place_at`. Reading a hint records a
|
||||
size dependency and pins the frame where the hint declared a fraction, the
|
||||
size dependency and pins the rel base where the hint declared a fraction, the
|
||||
same pin a rule that is a fraction takes.
|
||||
|
||||
**What that leaves, and the design that would remove it.** A widget that
|
||||
@@ -373,23 +373,23 @@ either answer moved, which also retires `re_asked`'s deferral. Do it only
|
||||
once an app screen shows the cost, and measure that screen first.
|
||||
|
||||
**There is one coordinate unit, the window** (`1512d84`, `23523ee`). Every box in the
|
||||
tree is a region in window units; a widget's frame is a *length* in the same
|
||||
tree is a region in window units; a widget's rel base is a *length* in the same
|
||||
units and is only what fractions resolve against, so a widget's box need not
|
||||
be its frame and padding can take from both. A region node's entry is a
|
||||
be its rel base and padding can take from both. A region node's entry is a
|
||||
translation -- a `rel 1` region anchored where its box starts -- so nothing
|
||||
composes a frame back up a chain.
|
||||
composes a rel base back up a chain.
|
||||
|
||||
A frame decided for a child is therefore a length of the window too: a row's
|
||||
slot, padding's frame less its pixels, or the box a stack's sizing child
|
||||
A rel base decided for a child is therefore a length of the window too: a row's
|
||||
slot, padding's rel base less its pixels, or the box a stack's sizing child
|
||||
decided (which arrives as `Part::Sized`). It is never a fraction of the
|
||||
parent's frame, because a slot of a row is not a fraction of anything the row
|
||||
parent's rel base, because a slot of a row is not a fraction of anything the row
|
||||
can name -- a division of two lengths, which a `rel + px` length cannot hold.
|
||||
A widget's own declaration *is* a fraction, of whichever of those reached it,
|
||||
and it is the only one of them that also places the box inside the part.
|
||||
|
||||
Validity has a pin for each: `LayoutHolds::region_len` for the box's symbolic
|
||||
length and `frame_len` for the frame's. A range of window pixels cannot say
|
||||
which frame an answer is a fraction of, since two frames are different
|
||||
length and `rel_base` for the rel base's. A range of window pixels cannot say
|
||||
which rel base an answer is a fraction of, since two rel bases are different
|
||||
lengths at the same window size. Resolving any of these lengths in pixels is
|
||||
a read of the window, and `Painter::to_px` is where that read is taken --
|
||||
pinning the window where the length has a fraction in it, and nothing where
|
||||
@@ -449,10 +449,10 @@ floats.
|
||||
|
||||
Every length in the tree is a length of the window, so it becomes pixels in
|
||||
one multiply wherever it is read: `Painter::px_size` and `px_len` for the
|
||||
box, `frame_len` for the frame. There is no chain to walk and no coordinate
|
||||
frame in the way, so a region node cannot break it and warm and cold reach
|
||||
every length by the same expression. (Before `1512d84` a frame was a length
|
||||
of its parent's frame and a local redraw walked back up the parent chain in
|
||||
box, `rel_base` for the rel base. There is no chain to walk and no coordinate
|
||||
rel base in the way, so a region node cannot break it and warm and cold reach
|
||||
every length by the same expression. (Before `1512d84` a rel base was a length
|
||||
of its parent's rel base and a local redraw walked back up the parent chain in
|
||||
`asked_px`; both are gone.)
|
||||
|
||||
- **`Holds::through` is the exact preimage of `px + floor(rel * box)`**:
|
||||
@@ -470,7 +470,7 @@ of its parent's frame and a local redraw walked back up the parent chain in
|
||||
- **`px` is not stored on `ActiveData`, deliberately.** A resize every
|
||||
widget's `Holds` admits redraws nothing, so a stored pixel length would
|
||||
be stale on every widget in the tree with nothing to say so. What is
|
||||
stored is the symbolic frame, which a redraw resolves against the window
|
||||
stored is the symbolic rel base, which a redraw resolves against the window
|
||||
it has.
|
||||
- **The window is not a move entry** (`5b78002`). A chain bottoms out in
|
||||
`MoveIdx::NONE`; the window is applied where a fraction becomes pixels,
|
||||
@@ -502,8 +502,8 @@ of its parent's frame and a local redraw walked back up the parent chain in
|
||||
parent may reuse an answer while redrawing the placed output. Translate the
|
||||
drawing contract back through its placement; do not intersect it into the
|
||||
answer contract.
|
||||
- A fraction resolves once against its frame. A report returns raw and is
|
||||
composed only where a parent narrowed that frame. A part's own pixel length
|
||||
- A fraction resolves once against its rel base. A report returns raw and is
|
||||
composed only where a parent narrowed that rel base. A part's own pixel length
|
||||
is added rather than scaled, so a pixel length remains that many pixels at
|
||||
every nesting depth.
|
||||
- An asked-but-undrawn size dependency belongs to the widget that asked. Keep
|
||||
@@ -557,7 +557,7 @@ must still agree exactly.
|
||||
parts from cold at every other window. There is still no case that changes
|
||||
a tree twice with a resize between, and none that resizes twice.
|
||||
- The fuzzer grows no `rel` rules and never re-parents a widget, so neither
|
||||
a fraction resolved against a frame nor a subtree changing hands is
|
||||
a fraction resolved against a rel base nor a subtree changing hands is
|
||||
covered by any generated tree. Both have cost a defect that only a
|
||||
hand-written expectation or a render caught.
|
||||
|
||||
@@ -568,8 +568,8 @@ must still agree exactly.
|
||||
existed only because a widget was drawn twice; one draw leaves it nothing
|
||||
to name. A plan that proposes bookkeeping for a distinction should first
|
||||
ask whether the distinction has to exist.
|
||||
- **A frame narrowed by a region does not move when its part moves.** A
|
||||
narrowed frame must be a *length*, put back into the part on every
|
||||
- **A rel base narrowed by a region does not move when its part moves.** A
|
||||
narrowed rel base must be a *length*, put back into the part on every
|
||||
placement, exactly as a declared rule already is.
|
||||
- **Choosing between a fixed and a relative child in pixels at the span's
|
||||
current width** admits multiple self-sizing fixed points; seed 13 settles
|
||||
@@ -584,8 +584,8 @@ must still agree exactly.
|
||||
phase. A symbolic pin survives a resize because every ask box is
|
||||
symbolically stable across one, so the pin only fails where an answer
|
||||
changed, which is a real relayout.
|
||||
- **Resolving a rule that is a fraction of the frame from the record instead
|
||||
of redrawing** recovers nothing: `reuse outside: a frame length` is 3 of
|
||||
- **Resolving a rule that is a fraction of the rel base from the record instead
|
||||
of redrawing** recovers nothing: `reuse outside: a rel base` is 3 of
|
||||
264 cold draws at seed 1 and 1 of 758 at seed 13.
|
||||
- **A `git bisect`** once named a commit that could not be the cause; read
|
||||
the tree rather than the bisect when that happens.
|
||||
|
||||
Reference in new issue
Block a user