Measured nodes in a cached subtree grow by a rounding step on every layout pass
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- cpp, javascript, node.js
- Ambito
- frontend
Direzione di ricerca
Start by running the provided Node.js reproduction with Yoga 3.2.1 and compare it with the point-scale-factor-zero result. Trace how calculateLayout handles cached subtrees and pixel-grid rounding for measured nodes; the payload does not name source files or tests. Done when repeated layout passes leave unchanged measured-node heights at 28.8 and a regression test covers this cached-subtree case.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
With a point scale factor set, measured nodes inside a subtree that comes from the layout cache grow by a rounding step on many calculateLayout calls, and keep growing. In a UI where one node changes size every frame (a progress bar), text boxes grow until the text, centered in its box, drifts onto the next line.
Repro with yoga-layout 3.2.1 on Node 26 (macOS arm64):
// yoga-layout 3.2.1: measured nodes in a cached subtree grow on every layout pass.
import Yoga, {Edge, FlexDirection, PositionType} from 'yoga-layout';
const config = Yoga.Config.create();
config.setPointScaleFactor(100); // round to 0.01 layout units
const root = Yoga.Node.create(config);
root.setWidth(620);
root.setPadding(Edge.All, 24.3);
// Changing this sibling's width relays out the root, while the list
// below is served from the layout cache.
const bar = Yoga.Node.create(config);
bar.setHeight(8);
bar.setWidth(10);
root.insertChild(bar, 0);
const spacer = Yoga.Node.create(config);
spacer.setHeight(517.37);
root.insertChild(spacer, 1);
const anchor = Yoga.Node.create(config);
anchor.setHeight(50.8);
root.insertChild(anchor, 2);
const list = Yoga.Node.create(config);
list.setPositionType(PositionType.Absolute);
list.setPosition(Edge.Bottom, '110%');
anchor.insertChild(list, 0);
const labels = [];
for (let i = 0; i < 30; i++) {
const row = Yoga.Node.create(config);
row.setFlexDirection(FlexDirection.Row);
row.setPadding(Edge.Vertical, 10);
const label = Yoga.Node.create(config);
label.setMeasureFunc(() => ({width: 70.37, height: 28.8}));
row.insertChild(label, 0);
list.insertChild(row, i);
labels.push(label);
}
// Each label measures 28.8 tall; print the ones whose layout height grew.
const grown = () =>
labels
.map((label, i) => [i + 1, label.getComputedHeight()])
.filter(([, h]) => h > 28.8 + 0.005)
.map(([i, h]) => `#${i}=${h.toFixed(2)}`)
.join(' ') || '(none)';
root.calculateLayout(undefined, undefined);
console.log('pass 0 ', grown());
for (let pass = 1; pass <= 600; pass++) {
bar.setWidth(10 + (pass % 50));
root.calculateLayout(undefined, undefined);
if ([1, 10, 100, 600].includes(pass))
console.log(`pass ${pass}`.padEnd(9), grown());
}
Output:
pass 0 (none)
pass 1 #1=28.81 #2=28.81 #3=28.81 #4=28.81 #5=28.81 #6=28.81 #7=28.81 #8=28.81 #9=28.81 #10=28.81 #11=28.81 #12=28.81 #13=28.81 #14=28.81 #15=28.81 #16=28.81 #17=28.81 #19=28.81 #20=28.81 #21=28.81 #22=28.81 #23=28.81 #24=28.81 #25=28.81 #26=28.81 #27=28.81 #28=28.81 #29=28.81 #30=28.81
pass 10 #1=28.82 #2=28.83 #3=28.85 #4=28.90 #5=28.90 #6=28.82 #7=28.83 #8=28.90 #9=28.90 #10=28.90 #11=28.90 #12=28.82 #13=28.81 #14=28.90 #15=28.86 #16=28.86 #17=28.82 #19=28.81 #20=28.82 #21=28.86 #22=28.86 #23=28.81 #24=28.86 #25=28.90 #26=28.90 #27=28.90 #28=28.81 #29=28.90 #30=28.92
pass 100 #1=28.82 #2=28.83 #3=28.85 #4=29.00 #5=29.00 #6=28.82 #7=28.83 #8=29.00 #9=29.00 #10=29.00 #11=29.00 #12=28.82 #13=28.81 #14=29.80 #15=28.86 #16=28.86 #17=28.82 #19=28.81 #20=28.82 #21=28.86 #22=28.86 #23=28.81 #24=28.86 #25=29.00 #26=29.00 #27=29.00 #28=28.81 #29=29.00 #30=29.99
pass 600 #1=28.82 #2=28.83 #3=28.85 #4=29.00 #5=29.00 #6=28.82 #7=28.83 #8=29.00 #9=29.00 #10=29.00 #11=29.00 #12=28.82 #13=28.81 #14=34.80 #15=28.86 #16=28.86 #17=28.82 #19=28.81 #20=28.82 #21=28.86 #22=28.86 #23=28.81 #24=28.86 #25=29.00 #26=29.00 #27=29.00 #28=28.81 #29=29.00 #30=35.95
Every label measures 28.8 tall and nothing in the list changes between passes. With setPointScaleFactor(0) all heights stay at 28.8.
My guess is that the pixel-grid rounding runs again over the cached subtree, which still holds the previous pass's rounded values. For measured nodes the top edge is floored and the bottom edge ceiled, so where float32 storage leaves a small residue in the absolute position, the height goes up one more step each time. Nodes without a measure function keep their size.
Found through @pmndrs/uikit, which sets a point scale factor of 100 (layout rounded to 0.01 units).
- Lingua principale
- C++
- Stelle
- 18.9k
- Fork
- 1.6k
- Merge medio
- 2g 5h
- PR unite (30g)
- 12
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di react/yoga
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 56/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 72/100
react/yoga#2027 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Stale computedFlexBasis is reused across layouts: a flex: 1 node keeps its previous size after relayout at a new root sizeForse già presa @mozzius l’ha presa 64 giorni fa. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
Issue simili
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 65/100
-
error not reported I/O low priority rt_lib
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
I maintainer di solito rispondono entro 1 giorno
-
[XLA] hlo/pass/README.md says passes implement Run; since the NVI change they implement RunImplAperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 91/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
NVIDIA-RTX/NRI#312 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 67/100
I maintainer di solito rispondono entro 9 giorni