Repository navigation
native: compare like sizes in Yoga's stricter-size cache rule - #1860
Merged
simonklee merged 4 commits intoOct 30, 2026
Merged
Conversation
When a column's height follows its content (any flexShrink 0 column, such as a scroll node's content), Yoga passes that height to every child as an "at most" cap. When the column grows, no cached size matches the larger cap, so Yoga called the text measure function for every text row: 1,002 calls for one appended row at 1,000 rows. The native text measure uses the cap only to clamp its result, so a size that was below the old cap is still valid. Where Yoga would call such a function, it now takes that cached size at the same width and stores it as a call's result. Its cache, and so every layout, stays the same as before. Host measures keep Yoga's rule. One appended row or one grown row now costs 1 call at any row count. Source additions: a vendored Yoga patch with the rule and a node flag, the flag argument through the bridge, and a test-only call counter. The twin-tree layout test is a new kind of check: it compares every node's layout with Yoga's own rule after each random edit. Issue: 352
Review found two changes that broke layout without a failing test: opting a host measure in to the larger-cap reuse, and dropping the percent-margin guard (a reuse would keep a stale computed margin). The host-measure tables now offer a host leaf a larger cap through both registrations and expect a new size, and the twin-tree test compares every margin, padding, and border edge too. The reuse no longer searches the layout cache entry: the measure pass at the new cap stores the measurement it needs, so counts stay the same (1 call per grown or appended row). Its comment stays in two places. Issue: 352
Yoga's measure cache compared the new available size without the node's margin with the old one with it. A width or height that grew by less than the margin looked like a shrink, so a measured node kept the size it had for the old width. A text with margin 1 and alignSelf "flex-start" wrapped at 18 columns after its parent grew from 20 to 21, where a fresh layout wraps at 19. Both sides of the rule now exclude a positive margin, as in the open upstream fix (react/yoga#1965). A negative margin keeps upstream's rule: a percent margin follows an owner size that no cache entry records, so subtracting it would accept a stale size. Incremental layouts of random flat trees of measured and empty leaves now equal fresh layouts: 0 of 132,487 node layouts differ, against 2,164 before. Source additions: the vendored patch, its line in the update script, and its paragraph in the vendor notes. The incremental-against-fresh test is a new kind of check. Issue: 374
Base automatically changed from
harden/352-scrollbox-height-change-remeasures-all-text
to
main
October 29, 2026 21:38
…mental-layout-differs-from-fresh # Conflicts: # packages/native/src/tests/yoga_test.zig # packages/native/src/vendor/update-zig-deps.sh # packages/native/src/vendor/zig-deps.md # packages/native/src/vendor/zig-deps.sha256 # packages/native/src/vendor/zig-deps.tar.gz
simonklee
deleted the
harden/374-yoga-incremental-layout-differs-from-fresh
branch
October 30, 2026 11:41
Dicklesworthstone
added a commit
to Dicklesworthstone/opentui
that referenced
this pull request
Oct 30, 2026
Incoming from anomalyco origin/main cb3d425, eighteen commits on top of local main e496dfb (54 local commits kept): - cb3d425 native: prepare culled subtrees only where they show (anomalyco#1867) - b8032e2 native: add a video player node (anomalyco#1800) - 26f59cf native: find viewport children with an exact index (anomalyco#1837) - bce826c core: paint TextTable into the frame (anomalyco#1834) - ea10479 core: paint the line-number gutter into the frame (anomalyco#1833) - bbf5719 native: add view resizes and box details to the twin harness (anomalyco#1842) - 27c87ef core: paint Select and TabSelect into the frame (anomalyco#1831) - 1ffb1d5 native: paint a node Yoga sizes to zero as zero cells (anomalyco#1869) - ed309e4 native: add culled, arrow and remount kinds to the twin harness (anomalyco#1836) - 6216869 native: compare like sizes in Yoga's stricter-size cache rule (anomalyco#1860) - 1f1b608 native: write terminal stdout from a native thread (anomalyco#1858) - 68f96b5 docs: rewrite the captured stdout limit for app authors - 057e8c2 core: bound captured stdout in split-footer mode (anomalyco#1856) - e1c27a4 core: save a crash dump when the Yoga worker test crashes (anomalyco#1868) - dfb1d21 native: let a split key finish before the simulated stop (anomalyco#1865) - eb51002 native: keep simulated input in arrival order (anomalyco#1864) - 60b7ce7 core: fix ScrollBox Markdown collapse and selection listener leak (anomalyco#1863) - ae15b99 native: ignore a nil keyboard enter on the WSLg clipboard helper (anomalyco#1862) The merge-tree is one clean tree 1ee7ad2, with 0 path deletions. 112 files change, 11196 insertions and 1018 deletions. The OpenAI File Downloader user-agent line stays at AGENTS.md:64 and packages/web/AGENTS.md:159. Local commits stay on main. This merge is pushed only to the Dicklesworthstone fork. anomalyco/opentui is not pushed. origin/harden/macos-tty-probe is left unfolded. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Yoga's measure cache compared the new available size without the node's margin with the old size with it. A width or height that grew by less than the margin looked like a shrink, so a measured node kept the size it had for the old width. A text with
margin: 1andalignSelf: "flex-start"wrapped at 18 columns after its parent grew from 20 to 21; a fresh layout wraps at 19. It stayed wrong until the width or text changed again.Both sides of the rule now exclude a positive margin, as in the open upstream fix (react/yoga#1965), applied as one more vendored Yoga patch. A negative margin keeps upstream's rule: a percent margin follows an owner size that no cache entry records. The rule now drops only hits whose old size the old cap may have clamped. Measure calls stay at 1 per grown or appended row in a scroll node's content, and random trees take 0.3 to 1.2 % more calls.
Tested by a Yoga test that compares incremental solves of random trees of measured and empty leaves with fresh solves (2,164 of 132,487 node layouts differed before, 0 now), by the cache predicate table, and by a text and textarea row.