@@ -1853,7 +1853,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
1853
1853
assert (child._parent == this );
1854
1854
assert (child.attached == attached);
1855
1855
assert (child.parentData != null );
1856
- child. _cleanRelayoutBoundary ( );
1856
+ _cleanChildRelayoutBoundary (child );
1857
1857
child.parentData! .detach ();
1858
1858
child.parentData = null ;
1859
1859
child._parent = null ;
@@ -2185,6 +2185,32 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2185
2185
}
2186
2186
bool _needsLayout = true ;
2187
2187
2188
+ /// The nearest relayout boundary enclosing this render object, if known.
2189
+ ///
2190
+ /// When a render object is marked as needing layout, its parent may
2191
+ /// as a result also need to be marked as needing layout.
2192
+ /// For details, see [markNeedsLayout] .
2193
+ /// A render object where relayout does not require relayout of the parent
2194
+ /// (because its size cannot change on relayout, or because
2195
+ /// its parent does not use the child's size for its own layout)
2196
+ /// is a "relayout boundary".
2197
+ ///
2198
+ /// This property is set in [layout] , and consulted by [markNeedsLayout] in
2199
+ /// deciding whether to recursively mark the parent as also needing layout.
2200
+ ///
2201
+ /// This property is initially null, and becomes null again if this
2202
+ /// render object is removed from the tree (with [dropChild] );
2203
+ /// it remains null until the first layout of this render object
2204
+ /// after it was most recently added to the tree.
2205
+ /// This property can also be null while an ancestor in the tree is
2206
+ /// currently doing layout, until this render object itself does layout.
2207
+ ///
2208
+ /// When not null, the relayout boundary is either this render object itself
2209
+ /// or one of its ancestors, and all the render objects in the ancestry chain
2210
+ /// up through that ancestor have the same [_relayoutBoundary] .
2211
+ /// Equivalently: when not null, the relayout boundary is either this render
2212
+ /// object itself or the same as that of its parent. (So [_relayoutBoundary]
2213
+ /// is one of `null` , `this` , or `parent!._relayoutBoundary!` .)
2188
2214
RenderObject ? _relayoutBoundary;
2189
2215
2190
2216
/// Whether [invokeLayoutCallback] for this render object is currently running.
@@ -2222,7 +2248,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2222
2248
/// (where it will always be false).
2223
2249
static bool debugCheckingIntrinsics = false ;
2224
2250
2225
- bool _debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout () {
2251
+ bool _debugRelayoutBoundaryAlreadyMarkedNeedsLayout () {
2226
2252
if (_relayoutBoundary == null ) {
2227
2253
// We don't know where our relayout boundary is yet.
2228
2254
return true ;
@@ -2281,7 +2307,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2281
2307
void markNeedsLayout () {
2282
2308
assert (_debugCanPerformMutations);
2283
2309
if (_needsLayout) {
2284
- assert (_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout ());
2310
+ assert (_debugRelayoutBoundaryAlreadyMarkedNeedsLayout ());
2285
2311
return ;
2286
2312
}
2287
2313
if (_relayoutBoundary == null ) {
@@ -2346,32 +2372,36 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2346
2372
markParentNeedsLayout ();
2347
2373
}
2348
2374
2349
- void _cleanRelayoutBoundary () {
2350
- if (_relayoutBoundary != this ) {
2351
- _relayoutBoundary = null ;
2352
- visitChildren (_cleanChildRelayoutBoundary);
2375
+ /// Set [_relayoutBoundary] to null throughout this render object's subtree,
2376
+ /// stopping at relayout boundaries.
2377
+ // This is a static method to reduce closure allocation with visitChildren.
2378
+ static void _cleanChildRelayoutBoundary (RenderObject child) {
2379
+ if (child._relayoutBoundary != child) {
2380
+ child.visitChildren (_cleanChildRelayoutBoundary);
2381
+ child._relayoutBoundary = null ;
2353
2382
}
2354
2383
}
2355
2384
2356
- void _propagateRelayoutBoundary () {
2357
- if (_relayoutBoundary == this ) {
2385
+ // This is a static method to reduce closure allocation with visitChildren.
2386
+ static void _propagateRelayoutBoundaryToChild (RenderObject child) {
2387
+ if (child._relayoutBoundary == child) {
2358
2388
return ;
2359
2389
}
2360
- final RenderObject ? parentRelayoutBoundary = parent? ._relayoutBoundary;
2390
+ final RenderObject ? parentRelayoutBoundary = child. parent? ._relayoutBoundary;
2361
2391
assert (parentRelayoutBoundary != null );
2362
- if (parentRelayoutBoundary != _relayoutBoundary) {
2363
- _relayoutBoundary = parentRelayoutBoundary;
2364
- visitChildren (_propagateRelayoutBoundaryToChild);
2365
- }
2392
+ assert (parentRelayoutBoundary != child._relayoutBoundary);
2393
+ child._setRelayoutBoundary (parentRelayoutBoundary! );
2366
2394
}
2367
2395
2368
- // Reduces closure allocation for visitChildren use cases.
2369
- static void _cleanChildRelayoutBoundary (RenderObject child) {
2370
- child._cleanRelayoutBoundary ();
2371
- }
2372
-
2373
- static void _propagateRelayoutBoundaryToChild (RenderObject child) {
2374
- child._propagateRelayoutBoundary ();
2396
+ /// Set [_relayoutBoundary] to [value] throughout this render object's
2397
+ /// subtree, including this render object but stopping at relayout boundaries
2398
+ /// thereafter.
2399
+ void _setRelayoutBoundary (RenderObject value) {
2400
+ assert (value != _relayoutBoundary);
2401
+ // This may temporarily break the _relayoutBoundary invariant at children;
2402
+ // the visitChildren restores the invariant.
2403
+ _relayoutBoundary = value;
2404
+ visitChildren (_propagateRelayoutBoundaryToChild);
2375
2405
}
2376
2406
2377
2407
/// Bootstrap the rendering pipeline by scheduling the very first layout.
@@ -2396,6 +2426,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2396
2426
2397
2427
@pragma ('vm:notify-debugger-on-exception' )
2398
2428
void _layoutWithoutResize () {
2429
+ assert (_needsLayout);
2399
2430
assert (_relayoutBoundary == this );
2400
2431
RenderObject ? debugPreviousActiveLayout;
2401
2432
assert (! _debugMutationsLocked);
@@ -2520,8 +2551,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2520
2551
}());
2521
2552
2522
2553
if (relayoutBoundary != _relayoutBoundary) {
2523
- _relayoutBoundary = relayoutBoundary;
2524
- visitChildren (_propagateRelayoutBoundaryToChild);
2554
+ _setRelayoutBoundary (relayoutBoundary);
2525
2555
}
2526
2556
2527
2557
if (! kReleaseMode && debugProfileLayoutsEnabled) {
@@ -2530,13 +2560,15 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
2530
2560
return ;
2531
2561
}
2532
2562
_constraints = constraints;
2563
+
2533
2564
if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) {
2534
2565
// The local relayout boundary has changed, must notify children in case
2535
2566
// they also need updating. Otherwise, they will be confused about what
2536
2567
// their actual relayout boundary is later.
2537
2568
visitChildren (_cleanChildRelayoutBoundary);
2538
2569
}
2539
2570
_relayoutBoundary = relayoutBoundary;
2571
+
2540
2572
assert (! _debugMutationsLocked);
2541
2573
assert (! _doingThisLayoutWithCallback);
2542
2574
assert (() {
0 commit comments