Skip to content

Key cached layouts on the owner size a node's percentages resolve against - #2042

Merged
javache merged 2 commits into
react:mainfrom
YevheniiKotyrlo:fix/owner-size-cache-key
Oct 19, 2026
Merged

javache merged 2 commits into
react:mainfrom
YevheniiKotyrlo:fix/owner-size-cache-key

Conversation

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor

Problem

A node keeps its cached layout after its owner resizes, so its percentage padding, margins and min/max sizes stay resolved against the owner's old size (#1626). calculateLayoutInternal keys cachedLayout and cachedMeasurements on the available size and the sizing modes only:

  } else if (performLayout) {
    if (yoga::inexactEquals(
            layout->cachedLayout.availableWidth, availableWidth) &&
        yoga::inexactEquals(
            layout->cachedLayout.availableHeight, availableHeight) &&
        layout->cachedLayout.widthSizingMode == widthSizingMode &&
        layout->cachedLayout.heightSizingMode == heightSizingMode) {
      cachedResults = &layout->cachedLayout;

A node with a definite size is given the same available size and modes whatever its owner's size, so the entry hits, while padding-left: 50% or min-width: 100% resolve against ownerWidth, which the entry does not record:

Child, laid out again after the root resizes Expected main
width: 50; padding-left: 50%, root 100 → 60 padding 30 50
width: 50; min-width: 100%, root 100 → 200 width 200 100
height: 50; min-height: 100% in a row, root 100 → 200 height 200 100

Any node with a definite size and a percentage padding, margin or size bound is affected once its owner changes size and the node itself does not change.

Solution

Each cache entry records the owner width and height it was computed against. A lookup for a node whose style resolves a percentage against the owner's width (padding, margin, width, min-width, max-width) or height (height, min-height, max-height) also requires that size to match, so the sizing constraint and the percentage-resolution size are separate parts of the key, as suggested in #1626. A node with no such percentage hits the cache exactly as before.

Fixes #1626.

Tests

  • YGRelayoutTest: percent_padding_follows_owner_size_on_relayout, percent_min_width_follows_owner_size_on_relayout and percent_min_height_follows_owner_size_on_relayout lay out the rows of the table above.
  • YGMeasureCacheTest: remeasure_when_owner_resizes_with_percent_padding asserts the measure function runs again and the padding follows; keep_cached_measurement_when_owner_resizes_without_percentages asserts the measure count does not move when nothing resolves against the owner.

On main the four percentage tests fail with the values in the table (and padding 10 instead of 20); the cache-retention test passes before and after.

Verification

Each CI job, run locally with the workflow's own commands:

  • ubuntu:24.04 with Clang 18 (libc++) and GCC 13: ./unit_tests Debug and Release, 864 passed in each of the four, 0 warnings · ./build_fuzz_tests Debug and Release · benchmark and capture built, benchmark and benchmarklegacy run
  • MSVC 19.51: benchmark and capture built, both benchmarks run · ./gradlew assembleDebug assembleRelease on Windows · swift build -c debug and -c release (Xcode 27.0), 0 warnings
  • node:20 image: yarn build, yarn test (573 passed), yarn benchmark in javascript/
  • clang-format 21.1.2: clean on every changed file

yarn gentest-validate and the website were not run; the change touches no fixture or doc.

Median layout time over 7 interleaved benchmark rounds against main: chat-mac +1.8%, feed-android −0.7%, profile-ios +0.7%, rendering-sample-mac −3.2%.

No open or closed PR addresses #1626; searched PRs for percent padding cache, owner size cache, cachedLayout percent, percentage relayout, min-width percent and cache percentage.

Base

main at 6ac92f4.

…inst

A clean node's cached layout and measurements are keyed on its available
size and sizing modes. Its percentage padding, margin, width, min-width
and max-width resolve against the owner's width (and its percentage
height bounds against the owner's height), which the key does not
record, so a node of fixed size keeps the layout its percentages
produced under its owner's previous size.

Each cache entry now records the owner size it was computed against,
and a lookup for a node whose style resolves a percentage against the
owner's width or height requires that size to match.

Fixes react#1626
@meta-cla meta-cla Bot added the CLA Signed label Oct 16, 2026
@YevheniiKotyrlo
YevheniiKotyrlo marked this pull request as ready for review October 16, 2026 08:28
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 16, 2026
@meta-codesync

meta-codesync Bot commented Oct 16, 2026

Copy link
Copy Markdown

@javache has imported this pull request. If you are a Meta employee, you can view this in D125706276.

@javache
javache merged commit 033064f into react:main Oct 19, 2026
34 of 36 checks passed
tomekzaw added a commit to tomekzaw/yoga that referenced this pull request Oct 19, 2026
…ment

The lookup for unconstrained FitContent measurements skipped the owner size
check that react#2042 added to the other cache lookups. A clean node with a fixed
width and percentage padding, margin or width keeps the same available width
when its owner's width changes, so a taller owner made it reuse a measurement
whose percentages were resolved against the previous width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Percentage padding not updated when the parent size changes

2 participants