1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'dart:ui' as ui show PictureRecorder;
6
7import 'package:flutter/animation.dart';
8import 'package:flutter/foundation.dart';
9import 'package:flutter/gestures.dart';
10import 'package:flutter/painting.dart';
11import 'package:flutter/scheduler.dart';
12import 'package:flutter/semantics.dart';
13
14import 'debug.dart';
15import 'layer.dart';
16
17export 'package:flutter/foundation.dart' show
18 DiagnosticPropertiesBuilder,
19 DiagnosticsNode,
20 DiagnosticsProperty,
21 DoubleProperty,
22 EnumProperty,
23 ErrorDescription,
24 ErrorHint,
25 ErrorSummary,
26 FlagProperty,
27 FlutterError,
28 InformationCollector,
29 IntProperty,
30 StringProperty;
31export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
32export 'package:flutter/painting.dart';
33
34/// Base class for data associated with a [RenderObject] by its parent.
35///
36/// Some render objects wish to store data on their children, such as the
37/// children's input parameters to the parent's layout algorithm or the
38/// children's position relative to other children.
39///
40/// See also:
41///
42/// * [RenderObject.setupParentData], which [RenderObject] subclasses may
43/// override to attach specific types of parent data to children.
44class ParentData {
45 /// Called when the RenderObject is removed from the tree.
46 @protected
47 @mustCallSuper
48 void detach() { }
49
50 @override
51 String toString() => '<none>';
52}
53
54/// Signature for painting into a [PaintingContext].
55///
56/// The `offset` argument is the offset from the origin of the coordinate system
57/// of the [PaintingContext.canvas] to the coordinate system of the callee.
58///
59/// Used by many of the methods of [PaintingContext].
60typedef PaintingContextCallback = void Function(PaintingContext context, Offset offset);
61
62/// A place to paint.
63///
64/// Rather than holding a canvas directly, [RenderObject]s paint using a painting
65/// context. The painting context has a [Canvas], which receives the
66/// individual draw operations, and also has functions for painting child
67/// render objects.
68///
69/// When painting a child render object, the canvas held by the painting context
70/// can change because the draw operations issued before and after painting the
71/// child might be recorded in separate compositing layers. For this reason, do
72/// not hold a reference to the canvas across operations that might paint
73/// child render objects.
74///
75/// New [PaintingContext] objects are created automatically when using
76/// [PaintingContext.repaintCompositedChild] and [pushLayer].
77class PaintingContext extends ClipContext {
78
79 /// Creates a painting context.
80 ///
81 /// Typically only called by [PaintingContext.repaintCompositedChild]
82 /// and [pushLayer].
83 @protected
84 PaintingContext(this._containerLayer, this.estimatedBounds);
85
86 final ContainerLayer _containerLayer;
87
88 /// An estimate of the bounds within which the painting context's [canvas]
89 /// will record painting commands. This can be useful for debugging.
90 ///
91 /// The canvas will allow painting outside these bounds.
92 ///
93 /// The [estimatedBounds] rectangle is in the [canvas] coordinate system.
94 final Rect estimatedBounds;
95
96 /// Repaint the given render object.
97 ///
98 /// The render object must be attached to a [PipelineOwner], must have a
99 /// composited layer, and must be in need of painting. The render object's
100 /// layer, if any, is re-used, along with any layers in the subtree that don't
101 /// need to be repainted.
102 ///
103 /// See also:
104 ///
105 /// * [RenderObject.isRepaintBoundary], which determines if a [RenderObject]
106 /// has a composited layer.
107 static void repaintCompositedChild(RenderObject child, { bool debugAlsoPaintedParent = false }) {
108 assert(child._needsPaint);
109 _repaintCompositedChild(
110 child,
111 debugAlsoPaintedParent: debugAlsoPaintedParent,
112 );
113 }
114
115 static void _repaintCompositedChild(
116 RenderObject child, {
117 bool debugAlsoPaintedParent = false,
118 PaintingContext? childContext,
119 }) {
120 assert(child.isRepaintBoundary);
121 assert(() {
122 // register the call for RepaintBoundary metrics
123 child.debugRegisterRepaintBoundaryPaint(
124 includedParent: debugAlsoPaintedParent,
125 includedChild: true,
126 );
127 return true;
128 }());
129 OffsetLayer? childLayer = child._layerHandle.layer as OffsetLayer?;
130 if (childLayer == null) {
131 assert(debugAlsoPaintedParent);
132 assert(child._layerHandle.layer == null);
133
134 // Not using the `layer` setter because the setter asserts that we not
135 // replace the layer for repaint boundaries. That assertion does not
136 // apply here because this is exactly the place designed to create a
137 // layer for repaint boundaries.
138 final OffsetLayer layer = child.updateCompositedLayer(oldLayer: null);
139 child._layerHandle.layer = childLayer = layer;
140 } else {
141 assert(debugAlsoPaintedParent || childLayer.attached);
142 Offset? debugOldOffset;
143 assert(() {
144 debugOldOffset = childLayer!.offset;
145 return true;
146 }());
147 childLayer.removeAllChildren();
148 final OffsetLayer updatedLayer = child.updateCompositedLayer(oldLayer: childLayer);
149 assert(identical(updatedLayer, childLayer),
150 '$child created a new layer instance $updatedLayer instead of reusing the '
151 'existing layer $childLayer. See the documentation of RenderObject.updateCompositedLayer '
152 'for more information on how to correctly implement this method.'
153 );
154 assert(debugOldOffset == updatedLayer.offset);
155 }
156 child._needsCompositedLayerUpdate = false;
157
158 assert(identical(childLayer, child._layerHandle.layer));
159 assert(child._layerHandle.layer is OffsetLayer);
160 assert(() {
161 childLayer!.debugCreator = child.debugCreator ?? child.runtimeType;
162 return true;
163 }());
164
165 childContext ??= PaintingContext(childLayer, child.paintBounds);
166 child._paintWithContext(childContext, Offset.zero);
167
168 // Double-check that the paint method did not replace the layer (the first
169 // check is done in the [layer] setter itself).
170 assert(identical(childLayer, child._layerHandle.layer));
171 childContext.stopRecordingIfNeeded();
172 }
173
174 /// Update the composited layer of [child] without repainting its children.
175 ///
176 /// The render object must be attached to a [PipelineOwner], must have a
177 /// composited layer, and must be in need of a composited layer update but
178 /// not in need of painting. The render object's layer is re-used, and none
179 /// of its children are repaint or their layers updated.
180 ///
181 /// See also:
182 ///
183 /// * [RenderObject.isRepaintBoundary], which determines if a [RenderObject]
184 /// has a composited layer.
185 static void updateLayerProperties(RenderObject child) {
186 assert(child.isRepaintBoundary && child._wasRepaintBoundary);
187 assert(!child._needsPaint);
188 assert(child._layerHandle.layer != null);
189
190 final OffsetLayer childLayer = child._layerHandle.layer! as OffsetLayer;
191 Offset? debugOldOffset;
192 assert(() {
193 debugOldOffset = childLayer.offset;
194 return true;
195 }());
196 final OffsetLayer updatedLayer = child.updateCompositedLayer(oldLayer: childLayer);
197 assert(identical(updatedLayer, childLayer),
198 '$child created a new layer instance $updatedLayer instead of reusing the '
199 'existing layer $childLayer. See the documentation of RenderObject.updateCompositedLayer '
200 'for more information on how to correctly implement this method.'
201 );
202 assert(debugOldOffset == updatedLayer.offset);
203 child._needsCompositedLayerUpdate = false;
204 }
205
206 /// In debug mode, repaint the given render object using a custom painting
207 /// context that can record the results of the painting operation in addition
208 /// to performing the regular paint of the child.
209 ///
210 /// See also:
211 ///
212 /// * [repaintCompositedChild], for repainting a composited child without
213 /// instrumentation.
214 static void debugInstrumentRepaintCompositedChild(
215 RenderObject child, {
216 bool debugAlsoPaintedParent = false,
217 required PaintingContext customContext,
218 }) {
219 assert(() {
220 _repaintCompositedChild(
221 child,
222 debugAlsoPaintedParent: debugAlsoPaintedParent,
223 childContext: customContext,
224 );
225 return true;
226 }());
227 }
228
229 /// Paint a child [RenderObject].
230 ///
231 /// If the child has its own composited layer, the child will be composited
232 /// into the layer subtree associated with this painting context. Otherwise,
233 /// the child will be painted into the current PictureLayer for this context.
234 void paintChild(RenderObject child, Offset offset) {
235 assert(() {
236 debugOnProfilePaint?.call(child);
237 return true;
238 }());
239
240 if (child.isRepaintBoundary) {
241 stopRecordingIfNeeded();
242 _compositeChild(child, offset);
243 // If a render object was a repaint boundary but no longer is one, this
244 // is where the framework managed layer is automatically disposed.
245 } else if (child._wasRepaintBoundary) {
246 assert(child._layerHandle.layer is OffsetLayer);
247 child._layerHandle.layer = null;
248 child._paintWithContext(this, offset);
249 } else {
250 child._paintWithContext(this, offset);
251 }
252 }
253
254 void _compositeChild(RenderObject child, Offset offset) {
255 assert(!_isRecording);
256 assert(child.isRepaintBoundary);
257 assert(_canvas == null || _canvas!.getSaveCount() == 1);
258
259 // Create a layer for our child, and paint the child into it.
260 if (child._needsPaint || !child._wasRepaintBoundary) {
261 repaintCompositedChild(child, debugAlsoPaintedParent: true);
262 } else {
263 if (child._needsCompositedLayerUpdate) {
264 updateLayerProperties(child);
265 }
266 assert(() {
267 // register the call for RepaintBoundary metrics
268 child.debugRegisterRepaintBoundaryPaint();
269 child._layerHandle.layer!.debugCreator = child.debugCreator ?? child;
270 return true;
271 }());
272 }
273 assert(child._layerHandle.layer is OffsetLayer);
274 final OffsetLayer childOffsetLayer = child._layerHandle.layer! as OffsetLayer;
275 childOffsetLayer.offset = offset;
276 appendLayer(childOffsetLayer);
277 }
278
279 /// Adds a layer to the recording requiring that the recording is already
280 /// stopped.
281 ///
282 /// Do not call this function directly: call [addLayer] or [pushLayer]
283 /// instead. This function is called internally when all layers not
284 /// generated from the [canvas] are added.
285 ///
286 /// Subclasses that need to customize how layers are added should override
287 /// this method.
288 @protected
289 void appendLayer(Layer layer) {
290 assert(!_isRecording);
291 layer.remove();
292 _containerLayer.append(layer);
293 }
294
295 bool get _isRecording {
296 final bool hasCanvas = _canvas != null;
297 assert(() {
298 if (hasCanvas) {
299 assert(_currentLayer != null);
300 assert(_recorder != null);
301 assert(_canvas != null);
302 } else {
303 assert(_currentLayer == null);
304 assert(_recorder == null);
305 assert(_canvas == null);
306 }
307 return true;
308 }());
309 return hasCanvas;
310 }
311
312 // Recording state
313 PictureLayer? _currentLayer;
314 ui.PictureRecorder? _recorder;
315 Canvas? _canvas;
316
317 /// The canvas on which to paint.
318 ///
319 /// The current canvas can change whenever you paint a child using this
320 /// context, which means it's fragile to hold a reference to the canvas
321 /// returned by this getter.
322 @override
323 Canvas get canvas {
324 if (_canvas == null) {
325 _startRecording();
326 }
327 assert(_currentLayer != null);
328 return _canvas!;
329 }
330
331 void _startRecording() {
332 assert(!_isRecording);
333 _currentLayer = PictureLayer(estimatedBounds);
334 _recorder = ui.PictureRecorder();
335 _canvas = Canvas(_recorder!);
336 _containerLayer.append(_currentLayer!);
337 }
338
339 /// Adds a [CompositionCallback] for the current [ContainerLayer] used by this
340 /// context.
341 ///
342 /// Composition callbacks are called whenever the layer tree containing the
343 /// current layer of this painting context gets composited, or when it gets
344 /// detached and will not be rendered again. This happens regardless of
345 /// whether the layer is added via retained rendering or not.
346 ///
347 /// {@macro flutter.rendering.Layer.compositionCallbacks}
348 ///
349 /// See also:
350 /// * [Layer.addCompositionCallback].
351 VoidCallback addCompositionCallback(CompositionCallback callback) {
352 return _containerLayer.addCompositionCallback(callback);
353 }
354
355 /// Stop recording to a canvas if recording has started.
356 ///
357 /// Do not call this function directly: functions in this class will call
358 /// this method as needed. This function is called internally to ensure that
359 /// recording is stopped before adding layers or finalizing the results of a
360 /// paint.
361 ///
362 /// Subclasses that need to customize how recording to a canvas is performed
363 /// should override this method to save the results of the custom canvas
364 /// recordings.
365 @protected
366 @mustCallSuper
367 void stopRecordingIfNeeded() {
368 if (!_isRecording) {
369 return;
370 }
371 assert(() {
372 if (debugRepaintRainbowEnabled) {
373 final Paint paint = Paint()
374 ..style = PaintingStyle.stroke
375 ..strokeWidth = 6.0
376 ..color = debugCurrentRepaintColor.toColor();
377 canvas.drawRect(estimatedBounds.deflate(3.0), paint);
378 }
379 if (debugPaintLayerBordersEnabled) {
380 final Paint paint = Paint()
381 ..style = PaintingStyle.stroke
382 ..strokeWidth = 1.0
383 ..color = const Color(0xFFFF9800);
384 canvas.drawRect(estimatedBounds, paint);
385 }
386 return true;
387 }());
388 _currentLayer!.picture = _recorder!.endRecording();
389 _currentLayer = null;
390 _recorder = null;
391 _canvas = null;
392 }
393
394 /// Hints that the painting in the current layer is complex and would benefit
395 /// from caching.
396 ///
397 /// If this hint is not set, the compositor will apply its own heuristics to
398 /// decide whether the current layer is complex enough to benefit from
399 /// caching.
400 ///
401 /// Calling this ensures a [Canvas] is available. Only draw calls on the
402 /// current canvas will be hinted; the hint is not propagated to new canvases
403 /// created after a new layer is added to the painting context (e.g. with
404 /// [addLayer] or [pushLayer]).
405 void setIsComplexHint() {
406 if (_currentLayer == null) {
407 _startRecording();
408 }
409 _currentLayer!.isComplexHint = true;
410 }
411
412 /// Hints that the painting in the current layer is likely to change next frame.
413 ///
414 /// This hint tells the compositor not to cache the current layer because the
415 /// cache will not be used in the future. If this hint is not set, the
416 /// compositor will apply its own heuristics to decide whether the current
417 /// layer is likely to be reused in the future.
418 ///
419 /// Calling this ensures a [Canvas] is available. Only draw calls on the
420 /// current canvas will be hinted; the hint is not propagated to new canvases
421 /// created after a new layer is added to the painting context (e.g. with
422 /// [addLayer] or [pushLayer]).
423 void setWillChangeHint() {
424 if (_currentLayer == null) {
425 _startRecording();
426 }
427 _currentLayer!.willChangeHint = true;
428 }
429
430 /// Adds a composited leaf layer to the recording.
431 ///
432 /// After calling this function, the [canvas] property will change to refer to
433 /// a new [Canvas] that draws on top of the given layer.
434 ///
435 /// A [RenderObject] that uses this function is very likely to require its
436 /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs
437 /// ancestor render objects that this render object will include a composited
438 /// layer, which, for example, causes them to use composited clips.
439 ///
440 /// See also:
441 ///
442 /// * [pushLayer], for adding a layer and painting further contents within
443 /// it.
444 void addLayer(Layer layer) {
445 stopRecordingIfNeeded();
446 appendLayer(layer);
447 }
448
449 /// Appends the given layer to the recording, and calls the `painter` callback
450 /// with that layer, providing the `childPaintBounds` as the estimated paint
451 /// bounds of the child. The `childPaintBounds` can be used for debugging but
452 /// have no effect on painting.
453 ///
454 /// The given layer must be an unattached orphan. (Providing a newly created
455 /// object, rather than reusing an existing layer, satisfies that
456 /// requirement.)
457 ///
458 /// {@template flutter.rendering.PaintingContext.pushLayer.offset}
459 /// The `offset` is the offset to pass to the `painter`. In particular, it is
460 /// not an offset applied to the layer itself. Layers conceptually by default
461 /// have no position or size, though they can transform their contents. For
462 /// example, an [OffsetLayer] applies an offset to its children.
463 /// {@endtemplate}
464 ///
465 /// If the `childPaintBounds` are not specified then the current layer's paint
466 /// bounds are used. This is appropriate if the child layer does not apply any
467 /// transformation or clipping to its contents. The `childPaintBounds`, if
468 /// specified, must be in the coordinate system of the new layer (i.e. as seen
469 /// by its children after it applies whatever transform to its contents), and
470 /// should not go outside the current layer's paint bounds.
471 ///
472 /// See also:
473 ///
474 /// * [addLayer], for pushing a layer without painting further contents
475 /// within it.
476 void pushLayer(ContainerLayer childLayer, PaintingContextCallback painter, Offset offset, { Rect? childPaintBounds }) {
477 // If a layer is being reused, it may already contain children. We remove
478 // them so that `painter` can add children that are relevant for this frame.
479 if (childLayer.hasChildren) {
480 childLayer.removeAllChildren();
481 }
482 stopRecordingIfNeeded();
483 appendLayer(childLayer);
484 final PaintingContext childContext = createChildContext(childLayer, childPaintBounds ?? estimatedBounds);
485
486 painter(childContext, offset);
487 childContext.stopRecordingIfNeeded();
488 }
489
490 /// Creates a painting context configured to paint into [childLayer].
491 ///
492 /// The `bounds` are estimated paint bounds for debugging purposes.
493 @protected
494 PaintingContext createChildContext(ContainerLayer childLayer, Rect bounds) {
495 return PaintingContext(childLayer, bounds);
496 }
497
498 /// Clip further painting using a rectangle.
499 ///
500 /// {@template flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
501 /// The `needsCompositing` argument specifies whether the child needs
502 /// compositing. Typically this matches the value of
503 /// [RenderObject.needsCompositing] for the caller. If false, this method
504 /// returns null, indicating that a layer is no longer necessary. If a render
505 /// object calling this method stores the `oldLayer` in its
506 /// [RenderObject.layer] field, it should set that field to null.
507 ///
508 /// When `needsCompositing` is false, this method will use a more efficient
509 /// way to apply the layer effect than actually creating a layer.
510 /// {@endtemplate}
511 ///
512 /// {@template flutter.rendering.PaintingContext.pushClipRect.offset}
513 /// The `offset` argument is the offset from the origin of the canvas'
514 /// coordinate system to the origin of the caller's coordinate system.
515 /// {@endtemplate}
516 ///
517 /// The `clipRect` is the rectangle (in the caller's coordinate system) to use
518 /// to clip the painting done by [painter]. It should not include the
519 /// `offset`.
520 ///
521 /// The `painter` callback will be called while the `clipRect` is applied. It
522 /// is called synchronously during the call to [pushClipRect].
523 ///
524 /// The `clipBehavior` argument controls how the rectangle is clipped.
525 ///
526 /// {@template flutter.rendering.PaintingContext.pushClipRect.oldLayer}
527 /// For the `oldLayer` argument, specify the layer created in the previous
528 /// frame. This gives the engine more information for performance
529 /// optimizations. Typically this is the value of [RenderObject.layer] that a
530 /// render object creates once, then reuses for all subsequent frames until a
531 /// layer is no longer needed (e.g. the render object no longer needs
532 /// compositing) or until the render object changes the type of the layer
533 /// (e.g. from opacity layer to a clip rect layer).
534 /// {@endtemplate}
535 ClipRectLayer? pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.hardEdge, ClipRectLayer? oldLayer }) {
536 if (clipBehavior == Clip.none) {
537 painter(this, offset);
538 return null;
539 }
540 final Rect offsetClipRect = clipRect.shift(offset);
541 if (needsCompositing) {
542 final ClipRectLayer layer = oldLayer ?? ClipRectLayer();
543 layer
544 ..clipRect = offsetClipRect
545 ..clipBehavior = clipBehavior;
546 pushLayer(layer, painter, offset, childPaintBounds: offsetClipRect);
547 return layer;
548 } else {
549 clipRectAndPaint(offsetClipRect, clipBehavior, offsetClipRect, () => painter(this, offset));
550 return null;
551 }
552 }
553
554 /// Clip further painting using a rounded rectangle.
555 ///
556 /// {@macro flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
557 ///
558 /// {@macro flutter.rendering.PaintingContext.pushClipRect.offset}
559 ///
560 /// The `bounds` argument is used to specify the region of the canvas (in the
561 /// caller's coordinate system) into which `painter` will paint.
562 ///
563 /// The `clipRRect` argument specifies the rounded-rectangle (in the caller's
564 /// coordinate system) to use to clip the painting done by `painter`. It
565 /// should not include the `offset`.
566 ///
567 /// The `painter` callback will be called while the `clipRRect` is applied. It
568 /// is called synchronously during the call to [pushClipRRect].
569 ///
570 /// The `clipBehavior` argument controls how the rounded rectangle is clipped.
571 ///
572 /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
573 ClipRRectLayer? pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.antiAlias, ClipRRectLayer? oldLayer }) {
574 if (clipBehavior == Clip.none) {
575 painter(this, offset);
576 return null;
577 }
578 final Rect offsetBounds = bounds.shift(offset);
579 final RRect offsetClipRRect = clipRRect.shift(offset);
580 if (needsCompositing) {
581 final ClipRRectLayer layer = oldLayer ?? ClipRRectLayer();
582 layer
583 ..clipRRect = offsetClipRRect
584 ..clipBehavior = clipBehavior;
585 pushLayer(layer, painter, offset, childPaintBounds: offsetBounds);
586 return layer;
587 } else {
588 clipRRectAndPaint(offsetClipRRect, clipBehavior, offsetBounds, () => painter(this, offset));
589 return null;
590 }
591 }
592
593 /// Clip further painting using a path.
594 ///
595 /// {@macro flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
596 ///
597 /// {@macro flutter.rendering.PaintingContext.pushClipRect.offset}
598 ///
599 /// The `bounds` argument is used to specify the region of the canvas (in the
600 /// caller's coordinate system) into which `painter` will paint.
601 ///
602 /// The `clipPath` argument specifies the [Path] (in the caller's coordinate
603 /// system) to use to clip the painting done by `painter`. It should not
604 /// include the `offset`.
605 ///
606 /// The `painter` callback will be called while the `clipPath` is applied. It
607 /// is called synchronously during the call to [pushClipPath].
608 ///
609 /// The `clipBehavior` argument controls how the path is clipped.
610 ///
611 /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
612 ClipPathLayer? pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter, { Clip clipBehavior = Clip.antiAlias, ClipPathLayer? oldLayer }) {
613 if (clipBehavior == Clip.none) {
614 painter(this, offset);
615 return null;
616 }
617 final Rect offsetBounds = bounds.shift(offset);
618 final Path offsetClipPath = clipPath.shift(offset);
619 if (needsCompositing) {
620 final ClipPathLayer layer = oldLayer ?? ClipPathLayer();
621 layer
622 ..clipPath = offsetClipPath
623 ..clipBehavior = clipBehavior;
624 pushLayer(layer, painter, offset, childPaintBounds: offsetBounds);
625 return layer;
626 } else {
627 clipPathAndPaint(offsetClipPath, clipBehavior, offsetBounds, () => painter(this, offset));
628 return null;
629 }
630 }
631
632 /// Blend further painting with a color filter.
633 ///
634 /// {@macro flutter.rendering.PaintingContext.pushLayer.offset}
635 ///
636 /// The `colorFilter` argument is the [ColorFilter] value to use when blending
637 /// the painting done by `painter`.
638 ///
639 /// The `painter` callback will be called while the `colorFilter` is applied.
640 /// It is called synchronously during the call to [pushColorFilter].
641 ///
642 /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
643 ///
644 /// A [RenderObject] that uses this function is very likely to require its
645 /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs
646 /// ancestor render objects that this render object will include a composited
647 /// layer, which, for example, causes them to use composited clips.
648 ColorFilterLayer pushColorFilter(Offset offset, ColorFilter colorFilter, PaintingContextCallback painter, { ColorFilterLayer? oldLayer }) {
649 final ColorFilterLayer layer = oldLayer ?? ColorFilterLayer();
650 layer.colorFilter = colorFilter;
651 pushLayer(layer, painter, offset);
652 return layer;
653 }
654
655 /// Transform further painting using a matrix.
656 ///
657 /// {@macro flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
658 ///
659 /// The `offset` argument is the offset to pass to `painter` and the offset to
660 /// the origin used by `transform`.
661 ///
662 /// The `transform` argument is the [Matrix4] with which to transform the
663 /// coordinate system while calling `painter`. It should not include `offset`.
664 /// It is applied effectively after applying `offset`.
665 ///
666 /// The `painter` callback will be called while the `transform` is applied. It
667 /// is called synchronously during the call to [pushTransform].
668 ///
669 /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
670 TransformLayer? pushTransform(bool needsCompositing, Offset offset, Matrix4 transform, PaintingContextCallback painter, { TransformLayer? oldLayer }) {
671 final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0)
672 ..multiply(transform)..translate(-offset.dx, -offset.dy);
673 if (needsCompositing) {
674 final TransformLayer layer = oldLayer ?? TransformLayer();
675 layer.transform = effectiveTransform;
676 pushLayer(
677 layer,
678 painter,
679 offset,
680 childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, estimatedBounds),
681 );
682 return layer;
683 } else {
684 canvas
685 ..save()
686 ..transform(effectiveTransform.storage);
687 painter(this, offset);
688 canvas.restore();
689 return null;
690 }
691 }
692
693 /// Blend further painting with an alpha value.
694 ///
695 /// The `offset` argument indicates an offset to apply to all the children
696 /// (the rendering created by `painter`).
697 ///
698 /// The `alpha` argument is the alpha value to use when blending the painting
699 /// done by `painter`. An alpha value of 0 means the painting is fully
700 /// transparent and an alpha value of 255 means the painting is fully opaque.
701 ///
702 /// The `painter` callback will be called while the `alpha` is applied. It
703 /// is called synchronously during the call to [pushOpacity].
704 ///
705 /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
706 ///
707 /// A [RenderObject] that uses this function is very likely to require its
708 /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs
709 /// ancestor render objects that this render object will include a composited
710 /// layer, which, for example, causes them to use composited clips.
711 OpacityLayer pushOpacity(Offset offset, int alpha, PaintingContextCallback painter, { OpacityLayer? oldLayer }) {
712 final OpacityLayer layer = oldLayer ?? OpacityLayer();
713 layer
714 ..alpha = alpha
715 ..offset = offset;
716 pushLayer(layer, painter, Offset.zero);
717 return layer;
718 }
719
720 @override
721 String toString() => '${objectRuntimeType(this, 'PaintingContext')}#$hashCode(layer: $_containerLayer, canvas bounds: $estimatedBounds)';
722}
723
724/// An abstract set of layout constraints.
725///
726/// Concrete layout models (such as box) will create concrete subclasses to
727/// communicate layout constraints between parents and children.
728///
729/// ## Writing a Constraints subclass
730///
731/// When creating a new [RenderObject] subclass with a new layout protocol, one
732/// will usually need to create a new [Constraints] subclass to express the
733/// input to the layout algorithms.
734///
735/// A [Constraints] subclass should be immutable (all fields final). There are
736/// several members to implement, in addition to whatever fields, constructors,
737/// and helper methods one may find useful for a particular layout protocol:
738///
739/// * The [isTight] getter, which should return true if the object represents a
740/// case where the [RenderObject] class has no choice for how to lay itself
741/// out. For example, [BoxConstraints] returns true for [isTight] when both
742/// the minimum and maximum widths and the minimum and maximum heights are
743/// equal.
744///
745/// * The [isNormalized] getter, which should return true if the object
746/// represents its data in its canonical form. Sometimes, it is possible for
747/// fields to be redundant with each other, such that several different
748/// representations have the same implications. For example, a
749/// [BoxConstraints] instance with its minimum width greater than its maximum
750/// width is equivalent to one where the maximum width is set to that minimum
751/// width (`2<w<1` is equivalent to `2<w<2`, since minimum constraints have
752/// priority). This getter is used by the default implementation of
753/// [debugAssertIsValid].
754///
755/// * The [debugAssertIsValid] method, which should assert if there's anything
756/// wrong with the constraints object. (We use this approach rather than
757/// asserting in constructors so that our constructors can be `const` and so
758/// that it is possible to create invalid constraints temporarily while
759/// building valid ones.) See the implementation of
760/// [BoxConstraints.debugAssertIsValid] for an example of the detailed checks
761/// that can be made.
762///
763/// * The [==] operator and the [hashCode] getter, so that constraints can be
764/// compared for equality. If a render object is given constraints that are
765/// equal, then the rendering library will avoid laying the object out again
766/// if it is not dirty.
767///
768/// * The [toString] method, which should describe the constraints so that they
769/// appear in a usefully readable form in the output of [debugDumpRenderTree].
770@immutable
771abstract class Constraints {
772 /// Abstract const constructor. This constructor enables subclasses to provide
773 /// const constructors so that they can be used in const expressions.
774 const Constraints();
775
776 /// Whether there is exactly one size possible given these constraints.
777 bool get isTight;
778
779 /// Whether the constraint is expressed in a consistent manner.
780 bool get isNormalized;
781
782 /// Asserts that the constraints are valid.
783 ///
784 /// This might involve checks more detailed than [isNormalized].
785 ///
786 /// For example, the [BoxConstraints] subclass verifies that the constraints
787 /// are not [double.nan].
788 ///
789 /// If the `isAppliedConstraint` argument is true, then even stricter rules
790 /// are enforced. This argument is set to true when checking constraints that
791 /// are about to be applied to a [RenderObject] during layout, as opposed to
792 /// constraints that may be further affected by other constraints. For
793 /// example, the asserts for verifying the validity of
794 /// [RenderConstrainedBox.additionalConstraints] do not set this argument, but
795 /// the asserts for verifying the argument passed to the [RenderObject.layout]
796 /// method do.
797 ///
798 /// The `informationCollector` argument takes an optional callback which is
799 /// called when an exception is to be thrown. The collected information is
800 /// then included in the message after the error line.
801 ///
802 /// Returns the same as [isNormalized] if asserts are disabled.
803 bool debugAssertIsValid({
804 bool isAppliedConstraint = false,
805 InformationCollector? informationCollector,
806 }) {
807 assert(isNormalized);
808 return isNormalized;
809 }
810}
811
812/// Signature for a function that is called for each [RenderObject].
813///
814/// Used by [RenderObject.visitChildren] and [RenderObject.visitChildrenForSemantics].
815typedef RenderObjectVisitor = void Function(RenderObject child);
816
817/// Signature for a function that is called during layout.
818///
819/// Used by [RenderObject.invokeLayoutCallback].
820typedef LayoutCallback<T extends Constraints> = void Function(T constraints);
821
822class _LocalSemanticsHandle implements SemanticsHandle {
823 _LocalSemanticsHandle._(PipelineOwner owner, this.listener)
824 : _owner = owner {
825 // TODO(polina-c): stop duplicating code across disposables
826 // https://github.com/flutter/flutter/issues/137435
827 if (kFlutterMemoryAllocationsEnabled) {
828 FlutterMemoryAllocations.instance.dispatchObjectCreated(
829 library: 'package:flutter/rendering.dart',
830 className: '$_LocalSemanticsHandle',
831 object: this,
832 );
833 }
834
835 if (listener != null) {
836 _owner.semanticsOwner!.addListener(listener!);
837 }
838 }
839
840 final PipelineOwner _owner;
841
842 /// The callback that will be notified when the semantics tree updates.
843 final VoidCallback? listener;
844
845 @override
846 void dispose() {
847 // TODO(polina-c): stop duplicating code across disposables
848 // https://github.com/flutter/flutter/issues/137435
849 if (kFlutterMemoryAllocationsEnabled) {
850 FlutterMemoryAllocations.instance.dispatchObjectDisposed(object: this);
851 }
852
853 if (listener != null) {
854 _owner.semanticsOwner!.removeListener(listener!);
855 }
856 _owner._didDisposeSemanticsHandle();
857 }
858}
859
860/// The pipeline owner manages the rendering pipeline.
861///
862/// The pipeline owner provides an interface for driving the rendering pipeline
863/// and stores the state about which render objects have requested to be visited
864/// in each stage of the pipeline. To flush the pipeline, call the following
865/// functions in order:
866///
867/// 1. [flushLayout] updates any render objects that need to compute their
868/// layout. During this phase, the size and position of each render
869/// object is calculated. Render objects might dirty their painting or
870/// compositing state during this phase.
871/// 2. [flushCompositingBits] updates any render objects that have dirty
872/// compositing bits. During this phase, each render object learns whether
873/// any of its children require compositing. This information is used during
874/// the painting phase when selecting how to implement visual effects such as
875/// clipping. If a render object has a composited child, it needs to use a
876/// [Layer] to create the clip in order for the clip to apply to the
877/// composited child (which will be painted into its own [Layer]).
878/// 3. [flushPaint] visits any render objects that need to paint. During this
879/// phase, render objects get a chance to record painting commands into
880/// [PictureLayer]s and construct other composited [Layer]s.
881/// 4. Finally, if semantics are enabled, [flushSemantics] will compile the
882/// semantics for the render objects. This semantic information is used by
883/// assistive technology to improve the accessibility of the render tree.
884///
885/// The [RendererBinding] holds the pipeline owner for the render objects that
886/// are visible on screen. You can create other pipeline owners to manage
887/// off-screen objects, which can flush their pipelines independently of the
888/// on-screen render objects.
889///
890/// [PipelineOwner]s can be organized in a tree to manage multiple render trees,
891/// where each [PipelineOwner] is responsible for one of the render trees. To
892/// build or modify the tree, call [adoptChild] or [dropChild]. During each of
893/// the different flush phases described above, a [PipelineOwner] will first
894/// perform the phase on the nodes it manages in its own render tree before
895/// calling the same flush method on its children. No assumption must be made
896/// about the order in which child [PipelineOwner]s are flushed.
897///
898/// A [PipelineOwner] may also be [attach]ed to a [PipelineManifold], which
899/// gives it access to platform functionality usually exposed by the bindings
900/// without tying it to a specific binding implementation. All [PipelineOwner]s
901/// in a given tree must be attached to the same [PipelineManifold]. This
902/// happens automatically during [adoptChild].
903class PipelineOwner with DiagnosticableTreeMixin {
904 /// Creates a pipeline owner.
905 ///
906 /// Typically created by the binding (e.g., [RendererBinding]), but can be
907 /// created separately from the binding to drive off-screen render objects
908 /// through the rendering pipeline.
909 PipelineOwner({
910 this.onNeedVisualUpdate,
911 this.onSemanticsOwnerCreated,
912 this.onSemanticsUpdate,
913 this.onSemanticsOwnerDisposed,
914 }){
915 // TODO(polina-c): stop duplicating code across disposables
916 // https://github.com/flutter/flutter/issues/137435
917 if (kFlutterMemoryAllocationsEnabled) {
918 FlutterMemoryAllocations.instance.dispatchObjectCreated(
919 library: 'package:flutter/rendering.dart',
920 className: '$PipelineOwner',
921 object: this,
922 );
923 }
924 }
925
926 /// Called when a render object associated with this pipeline owner wishes to
927 /// update its visual appearance.
928 ///
929 /// Typical implementations of this function will schedule a task to flush the
930 /// various stages of the pipeline. This function might be called multiple
931 /// times in quick succession. Implementations should take care to discard
932 /// duplicate calls quickly.
933 ///
934 /// When the [PipelineOwner] is attached to a [PipelineManifold] and
935 /// [onNeedVisualUpdate] is provided, the [onNeedVisualUpdate] callback is
936 /// invoked instead of calling [PipelineManifold.requestVisualUpdate].
937 final VoidCallback? onNeedVisualUpdate;
938
939 /// Called whenever this pipeline owner creates a semantics object.
940 ///
941 /// Typical implementations will schedule the creation of the initial
942 /// semantics tree.
943 final VoidCallback? onSemanticsOwnerCreated;
944
945 /// Called whenever this pipeline owner's semantics owner emits a [SemanticsUpdate].
946 ///
947 /// Typical implementations will delegate the [SemanticsUpdate] to a [FlutterView]
948 /// that can handle the [SemanticsUpdate].
949 final SemanticsUpdateCallback? onSemanticsUpdate;
950
951 /// Called whenever this pipeline owner disposes its semantics owner.
952 ///
953 /// Typical implementations will tear down the semantics tree.
954 final VoidCallback? onSemanticsOwnerDisposed;
955
956 /// Calls [onNeedVisualUpdate] if [onNeedVisualUpdate] is not null.
957 ///
958 /// Used to notify the pipeline owner that an associated render object wishes
959 /// to update its visual appearance.
960 void requestVisualUpdate() {
961 if (onNeedVisualUpdate != null) {
962 onNeedVisualUpdate!();
963 } else {
964 _manifold?.requestVisualUpdate();
965 }
966 }
967
968 /// The unique object managed by this pipeline that has no parent.
969 RenderObject? get rootNode => _rootNode;
970 RenderObject? _rootNode;
971 set rootNode(RenderObject? value) {
972 if (_rootNode == value) {
973 return;
974 }
975 _rootNode?.detach();
976 _rootNode = value;
977 _rootNode?.attach(this);
978 }
979
980 // Whether the current [flushLayout] call should pause to incorporate the
981 // [RenderObject]s in `_nodesNeedingLayout` into the current dirty list,
982 // before continuing to process dirty relayout boundaries.
983 //
984 // This flag is set to true when a [RenderObject.invokeLayoutCallback]
985 // returns, to avoid laying out dirty relayout boundaries in an incorrect
986 // order and causing them to be laid out more than once per frame. See
987 // layout_builder_mutations_test.dart for an example.
988 //
989 // The new dirty nodes are not immediately merged after a
990 // [RenderObject.invokeLayoutCallback] call because we may encounter multiple
991 // such calls while processing a single relayout boundary in [flushLayout].
992 // Batching new dirty nodes can reduce the number of merges [flushLayout]
993 // has to perform.
994 bool _shouldMergeDirtyNodes = false;
995 List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
996
997 /// Whether this pipeline is currently in the layout phase.
998 ///
999 /// Specifically, whether [flushLayout] is currently running.
1000 ///
1001 /// Only valid when asserts are enabled; in release builds, this
1002 /// always returns false.
1003 bool get debugDoingLayout => _debugDoingLayout;
1004 bool _debugDoingLayout = false;
1005 bool _debugDoingChildLayout = false;
1006
1007 /// Update the layout information for all dirty render objects.
1008 ///
1009 /// This function is one of the core stages of the rendering pipeline. Layout
1010 /// information is cleaned prior to painting so that render objects will
1011 /// appear on screen in their up-to-date locations.
1012 ///
1013 /// See [RendererBinding] for an example of how this function is used.
1014 void flushLayout() {
1015 if (!kReleaseMode) {
1016 Map<String, String>? debugTimelineArguments;
1017 assert(() {
1018 if (debugEnhanceLayoutTimelineArguments) {
1019 debugTimelineArguments = <String, String>{
1020 'dirty count': '${_nodesNeedingLayout.length}',
1021 'dirty list': '$_nodesNeedingLayout',
1022 };
1023 }
1024 return true;
1025 }());
1026 FlutterTimeline.startSync(
1027 'LAYOUT$_debugRootSuffixForTimelineEventNames',
1028 arguments: debugTimelineArguments,
1029 );
1030 }
1031 assert(() {
1032 _debugDoingLayout = true;
1033 return true;
1034 }());
1035 try {
1036 while (_nodesNeedingLayout.isNotEmpty) {
1037 assert(!_shouldMergeDirtyNodes);
1038 final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
1039 _nodesNeedingLayout = <RenderObject>[];
1040 dirtyNodes.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
1041 for (int i = 0; i < dirtyNodes.length; i++) {
1042 if (_shouldMergeDirtyNodes) {
1043 _shouldMergeDirtyNodes = false;
1044 if (_nodesNeedingLayout.isNotEmpty) {
1045 _nodesNeedingLayout.addAll(dirtyNodes.getRange(i, dirtyNodes.length));
1046 break;
1047 }
1048 }
1049 final RenderObject node = dirtyNodes[i];
1050 if (node._needsLayout && node.owner == this) {
1051 node._layoutWithoutResize();
1052 }
1053 }
1054 // No need to merge dirty nodes generated from processing the last
1055 // relayout boundary back.
1056 _shouldMergeDirtyNodes = false;
1057 }
1058
1059 assert(() {
1060 _debugDoingChildLayout = true;
1061 return true;
1062 }());
1063 for (final PipelineOwner child in _children) {
1064 child.flushLayout();
1065 }
1066 assert(_nodesNeedingLayout.isEmpty, 'Child PipelineOwners must not dirty nodes in their parent.');
1067 } finally {
1068 _shouldMergeDirtyNodes = false;
1069 assert(() {
1070 _debugDoingLayout = false;
1071 _debugDoingChildLayout = false;
1072 return true;
1073 }());
1074 if (!kReleaseMode) {
1075 FlutterTimeline.finishSync();
1076 }
1077 }
1078 }
1079
1080 // This flag is used to allow the kinds of mutations performed by GlobalKey
1081 // reparenting while a LayoutBuilder is being rebuilt and in so doing tries to
1082 // move a node from another LayoutBuilder subtree that hasn't been updated
1083 // yet. To set this, call [_enableMutationsToDirtySubtrees], which is called
1084 // by [RenderObject.invokeLayoutCallback].
1085 bool _debugAllowMutationsToDirtySubtrees = false;
1086
1087 // See [RenderObject.invokeLayoutCallback].
1088 void _enableMutationsToDirtySubtrees(VoidCallback callback) {
1089 assert(_debugDoingLayout);
1090 bool? oldState;
1091 assert(() {
1092 oldState = _debugAllowMutationsToDirtySubtrees;
1093 _debugAllowMutationsToDirtySubtrees = true;
1094 return true;
1095 }());
1096 try {
1097 callback();
1098 } finally {
1099 _shouldMergeDirtyNodes = true;
1100 assert(() {
1101 _debugAllowMutationsToDirtySubtrees = oldState!;
1102 return true;
1103 }());
1104 }
1105 }
1106
1107 final List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[];
1108 /// Updates the [RenderObject.needsCompositing] bits.
1109 ///
1110 /// Called as part of the rendering pipeline after [flushLayout] and before
1111 /// [flushPaint].
1112 void flushCompositingBits() {
1113 if (!kReleaseMode) {
1114 FlutterTimeline.startSync('UPDATING COMPOSITING BITS$_debugRootSuffixForTimelineEventNames');
1115 }
1116 _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
1117 for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) {
1118 if (node._needsCompositingBitsUpdate && node.owner == this) {
1119 node._updateCompositingBits();
1120 }
1121 }
1122 _nodesNeedingCompositingBitsUpdate.clear();
1123 for (final PipelineOwner child in _children) {
1124 child.flushCompositingBits();
1125 }
1126 assert(_nodesNeedingCompositingBitsUpdate.isEmpty, 'Child PipelineOwners must not dirty nodes in their parent.');
1127 if (!kReleaseMode) {
1128 FlutterTimeline.finishSync();
1129 }
1130 }
1131
1132 List<RenderObject> _nodesNeedingPaint = <RenderObject>[];
1133
1134 /// Whether this pipeline is currently in the paint phase.
1135 ///
1136 /// Specifically, whether [flushPaint] is currently running.
1137 ///
1138 /// Only valid when asserts are enabled. In release builds,
1139 /// this always returns false.
1140 bool get debugDoingPaint => _debugDoingPaint;
1141 bool _debugDoingPaint = false;
1142
1143 /// Update the display lists for all render objects.
1144 ///
1145 /// This function is one of the core stages of the rendering pipeline.
1146 /// Painting occurs after layout and before the scene is recomposited so that
1147 /// scene is composited with up-to-date display lists for every render object.
1148 ///
1149 /// See [RendererBinding] for an example of how this function is used.
1150 void flushPaint() {
1151 if (!kReleaseMode) {
1152 Map<String, String>? debugTimelineArguments;
1153 assert(() {
1154 if (debugEnhancePaintTimelineArguments) {
1155 debugTimelineArguments = <String, String>{
1156 'dirty count': '${_nodesNeedingPaint.length}',
1157 'dirty list': '$_nodesNeedingPaint',
1158 };
1159 }
1160 return true;
1161 }());
1162 FlutterTimeline.startSync(
1163 'PAINT$_debugRootSuffixForTimelineEventNames',
1164 arguments: debugTimelineArguments,
1165 );
1166 }
1167 try {
1168 assert(() {
1169 _debugDoingPaint = true;
1170 return true;
1171 }());
1172 final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
1173 _nodesNeedingPaint = <RenderObject>[];
1174
1175 // Sort the dirty nodes in reverse order (deepest first).
1176 for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
1177 assert(node._layerHandle.layer != null);
1178 if ((node._needsPaint || node._needsCompositedLayerUpdate) && node.owner == this) {
1179 if (node._layerHandle.layer!.attached) {
1180 assert(node.isRepaintBoundary);
1181 if (node._needsPaint) {
1182 PaintingContext.repaintCompositedChild(node);
1183 } else {
1184 PaintingContext.updateLayerProperties(node);
1185 }
1186 } else {
1187 node._skippedPaintingOnLayer();
1188 }
1189 }
1190 }
1191 for (final PipelineOwner child in _children) {
1192 child.flushPaint();
1193 }
1194 assert(_nodesNeedingPaint.isEmpty, 'Child PipelineOwners must not dirty nodes in their parent.');
1195 } finally {
1196 assert(() {
1197 _debugDoingPaint = false;
1198 return true;
1199 }());
1200 if (!kReleaseMode) {
1201 FlutterTimeline.finishSync();
1202 }
1203 }
1204 }
1205
1206 /// The object that is managing semantics for this pipeline owner, if any.
1207 ///
1208 /// An owner is created by [ensureSemantics] or when the [PipelineManifold] to
1209 /// which this owner is connected has [PipelineManifold.semanticsEnabled] set
1210 /// to true. The owner is valid for as long as
1211 /// [PipelineManifold.semanticsEnabled] remains true or while there are
1212 /// outstanding [SemanticsHandle]s from calls to [ensureSemantics]. The
1213 /// [semanticsOwner] field will revert to null once both conditions are no
1214 /// longer met.
1215 ///
1216 /// When [semanticsOwner] is null, the [PipelineOwner] skips all steps
1217 /// relating to semantics.
1218 SemanticsOwner? get semanticsOwner => _semanticsOwner;
1219 SemanticsOwner? _semanticsOwner;
1220
1221 /// The number of clients registered to listen for semantics.
1222 ///
1223 /// The number is increased whenever [ensureSemantics] is called and decreased
1224 /// when [SemanticsHandle.dispose] is called.
1225 int get debugOutstandingSemanticsHandles => _outstandingSemanticsHandles;
1226 int _outstandingSemanticsHandles = 0;
1227
1228 /// Opens a [SemanticsHandle] and calls [listener] whenever the semantics tree
1229 /// generated from the render tree owned by this [PipelineOwner] updates.
1230 ///
1231 /// Calling this method only ensures that this particular [PipelineOwner] will
1232 /// generate a semantics tree. Consider calling
1233 /// [SemanticsBinding.ensureSemantics] instead to turn on semantics globally
1234 /// for the entire app.
1235 ///
1236 /// The [PipelineOwner] updates the semantics tree only when there are clients
1237 /// that wish to use the semantics tree. These clients express their interest
1238 /// by holding [SemanticsHandle] objects that notify them whenever the
1239 /// semantics tree updates.
1240 ///
1241 /// Clients can close their [SemanticsHandle] by calling
1242 /// [SemanticsHandle.dispose]. Once all the outstanding [SemanticsHandle]
1243 /// objects for a given [PipelineOwner] are closed, the [PipelineOwner] stops
1244 /// maintaining the semantics tree.
1245 SemanticsHandle ensureSemantics({ VoidCallback? listener }) {
1246 _outstandingSemanticsHandles += 1;
1247 _updateSemanticsOwner();
1248 return _LocalSemanticsHandle._(this, listener);
1249 }
1250
1251 void _updateSemanticsOwner() {
1252 if ((_manifold?.semanticsEnabled ?? false) || _outstandingSemanticsHandles > 0) {
1253 if (_semanticsOwner == null) {
1254 assert(onSemanticsUpdate != null, 'Attempted to enable semantics without configuring an onSemanticsUpdate callback.');
1255 _semanticsOwner = SemanticsOwner(onSemanticsUpdate: onSemanticsUpdate!);
1256 onSemanticsOwnerCreated?.call();
1257 }
1258 } else if (_semanticsOwner != null) {
1259 _semanticsOwner?.dispose();
1260 _semanticsOwner = null;
1261 onSemanticsOwnerDisposed?.call();
1262 }
1263 }
1264
1265 void _didDisposeSemanticsHandle() {
1266 assert(_semanticsOwner != null);
1267 _outstandingSemanticsHandles -= 1;
1268 _updateSemanticsOwner();
1269 }
1270
1271 bool _debugDoingSemantics = false;
1272 final Set<RenderObject> _nodesNeedingSemantics = <RenderObject>{};
1273
1274 /// Update the semantics for render objects marked as needing a semantics
1275 /// update.
1276 ///
1277 /// Initially, only the root node, as scheduled by
1278 /// [RenderObject.scheduleInitialSemantics], needs a semantics update.
1279 ///
1280 /// This function is one of the core stages of the rendering pipeline. The
1281 /// semantics are compiled after painting and only after
1282 /// [RenderObject.scheduleInitialSemantics] has been called.
1283 ///
1284 /// See [RendererBinding] for an example of how this function is used.
1285 void flushSemantics() {
1286 if (_semanticsOwner == null) {
1287 return;
1288 }
1289 if (!kReleaseMode) {
1290 FlutterTimeline.startSync('SEMANTICS$_debugRootSuffixForTimelineEventNames');
1291 }
1292 assert(_semanticsOwner != null);
1293 assert(() {
1294 _debugDoingSemantics = true;
1295 return true;
1296 }());
1297 try {
1298 final List<RenderObject> nodesToProcess = _nodesNeedingSemantics.toList()
1299 ..sort((RenderObject a, RenderObject b) => a.depth - b.depth);
1300 _nodesNeedingSemantics.clear();
1301 for (final RenderObject node in nodesToProcess) {
1302 if (node._needsSemanticsUpdate && node.owner == this) {
1303 node._updateSemantics();
1304 }
1305 }
1306 _semanticsOwner!.sendSemanticsUpdate();
1307 for (final PipelineOwner child in _children) {
1308 child.flushSemantics();
1309 }
1310 assert(_nodesNeedingSemantics.isEmpty, 'Child PipelineOwners must not dirty nodes in their parent.');
1311 } finally {
1312 assert(() {
1313 _debugDoingSemantics = false;
1314 return true;
1315 }());
1316 if (!kReleaseMode) {
1317 FlutterTimeline.finishSync();
1318 }
1319 }
1320 }
1321
1322 @override
1323 List<DiagnosticsNode> debugDescribeChildren() {
1324 return <DiagnosticsNode>[
1325 for (final PipelineOwner child in _children)
1326 child.toDiagnosticsNode(),
1327 ];
1328 }
1329
1330 @override
1331 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1332 super.debugFillProperties(properties);
1333 properties.add(DiagnosticsProperty<RenderObject>('rootNode', rootNode, defaultValue: null));
1334 }
1335
1336 // TREE MANAGEMENT
1337
1338 final Set<PipelineOwner> _children = <PipelineOwner>{};
1339 PipelineManifold? _manifold;
1340
1341 PipelineOwner? _debugParent;
1342 bool _debugSetParent(PipelineOwner child, PipelineOwner? parent) {
1343 child._debugParent = parent;
1344 return true;
1345 }
1346
1347 String get _debugRootSuffixForTimelineEventNames => _debugParent == null ? ' (root)' : '';
1348
1349 /// Mark this [PipelineOwner] as attached to the given [PipelineManifold].
1350 ///
1351 /// Typically, this is only called directly on the root [PipelineOwner].
1352 /// Children are automatically attached to their parent's [PipelineManifold]
1353 /// when [adoptChild] is called.
1354 void attach(PipelineManifold manifold) {
1355 assert(_manifold == null);
1356 _manifold = manifold;
1357 _manifold!.addListener(_updateSemanticsOwner);
1358 _updateSemanticsOwner();
1359
1360 for (final PipelineOwner child in _children) {
1361 child.attach(manifold);
1362 }
1363 }
1364
1365 /// Mark this [PipelineOwner] as detached.
1366 ///
1367 /// Typically, this is only called directly on the root [PipelineOwner].
1368 /// Children are automatically detached from their parent's [PipelineManifold]
1369 /// when [dropChild] is called.
1370 void detach() {
1371 assert(_manifold != null);
1372 _manifold!.removeListener(_updateSemanticsOwner);
1373 _manifold = null;
1374 // Not updating the semantics owner here to not disrupt any of its clients
1375 // in case we get re-attached. If necessary, semantics owner will be updated
1376 // in "attach", or disposed in "dispose", if not reattached.
1377
1378 for (final PipelineOwner child in _children) {
1379 child.detach();
1380 }
1381 }
1382
1383 // In theory, child list modifications are also disallowed between
1384 // _debugDoingChildrenLayout and _debugDoingPaint as well as between
1385 // _debugDoingPaint and _debugDoingSemantics. However, since the associated
1386 // flush methods are usually called back to back, this gets us close enough.
1387 bool get _debugAllowChildListModifications => !_debugDoingChildLayout && !_debugDoingPaint && !_debugDoingSemantics;
1388
1389 /// Adds `child` to this [PipelineOwner].
1390 ///
1391 /// During the phases of frame production (see [RendererBinding.drawFrame]),
1392 /// the parent [PipelineOwner] will complete a phase for the nodes it owns
1393 /// directly before invoking the flush method corresponding to the current
1394 /// phase on its child [PipelineOwner]s. For example, during layout, the
1395 /// parent [PipelineOwner] will first lay out its own nodes before calling
1396 /// [flushLayout] on its children. During paint, it will first paint its own
1397 /// nodes before calling [flushPaint] on its children. This order also applies
1398 /// for all the other phases.
1399 ///
1400 /// No assumptions must be made about the order in which child
1401 /// [PipelineOwner]s are flushed.
1402 ///
1403 /// No new children may be added after the [PipelineOwner] has started calling
1404 /// [flushLayout] on any of its children until the end of the current frame.
1405 ///
1406 /// To remove a child, call [dropChild].
1407 void adoptChild(PipelineOwner child) {
1408 assert(child._debugParent == null);
1409 assert(!_children.contains(child));
1410 assert(_debugAllowChildListModifications, 'Cannot modify child list after layout.');
1411 _children.add(child);
1412 if (!kReleaseMode) {
1413 _debugSetParent(child, this);
1414 }
1415 if (_manifold != null) {
1416 child.attach(_manifold!);
1417 }
1418 }
1419
1420 /// Removes a child [PipelineOwner] previously added via [adoptChild].
1421 ///
1422 /// This node will cease to call the flush methods on the `child` during frame
1423 /// production.
1424 ///
1425 /// No children may be removed after the [PipelineOwner] has started calling
1426 /// [flushLayout] on any of its children until the end of the current frame.
1427 void dropChild(PipelineOwner child) {
1428 assert(child._debugParent == this);
1429 assert(_children.contains(child));
1430 assert(_debugAllowChildListModifications, 'Cannot modify child list after layout.');
1431 _children.remove(child);
1432 if (!kReleaseMode) {
1433 _debugSetParent(child, null);
1434 }
1435 if (_manifold != null) {
1436 child.detach();
1437 }
1438 }
1439
1440 /// Calls `visitor` for each immediate child of this [PipelineOwner].
1441 ///
1442 /// See also:
1443 ///
1444 /// * [adoptChild] to add a child.
1445 /// * [dropChild] to remove a child.
1446 void visitChildren(PipelineOwnerVisitor visitor) {
1447 _children.forEach(visitor);
1448 }
1449
1450 /// Release any resources held by this pipeline owner.
1451 ///
1452 /// Prior to calling this method the pipeline owner must be removed from the
1453 /// pipeline owner tree, i.e. it must have neither a parent nor any children
1454 /// (see [dropChild]). It also must be [detach]ed from any [PipelineManifold].
1455 ///
1456 /// The object is no longer usable after calling dispose.
1457 void dispose() {
1458 assert(_children.isEmpty);
1459 assert(rootNode == null);
1460 assert(_manifold == null);
1461 assert(_debugParent == null);
1462 if (kFlutterMemoryAllocationsEnabled) {
1463 FlutterMemoryAllocations.instance.dispatchObjectDisposed(object: this);
1464 }
1465 _semanticsOwner?.dispose();
1466 _semanticsOwner = null;
1467 _nodesNeedingLayout.clear();
1468 _nodesNeedingCompositingBitsUpdate.clear();
1469 _nodesNeedingPaint.clear();
1470 _nodesNeedingSemantics.clear();
1471 }
1472}
1473
1474/// Signature for the callback to [PipelineOwner.visitChildren].
1475///
1476/// The argument is the child being visited.
1477typedef PipelineOwnerVisitor = void Function(PipelineOwner child);
1478
1479/// Manages a tree of [PipelineOwner]s.
1480///
1481/// All [PipelineOwner]s within a tree are attached to the same
1482/// [PipelineManifold], which gives them access to shared functionality such
1483/// as requesting a visual update (by calling [requestVisualUpdate]). As such,
1484/// the [PipelineManifold] gives the [PipelineOwner]s access to functionality
1485/// usually provided by the bindings without tying the [PipelineOwner]s to a
1486/// particular binding implementation.
1487///
1488/// The root of the [PipelineOwner] tree is attached to a [PipelineManifold] by
1489/// passing the manifold to [PipelineOwner.attach]. Children are attached to the
1490/// same [PipelineManifold] as their parent when they are adopted via
1491/// [PipelineOwner.adoptChild].
1492///
1493/// [PipelineOwner]s can register listeners with the [PipelineManifold] to be
1494/// informed when certain values provided by the [PipelineManifold] change.
1495abstract class PipelineManifold implements Listenable {
1496 /// Whether [PipelineOwner]s connected to this [PipelineManifold] should
1497 /// collect semantics information and produce a semantics tree.
1498 ///
1499 /// The [PipelineManifold] notifies its listeners (managed with [addListener]
1500 /// and [removeListener]) when this property changes its value.
1501 ///
1502 /// See also:
1503 ///
1504 /// * [SemanticsBinding.semanticsEnabled], which [PipelineManifold]
1505 /// implementations typically use to back this property.
1506 bool get semanticsEnabled;
1507
1508 /// Called by a [PipelineOwner] connected to this [PipelineManifold] when a
1509 /// [RenderObject] associated with that pipeline owner wishes to update its
1510 /// visual appearance.
1511 ///
1512 /// Typical implementations of this function will schedule a task to flush the
1513 /// various stages of the pipeline. This function might be called multiple
1514 /// times in quick succession. Implementations should take care to discard
1515 /// duplicate calls quickly.
1516 ///
1517 /// A [PipelineOwner] connected to this [PipelineManifold] will call
1518 /// [PipelineOwner.onNeedVisualUpdate] instead of this method if it has been
1519 /// configured with a non-null [PipelineOwner.onNeedVisualUpdate] callback.
1520 ///
1521 /// See also:
1522 ///
1523 /// * [SchedulerBinding.ensureVisualUpdate], which [PipelineManifold]
1524 /// implementations typically call to implement this method.
1525 void requestVisualUpdate();
1526}
1527
1528const String _flutterRenderingLibrary = 'package:flutter/rendering.dart';
1529
1530/// An object in the render tree.
1531///
1532/// The [RenderObject] class hierarchy is the core of the rendering
1533/// library's reason for being.
1534///
1535/// {@youtube 560 315 https://www.youtube.com/watch?v=zmbmrw07qBc}
1536///
1537/// [RenderObject]s have a [parent], and have a slot called [parentData] in
1538/// which the parent [RenderObject] can store child-specific data, for example,
1539/// the child position. The [RenderObject] class also implements the basic
1540/// layout and paint protocols.
1541///
1542/// The [RenderObject] class, however, does not define a child model (e.g.
1543/// whether a node has zero, one, or more children). It also doesn't define a
1544/// coordinate system (e.g. whether children are positioned in Cartesian
1545/// coordinates, in polar coordinates, etc) or a specific layout protocol (e.g.
1546/// whether the layout is width-in-height-out, or constraint-in-size-out, or
1547/// whether the parent sets the size and position of the child before or after
1548/// the child lays out, etc; or indeed whether the children are allowed to read
1549/// their parent's [parentData] slot).
1550///
1551/// The [RenderBox] subclass introduces the opinion that the layout
1552/// system uses Cartesian coordinates.
1553///
1554/// ## Lifecycle
1555///
1556/// A [RenderObject] must [dispose] when it is no longer needed. The creator
1557/// of the object is responsible for disposing of it. Typically, the creator is
1558/// a [RenderObjectElement], and that element will dispose the object it creates
1559/// when it is unmounted.
1560///
1561/// [RenderObject]s are responsible for cleaning up any expensive resources
1562/// they hold when [dispose] is called, such as [Picture] or [Image] objects.
1563/// This includes any [Layer]s that the render object has directly created. The
1564/// base implementation of dispose will nullify the [layer] property. Subclasses
1565/// must also nullify any other layer(s) it directly creates.
1566///
1567/// ## Writing a RenderObject subclass
1568///
1569/// In most cases, subclassing [RenderObject] itself is overkill, and
1570/// [RenderBox] would be a better starting point. However, if a render object
1571/// doesn't want to use a Cartesian coordinate system, then it should indeed
1572/// inherit from [RenderObject] directly. This allows it to define its own
1573/// layout protocol by using a new subclass of [Constraints] rather than using
1574/// [BoxConstraints], and by potentially using an entirely new set of objects
1575/// and values to represent the result of the output rather than just a [Size].
1576/// This increased flexibility comes at the cost of not being able to rely on
1577/// the features of [RenderBox]. For example, [RenderBox] implements an
1578/// intrinsic sizing protocol that allows you to measure a child without fully
1579/// laying it out, in such a way that if that child changes size, the parent
1580/// will be laid out again (to take into account the new dimensions of the
1581/// child). This is a subtle and bug-prone feature to get right.
1582///
1583/// Most aspects of writing a [RenderBox] apply to writing a [RenderObject] as
1584/// well, and therefore the discussion at [RenderBox] is recommended background
1585/// reading. The main differences are around layout and hit testing, since those
1586/// are the aspects that [RenderBox] primarily specializes.
1587///
1588/// ### Layout
1589///
1590/// A layout protocol begins with a subclass of [Constraints]. See the
1591/// discussion at [Constraints] for more information on how to write a
1592/// [Constraints] subclass.
1593///
1594/// The [performLayout] method should take the [constraints], and apply them.
1595/// The output of the layout algorithm is fields set on the object that describe
1596/// the geometry of the object for the purposes of the parent's layout. For
1597/// example, with [RenderBox] the output is the [RenderBox.size] field. This
1598/// output should only be read by the parent if the parent specified
1599/// `parentUsesSize` as true when calling [layout] on the child.
1600///
1601/// Anytime anything changes on a render object that would affect the layout of
1602/// that object, it should call [markNeedsLayout].
1603///
1604/// ### Hit Testing
1605///
1606/// Hit testing is even more open-ended than layout. There is no method to
1607/// override, you are expected to provide one.
1608///
1609/// The general behavior of your hit-testing method should be similar to the
1610/// behavior described for [RenderBox]. The main difference is that the input
1611/// need not be an [Offset]. You are also allowed to use a different subclass of
1612/// [HitTestEntry] when adding entries to the [HitTestResult]. When the
1613/// [handleEvent] method is called, the same object that was added to the
1614/// [HitTestResult] will be passed in, so it can be used to track information
1615/// like the precise coordinate of the hit, in whatever coordinate system is
1616/// used by the new layout protocol.
1617///
1618/// ### Adapting from one protocol to another
1619///
1620/// In general, the root of a Flutter render object tree is a [RenderView]. This
1621/// object has a single child, which must be a [RenderBox]. Thus, if you want to
1622/// have a custom [RenderObject] subclass in the render tree, you have two
1623/// choices: you either need to replace the [RenderView] itself, or you need to
1624/// have a [RenderBox] that has your class as its child. (The latter is the much
1625/// more common case.)
1626///
1627/// This [RenderBox] subclass converts from the box protocol to the protocol of
1628/// your class.
1629///
1630/// In particular, this means that for hit testing it overrides
1631/// [RenderBox.hitTest], and calls whatever method you have in your class for
1632/// hit testing.
1633///
1634/// Similarly, it overrides [performLayout] to create a [Constraints] object
1635/// appropriate for your class and passes that to the child's [layout] method.
1636///
1637/// ### Layout interactions between render objects
1638///
1639/// In general, the layout of a render object should only depend on the output of
1640/// its child's layout, and then only if `parentUsesSize` is set to true in the
1641/// [layout] call. Furthermore, if it is set to true, the parent must call the
1642/// child's [layout] if the child is to be rendered, because otherwise the
1643/// parent will not be notified when the child changes its layout outputs.
1644///
1645/// It is possible to set up render object protocols that transfer additional
1646/// information. For example, in the [RenderBox] protocol you can query your
1647/// children's intrinsic dimensions and baseline geometry. However, if this is
1648/// done then it is imperative that the child call [markNeedsLayout] on the
1649/// parent any time that additional information changes, if the parent used it
1650/// in the last layout phase. For an example of how to implement this, see the
1651/// [RenderBox.markNeedsLayout] method. It overrides
1652/// [RenderObject.markNeedsLayout] so that if a parent has queried the intrinsic
1653/// or baseline information, it gets marked dirty whenever the child's geometry
1654/// changes.
1655abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarget {
1656 /// Initializes internal fields for subclasses.
1657 RenderObject() {
1658 if (kFlutterMemoryAllocationsEnabled) {
1659 FlutterMemoryAllocations.instance.dispatchObjectCreated(
1660 library: _flutterRenderingLibrary,
1661 className: '$RenderObject',
1662 object: this,
1663 );
1664 }
1665 _needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
1666 _wasRepaintBoundary = isRepaintBoundary;
1667 }
1668
1669 /// Cause the entire subtree rooted at the given [RenderObject] to be marked
1670 /// dirty for layout, paint, etc, so that the effects of a hot reload can be
1671 /// seen, or so that the effect of changing a global debug flag (such as
1672 /// [debugPaintSizeEnabled]) can be applied.
1673 ///
1674 /// This is called by the [RendererBinding] in response to the
1675 /// `ext.flutter.reassemble` hook, which is used by development tools when the
1676 /// application code has changed, to cause the widget tree to pick up any
1677 /// changed implementations.
1678 ///
1679 /// This is expensive and should not be called except during development.
1680 ///
1681 /// See also:
1682 ///
1683 /// * [BindingBase.reassembleApplication]
1684 void reassemble() {
1685 markNeedsLayout();
1686 markNeedsCompositingBitsUpdate();
1687 markNeedsPaint();
1688 markNeedsSemanticsUpdate();
1689 visitChildren((RenderObject child) {
1690 child.reassemble();
1691 });
1692 }
1693
1694 /// Whether this has been disposed.
1695 ///
1696 /// If asserts are disabled, this property is always null.
1697 bool? get debugDisposed {
1698 bool? disposed;
1699 assert(() {
1700 disposed = _debugDisposed;
1701 return true;
1702 }());
1703 return disposed;
1704 }
1705
1706 bool _debugDisposed = false;
1707
1708 /// Release any resources held by this render object.
1709 ///
1710 /// The object that creates a RenderObject is in charge of disposing it.
1711 /// If this render object has created any children directly, it must dispose
1712 /// of those children in this method as well. It must not dispose of any
1713 /// children that were created by some other object, such as
1714 /// a [RenderObjectElement]. Those children will be disposed when that
1715 /// element unmounts, which may be delayed if the element is moved to another
1716 /// part of the tree.
1717 ///
1718 /// Implementations of this method must end with a call to the inherited
1719 /// method, as in `super.dispose()`.
1720 ///
1721 /// The object is no longer usable after calling dispose.
1722 @mustCallSuper
1723 void dispose() {
1724 assert(!_debugDisposed);
1725 if (kFlutterMemoryAllocationsEnabled) {
1726 FlutterMemoryAllocations.instance.dispatchObjectDisposed(object: this);
1727 }
1728 _layerHandle.layer = null;
1729 assert(() {
1730 // TODO(dnfield): Enable this assert once clients have had a chance to
1731 // migrate.
1732 // visitChildren((RenderObject child) {
1733 // assert(
1734 // child.debugDisposed!,
1735 // '${child.runtimeType} (child of $runtimeType) must be disposed before calling super.dispose().',
1736 // );
1737 // });
1738 _debugDisposed = true;
1739 return true;
1740 }());
1741 }
1742
1743 // LAYOUT
1744
1745 /// Data for use by the parent render object.
1746 ///
1747 /// The parent data is used by the render object that lays out this object
1748 /// (typically this object's parent in the render tree) to store information
1749 /// relevant to itself and to any other nodes who happen to know exactly what
1750 /// the data means. The parent data is opaque to the child.
1751 ///
1752 /// * The parent data field must not be directly set, except by calling
1753 /// [setupParentData] on the parent node.
1754 /// * The parent data can be set before the child is added to the parent, by
1755 /// calling [setupParentData] on the future parent node.
1756 /// * The conventions for using the parent data depend on the layout protocol
1757 /// used between the parent and child. For example, in box layout, the
1758 /// parent data is completely opaque but in sector layout the child is
1759 /// permitted to read some fields of the parent data.
1760 ParentData? parentData;
1761
1762 /// Override to setup parent data correctly for your children.
1763 ///
1764 /// You can call this function to set up the parent data for child before the
1765 /// child is added to the parent's child list.
1766 void setupParentData(covariant RenderObject child) {
1767 assert(_debugCanPerformMutations);
1768 if (child.parentData is! ParentData) {
1769 child.parentData = ParentData();
1770 }
1771 }
1772
1773 /// The depth of this render object in the render tree.
1774 ///
1775 /// The depth of nodes in a tree monotonically increases as you traverse down
1776 /// the tree: a node always has a [depth] greater than its ancestors.
1777 /// There's no guarantee regarding depth between siblings.
1778 ///
1779 /// The [depth] of a child can be more than one greater than the [depth] of
1780 /// the parent, because the [depth] values are never decreased: all that
1781 /// matters is that it's greater than the parent. Consider a tree with a root
1782 /// node A, a child B, and a grandchild C. Initially, A will have [depth] 0,
1783 /// B [depth] 1, and C [depth] 2. If C is moved to be a child of A,
1784 /// sibling of B, then the numbers won't change. C's [depth] will still be 2.
1785 ///
1786 /// The depth of a node is used to ensure that nodes are processed in
1787 /// depth order. The [depth] is automatically maintained by the [adoptChild]
1788 /// and [dropChild] methods.
1789 int get depth => _depth;
1790 int _depth = 0;
1791
1792 /// Adjust the [depth] of the given [child] to be greater than this node's own
1793 /// [depth].
1794 ///
1795 /// Only call this method from overrides of [redepthChildren].
1796 @protected
1797 void redepthChild(RenderObject child) {
1798 assert(child.owner == owner);
1799 if (child._depth <= _depth) {
1800 child._depth = _depth + 1;
1801 child.redepthChildren();
1802 }
1803 }
1804
1805 /// Adjust the [depth] of this node's children, if any.
1806 ///
1807 /// Override this method in subclasses with child nodes to call [redepthChild]
1808 /// for each child. Do not call this method directly.
1809 @protected
1810 void redepthChildren() { }
1811
1812 /// The parent of this render object in the render tree.
1813 ///
1814 /// The [parent] of the root node in the render tree is null.
1815 RenderObject? get parent => _parent;
1816 RenderObject? _parent;
1817
1818 /// Called by subclasses when they decide a render object is a child.
1819 ///
1820 /// Only for use by subclasses when changing their child lists. Calling this
1821 /// in other cases will lead to an inconsistent tree and probably cause crashes.
1822 @mustCallSuper
1823 @protected
1824 void adoptChild(RenderObject child) {
1825 assert(child._parent == null);
1826 assert(() {
1827 RenderObject node = this;
1828 while (node.parent != null) {
1829 node = node.parent!;
1830 }
1831 assert(node != child); // indicates we are about to create a cycle
1832 return true;
1833 }());
1834
1835 setupParentData(child);
1836 markNeedsLayout();
1837 markNeedsCompositingBitsUpdate();
1838 markNeedsSemanticsUpdate();
1839 child._parent = this;
1840 if (attached) {
1841 child.attach(_owner!);
1842 }
1843 redepthChild(child);
1844 }
1845
1846 /// Called by subclasses when they decide a render object is no longer a child.
1847 ///
1848 /// Only for use by subclasses when changing their child lists. Calling this
1849 /// in other cases will lead to an inconsistent tree and probably cause crashes.
1850 @mustCallSuper
1851 @protected
1852 void dropChild(RenderObject child) {
1853 assert(child._parent == this);
1854 assert(child.attached == attached);
1855 assert(child.parentData != null);
1856 child._cleanRelayoutBoundary();
1857 child.parentData!.detach();
1858 child.parentData = null;
1859 child._parent = null;
1860 if (attached) {
1861 child.detach();
1862 }
1863 markNeedsLayout();
1864 markNeedsCompositingBitsUpdate();
1865 markNeedsSemanticsUpdate();
1866 }
1867
1868 /// Calls visitor for each immediate child of this render object.
1869 ///
1870 /// Override in subclasses with children and call the visitor for each child.
1871 void visitChildren(RenderObjectVisitor visitor) { }
1872
1873 /// The object responsible for creating this render object.
1874 ///
1875 /// Used in debug messages.
1876 ///
1877 /// See also:
1878 ///
1879 /// * [DebugCreator], which the [widgets] library uses as values for this field.
1880 Object? debugCreator;
1881
1882 void _reportException(String method, Object exception, StackTrace stack) {
1883 FlutterError.reportError(FlutterErrorDetails(
1884 exception: exception,
1885 stack: stack,
1886 library: 'rendering library',
1887 context: ErrorDescription('during $method()'),
1888 informationCollector: () => <DiagnosticsNode>[
1889 // debugCreator should always be null outside of debugMode, but we want
1890 // the tree shaker to notice this.
1891 if (kDebugMode && debugCreator != null)
1892 DiagnosticsDebugCreator(debugCreator!),
1893 describeForError('The following RenderObject was being processed when the exception was fired'),
1894 // TODO(jacobr): this error message has a code smell. Consider whether
1895 // displaying the truncated children is really useful for command line
1896 // users. Inspector users can see the full tree by clicking on the
1897 // render object so this may not be that useful.
1898 describeForError('RenderObject', style: DiagnosticsTreeStyle.truncateChildren),
1899 ],
1900 ));
1901 }
1902
1903 /// Whether [performResize] for this render object is currently running.
1904 ///
1905 /// Only valid when asserts are enabled. In release builds, always returns
1906 /// false.
1907 bool get debugDoingThisResize => _debugDoingThisResize;
1908 bool _debugDoingThisResize = false;
1909
1910 /// Whether [performLayout] for this render object is currently running.
1911 ///
1912 /// Only valid when asserts are enabled. In release builds, always returns
1913 /// false.
1914 bool get debugDoingThisLayout => _debugDoingThisLayout;
1915 bool _debugDoingThisLayout = false;
1916
1917 /// The render object that is actively computing layout.
1918 ///
1919 /// Only valid when asserts are enabled. In release builds, always returns
1920 /// null.
1921 static RenderObject? get debugActiveLayout => _debugActiveLayout;
1922 static RenderObject? _debugActiveLayout;
1923
1924 /// Set [debugActiveLayout] to null when [inner] callback is called.
1925 /// This is useful when you have to temporarily clear that variable to
1926 /// disable some false-positive checks, such as when computing toStringDeep
1927 /// or using custom trees.
1928 @pragma('vm:prefer-inline')
1929 static T _withDebugActiveLayoutCleared<T>(T Function() inner) {
1930 RenderObject? debugPreviousActiveLayout;
1931 assert(() {
1932 debugPreviousActiveLayout = _debugActiveLayout;
1933 _debugActiveLayout = null;
1934 return true;
1935 }());
1936 final T result = inner();
1937 assert(() {
1938 _debugActiveLayout = debugPreviousActiveLayout;
1939 return true;
1940 }());
1941 return result;
1942 }
1943
1944 /// Whether the parent render object is permitted to use this render object's
1945 /// size.
1946 ///
1947 /// Determined by the `parentUsesSize` parameter to [layout].
1948 ///
1949 /// Only valid when asserts are enabled. In release builds, throws.
1950 bool get debugCanParentUseSize => _debugCanParentUseSize!;
1951 bool? _debugCanParentUseSize;
1952
1953 bool _debugMutationsLocked = false;
1954
1955 /// Whether tree mutations are currently permitted.
1956 ///
1957 /// This is only useful during layout. One should also not mutate the tree at
1958 /// other times (e.g. during paint or while assembling the semantic tree) but
1959 /// this function does not currently enforce those conventions.
1960 ///
1961 /// Only valid when asserts are enabled. This will throw in release builds.
1962 bool get _debugCanPerformMutations {
1963 late bool result;
1964 assert(() {
1965 if (_debugDisposed) {
1966 throw FlutterError.fromParts(<DiagnosticsNode>[
1967 ErrorSummary('A disposed RenderObject was mutated.'),
1968 DiagnosticsProperty<RenderObject>(
1969 'The disposed RenderObject was',
1970 this,
1971 style: DiagnosticsTreeStyle.errorProperty,
1972 ),
1973 ]);
1974 }
1975
1976 final PipelineOwner? owner = this.owner;
1977 // Detached nodes are allowed to mutate and the "can perform mutations"
1978 // check will be performed when they re-attach. This assert is only useful
1979 // during layout.
1980 if (owner == null || !owner.debugDoingLayout) {
1981 result = true;
1982 return true;
1983 }
1984
1985 RenderObject? activeLayoutRoot = this;
1986 while (activeLayoutRoot != null) {
1987 final bool mutationsToDirtySubtreesAllowed = activeLayoutRoot.owner?._debugAllowMutationsToDirtySubtrees ?? false;
1988 final bool doingLayoutWithCallback = activeLayoutRoot._doingThisLayoutWithCallback;
1989 // Mutations on this subtree is allowed when:
1990 // - the "activeLayoutRoot" subtree is being mutated in a layout callback.
1991 // - a different part of the render tree is doing a layout callback,
1992 // and this subtree is being reparented to that subtree, as a result
1993 // of global key reparenting.
1994 if (doingLayoutWithCallback || mutationsToDirtySubtreesAllowed && activeLayoutRoot._needsLayout) {
1995 result = true;
1996 return true;
1997 }
1998
1999 if (!activeLayoutRoot._debugMutationsLocked) {
2000 final RenderObject? p = activeLayoutRoot.debugLayoutParent;
2001 activeLayoutRoot = p is RenderObject ? p : null;
2002 } else {
2003 // activeLayoutRoot found.
2004 break;
2005 }
2006 }
2007
2008 final RenderObject debugActiveLayout = RenderObject.debugActiveLayout!;
2009 final String culpritMethodName = debugActiveLayout.debugDoingThisLayout ? 'performLayout' : 'performResize';
2010 final String culpritFullMethodName = '${debugActiveLayout.runtimeType}.$culpritMethodName';
2011 result = false;
2012
2013 if (activeLayoutRoot == null) {
2014 throw FlutterError.fromParts(<DiagnosticsNode>[
2015 ErrorSummary('A $runtimeType was mutated in $culpritFullMethodName.'),
2016 ErrorDescription(
2017 'The RenderObject was mutated when none of its ancestors is actively performing layout.',
2018 ),
2019 DiagnosticsProperty<RenderObject>(
2020 'The RenderObject being mutated was',
2021 this,
2022 style: DiagnosticsTreeStyle.errorProperty,
2023 ),
2024 DiagnosticsProperty<RenderObject>(
2025 'The RenderObject that was mutating the said $runtimeType was',
2026 debugActiveLayout,
2027 style: DiagnosticsTreeStyle.errorProperty,
2028 ),
2029 ]);
2030 }
2031
2032 if (activeLayoutRoot == this) {
2033 throw FlutterError.fromParts(<DiagnosticsNode>[
2034 ErrorSummary('A $runtimeType was mutated in its own $culpritMethodName implementation.'),
2035 ErrorDescription('A RenderObject must not re-dirty itself while still being laid out.'),
2036 DiagnosticsProperty<RenderObject>(
2037 'The RenderObject being mutated was',
2038 this,
2039 style: DiagnosticsTreeStyle.errorProperty,
2040 ),
2041 ErrorHint('Consider using the LayoutBuilder widget to dynamically change a subtree during layout.'),
2042 ]);
2043 }
2044
2045 final ErrorSummary summary = ErrorSummary('A $runtimeType was mutated in $culpritFullMethodName.');
2046 final bool isMutatedByAncestor = activeLayoutRoot == debugActiveLayout;
2047 final String description = isMutatedByAncestor
2048 ? 'A RenderObject must not mutate its descendants in its $culpritMethodName method.'
2049 : 'A RenderObject must not mutate another RenderObject from a different render subtree '
2050 'in its $culpritMethodName method.';
2051
2052 throw FlutterError.fromParts(<DiagnosticsNode>[
2053 summary,
2054 ErrorDescription(description),
2055 DiagnosticsProperty<RenderObject>(
2056 'The RenderObject being mutated was',
2057 this,
2058 style: DiagnosticsTreeStyle.errorProperty,
2059 ),
2060 DiagnosticsProperty<RenderObject>(
2061 'The ${isMutatedByAncestor ? 'ancestor ' : ''}RenderObject that was mutating the said $runtimeType was',
2062 debugActiveLayout,
2063 style: DiagnosticsTreeStyle.errorProperty,
2064 ),
2065 if (!isMutatedByAncestor) DiagnosticsProperty<RenderObject>(
2066 'Their common ancestor was',
2067 activeLayoutRoot,
2068 style: DiagnosticsTreeStyle.errorProperty,
2069 ),
2070 ErrorHint(
2071 'Mutating the layout of another RenderObject may cause some RenderObjects in its subtree to be laid out more than once. '
2072 'Consider using the LayoutBuilder widget to dynamically mutate a subtree during layout.'
2073 ),
2074 ]);
2075 }());
2076 return result;
2077 }
2078
2079 /// The [RenderObject] that's expected to call [layout] on this [RenderObject]
2080 /// in its [performLayout] implementation.
2081 ///
2082 /// This method is used to implement an assert that ensures the render subtree
2083 /// actively performing layout can not get accidentally mutated. It's only
2084 /// implemented in debug mode and always returns null in release mode.
2085 ///
2086 /// The default implementation returns [parent] and overriding is rarely
2087 /// needed. A [RenderObject] subclass that expects its
2088 /// [RenderObject.performLayout] to be called from a different [RenderObject]
2089 /// that's not its [parent] should override this property to return the actual
2090 /// layout parent.
2091 @protected
2092 RenderObject? get debugLayoutParent {
2093 RenderObject? layoutParent;
2094 assert(() {
2095 layoutParent = parent;
2096 return true;
2097 }());
2098 return layoutParent;
2099 }
2100
2101 /// The owner for this render object (null if unattached).
2102 ///
2103 /// The entire render tree that this render object belongs to
2104 /// will have the same owner.
2105 PipelineOwner? get owner => _owner;
2106 PipelineOwner? _owner;
2107
2108 /// Whether the render tree this render object belongs to is attached to a [PipelineOwner].
2109 ///
2110 /// This becomes true during the call to [attach].
2111 ///
2112 /// This becomes false during the call to [detach].
2113 bool get attached => _owner != null;
2114
2115 /// Mark this render object as attached to the given owner.
2116 ///
2117 /// Typically called only from the [parent]'s [attach] method, and by the
2118 /// [owner] to mark the root of a tree as attached.
2119 ///
2120 /// Subclasses with children should override this method to
2121 /// [attach] all their children to the same [owner]
2122 /// after calling the inherited method, as in `super.attach(owner)`.
2123 @mustCallSuper
2124 void attach(PipelineOwner owner) {
2125 assert(!_debugDisposed);
2126 assert(_owner == null);
2127 _owner = owner;
2128 // If the node was dirtied in some way while unattached, make sure to add
2129 // it to the appropriate dirty list now that an owner is available
2130 if (_needsLayout && _relayoutBoundary != null) {
2131 // Don't enter this block if we've never laid out at all;
2132 // scheduleInitialLayout() will handle it
2133 _needsLayout = false;
2134 markNeedsLayout();
2135 }
2136 if (_needsCompositingBitsUpdate) {
2137 _needsCompositingBitsUpdate = false;
2138 markNeedsCompositingBitsUpdate();
2139 }
2140 if (_needsPaint && _layerHandle.layer != null) {
2141 // Don't enter this block if we've never painted at all;
2142 // scheduleInitialPaint() will handle it
2143 _needsPaint = false;
2144 markNeedsPaint();
2145 }
2146 if (_needsSemanticsUpdate && _semanticsConfiguration.isSemanticBoundary) {
2147 // Don't enter this block if we've never updated semantics at all;
2148 // scheduleInitialSemantics() will handle it
2149 _needsSemanticsUpdate = false;
2150 markNeedsSemanticsUpdate();
2151 }
2152 }
2153
2154 /// Mark this render object as detached from its [PipelineOwner].
2155 ///
2156 /// Typically called only from the [parent]'s [detach], and by the [owner] to
2157 /// mark the root of a tree as detached.
2158 ///
2159 /// Subclasses with children should override this method to
2160 /// [detach] all their children after calling the inherited method,
2161 /// as in `super.detach()`.
2162 @mustCallSuper
2163 void detach() {
2164 assert(_owner != null);
2165 _owner = null;
2166 assert(parent == null || attached == parent!.attached);
2167 }
2168
2169 /// Whether this render object's layout information is dirty.
2170 ///
2171 /// This is only set in debug mode. In general, render objects should not need
2172 /// to condition their runtime behavior on whether they are dirty or not,
2173 /// since they should only be marked dirty immediately prior to being laid
2174 /// out and painted. In release builds, this throws.
2175 ///
2176 /// It is intended to be used by tests and asserts.
2177 bool get debugNeedsLayout {
2178 late bool result;
2179 assert(() {
2180 result = _needsLayout;
2181 return true;
2182 }());
2183 return result;
2184 }
2185 bool _needsLayout = true;
2186
2187 RenderObject? _relayoutBoundary;
2188
2189 /// Whether [invokeLayoutCallback] for this render object is currently running.
2190 bool get debugDoingThisLayoutWithCallback => _doingThisLayoutWithCallback;
2191 bool _doingThisLayoutWithCallback = false;
2192
2193 /// The layout constraints most recently supplied by the parent.
2194 ///
2195 /// If layout has not yet happened, accessing this getter will
2196 /// throw a [StateError] exception.
2197 @protected
2198 Constraints get constraints {
2199 if (_constraints == null) {
2200 throw StateError('A RenderObject does not have any constraints before it has been laid out.');
2201 }
2202 return _constraints!;
2203 }
2204 Constraints? _constraints;
2205
2206 /// Verify that the object's constraints are being met. Override
2207 /// this function in a subclass to verify that your state matches
2208 /// the constraints object. This function is only called in checked
2209 /// mode and only when needsLayout is false. If the constraints are
2210 /// not met, it should assert or throw an exception.
2211 @protected
2212 void debugAssertDoesMeetConstraints();
2213
2214 /// When true, debugAssertDoesMeetConstraints() is currently
2215 /// executing asserts for verifying the consistent behavior of
2216 /// intrinsic dimensions methods.
2217 ///
2218 /// This should only be set by debugAssertDoesMeetConstraints()
2219 /// implementations. It is used by tests to selectively ignore
2220 /// custom layout callbacks. It should not be set outside of
2221 /// debugAssertDoesMeetConstraints(), and should not be checked in
2222 /// release mode (where it will always be false).
2223 static bool debugCheckingIntrinsics = false;
2224 bool _debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout() {
2225 if (_relayoutBoundary == null) {
2226 // We don't know where our relayout boundary is yet.
2227 return true;
2228 }
2229 RenderObject node = this;
2230 while (node != _relayoutBoundary) {
2231 assert(node._relayoutBoundary == _relayoutBoundary);
2232 assert(node.parent != null);
2233 node = node.parent!;
2234 if ((!node._needsLayout) && (!node._debugDoingThisLayout)) {
2235 return false;
2236 }
2237 }
2238 assert(node._relayoutBoundary == node);
2239 return true;
2240 }
2241
2242 /// Mark this render object's layout information as dirty, and either register
2243 /// this object with its [PipelineOwner], or defer to the parent, depending on
2244 /// whether this object is a relayout boundary or not respectively.
2245 ///
2246 /// ## Background
2247 ///
2248 /// Rather than eagerly updating layout information in response to writes into
2249 /// a render object, we instead mark the layout information as dirty, which
2250 /// schedules a visual update. As part of the visual update, the rendering
2251 /// pipeline updates the render object's layout information.
2252 ///
2253 /// This mechanism batches the layout work so that multiple sequential writes
2254 /// are coalesced, removing redundant computation.
2255 ///
2256 /// If a render object's parent indicates that it uses the size of one of its
2257 /// render object children when computing its layout information, this
2258 /// function, when called for the child, will also mark the parent as needing
2259 /// layout. In that case, since both the parent and the child need to have
2260 /// their layout recomputed, the pipeline owner is only notified about the
2261 /// parent; when the parent is laid out, it will call the child's [layout]
2262 /// method and thus the child will be laid out as well.
2263 ///
2264 /// Once [markNeedsLayout] has been called on a render object,
2265 /// [debugNeedsLayout] returns true for that render object until just after
2266 /// the pipeline owner has called [layout] on the render object.
2267 ///
2268 /// ## Special cases
2269 ///
2270 /// Some subclasses of [RenderObject], notably [RenderBox], have other
2271 /// situations in which the parent needs to be notified if the child is
2272 /// dirtied (e.g., if the child's intrinsic dimensions or baseline changes).
2273 /// Such subclasses override markNeedsLayout and either call
2274 /// `super.markNeedsLayout()`, in the normal case, or call
2275 /// [markParentNeedsLayout], in the case where the parent needs to be laid out
2276 /// as well as the child.
2277 ///
2278 /// If [sizedByParent] has changed, calls
2279 /// [markNeedsLayoutForSizedByParentChange] instead of [markNeedsLayout].
2280 void markNeedsLayout() {
2281 assert(_debugCanPerformMutations);
2282 if (_needsLayout) {
2283 assert(_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout());
2284 return;
2285 }
2286 if (_relayoutBoundary == null) {
2287 _needsLayout = true;
2288 if (parent != null) {
2289 // _relayoutBoundary is cleaned by an ancestor in RenderObject.layout.
2290 // Conservatively mark everything dirty until it reaches the closest
2291 // known relayout boundary.
2292 markParentNeedsLayout();
2293 }
2294 return;
2295 }
2296 if (_relayoutBoundary != this) {
2297 markParentNeedsLayout();
2298 } else {
2299 _needsLayout = true;
2300 if (owner != null) {
2301 assert(() {
2302 if (debugPrintMarkNeedsLayoutStacks) {
2303 debugPrintStack(label: 'markNeedsLayout() called for $this');
2304 }
2305 return true;
2306 }());
2307 owner!._nodesNeedingLayout.add(this);
2308 owner!.requestVisualUpdate();
2309 }
2310 }
2311 }
2312
2313 /// Mark this render object's layout information as dirty, and then defer to
2314 /// the parent.
2315 ///
2316 /// This function should only be called from [markNeedsLayout] or
2317 /// [markNeedsLayoutForSizedByParentChange] implementations of subclasses that
2318 /// introduce more reasons for deferring the handling of dirty layout to the
2319 /// parent. See [markNeedsLayout] for details.
2320 ///
2321 /// Only call this if [parent] is not null.
2322 @protected
2323 void markParentNeedsLayout() {
2324 assert(_debugCanPerformMutations);
2325 _needsLayout = true;
2326 assert(this.parent != null);
2327 final RenderObject parent = this.parent!;
2328 if (!_doingThisLayoutWithCallback) {
2329 parent.markNeedsLayout();
2330 } else {
2331 assert(parent._debugDoingThisLayout);
2332 }
2333 assert(parent == this.parent);
2334 }
2335
2336 /// Mark this render object's layout information as dirty (like
2337 /// [markNeedsLayout]), and additionally also handle any necessary work to
2338 /// handle the case where [sizedByParent] has changed value.
2339 ///
2340 /// This should be called whenever [sizedByParent] might have changed.
2341 ///
2342 /// Only call this if [parent] is not null.
2343 void markNeedsLayoutForSizedByParentChange() {
2344 markNeedsLayout();
2345 markParentNeedsLayout();
2346 }
2347
2348 void _cleanRelayoutBoundary() {
2349 if (_relayoutBoundary != this) {
2350 _relayoutBoundary = null;
2351 visitChildren(_cleanChildRelayoutBoundary);
2352 }
2353 }
2354
2355 void _propagateRelayoutBoundary() {
2356 if (_relayoutBoundary == this) {
2357 return;
2358 }
2359 final RenderObject? parentRelayoutBoundary = parent?._relayoutBoundary;
2360 assert(parentRelayoutBoundary != null);
2361 if (parentRelayoutBoundary != _relayoutBoundary) {
2362 _relayoutBoundary = parentRelayoutBoundary;
2363 visitChildren(_propagateRelayoutBoundaryToChild);
2364 }
2365 }
2366
2367 // Reduces closure allocation for visitChildren use cases.
2368 static void _cleanChildRelayoutBoundary(RenderObject child) {
2369 child._cleanRelayoutBoundary();
2370 }
2371
2372 static void _propagateRelayoutBoundaryToChild(RenderObject child) {
2373 child._propagateRelayoutBoundary();
2374 }
2375
2376 /// Bootstrap the rendering pipeline by scheduling the very first layout.
2377 ///
2378 /// Requires this render object to be attached and that this render object
2379 /// is the root of the render tree.
2380 ///
2381 /// See [RenderView] for an example of how this function is used.
2382 void scheduleInitialLayout() {
2383 assert(!_debugDisposed);
2384 assert(attached);
2385 assert(parent is! RenderObject);
2386 assert(!owner!._debugDoingLayout);
2387 assert(_relayoutBoundary == null);
2388 _relayoutBoundary = this;
2389 assert(() {
2390 _debugCanParentUseSize = false;
2391 return true;
2392 }());
2393 owner!._nodesNeedingLayout.add(this);
2394 }
2395
2396 @pragma('vm:notify-debugger-on-exception')
2397 void _layoutWithoutResize() {
2398 assert(_relayoutBoundary == this);
2399 RenderObject? debugPreviousActiveLayout;
2400 assert(!_debugMutationsLocked);
2401 assert(!_doingThisLayoutWithCallback);
2402 assert(_debugCanParentUseSize != null);
2403 assert(() {
2404 _debugMutationsLocked = true;
2405 _debugDoingThisLayout = true;
2406 debugPreviousActiveLayout = _debugActiveLayout;
2407 _debugActiveLayout = this;
2408 if (debugPrintLayouts) {
2409 debugPrint('Laying out (without resize) $this');
2410 }
2411 return true;
2412 }());
2413 try {
2414 performLayout();
2415 markNeedsSemanticsUpdate();
2416 } catch (e, stack) {
2417 _reportException('performLayout', e, stack);
2418 }
2419 assert(() {
2420 _debugActiveLayout = debugPreviousActiveLayout;
2421 _debugDoingThisLayout = false;
2422 _debugMutationsLocked = false;
2423 return true;
2424 }());
2425 _needsLayout = false;
2426 markNeedsPaint();
2427 }
2428
2429 /// Compute the layout for this render object.
2430 ///
2431 /// This method is the main entry point for parents to ask their children to
2432 /// update their layout information. The parent passes a constraints object,
2433 /// which informs the child as to which layouts are permissible. The child is
2434 /// required to obey the given constraints.
2435 ///
2436 /// If the parent reads information computed during the child's layout, the
2437 /// parent must pass true for `parentUsesSize`. In that case, the parent will
2438 /// be marked as needing layout whenever the child is marked as needing layout
2439 /// because the parent's layout information depends on the child's layout
2440 /// information. If the parent uses the default value (false) for
2441 /// `parentUsesSize`, the child can change its layout information (subject to
2442 /// the given constraints) without informing the parent.
2443 ///
2444 /// Subclasses should not override [layout] directly. Instead, they should
2445 /// override [performResize] and/or [performLayout]. The [layout] method
2446 /// delegates the actual work to [performResize] and [performLayout].
2447 ///
2448 /// The parent's [performLayout] method should call the [layout] of all its
2449 /// children unconditionally. It is the [layout] method's responsibility (as
2450 /// implemented here) to return early if the child does not need to do any
2451 /// work to update its layout information.
2452 @pragma('vm:notify-debugger-on-exception')
2453 void layout(Constraints constraints, { bool parentUsesSize = false }) {
2454 assert(!_debugDisposed);
2455 if (!kReleaseMode && debugProfileLayoutsEnabled) {
2456 Map<String, String>? debugTimelineArguments;
2457 assert(() {
2458 if (debugEnhanceLayoutTimelineArguments) {
2459 debugTimelineArguments = toDiagnosticsNode().toTimelineArguments();
2460 }
2461 return true;
2462 }());
2463 FlutterTimeline.startSync(
2464 '$runtimeType',
2465 arguments: debugTimelineArguments,
2466 );
2467 }
2468 assert(constraints.debugAssertIsValid(
2469 isAppliedConstraint: true,
2470 informationCollector: () {
2471 final List<String> stack = StackTrace.current.toString().split('\n');
2472 int? targetFrame;
2473 final Pattern layoutFramePattern = RegExp(r'^#[0-9]+ +Render(?:Object|Box).layout \(');
2474 for (int i = 0; i < stack.length; i += 1) {
2475 if (layoutFramePattern.matchAsPrefix(stack[i]) != null) {
2476 targetFrame = i + 1;
2477 } else if (targetFrame != null) {
2478 break;
2479 }
2480 }
2481 if (targetFrame != null && targetFrame < stack.length) {
2482 final Pattern targetFramePattern = RegExp(r'^#[0-9]+ +(.+)$');
2483 final Match? targetFrameMatch = targetFramePattern.matchAsPrefix(stack[targetFrame]);
2484 final String? problemFunction = (targetFrameMatch != null && targetFrameMatch.groupCount > 0) ? targetFrameMatch.group(1) : stack[targetFrame].trim();
2485 return <DiagnosticsNode>[
2486 ErrorDescription(
2487 "These invalid constraints were provided to $runtimeType's layout() "
2488 'function by the following function, which probably computed the '
2489 'invalid constraints in question:\n'
2490 ' $problemFunction',
2491 ),
2492 ];
2493 }
2494 return <DiagnosticsNode>[];
2495 },
2496 ));
2497 assert(!_debugDoingThisResize);
2498 assert(!_debugDoingThisLayout);
2499 final bool isRelayoutBoundary = !parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject;
2500 final RenderObject relayoutBoundary = isRelayoutBoundary ? this : parent!._relayoutBoundary!;
2501 assert(() {
2502 _debugCanParentUseSize = parentUsesSize;
2503 return true;
2504 }());
2505
2506 if (!_needsLayout && constraints == _constraints) {
2507 assert(() {
2508 // in case parentUsesSize changed since the last invocation, set size
2509 // to itself, so it has the right internal debug values.
2510 _debugDoingThisResize = sizedByParent;
2511 _debugDoingThisLayout = !sizedByParent;
2512 final RenderObject? debugPreviousActiveLayout = _debugActiveLayout;
2513 _debugActiveLayout = this;
2514 debugResetSize();
2515 _debugActiveLayout = debugPreviousActiveLayout;
2516 _debugDoingThisLayout = false;
2517 _debugDoingThisResize = false;
2518 return true;
2519 }());
2520
2521 if (relayoutBoundary != _relayoutBoundary) {
2522 _relayoutBoundary = relayoutBoundary;
2523 visitChildren(_propagateRelayoutBoundaryToChild);
2524 }
2525
2526 if (!kReleaseMode && debugProfileLayoutsEnabled) {
2527 FlutterTimeline.finishSync();
2528 }
2529 return;
2530 }
2531 _constraints = constraints;
2532 if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) {
2533 // The local relayout boundary has changed, must notify children in case
2534 // they also need updating. Otherwise, they will be confused about what
2535 // their actual relayout boundary is later.
2536 visitChildren(_cleanChildRelayoutBoundary);
2537 }
2538 _relayoutBoundary = relayoutBoundary;
2539 assert(!_debugMutationsLocked);
2540 assert(!_doingThisLayoutWithCallback);
2541 assert(() {
2542 _debugMutationsLocked = true;
2543 if (debugPrintLayouts) {
2544 debugPrint('Laying out (${sizedByParent ? "with separate resize" : "with resize allowed"}) $this');
2545 }
2546 return true;
2547 }());
2548 if (sizedByParent) {
2549 assert(() {
2550 _debugDoingThisResize = true;
2551 return true;
2552 }());
2553 try {
2554 performResize();
2555 assert(() {
2556 debugAssertDoesMeetConstraints();
2557 return true;
2558 }());
2559 } catch (e, stack) {
2560 _reportException('performResize', e, stack);
2561 }
2562 assert(() {
2563 _debugDoingThisResize = false;
2564 return true;
2565 }());
2566 }
2567 RenderObject? debugPreviousActiveLayout;
2568 assert(() {
2569 _debugDoingThisLayout = true;
2570 debugPreviousActiveLayout = _debugActiveLayout;
2571 _debugActiveLayout = this;
2572 return true;
2573 }());
2574 try {
2575 performLayout();
2576 markNeedsSemanticsUpdate();
2577 assert(() {
2578 debugAssertDoesMeetConstraints();
2579 return true;
2580 }());
2581 } catch (e, stack) {
2582 _reportException('performLayout', e, stack);
2583 }
2584 assert(() {
2585 _debugActiveLayout = debugPreviousActiveLayout;
2586 _debugDoingThisLayout = false;
2587 _debugMutationsLocked = false;
2588 return true;
2589 }());
2590 _needsLayout = false;
2591 markNeedsPaint();
2592
2593 if (!kReleaseMode && debugProfileLayoutsEnabled) {
2594 FlutterTimeline.finishSync();
2595 }
2596 }
2597
2598 /// If a subclass has a "size" (the state controlled by `parentUsesSize`,
2599 /// whatever it is in the subclass, e.g. the actual `size` property of
2600 /// [RenderBox]), and the subclass verifies that in debug mode this "size"
2601 /// property isn't used when [debugCanParentUseSize] isn't set, then that
2602 /// subclass should override [debugResetSize] to reapply the current values of
2603 /// [debugCanParentUseSize] to that state.
2604 @protected
2605 void debugResetSize() { }
2606
2607 /// Whether the constraints are the only input to the sizing algorithm (in
2608 /// particular, child nodes have no impact).
2609 ///
2610 /// Returning false is always correct, but returning true can be more
2611 /// efficient when computing the size of this render object because we don't
2612 /// need to recompute the size if the constraints don't change.
2613 ///
2614 /// Typically, subclasses will always return the same value. If the value can
2615 /// change, then, when it does change, the subclass should make sure to call
2616 /// [markNeedsLayoutForSizedByParentChange].
2617 ///
2618 /// Subclasses that return true must not change the dimensions of this render
2619 /// object in [performLayout]. Instead, that work should be done by
2620 /// [performResize] or - for subclasses of [RenderBox] - in
2621 /// [RenderBox.computeDryLayout].
2622 @protected
2623 bool get sizedByParent => false;
2624
2625 /// {@template flutter.rendering.RenderObject.performResize}
2626 /// Updates the render objects size using only the constraints.
2627 ///
2628 /// Do not call this function directly: call [layout] instead. This function
2629 /// is called by [layout] when there is actually work to be done by this
2630 /// render object during layout. The layout constraints provided by your
2631 /// parent are available via the [constraints] getter.
2632 ///
2633 /// This function is called only if [sizedByParent] is true.
2634 /// {@endtemplate}
2635 ///
2636 /// Subclasses that set [sizedByParent] to true should override this method to
2637 /// compute their size. Subclasses of [RenderBox] should consider overriding
2638 /// [RenderBox.computeDryLayout] instead.
2639 @protected
2640 void performResize();
2641
2642 /// Do the work of computing the layout for this render object.
2643 ///
2644 /// Do not call this function directly: call [layout] instead. This function
2645 /// is called by [layout] when there is actually work to be done by this
2646 /// render object during layout. The layout constraints provided by your
2647 /// parent are available via the [constraints] getter.
2648 ///
2649 /// If [sizedByParent] is true, then this function should not actually change
2650 /// the dimensions of this render object. Instead, that work should be done by
2651 /// [performResize]. If [sizedByParent] is false, then this function should
2652 /// both change the dimensions of this render object and instruct its children
2653 /// to layout.
2654 ///
2655 /// In implementing this function, you must call [layout] on each of your
2656 /// children, passing true for parentUsesSize if your layout information is
2657 /// dependent on your child's layout information. Passing true for
2658 /// parentUsesSize ensures that this render object will undergo layout if the
2659 /// child undergoes layout. Otherwise, the child can change its layout
2660 /// information without informing this render object.
2661 @protected
2662 void performLayout();
2663
2664 /// Allows mutations to be made to this object's child list (and any
2665 /// descendants) as well as to any other dirty nodes in the render tree owned
2666 /// by the same [PipelineOwner] as this object. The `callback` argument is
2667 /// invoked synchronously, and the mutations are allowed only during that
2668 /// callback's execution.
2669 ///
2670 /// This exists to allow child lists to be built on-demand during layout (e.g.
2671 /// based on the object's size), and to enable nodes to be moved around the
2672 /// tree as this happens (e.g. to handle [GlobalKey] reparenting), while still
2673 /// ensuring that any particular node is only laid out once per frame.
2674 ///
2675 /// Calling this function disables a number of assertions that are intended to
2676 /// catch likely bugs. As such, using this function is generally discouraged.
2677 ///
2678 /// This function can only be called during layout.
2679 @protected
2680 void invokeLayoutCallback<T extends Constraints>(LayoutCallback<T> callback) {
2681 assert(_debugMutationsLocked);
2682 assert(_debugDoingThisLayout);
2683 assert(!_doingThisLayoutWithCallback);
2684 _doingThisLayoutWithCallback = true;
2685 try {
2686 owner!._enableMutationsToDirtySubtrees(() { callback(constraints as T); });
2687 } finally {
2688 _doingThisLayoutWithCallback = false;
2689 }
2690 }
2691
2692 // PAINTING
2693
2694 /// Whether [paint] for this render object is currently running.
2695 ///
2696 /// Only valid when asserts are enabled. In release builds, always returns
2697 /// false.
2698 bool get debugDoingThisPaint => _debugDoingThisPaint;
2699 bool _debugDoingThisPaint = false;
2700
2701 /// The render object that is actively painting.
2702 ///
2703 /// Only valid when asserts are enabled. In release builds, always returns
2704 /// null.
2705 static RenderObject? get debugActivePaint => _debugActivePaint;
2706 static RenderObject? _debugActivePaint;
2707
2708 /// Whether this render object repaints separately from its parent.
2709 ///
2710 /// Override this in subclasses to indicate that instances of your class ought
2711 /// to repaint independently. For example, render objects that repaint
2712 /// frequently might want to repaint themselves without requiring their parent
2713 /// to repaint.
2714 ///
2715 /// If this getter returns true, the [paintBounds] are applied to this object
2716 /// and all descendants. The framework invokes [RenderObject.updateCompositedLayer]
2717 /// to create an [OffsetLayer] and assigns it to the [layer] field.
2718 /// Render objects that declare themselves as repaint boundaries must not replace
2719 /// the layer created by the framework.
2720 ///
2721 /// If the value of this getter changes, [markNeedsCompositingBitsUpdate] must
2722 /// be called.
2723 ///
2724 /// See [RepaintBoundary] for more information about how repaint boundaries function.
2725 bool get isRepaintBoundary => false;
2726
2727 /// Called, in debug mode, if [isRepaintBoundary] is true, when either the
2728 /// this render object or its parent attempt to paint.
2729 ///
2730 /// This can be used to record metrics about whether the node should actually
2731 /// be a repaint boundary.
2732 void debugRegisterRepaintBoundaryPaint({ bool includedParent = true, bool includedChild = false }) { }
2733
2734 /// Whether this render object always needs compositing.
2735 ///
2736 /// Override this in subclasses to indicate that your paint function always
2737 /// creates at least one composited layer. For example, videos should return
2738 /// true if they use hardware decoders.
2739 ///
2740 /// You must call [markNeedsCompositingBitsUpdate] if the value of this getter
2741 /// changes. (This is implied when [adoptChild] or [dropChild] are called.)
2742 @protected
2743 bool get alwaysNeedsCompositing => false;
2744
2745 late bool _wasRepaintBoundary;
2746
2747 /// Update the composited layer owned by this render object.
2748 ///
2749 /// This method is called by the framework when [isRepaintBoundary] is true.
2750 ///
2751 /// If [oldLayer] is `null`, this method must return a new [OffsetLayer]
2752 /// (or subtype thereof). If [oldLayer] is not `null`, then this method must
2753 /// reuse the layer instance that is provided - it is an error to create a new
2754 /// layer in this instance. The layer will be disposed by the framework when
2755 /// either the render object is disposed or if it is no longer a repaint
2756 /// boundary.
2757 ///
2758 /// The [OffsetLayer.offset] property will be managed by the framework and
2759 /// must not be updated by this method.
2760 ///
2761 /// If a property of the composited layer needs to be updated, the render object
2762 /// must call [markNeedsCompositedLayerUpdate] which will schedule this method
2763 /// to be called without repainting children. If this widget was marked as
2764 /// needing to paint and needing a composited layer update, this method is only
2765 /// called once.
2766 // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/102102 revisit the
2767 // constraint that the instance/type of layer cannot be changed at runtime.
2768 OffsetLayer updateCompositedLayer({required covariant OffsetLayer? oldLayer}) {
2769 assert(isRepaintBoundary);
2770 return oldLayer ?? OffsetLayer();
2771 }
2772
2773 /// The compositing layer that this render object uses to repaint.
2774 ///
2775 /// If this render object is not a repaint boundary, it is the responsibility
2776 /// of the [paint] method to populate this field. If [needsCompositing] is
2777 /// true, this field may be populated with the root-most layer used by the
2778 /// render object implementation. When repainting, instead of creating a new
2779 /// layer the render object may update the layer stored in this field for better
2780 /// performance. It is also OK to leave this field as null and create a new
2781 /// layer on every repaint, but without the performance benefit. If
2782 /// [needsCompositing] is false, this field must be set to null either by
2783 /// never populating this field, or by setting it to null when the value of
2784 /// [needsCompositing] changes from true to false.
2785 ///
2786 /// If a new layer is created and stored in some other field on the render
2787 /// object, the render object must use a [LayerHandle] to store it. A layer
2788 /// handle will prevent the layer from being disposed before the render
2789 /// object is finished with it, and it will also make sure that the layer
2790 /// gets appropriately disposed when the render object creates a replacement
2791 /// or nulls it out. The render object must null out the [LayerHandle.layer]
2792 /// in its [dispose] method.
2793 ///
2794 /// If this render object is a repaint boundary, the framework automatically
2795 /// creates an [OffsetLayer] and populates this field prior to calling the
2796 /// [paint] method. The [paint] method must not replace the value of this
2797 /// field.
2798 @protected
2799 ContainerLayer? get layer {
2800 assert(!isRepaintBoundary || _layerHandle.layer == null || _layerHandle.layer is OffsetLayer);
2801 return _layerHandle.layer;
2802 }
2803
2804 @protected
2805 set layer(ContainerLayer? newLayer) {
2806 assert(
2807 !isRepaintBoundary,
2808 'Attempted to set a layer to a repaint boundary render object.\n'
2809 'The framework creates and assigns an OffsetLayer to a repaint '
2810 'boundary automatically.',
2811 );
2812 _layerHandle.layer = newLayer;
2813 }
2814
2815 final LayerHandle<ContainerLayer> _layerHandle = LayerHandle<ContainerLayer>();
2816
2817 /// In debug mode, the compositing layer that this render object uses to repaint.
2818 ///
2819 /// This getter is intended for debugging purposes only. In release builds, it
2820 /// always returns null. In debug builds, it returns the layer even if the layer
2821 /// is dirty.
2822 ///
2823 /// For production code, consider [layer].
2824 ContainerLayer? get debugLayer {
2825 ContainerLayer? result;
2826 assert(() {
2827 result = _layerHandle.layer;
2828 return true;
2829 }());
2830 return result;
2831 }
2832
2833 bool _needsCompositingBitsUpdate = false; // set to true when a child is added
2834 /// Mark the compositing state for this render object as dirty.
2835 ///
2836 /// This is called to indicate that the value for [needsCompositing] needs to
2837 /// be recomputed during the next [PipelineOwner.flushCompositingBits] engine
2838 /// phase.
2839 ///
2840 /// When the subtree is mutated, we need to recompute our
2841 /// [needsCompositing] bit, and some of our ancestors need to do the
2842 /// same (in case ours changed in a way that will change theirs). To
2843 /// this end, [adoptChild] and [dropChild] call this method, and, as
2844 /// necessary, this method calls the parent's, etc, walking up the
2845 /// tree to mark all the nodes that need updating.
2846 ///
2847 /// This method does not schedule a rendering frame, because since
2848 /// it cannot be the case that _only_ the compositing bits changed,
2849 /// something else will have scheduled a frame for us.
2850 void markNeedsCompositingBitsUpdate() {
2851 assert(!_debugDisposed);
2852 if (_needsCompositingBitsUpdate) {
2853 return;
2854 }
2855 _needsCompositingBitsUpdate = true;
2856 if (parent is RenderObject) {
2857 final RenderObject parent = this.parent!;
2858 if (parent._needsCompositingBitsUpdate) {
2859 return;
2860 }
2861
2862 if ((!_wasRepaintBoundary || !isRepaintBoundary) && !parent.isRepaintBoundary) {
2863 parent.markNeedsCompositingBitsUpdate();
2864 return;
2865 }
2866 }
2867 // parent is fine (or there isn't one), but we are dirty
2868 if (owner != null) {
2869 owner!._nodesNeedingCompositingBitsUpdate.add(this);
2870 }
2871 }
2872
2873 late bool _needsCompositing; // initialized in the constructor
2874 /// Whether we or one of our descendants has a compositing layer.
2875 ///
2876 /// If this node needs compositing as indicated by this bit, then all ancestor
2877 /// nodes will also need compositing.
2878 ///
2879 /// Only legal to call after [PipelineOwner.flushLayout] and
2880 /// [PipelineOwner.flushCompositingBits] have been called.
2881 bool get needsCompositing {
2882 assert(!_needsCompositingBitsUpdate); // make sure we don't use this bit when it is dirty
2883 return _needsCompositing;
2884 }
2885
2886 void _updateCompositingBits() {
2887 if (!_needsCompositingBitsUpdate) {
2888 return;
2889 }
2890 final bool oldNeedsCompositing = _needsCompositing;
2891 _needsCompositing = false;
2892 visitChildren((RenderObject child) {
2893 child._updateCompositingBits();
2894 if (child.needsCompositing) {
2895 _needsCompositing = true;
2896 }
2897 });
2898 if (isRepaintBoundary || alwaysNeedsCompositing) {
2899 _needsCompositing = true;
2900 }
2901 // If a node was previously a repaint boundary, but no longer is one, then
2902 // regardless of its compositing state we need to find a new parent to
2903 // paint from. To do this, we mark it clean again so that the traversal
2904 // in markNeedsPaint is not short-circuited. It is removed from _nodesNeedingPaint
2905 // so that we do not attempt to paint from it after locating a parent.
2906 if (!isRepaintBoundary && _wasRepaintBoundary) {
2907 _needsPaint = false;
2908 _needsCompositedLayerUpdate = false;
2909 owner?._nodesNeedingPaint.remove(this);
2910 _needsCompositingBitsUpdate = false;
2911 markNeedsPaint();
2912 } else if (oldNeedsCompositing != _needsCompositing) {
2913 _needsCompositingBitsUpdate = false;
2914 markNeedsPaint();
2915 } else {
2916 _needsCompositingBitsUpdate = false;
2917 }
2918 }
2919
2920 /// Whether this render object's paint information is dirty.
2921 ///
2922 /// This is only set in debug mode. In general, render objects should not need
2923 /// to condition their runtime behavior on whether they are dirty or not,
2924 /// since they should only be marked dirty immediately prior to being laid
2925 /// out and painted. (In release builds, this throws.)
2926 ///
2927 /// It is intended to be used by tests and asserts.
2928 ///
2929 /// It is possible (and indeed, quite common) for [debugNeedsPaint] to be
2930 /// false and [debugNeedsLayout] to be true. The render object will still be
2931 /// repainted in the next frame when this is the case, because the
2932 /// [markNeedsPaint] method is implicitly called by the framework after a
2933 /// render object is laid out, prior to the paint phase.
2934 bool get debugNeedsPaint {
2935 late bool result;
2936 assert(() {
2937 result = _needsPaint;
2938 return true;
2939 }());
2940 return result;
2941 }
2942 bool _needsPaint = true;
2943
2944 /// Whether this render object's layer information is dirty.
2945 ///
2946 /// This is only set in debug mode. In general, render objects should not need
2947 /// to condition their runtime behavior on whether they are dirty or not,
2948 /// since they should only be marked dirty immediately prior to being laid
2949 /// out and painted. (In release builds, this throws.)
2950 ///
2951 /// It is intended to be used by tests and asserts.
2952 bool get debugNeedsCompositedLayerUpdate {
2953 late bool result;
2954 assert(() {
2955 result = _needsCompositedLayerUpdate;
2956 return true;
2957 }());
2958 return result;
2959 }
2960 bool _needsCompositedLayerUpdate = false;
2961
2962 /// Mark this render object as having changed its visual appearance.
2963 ///
2964 /// Rather than eagerly updating this render object's display list
2965 /// in response to writes, we instead mark the render object as needing to
2966 /// paint, which schedules a visual update. As part of the visual update, the
2967 /// rendering pipeline will give this render object an opportunity to update
2968 /// its display list.
2969 ///
2970 /// This mechanism batches the painting work so that multiple sequential
2971 /// writes are coalesced, removing redundant computation.
2972 ///
2973 /// Once [markNeedsPaint] has been called on a render object,
2974 /// [debugNeedsPaint] returns true for that render object until just after
2975 /// the pipeline owner has called [paint] on the render object.
2976 ///
2977 /// See also:
2978 ///
2979 /// * [RepaintBoundary], to scope a subtree of render objects to their own
2980 /// layer, thus limiting the number of nodes that [markNeedsPaint] must mark
2981 /// dirty.
2982 void markNeedsPaint() {
2983 assert(!_debugDisposed);
2984 assert(owner == null || !owner!.debugDoingPaint);
2985 if (_needsPaint) {
2986 return;
2987 }
2988 _needsPaint = true;
2989 // If this was not previously a repaint boundary it will not have
2990 // a layer we can paint from.
2991 if (isRepaintBoundary && _wasRepaintBoundary) {
2992 assert(() {
2993 if (debugPrintMarkNeedsPaintStacks) {
2994 debugPrintStack(label: 'markNeedsPaint() called for $this');
2995 }
2996 return true;
2997 }());
2998 // If we always have our own layer, then we can just repaint
2999 // ourselves without involving any other nodes.
3000 assert(_layerHandle.layer is OffsetLayer);
3001 if (owner != null) {
3002 owner!._nodesNeedingPaint.add(this);
3003 owner!.requestVisualUpdate();
3004 }
3005 } else if (parent is RenderObject) {
3006 parent!.markNeedsPaint();
3007 } else {
3008 assert(() {
3009 if (debugPrintMarkNeedsPaintStacks) {
3010 debugPrintStack(label: 'markNeedsPaint() called for $this (root of render tree)');
3011 }
3012 return true;
3013 }());
3014 // If we are the root of the render tree and not a repaint boundary
3015 // then we have to paint ourselves, since nobody else can paint us.
3016 // We don't add ourselves to _nodesNeedingPaint in this case,
3017 // because the root is always told to paint regardless.
3018 //
3019 // Trees rooted at a RenderView do not go through this
3020 // code path because RenderViews are repaint boundaries.
3021 if (owner != null) {
3022 owner!.requestVisualUpdate();
3023 }
3024 }
3025 }
3026
3027 /// Mark this render object as having changed a property on its composited
3028 /// layer.
3029 ///
3030 /// Render objects that have a composited layer have [isRepaintBoundary] equal
3031 /// to true may update the properties of that composited layer without repainting
3032 /// their children. If this render object is a repaint boundary but does
3033 /// not yet have a composited layer created for it, this method will instead
3034 /// mark the nearest repaint boundary parent as needing to be painted.
3035 ///
3036 /// If this method is called on a render object that is not a repaint boundary
3037 /// or is a repaint boundary but hasn't been composited yet, it is equivalent
3038 /// to calling [markNeedsPaint].
3039 ///
3040 /// See also:
3041 ///
3042 /// * [RenderOpacity], which uses this method when its opacity is updated to
3043 /// update the layer opacity without repainting children.
3044 void markNeedsCompositedLayerUpdate() {
3045 assert(!_debugDisposed);
3046 assert(owner == null || !owner!.debugDoingPaint);
3047 if (_needsCompositedLayerUpdate || _needsPaint) {
3048 return;
3049 }
3050 _needsCompositedLayerUpdate = true;
3051 // If this was not previously a repaint boundary it will not have
3052 // a layer we can paint from.
3053 if (isRepaintBoundary && _wasRepaintBoundary) {
3054 // If we always have our own layer, then we can just repaint
3055 // ourselves without involving any other nodes.
3056 assert(_layerHandle.layer != null);
3057 if (owner != null) {
3058 owner!._nodesNeedingPaint.add(this);
3059 owner!.requestVisualUpdate();
3060 }
3061 } else {
3062 markNeedsPaint();
3063 }
3064 }
3065
3066 // Called when flushPaint() tries to make us paint but our layer is detached.
3067 // To make sure that our subtree is repainted when it's finally reattached,
3068 // even in the case where some ancestor layer is itself never marked dirty, we
3069 // have to mark our entire detached subtree as dirty and needing to be
3070 // repainted. That way, we'll eventually be repainted.
3071 void _skippedPaintingOnLayer() {
3072 assert(attached);
3073 assert(isRepaintBoundary);
3074 assert(_needsPaint || _needsCompositedLayerUpdate);
3075 assert(_layerHandle.layer != null);
3076 assert(!_layerHandle.layer!.attached);
3077 RenderObject? node = parent;
3078 while (node is RenderObject) {
3079 if (node.isRepaintBoundary) {
3080 if (node._layerHandle.layer == null) {
3081 // Looks like the subtree here has never been painted. Let it handle itself.
3082 break;
3083 }
3084 if (node._layerHandle.layer!.attached) {
3085 // It's the one that detached us, so it's the one that will decide to repaint us.
3086 break;
3087 }
3088 node._needsPaint = true;
3089 }
3090 node = node.parent;
3091 }
3092 }
3093
3094 /// Bootstrap the rendering pipeline by scheduling the very first paint.
3095 ///
3096 /// Requires that this render object is attached, is the root of the render
3097 /// tree, and has a composited layer.
3098 ///
3099 /// See [RenderView] for an example of how this function is used.
3100 void scheduleInitialPaint(ContainerLayer rootLayer) {
3101 assert(rootLayer.attached);
3102 assert(attached);
3103 assert(parent is! RenderObject);
3104 assert(!owner!._debugDoingPaint);
3105 assert(isRepaintBoundary);
3106 assert(_layerHandle.layer == null);
3107 _layerHandle.layer = rootLayer;
3108 assert(_needsPaint);
3109 owner!._nodesNeedingPaint.add(this);
3110 }
3111
3112 /// Replace the layer. This is only valid for the root of a render
3113 /// object subtree (whatever object [scheduleInitialPaint] was
3114 /// called on).
3115 ///
3116 /// This might be called if, e.g., the device pixel ratio changed.
3117 void replaceRootLayer(OffsetLayer rootLayer) {
3118 assert(!_debugDisposed);
3119 assert(rootLayer.attached);
3120 assert(attached);
3121 assert(parent is! RenderObject);
3122 assert(!owner!._debugDoingPaint);
3123 assert(isRepaintBoundary);
3124 assert(_layerHandle.layer != null); // use scheduleInitialPaint the first time
3125 _layerHandle.layer!.detach();
3126 _layerHandle.layer = rootLayer;
3127 markNeedsPaint();
3128 }
3129
3130 void _paintWithContext(PaintingContext context, Offset offset) {
3131 assert(!_debugDisposed);
3132 assert(() {
3133 if (_debugDoingThisPaint) {
3134 throw FlutterError.fromParts(<DiagnosticsNode>[
3135 ErrorSummary('Tried to paint a RenderObject reentrantly.'),
3136 describeForError(
3137 'The following RenderObject was already being painted when it was '
3138 'painted again',
3139 ),
3140 ErrorDescription(
3141 'Since this typically indicates an infinite recursion, it is '
3142 'disallowed.',
3143 ),
3144 ]);
3145 }
3146 return true;
3147 }());
3148 // If we still need layout, then that means that we were skipped in the
3149 // layout phase and therefore don't need painting. We might not know that
3150 // yet (that is, our layer might not have been detached yet), because the
3151 // same node that skipped us in layout is above us in the tree (obviously)
3152 // and therefore may not have had a chance to paint yet (since the tree
3153 // paints in reverse order). In particular this will happen if they have
3154 // a different layer, because there's a repaint boundary between us.
3155 if (_needsLayout) {
3156 return;
3157 }
3158 if (!kReleaseMode && debugProfilePaintsEnabled) {
3159 Map<String, String>? debugTimelineArguments;
3160 assert(() {
3161 if (debugEnhancePaintTimelineArguments) {
3162 debugTimelineArguments = toDiagnosticsNode().toTimelineArguments();
3163 }
3164 return true;
3165 }());
3166 FlutterTimeline.startSync(
3167 '$runtimeType',
3168 arguments: debugTimelineArguments,
3169 );
3170 }
3171 assert(() {
3172 if (_needsCompositingBitsUpdate) {
3173 if (parent is RenderObject) {
3174 final RenderObject parent = this.parent!;
3175 bool visitedByParent = false;
3176 parent.visitChildren((RenderObject child) {
3177 if (child == this) {
3178 visitedByParent = true;
3179 }
3180 });
3181 if (!visitedByParent) {
3182 throw FlutterError.fromParts(<DiagnosticsNode>[
3183 ErrorSummary(
3184 "A RenderObject was not visited by the parent's visitChildren "
3185 'during paint.',
3186 ),
3187 parent.describeForError(
3188 'The parent was',
3189 ),
3190 describeForError(
3191 'The child that was not visited was',
3192 ),
3193 ErrorDescription(
3194 'A RenderObject with children must implement visitChildren and '
3195 'call the visitor exactly once for each child; it also should not '
3196 'paint children that were removed with dropChild.',
3197 ),
3198 ErrorHint(
3199 'This usually indicates an error in the Flutter framework itself.',
3200 ),
3201 ]);
3202 }
3203 }
3204 throw FlutterError.fromParts(<DiagnosticsNode>[
3205 ErrorSummary(
3206 'Tried to paint a RenderObject before its compositing bits were '
3207 'updated.',
3208 ),
3209 describeForError(
3210 'The following RenderObject was marked as having dirty compositing '
3211 'bits at the time that it was painted',
3212 ),
3213 ErrorDescription(
3214 'A RenderObject that still has dirty compositing bits cannot be '
3215 'painted because this indicates that the tree has not yet been '
3216 'properly configured for creating the layer tree.',
3217 ),
3218 ErrorHint(
3219 'This usually indicates an error in the Flutter framework itself.',
3220 ),
3221 ]);
3222 }
3223 return true;
3224 }());
3225 RenderObject? debugLastActivePaint;
3226 assert(() {
3227 _debugDoingThisPaint = true;
3228 debugLastActivePaint = _debugActivePaint;
3229 _debugActivePaint = this;
3230 assert(!isRepaintBoundary || _layerHandle.layer != null);
3231 return true;
3232 }());
3233 _needsPaint = false;
3234 _needsCompositedLayerUpdate = false;
3235 _wasRepaintBoundary = isRepaintBoundary;
3236 try {
3237 paint(context, offset);
3238 assert(!_needsLayout); // check that the paint() method didn't mark us dirty again
3239 assert(!_needsPaint); // check that the paint() method didn't mark us dirty again
3240 } catch (e, stack) {
3241 _reportException('paint', e, stack);
3242 }
3243 assert(() {
3244 debugPaint(context, offset);
3245 _debugActivePaint = debugLastActivePaint;
3246 _debugDoingThisPaint = false;
3247 return true;
3248 }());
3249 if (!kReleaseMode && debugProfilePaintsEnabled) {
3250 FlutterTimeline.finishSync();
3251 }
3252 }
3253
3254 /// An estimate of the bounds within which this render object will paint.
3255 /// Useful for debugging flags such as [debugPaintLayerBordersEnabled].
3256 ///
3257 /// These are also the bounds used by [showOnScreen] to make a [RenderObject]
3258 /// visible on screen.
3259 Rect get paintBounds;
3260
3261 /// Override this method to paint debugging information.
3262 void debugPaint(PaintingContext context, Offset offset) { }
3263
3264 /// Paint this render object into the given context at the given offset.
3265 ///
3266 /// Subclasses should override this method to provide a visual appearance
3267 /// for themselves. The render object's local coordinate system is
3268 /// axis-aligned with the coordinate system of the context's canvas and the
3269 /// render object's local origin (i.e, x=0 and y=0) is placed at the given
3270 /// offset in the context's canvas.
3271 ///
3272 /// Do not call this function directly. If you wish to paint yourself, call
3273 /// [markNeedsPaint] instead to schedule a call to this function. If you wish
3274 /// to paint one of your children, call [PaintingContext.paintChild] on the
3275 /// given `context`.
3276 ///
3277 /// When painting one of your children (via a paint child function on the
3278 /// given context), the current canvas held by the context might change
3279 /// because draw operations before and after painting children might need to
3280 /// be recorded on separate compositing layers.
3281 void paint(PaintingContext context, Offset offset) { }
3282
3283 /// Applies the transform that would be applied when painting the given child
3284 /// to the given matrix.
3285 ///
3286 /// Used by coordinate conversion functions to translate coordinates local to
3287 /// one render object into coordinates local to another render object.
3288 ///
3289 /// Some RenderObjects will provide a zeroed out matrix in this method,
3290 /// indicating that the child should not paint anything or respond to hit
3291 /// tests currently. A parent may supply a non-zero matrix even though it
3292 /// does not paint its child currently, for example if the parent is a
3293 /// [RenderOffstage] with `offstage` set to true. In both of these cases,
3294 /// the parent must return `false` from [paintsChild].
3295 void applyPaintTransform(covariant RenderObject child, Matrix4 transform) {
3296 assert(child.parent == this);
3297 }
3298
3299 /// Whether the given child would be painted if [paint] were called.
3300 ///
3301 /// Some RenderObjects skip painting their children if they are configured to
3302 /// not produce any visible effects. For example, a [RenderOffstage] with
3303 /// its `offstage` property set to true, or a [RenderOpacity] with its opacity
3304 /// value set to zero.
3305 ///
3306 /// In these cases, the parent may still supply a non-zero matrix in
3307 /// [applyPaintTransform] to inform callers about where it would paint the
3308 /// child if the child were painted at all. Alternatively, the parent may
3309 /// supply a zeroed out matrix if it would not otherwise be able to determine
3310 /// a valid matrix for the child and thus cannot meaningfully determine where
3311 /// the child would paint.
3312 bool paintsChild(covariant RenderObject child) {
3313 assert(child.parent == this);
3314 return true;
3315 }
3316
3317 /// {@template flutter.rendering.RenderObject.getTransformTo}
3318 /// Applies the paint transform up the tree to `ancestor`.
3319 ///
3320 /// Returns a matrix that maps the local paint coordinate system to the
3321 /// coordinate system of `ancestor`.
3322 ///
3323 /// If `ancestor` is null, this method returns a matrix that maps from the
3324 /// local paint coordinate system to the coordinate system of the
3325 /// [PipelineOwner.rootNode].
3326 /// {@endtemplate}
3327 ///
3328 /// For the render tree owned by the [RendererBinding] (i.e. for the main
3329 /// render tree displayed on the device) this means that this method maps to
3330 /// the global coordinate system in logical pixels. To get physical pixels,
3331 /// use [applyPaintTransform] from the [RenderView] to further transform the
3332 /// coordinate.
3333 Matrix4 getTransformTo(RenderObject? ancestor) {
3334 final bool ancestorSpecified = ancestor != null;
3335 assert(attached);
3336 if (ancestor == null) {
3337 final RenderObject? rootNode = owner!.rootNode;
3338 if (rootNode is RenderObject) {
3339 ancestor = rootNode;
3340 }
3341 }
3342 final List<RenderObject> renderers = <RenderObject>[];
3343 for (RenderObject renderer = this; renderer != ancestor; renderer = renderer.parent!) {
3344 renderers.add(renderer);
3345 assert(renderer.parent != null); // Failed to find ancestor in parent chain.
3346 }
3347 if (ancestorSpecified) {
3348 renderers.add(ancestor!);
3349 }
3350 final Matrix4 transform = Matrix4.identity();
3351 for (int index = renderers.length - 1; index > 0; index -= 1) {
3352 renderers[index].applyPaintTransform(renderers[index - 1], transform);
3353 }
3354 return transform;
3355 }
3356
3357
3358 /// Returns a rect in this object's coordinate system that describes
3359 /// the approximate bounding box of the clip rect that would be
3360 /// applied to the given child during the paint phase, if any.
3361 ///
3362 /// Returns null if the child would not be clipped.
3363 ///
3364 /// This is used in the semantics phase to avoid including children
3365 /// that are not physically visible.
3366 ///
3367 /// RenderObjects that respect a [Clip] behavior when painting _must_ respect
3368 /// that same behavior when describing this value. For example, if passing
3369 /// [Clip.none] to [PaintingContext.pushClipRect] as the `clipBehavior`, then
3370 /// the implementation of this method must return null.
3371 Rect? describeApproximatePaintClip(covariant RenderObject child) => null;
3372
3373 /// Returns a rect in this object's coordinate system that describes
3374 /// which [SemanticsNode]s produced by the `child` should be included in the
3375 /// semantics tree. [SemanticsNode]s from the `child` that are positioned
3376 /// outside of this rect will be dropped. Child [SemanticsNode]s that are
3377 /// positioned inside this rect, but outside of [describeApproximatePaintClip]
3378 /// will be included in the tree marked as hidden. Child [SemanticsNode]s
3379 /// that are inside of both rect will be included in the tree as regular
3380 /// nodes.
3381 ///
3382 /// This method only returns a non-null value if the semantics clip rect
3383 /// is different from the rect returned by [describeApproximatePaintClip].
3384 /// If the semantics clip rect and the paint clip rect are the same, this
3385 /// method returns null.
3386 ///
3387 /// A viewport would typically implement this method to include semantic nodes
3388 /// in the semantics tree that are currently hidden just before the leading
3389 /// or just after the trailing edge. These nodes have to be included in the
3390 /// semantics tree to implement implicit accessibility scrolling on iOS where
3391 /// the viewport scrolls implicitly when moving the accessibility focus from
3392 /// the last visible node in the viewport to the first hidden one.
3393 ///
3394 /// See also:
3395 ///
3396 /// * [RenderViewportBase.cacheExtent], used by viewports to extend their
3397 /// semantics clip beyond their approximate paint clip.
3398 Rect? describeSemanticsClip(covariant RenderObject? child) => null;
3399
3400 // SEMANTICS
3401
3402 /// Bootstrap the semantics reporting mechanism by marking this node
3403 /// as needing a semantics update.
3404 ///
3405 /// Requires that this render object is attached, and is the root of
3406 /// the render tree.
3407 ///
3408 /// See [RendererBinding] for an example of how this function is used.
3409 void scheduleInitialSemantics() {
3410 assert(!_debugDisposed);
3411 assert(attached);
3412 assert(parent is! RenderObject);
3413 assert(!owner!._debugDoingSemantics);
3414 assert(_semantics == null);
3415 assert(_needsSemanticsUpdate);
3416 assert(owner!._semanticsOwner != null);
3417 owner!._nodesNeedingSemantics.add(this);
3418 owner!.requestVisualUpdate();
3419 }
3420
3421 /// Report the semantics of this node, for example for accessibility purposes.
3422 ///
3423 /// This method should be overridden by subclasses that have interesting
3424 /// semantic information.
3425 ///
3426 /// The given [SemanticsConfiguration] object is mutable and should be
3427 /// annotated in a manner that describes the current state. No reference
3428 /// should be kept to that object; mutating it outside of the context of the
3429 /// [describeSemanticsConfiguration] call (for example as a result of
3430 /// asynchronous computation) will at best have no useful effect and at worse
3431 /// will cause crashes as the data will be in an inconsistent state.
3432 ///
3433 /// {@tool snippet}
3434 ///
3435 /// The following snippet will describe the node as a button that responds to
3436 /// tap actions.
3437 ///
3438 /// ```dart
3439 /// abstract class SemanticButtonRenderObject extends RenderObject {
3440 /// @override
3441 /// void describeSemanticsConfiguration(SemanticsConfiguration config) {
3442 /// super.describeSemanticsConfiguration(config);
3443 /// config
3444 /// ..onTap = _handleTap
3445 /// ..label = 'I am a button'
3446 /// ..isButton = true;
3447 /// }
3448 ///
3449 /// void _handleTap() {
3450 /// // Do something.
3451 /// }
3452 /// }
3453 /// ```
3454 /// {@end-tool}
3455 @protected
3456 void describeSemanticsConfiguration(SemanticsConfiguration config) {
3457 // Nothing to do by default.
3458 }
3459
3460 /// Sends a [SemanticsEvent] associated with this render object's [SemanticsNode].
3461 ///
3462 /// If this render object has no semantics information, the first parent
3463 /// render object with a non-null semantic node is used.
3464 ///
3465 /// If semantics are disabled, no events are dispatched.
3466 ///
3467 /// See [SemanticsNode.sendEvent] for a full description of the behavior.
3468 void sendSemanticsEvent(SemanticsEvent semanticsEvent) {
3469 if (owner!.semanticsOwner == null) {
3470 return;
3471 }
3472 if (_semantics != null && !_semantics!.isMergedIntoParent) {
3473 _semantics!.sendEvent(semanticsEvent);
3474 } else if (parent != null) {
3475 parent!.sendSemanticsEvent(semanticsEvent);
3476 }
3477 }
3478
3479 // Use [_semanticsConfiguration] to access.
3480 SemanticsConfiguration? _cachedSemanticsConfiguration;
3481
3482 SemanticsConfiguration get _semanticsConfiguration {
3483 if (_cachedSemanticsConfiguration == null) {
3484 _cachedSemanticsConfiguration = SemanticsConfiguration();
3485 describeSemanticsConfiguration(_cachedSemanticsConfiguration!);
3486 assert(
3487 !_cachedSemanticsConfiguration!.explicitChildNodes || _cachedSemanticsConfiguration!.childConfigurationsDelegate == null,
3488 'A SemanticsConfiguration with explicitChildNode set to true cannot have a non-null childConfigsDelegate.',
3489 );
3490 }
3491 return _cachedSemanticsConfiguration!;
3492 }
3493
3494 /// The bounding box, in the local coordinate system, of this
3495 /// object, for accessibility purposes.
3496 Rect get semanticBounds;
3497
3498 bool _needsSemanticsUpdate = true;
3499 SemanticsNode? _semantics;
3500
3501 /// The semantics of this render object.
3502 ///
3503 /// Exposed only for testing and debugging. To learn about the semantics of
3504 /// render objects in production, obtain a [SemanticsHandle] from
3505 /// [PipelineOwner.ensureSemantics].
3506 ///
3507 /// Only valid in debug and profile mode. In release builds, always returns
3508 /// null.
3509 SemanticsNode? get debugSemantics {
3510 if (!kReleaseMode) {
3511 return _semantics;
3512 }
3513 return null;
3514 }
3515
3516 /// Removes all semantics from this render object and its descendants.
3517 ///
3518 /// Should only be called on objects whose [parent] is not a [RenderObject].
3519 ///
3520 /// Override this method if you instantiate new [SemanticsNode]s in an
3521 /// overridden [assembleSemanticsNode] method, to dispose of those nodes.
3522 @mustCallSuper
3523 void clearSemantics() {
3524 _needsSemanticsUpdate = true;
3525 _semantics = null;
3526 visitChildren((RenderObject child) {
3527 child.clearSemantics();
3528 });
3529 }
3530
3531 /// Mark this node as needing an update to its semantics description.
3532 ///
3533 /// This must be called whenever the semantics configuration of this
3534 /// [RenderObject] as annotated by [describeSemanticsConfiguration] changes in
3535 /// any way to update the semantics tree.
3536 void markNeedsSemanticsUpdate() {
3537 assert(!_debugDisposed);
3538 assert(!attached || !owner!._debugDoingSemantics);
3539 if (!attached || owner!._semanticsOwner == null) {
3540 _cachedSemanticsConfiguration = null;
3541 return;
3542 }
3543
3544 // Dirty the semantics tree starting at `this` until we have reached a
3545 // RenderObject that is a semantics boundary. All semantics past this
3546 // RenderObject are still up-to date. Therefore, we will later only rebuild
3547 // the semantics subtree starting at the identified semantics boundary.
3548
3549 final bool wasSemanticsBoundary = _semantics != null && (_cachedSemanticsConfiguration?.isSemanticBoundary ?? false);
3550
3551 bool mayProduceSiblingNodes =
3552 _cachedSemanticsConfiguration?.childConfigurationsDelegate != null ||
3553 _semanticsConfiguration.childConfigurationsDelegate != null;
3554 _cachedSemanticsConfiguration = null;
3555
3556 bool isEffectiveSemanticsBoundary = _semanticsConfiguration.isSemanticBoundary && wasSemanticsBoundary;
3557 RenderObject node = this;
3558
3559 // The sibling nodes will be attached to the parent of immediate semantics
3560 // node, thus marking this semantics boundary dirty is not enough, it needs
3561 // to find the first parent semantics boundary that does not have any
3562 // possible sibling node.
3563 while (node.parent != null && (mayProduceSiblingNodes || !isEffectiveSemanticsBoundary)) {
3564 if (node != this && node._needsSemanticsUpdate) {
3565 break;
3566 }
3567 node._needsSemanticsUpdate = true;
3568 // Since this node is a semantics boundary, the produced sibling nodes will
3569 // be attached to the parent semantics boundary. Thus, these sibling nodes
3570 // will not be carried to the next loop.
3571 if (isEffectiveSemanticsBoundary) {
3572 mayProduceSiblingNodes = false;
3573 }
3574
3575 node = node.parent!;
3576 isEffectiveSemanticsBoundary = node._semanticsConfiguration.isSemanticBoundary;
3577 if (isEffectiveSemanticsBoundary && node._semantics == null) {
3578 // We have reached a semantics boundary that doesn't own a semantics node.
3579 // That means the semantics of this branch are currently blocked and will
3580 // not appear in the semantics tree. We can abort the walk here.
3581 return;
3582 }
3583 }
3584 if (node != this && _semantics != null && _needsSemanticsUpdate) {
3585 // If `this` node has already been added to [owner._nodesNeedingSemantics]
3586 // remove it as it is no longer guaranteed that its semantics
3587 // node will continue to be in the tree. If it still is in the tree, the
3588 // ancestor `node` added to [owner._nodesNeedingSemantics] at the end of
3589 // this block will ensure that the semantics of `this` node actually gets
3590 // updated.
3591 // (See semantics_10_test.dart for an example why this is required).
3592 owner!._nodesNeedingSemantics.remove(this);
3593 }
3594 if (!node._needsSemanticsUpdate) {
3595 node._needsSemanticsUpdate = true;
3596 if (owner != null) {
3597 assert(node._semanticsConfiguration.isSemanticBoundary || node.parent == null);
3598 owner!._nodesNeedingSemantics.add(node);
3599 owner!.requestVisualUpdate();
3600 }
3601 }
3602 }
3603
3604 /// Updates the semantic information of the render object.
3605 void _updateSemantics() {
3606 assert(_semanticsConfiguration.isSemanticBoundary || parent == null);
3607 if (_needsLayout) {
3608 // There's not enough information in this subtree to compute semantics.
3609 // The subtree is probably being kept alive by a viewport but not laid out.
3610 return;
3611 }
3612 if (!kReleaseMode) {
3613 FlutterTimeline.startSync('Semantics.GetFragment');
3614 }
3615 final _SemanticsFragment fragment = _getSemanticsForParent(
3616 mergeIntoParent: _semantics?.parent?.isPartOfNodeMerging ?? false,
3617 blockUserActions: _semantics?.areUserActionsBlocked ?? false,
3618 );
3619 if (!kReleaseMode) {
3620 FlutterTimeline.finishSync();
3621 }
3622 assert(fragment is _InterestingSemanticsFragment);
3623 final _InterestingSemanticsFragment interestingFragment = fragment as _InterestingSemanticsFragment;
3624 final List<SemanticsNode> result = <SemanticsNode>[];
3625 final List<SemanticsNode> siblingNodes = <SemanticsNode>[];
3626
3627 if (!kReleaseMode) {
3628 FlutterTimeline.startSync('Semantics.compileChildren');
3629 }
3630 interestingFragment.compileChildren(
3631 parentSemanticsClipRect: _semantics?.parentSemanticsClipRect,
3632 parentPaintClipRect: _semantics?.parentPaintClipRect,
3633 elevationAdjustment: _semantics?.elevationAdjustment ?? 0.0,
3634 result: result,
3635 siblingNodes: siblingNodes,
3636 );
3637 if (!kReleaseMode) {
3638 FlutterTimeline.finishSync();
3639 }
3640 // Result may contain sibling nodes that are irrelevant for this update.
3641 assert(interestingFragment.config == null && result.any((SemanticsNode node) => node == _semantics));
3642 }
3643
3644 /// Returns the semantics that this node would like to add to its parent.
3645 _SemanticsFragment _getSemanticsForParent({
3646 required bool mergeIntoParent,
3647 required bool blockUserActions,
3648 }) {
3649 assert(!_needsLayout, 'Updated layout information required for $this to calculate semantics.');
3650
3651 final SemanticsConfiguration config = _semanticsConfiguration;
3652 bool dropSemanticsOfPreviousSiblings = config.isBlockingSemanticsOfPreviouslyPaintedNodes;
3653 bool producesForkingFragment = !config.hasBeenAnnotated && !config.isSemanticBoundary;
3654 final bool blockChildInteractions = blockUserActions || config.isBlockingUserActions;
3655 final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants;
3656 final List<SemanticsConfiguration> childConfigurations = <SemanticsConfiguration>[];
3657 final bool explicitChildNode = config.explicitChildNodes || parent == null;
3658 final ChildSemanticsConfigurationsDelegate? childConfigurationsDelegate = config.childConfigurationsDelegate;
3659 final Map<SemanticsConfiguration, _InterestingSemanticsFragment> configToFragment = <SemanticsConfiguration, _InterestingSemanticsFragment>{};
3660 final List<_InterestingSemanticsFragment> mergeUpFragments = <_InterestingSemanticsFragment>[];
3661 final List<List<_InterestingSemanticsFragment>> siblingMergeFragmentGroups = <List<_InterestingSemanticsFragment>>[];
3662 final bool hasTags = config.tagsForChildren?.isNotEmpty ?? false;
3663 visitChildrenForSemantics((RenderObject renderChild) {
3664 assert(!_needsLayout);
3665 final _SemanticsFragment parentFragment = renderChild._getSemanticsForParent(
3666 mergeIntoParent: childrenMergeIntoParent,
3667 blockUserActions: blockChildInteractions,
3668 );
3669 if (parentFragment.dropsSemanticsOfPreviousSiblings) {
3670 childConfigurations.clear();
3671 mergeUpFragments.clear();
3672 siblingMergeFragmentGroups.clear();
3673 if (!config.isSemanticBoundary) {
3674 dropSemanticsOfPreviousSiblings = true;
3675 }
3676 }
3677 for (final _InterestingSemanticsFragment fragment in parentFragment.mergeUpFragments) {
3678 fragment.addAncestor(this);
3679 if (hasTags) {
3680 fragment.addTags(config.tagsForChildren!);
3681 }
3682 if (childConfigurationsDelegate != null && fragment.config != null) {
3683 // This fragment need to go through delegate to determine whether it
3684 // merge up or not.
3685 childConfigurations.add(fragment.config!);
3686 configToFragment[fragment.config!] = fragment;
3687 } else {
3688 mergeUpFragments.add(fragment);
3689 }
3690 }
3691 if (parentFragment is _ContainerSemanticsFragment) {
3692 // Container fragments needs to propagate sibling merge group to be
3693 // compiled by _SwitchableSemanticsFragment.
3694 for (final List<_InterestingSemanticsFragment> siblingMergeGroup in parentFragment.siblingMergeGroups) {
3695 for (final _InterestingSemanticsFragment siblingMergingFragment in siblingMergeGroup) {
3696 siblingMergingFragment.addAncestor(this);
3697 if (hasTags) {
3698 siblingMergingFragment.addTags(config.tagsForChildren!);
3699 }
3700 }
3701 siblingMergeFragmentGroups.add(siblingMergeGroup);
3702 }
3703 }
3704 });
3705
3706 assert(childConfigurationsDelegate != null || configToFragment.isEmpty);
3707
3708 if (explicitChildNode) {
3709 for (final _InterestingSemanticsFragment fragment in mergeUpFragments) {
3710 fragment.markAsExplicit();
3711 }
3712 } else if (childConfigurationsDelegate != null) {
3713 final ChildSemanticsConfigurationsResult result = childConfigurationsDelegate(childConfigurations);
3714 mergeUpFragments.addAll(
3715 result.mergeUp.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) {
3716 final _InterestingSemanticsFragment? fragment = configToFragment[config];
3717 if (fragment == null) {
3718 // Parent fragment of Incomplete fragments can't be a forking
3719 // fragment since they need to be merged.
3720 producesForkingFragment = false;
3721 return _IncompleteSemanticsFragment(config: config, owner: this);
3722 }
3723 return fragment;
3724 }),
3725 );
3726 for (final Iterable<SemanticsConfiguration> group in result.siblingMergeGroups) {
3727 siblingMergeFragmentGroups.add(
3728 group.map<_InterestingSemanticsFragment>((SemanticsConfiguration config) {
3729 return configToFragment[config] ?? _IncompleteSemanticsFragment(config: config, owner: this);
3730 }).toList(),
3731 );
3732 }
3733 }
3734
3735 _needsSemanticsUpdate = false;
3736
3737 final _SemanticsFragment result;
3738 if (parent == null) {
3739 assert(!config.hasBeenAnnotated);
3740 assert(!mergeIntoParent);
3741 assert(siblingMergeFragmentGroups.isEmpty);
3742 _marksExplicitInMergeGroup(mergeUpFragments, isMergeUp: true);
3743 siblingMergeFragmentGroups.forEach(_marksExplicitInMergeGroup);
3744 result = _RootSemanticsFragment(
3745 owner: this,
3746 dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
3747 );
3748 } else if (producesForkingFragment) {
3749 result = _ContainerSemanticsFragment(
3750 siblingMergeGroups: siblingMergeFragmentGroups,
3751 dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
3752 );
3753 } else {
3754 _marksExplicitInMergeGroup(mergeUpFragments, isMergeUp: true);
3755 siblingMergeFragmentGroups.forEach(_marksExplicitInMergeGroup);
3756 result = _SwitchableSemanticsFragment(
3757 config: config,
3758 blockUserActions: blockUserActions,
3759 mergeIntoParent: mergeIntoParent,
3760 siblingMergeGroups: siblingMergeFragmentGroups,
3761 owner: this,
3762 dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
3763 );
3764 if (config.isSemanticBoundary) {
3765 final _SwitchableSemanticsFragment fragment = result as _SwitchableSemanticsFragment;
3766 fragment.markAsExplicit();
3767 }
3768 }
3769 result.addAll(mergeUpFragments);
3770 return result;
3771 }
3772
3773 void _marksExplicitInMergeGroup(List<_InterestingSemanticsFragment> mergeGroup, {bool isMergeUp = false}) {
3774 final Set<_InterestingSemanticsFragment> toBeExplicit = <_InterestingSemanticsFragment>{};
3775 for (int i = 0; i < mergeGroup.length; i += 1) {
3776 final _InterestingSemanticsFragment fragment = mergeGroup[i];
3777 if (!fragment.hasConfigForParent) {
3778 continue;
3779 }
3780 if (isMergeUp && !_semanticsConfiguration.isCompatibleWith(fragment.config)) {
3781 toBeExplicit.add(fragment);
3782 }
3783 final int siblingLength = i;
3784 for (int j = 0; j < siblingLength; j += 1) {
3785 final _InterestingSemanticsFragment siblingFragment = mergeGroup[j];
3786 if (!fragment.config!.isCompatibleWith(siblingFragment.config)) {
3787 toBeExplicit.add(fragment);
3788 toBeExplicit.add(siblingFragment);
3789 }
3790 }
3791 }
3792 for (final _InterestingSemanticsFragment fragment in toBeExplicit) {
3793 fragment.markAsExplicit();
3794 }
3795 }
3796
3797 /// Called when collecting the semantics of this node.
3798 ///
3799 /// The implementation has to return the children in paint order skipping all
3800 /// children that are not semantically relevant (e.g. because they are
3801 /// invisible).
3802 ///
3803 /// The default implementation mirrors the behavior of
3804 /// [visitChildren] (which is supposed to walk all the children).
3805 void visitChildrenForSemantics(RenderObjectVisitor visitor) {
3806 visitChildren(visitor);
3807 }
3808
3809 /// Assemble the [SemanticsNode] for this [RenderObject].
3810 ///
3811 /// If [describeSemanticsConfiguration] sets
3812 /// [SemanticsConfiguration.isSemanticBoundary] to true, this method is called
3813 /// with the `node` created for this [RenderObject], the `config` to be
3814 /// applied to that node and the `children` [SemanticsNode]s that descendants
3815 /// of this RenderObject have generated.
3816 ///
3817 /// By default, the method will annotate `node` with `config` and add the
3818 /// `children` to it.
3819 ///
3820 /// Subclasses can override this method to add additional [SemanticsNode]s
3821 /// to the tree. If new [SemanticsNode]s are instantiated in this method
3822 /// they must be disposed in [clearSemantics].
3823 void assembleSemanticsNode(
3824 SemanticsNode node,
3825 SemanticsConfiguration config,
3826 Iterable<SemanticsNode> children,
3827 ) {
3828 assert(node == _semantics);
3829 // TODO(a14n): remove the following cast by updating type of parameter in either updateWith or assembleSemanticsNode
3830 node.updateWith(config: config, childrenInInversePaintOrder: children as List<SemanticsNode>);
3831 }
3832
3833 // EVENTS
3834
3835 /// Override this method to handle pointer events that hit this render object.
3836 @override
3837 void handleEvent(PointerEvent event, covariant HitTestEntry entry) { }
3838
3839
3840 // HIT TESTING
3841
3842 // RenderObject subclasses are expected to have a method like the following
3843 // (with the signature being whatever passes for coordinates for this
3844 // particular class):
3845 //
3846 // bool hitTest(HitTestResult result, { Offset position }) {
3847 // // If the given position is not inside this node, then return false.
3848 // // Otherwise:
3849 // // For each child that intersects the position, in z-order starting from
3850 // // the top, call hitTest() for that child, passing it /result/, and the
3851 // // coordinates converted to the child's coordinate origin, and stop at
3852 // // the first child that returns true.
3853 // // Then, add yourself to /result/, and return true.
3854 // }
3855 //
3856 // If you add yourself to /result/ and still return false, then that means you
3857 // will see events but so will objects below you.
3858
3859
3860 /// Returns a human understandable name.
3861 @override
3862 String toStringShort() {
3863 String header = describeIdentity(this);
3864 if (!kReleaseMode) {
3865 if (_debugDisposed) {
3866 header += ' DISPOSED';
3867 return header;
3868 }
3869 if (_relayoutBoundary != null && _relayoutBoundary != this) {
3870 int count = 1;
3871 RenderObject? target = parent;
3872 while (target != null && target != _relayoutBoundary) {
3873 target = target.parent;
3874 count += 1;
3875 }
3876 header += ' relayoutBoundary=up$count';
3877 }
3878 if (_needsLayout) {
3879 header += ' NEEDS-LAYOUT';
3880 }
3881 if (_needsPaint) {
3882 header += ' NEEDS-PAINT';
3883 }
3884 if (_needsCompositingBitsUpdate) {
3885 header += ' NEEDS-COMPOSITING-BITS-UPDATE';
3886 }
3887 if (!attached) {
3888 header += ' DETACHED';
3889 }
3890 }
3891 return header;
3892 }
3893
3894 @override
3895 String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) => toStringShort();
3896
3897 /// Returns a description of the tree rooted at this node.
3898 /// If the prefix argument is provided, then every line in the output
3899 /// will be prefixed by that string.
3900 @override
3901 String toStringDeep({
3902 String prefixLineOne = '',
3903 String? prefixOtherLines = '',
3904 DiagnosticLevel minLevel = DiagnosticLevel.debug,
3905 }) {
3906 return _withDebugActiveLayoutCleared(() => super.toStringDeep(
3907 prefixLineOne: prefixLineOne,
3908 prefixOtherLines: prefixOtherLines,
3909 minLevel: minLevel,
3910 ));
3911 }
3912
3913 /// Returns a one-line detailed description of the render object.
3914 /// This description is often somewhat long.
3915 ///
3916 /// This includes the same information for this RenderObject as given by
3917 /// [toStringDeep], but does not recurse to any children.
3918 @override
3919 String toStringShallow({
3920 String joiner = ', ',
3921 DiagnosticLevel minLevel = DiagnosticLevel.debug,
3922 }) {
3923 return _withDebugActiveLayoutCleared(() => super.toStringShallow(joiner: joiner, minLevel: minLevel));
3924 }
3925
3926 @protected
3927 @override
3928 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3929 super.debugFillProperties(properties);
3930 properties.add(FlagProperty('needsCompositing', value: _needsCompositing, ifTrue: 'needs compositing'));
3931 properties.add(DiagnosticsProperty<Object?>('creator', debugCreator, defaultValue: null, level: DiagnosticLevel.debug));
3932 properties.add(DiagnosticsProperty<ParentData>('parentData', parentData, tooltip: (_debugCanParentUseSize ?? false) ? 'can use size' : null, missingIfNull: true));
3933 properties.add(DiagnosticsProperty<Constraints>('constraints', _constraints, missingIfNull: true));
3934 // don't access it via the "layer" getter since that's only valid when we don't need paint
3935 properties.add(DiagnosticsProperty<ContainerLayer>('layer', _layerHandle.layer, defaultValue: null));
3936 properties.add(DiagnosticsProperty<SemanticsNode>('semantics node', _semantics, defaultValue: null));
3937 properties.add(FlagProperty(
3938 'isBlockingSemanticsOfPreviouslyPaintedNodes',
3939 value: _semanticsConfiguration.isBlockingSemanticsOfPreviouslyPaintedNodes,
3940 ifTrue: 'blocks semantics of earlier render objects below the common boundary',
3941 ));
3942 properties.add(FlagProperty('isSemanticBoundary', value: _semanticsConfiguration.isSemanticBoundary, ifTrue: 'semantic boundary'));
3943 }
3944
3945 @override
3946 List<DiagnosticsNode> debugDescribeChildren() => <DiagnosticsNode>[];
3947
3948 /// Attempt to make (a portion of) this or a descendant [RenderObject] visible
3949 /// on screen.
3950 ///
3951 /// If `descendant` is provided, that [RenderObject] is made visible. If
3952 /// `descendant` is omitted, this [RenderObject] is made visible.
3953 ///
3954 /// The optional `rect` parameter describes which area of that [RenderObject]
3955 /// should be shown on screen. If `rect` is null, the entire
3956 /// [RenderObject] (as defined by its [paintBounds]) will be revealed. The
3957 /// `rect` parameter is interpreted relative to the coordinate system of
3958 /// `descendant` if that argument is provided and relative to this
3959 /// [RenderObject] otherwise.
3960 ///
3961 /// The `duration` parameter can be set to a non-zero value to bring the
3962 /// target object on screen in an animation defined by `curve`.
3963 ///
3964 /// See also:
3965 ///
3966 /// * [RenderViewportBase.showInViewport], which [RenderViewportBase] and
3967 /// [SingleChildScrollView] delegate this method to.
3968 void showOnScreen({
3969 RenderObject? descendant,
3970 Rect? rect,
3971 Duration duration = Duration.zero,
3972 Curve curve = Curves.ease,
3973 }) {
3974 if (parent is RenderObject) {
3975 parent!.showOnScreen(
3976 descendant: descendant ?? this,
3977 rect: rect,
3978 duration: duration,
3979 curve: curve,
3980 );
3981 }
3982 }
3983
3984 /// Adds a debug representation of a [RenderObject] optimized for including in
3985 /// error messages.
3986 ///
3987 /// The default [style] of [DiagnosticsTreeStyle.shallow] ensures that all of
3988 /// the properties of the render object are included in the error output but
3989 /// none of the children of the object are.
3990 ///
3991 /// You should always include a RenderObject in an error message if it is the
3992 /// [RenderObject] causing the failure or contract violation of the error.
3993 DiagnosticsNode describeForError(String name, { DiagnosticsTreeStyle style = DiagnosticsTreeStyle.shallow }) {
3994 return toDiagnosticsNode(name: name, style: style);
3995 }
3996}
3997
3998/// Generic mixin for render objects with one child.
3999///
4000/// Provides a child model for a render object subclass that has
4001/// a unique child, which is accessible via the [child] getter.
4002///
4003/// This mixin is typically used to implement render objects created
4004/// in a [SingleChildRenderObjectWidget].
4005mixin RenderObjectWithChildMixin<ChildType extends RenderObject> on RenderObject {
4006 /// Checks whether the given render object has the correct [runtimeType] to be
4007 /// a child of this render object.
4008 ///
4009 /// Does nothing if assertions are disabled.
4010 ///
4011 /// Always returns true.
4012 bool debugValidateChild(RenderObject child) {
4013 assert(() {
4014 if (child is! ChildType) {
4015 throw FlutterError.fromParts(<DiagnosticsNode>[
4016 ErrorSummary(
4017 'A $runtimeType expected a child of type $ChildType but received a '
4018 'child of type ${child.runtimeType}.',
4019 ),
4020 ErrorDescription(
4021 'RenderObjects expect specific types of children because they '
4022 'coordinate with their children during layout and paint. For '
4023 'example, a RenderSliver cannot be the child of a RenderBox because '
4024 'a RenderSliver does not understand the RenderBox layout protocol.',
4025 ),
4026 ErrorSpacer(),
4027 DiagnosticsProperty<Object?>(
4028 'The $runtimeType that expected a $ChildType child was created by',
4029 debugCreator,
4030 style: DiagnosticsTreeStyle.errorProperty,
4031 ),
4032 ErrorSpacer(),
4033 DiagnosticsProperty<Object?>(
4034 'The ${child.runtimeType} that did not match the expected child type '
4035 'was created by',
4036 child.debugCreator,
4037 style: DiagnosticsTreeStyle.errorProperty,
4038 ),
4039 ]);
4040 }
4041 return true;
4042 }());
4043 return true;
4044 }
4045
4046 ChildType? _child;
4047 /// The render object's unique child.
4048 ChildType? get child => _child;
4049 set child(ChildType? value) {
4050 if (_child != null) {
4051 dropChild(_child!);
4052 }
4053 _child = value;
4054 if (_child != null) {
4055 adoptChild(_child!);
4056 }
4057 }
4058
4059 @override
4060 void attach(PipelineOwner owner) {
4061 super.attach(owner);
4062 _child?.attach(owner);
4063 }
4064
4065 @override
4066 void detach() {
4067 super.detach();
4068 _child?.detach();
4069 }
4070
4071 @override
4072 void redepthChildren() {
4073 if (_child != null) {
4074 redepthChild(_child!);
4075 }
4076 }
4077
4078 @override
4079 void visitChildren(RenderObjectVisitor visitor) {
4080 if (_child != null) {
4081 visitor(_child!);
4082 }
4083 }
4084
4085 @override
4086 List<DiagnosticsNode> debugDescribeChildren() {
4087 return child != null ? <DiagnosticsNode>[child!.toDiagnosticsNode(name: 'child')] : <DiagnosticsNode>[];
4088 }
4089}
4090
4091/// Parent data to support a doubly-linked list of children.
4092///
4093/// The children can be traversed using [nextSibling] or [previousSibling],
4094/// which can be called on the parent data of the render objects
4095/// obtained via [ContainerRenderObjectMixin.firstChild] or
4096/// [ContainerRenderObjectMixin.lastChild].
4097mixin ContainerParentDataMixin<ChildType extends RenderObject> on ParentData {
4098 /// The previous sibling in the parent's child list.
4099 ChildType? previousSibling;
4100 /// The next sibling in the parent's child list.
4101 ChildType? nextSibling;
4102
4103 /// Clear the sibling pointers.
4104 @override
4105 void detach() {
4106 assert(previousSibling == null, 'Pointers to siblings must be nulled before detaching ParentData.');
4107 assert(nextSibling == null, 'Pointers to siblings must be nulled before detaching ParentData.');
4108 super.detach();
4109 }
4110}
4111
4112/// Generic mixin for render objects with a list of children.
4113///
4114/// Provides a child model for a render object subclass that has a doubly-linked
4115/// list of children.
4116///
4117/// The [ChildType] specifies the type of the children (extending [RenderObject]),
4118/// e.g. [RenderBox].
4119///
4120/// [ParentDataType] stores parent container data on its child render objects.
4121/// It must extend [ContainerParentDataMixin], which provides the interface
4122/// for visiting children. This data is populated by
4123/// [RenderObject.setupParentData] implemented by the class using this mixin.
4124///
4125/// When using [RenderBox] as the child type, you will usually want to make use of
4126/// [RenderBoxContainerDefaultsMixin] and extend [ContainerBoxParentData] for the
4127/// parent data.
4128///
4129/// Moreover, this is a required mixin for render objects returned to [MultiChildRenderObjectWidget].
4130///
4131/// See also:
4132///
4133/// * [SlottedContainerRenderObjectMixin], which organizes its children
4134/// in different named slots.
4135mixin ContainerRenderObjectMixin<ChildType extends RenderObject, ParentDataType extends ContainerParentDataMixin<ChildType>> on RenderObject {
4136 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType? equals }) {
4137 ParentDataType childParentData = child.parentData! as ParentDataType;
4138 while (childParentData.previousSibling != null) {
4139 assert(childParentData.previousSibling != child);
4140 child = childParentData.previousSibling!;
4141 childParentData = child.parentData! as ParentDataType;
4142 }
4143 return child == equals;
4144 }
4145 bool _debugUltimateNextSiblingOf(ChildType child, { ChildType? equals }) {
4146 ParentDataType childParentData = child.parentData! as ParentDataType;
4147 while (childParentData.nextSibling != null) {
4148 assert(childParentData.nextSibling != child);
4149 child = childParentData.nextSibling!;
4150 childParentData = child.parentData! as ParentDataType;
4151 }
4152 return child == equals;
4153 }
4154
4155 int _childCount = 0;
4156 /// The number of children.
4157 int get childCount => _childCount;
4158
4159 /// Checks whether the given render object has the correct [runtimeType] to be
4160 /// a child of this render object.
4161 ///
4162 /// Does nothing if assertions are disabled.
4163 ///
4164 /// Always returns true.
4165 bool debugValidateChild(RenderObject child) {
4166 assert(() {
4167 if (child is! ChildType) {
4168 throw FlutterError.fromParts(<DiagnosticsNode>[
4169 ErrorSummary(
4170 'A $runtimeType expected a child of type $ChildType but received a '
4171 'child of type ${child.runtimeType}.',
4172 ),
4173 ErrorDescription(
4174 'RenderObjects expect specific types of children because they '
4175 'coordinate with their children during layout and paint. For '
4176 'example, a RenderSliver cannot be the child of a RenderBox because '
4177 'a RenderSliver does not understand the RenderBox layout protocol.',
4178 ),
4179 ErrorSpacer(),
4180 DiagnosticsProperty<Object?>(
4181 'The $runtimeType that expected a $ChildType child was created by',
4182 debugCreator,
4183 style: DiagnosticsTreeStyle.errorProperty,
4184 ),
4185 ErrorSpacer(),
4186 DiagnosticsProperty<Object?>(
4187 'The ${child.runtimeType} that did not match the expected child type '
4188 'was created by',
4189 child.debugCreator,
4190 style: DiagnosticsTreeStyle.errorProperty,
4191 ),
4192 ]);
4193 }
4194 return true;
4195 }());
4196 return true;
4197 }
4198
4199 ChildType? _firstChild;
4200 ChildType? _lastChild;
4201 void _insertIntoChildList(ChildType child, { ChildType? after }) {
4202 final ParentDataType childParentData = child.parentData! as ParentDataType;
4203 assert(childParentData.nextSibling == null);
4204 assert(childParentData.previousSibling == null);
4205 _childCount += 1;
4206 assert(_childCount > 0);
4207 if (after == null) {
4208 // insert at the start (_firstChild)
4209 childParentData.nextSibling = _firstChild;
4210 if (_firstChild != null) {
4211 final ParentDataType firstChildParentData = _firstChild!.parentData! as ParentDataType;
4212 firstChildParentData.previousSibling = child;
4213 }
4214 _firstChild = child;
4215 _lastChild ??= child;
4216 } else {
4217 assert(_firstChild != null);
4218 assert(_lastChild != null);
4219 assert(_debugUltimatePreviousSiblingOf(after, equals: _firstChild));
4220 assert(_debugUltimateNextSiblingOf(after, equals: _lastChild));
4221 final ParentDataType afterParentData = after.parentData! as ParentDataType;
4222 if (afterParentData.nextSibling == null) {
4223 // insert at the end (_lastChild); we'll end up with two or more children
4224 assert(after == _lastChild);
4225 childParentData.previousSibling = after;
4226 afterParentData.nextSibling = child;
4227 _lastChild = child;
4228 } else {
4229 // insert in the middle; we'll end up with three or more children
4230 // set up links from child to siblings
4231 childParentData.nextSibling = afterParentData.nextSibling;
4232 childParentData.previousSibling = after;
4233 // set up links from siblings to child
4234 final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling!.parentData! as ParentDataType;
4235 final ParentDataType childNextSiblingParentData = childParentData.nextSibling!.parentData! as ParentDataType;
4236 childPreviousSiblingParentData.nextSibling = child;
4237 childNextSiblingParentData.previousSibling = child;
4238 assert(afterParentData.nextSibling == child);
4239 }
4240 }
4241 }
4242
4243 /// Insert child into this render object's child list after the given child.
4244 ///
4245 /// If `after` is null, then this inserts the child at the start of the list,
4246 /// and the child becomes the new [firstChild].
4247 void insert(ChildType child, { ChildType? after }) {
4248 assert(child != this, 'A RenderObject cannot be inserted into itself.');
4249 assert(after != this, 'A RenderObject cannot simultaneously be both the parent and the sibling of another RenderObject.');
4250 assert(child != after, 'A RenderObject cannot be inserted after itself.');
4251 assert(child != _firstChild);
4252 assert(child != _lastChild);
4253 adoptChild(child);
4254 _insertIntoChildList(child, after: after);
4255 }
4256
4257 /// Append child to the end of this render object's child list.
4258 void add(ChildType child) {
4259 insert(child, after: _lastChild);
4260 }
4261
4262 /// Add all the children to the end of this render object's child list.
4263 void addAll(List<ChildType>? children) {
4264 children?.forEach(add);
4265 }
4266
4267 void _removeFromChildList(ChildType child) {
4268 final ParentDataType childParentData = child.parentData! as ParentDataType;
4269 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
4270 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
4271 assert(_childCount >= 0);
4272 if (childParentData.previousSibling == null) {
4273 assert(_firstChild == child);
4274 _firstChild = childParentData.nextSibling;
4275 } else {
4276 final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling!.parentData! as ParentDataType;
4277 childPreviousSiblingParentData.nextSibling = childParentData.nextSibling;
4278 }
4279 if (childParentData.nextSibling == null) {
4280 assert(_lastChild == child);
4281 _lastChild = childParentData.previousSibling;
4282 } else {
4283 final ParentDataType childNextSiblingParentData = childParentData.nextSibling!.parentData! as ParentDataType;
4284 childNextSiblingParentData.previousSibling = childParentData.previousSibling;
4285 }
4286 childParentData.previousSibling = null;
4287 childParentData.nextSibling = null;
4288 _childCount -= 1;
4289 }
4290
4291 /// Remove this child from the child list.
4292 ///
4293 /// Requires the child to be present in the child list.
4294 void remove(ChildType child) {
4295 _removeFromChildList(child);
4296 dropChild(child);
4297 }
4298
4299 /// Remove all their children from this render object's child list.
4300 ///
4301 /// More efficient than removing them individually.
4302 void removeAll() {
4303 ChildType? child = _firstChild;
4304 while (child != null) {
4305 final ParentDataType childParentData = child.parentData! as ParentDataType;
4306 final ChildType? next = childParentData.nextSibling;
4307 childParentData.previousSibling = null;
4308 childParentData.nextSibling = null;
4309 dropChild(child);
4310 child = next;
4311 }
4312 _firstChild = null;
4313 _lastChild = null;
4314 _childCount = 0;
4315 }
4316
4317 /// Move the given `child` in the child list to be after another child.
4318 ///
4319 /// More efficient than removing and re-adding the child. Requires the child
4320 /// to already be in the child list at some position. Pass null for `after` to
4321 /// move the child to the start of the child list.
4322 void move(ChildType child, { ChildType? after }) {
4323 assert(child != this);
4324 assert(after != this);
4325 assert(child != after);
4326 assert(child.parent == this);
4327 final ParentDataType childParentData = child.parentData! as ParentDataType;
4328 if (childParentData.previousSibling == after) {
4329 return;
4330 }
4331 _removeFromChildList(child);
4332 _insertIntoChildList(child, after: after);
4333 markNeedsLayout();
4334 }
4335
4336 @override
4337 void attach(PipelineOwner owner) {
4338 super.attach(owner);
4339 ChildType? child = _firstChild;
4340 while (child != null) {
4341 child.attach(owner);
4342 final ParentDataType childParentData = child.parentData! as ParentDataType;
4343 child = childParentData.nextSibling;
4344 }
4345 }
4346
4347 @override
4348 void detach() {
4349 super.detach();
4350 ChildType? child = _firstChild;
4351 while (child != null) {
4352 child.detach();
4353 final ParentDataType childParentData = child.parentData! as ParentDataType;
4354 child = childParentData.nextSibling;
4355 }
4356 }
4357
4358 @override
4359 void redepthChildren() {
4360 ChildType? child = _firstChild;
4361 while (child != null) {
4362 redepthChild(child);
4363 final ParentDataType childParentData = child.parentData! as ParentDataType;
4364 child = childParentData.nextSibling;
4365 }
4366 }
4367
4368 @override
4369 void visitChildren(RenderObjectVisitor visitor) {
4370 ChildType? child = _firstChild;
4371 while (child != null) {
4372 visitor(child);
4373 final ParentDataType childParentData = child.parentData! as ParentDataType;
4374 child = childParentData.nextSibling;
4375 }
4376 }
4377
4378 /// The first child in the child list.
4379 ChildType? get firstChild => _firstChild;
4380
4381 /// The last child in the child list.
4382 ChildType? get lastChild => _lastChild;
4383
4384 /// The previous child before the given child in the child list.
4385 ChildType? childBefore(ChildType child) {
4386 assert(child.parent == this);
4387 final ParentDataType childParentData = child.parentData! as ParentDataType;
4388 return childParentData.previousSibling;
4389 }
4390
4391 /// The next child after the given child in the child list.
4392 ChildType? childAfter(ChildType child) {
4393 assert(child.parent == this);
4394 final ParentDataType childParentData = child.parentData! as ParentDataType;
4395 return childParentData.nextSibling;
4396 }
4397
4398 @override
4399 List<DiagnosticsNode> debugDescribeChildren() {
4400 final List<DiagnosticsNode> children = <DiagnosticsNode>[];
4401 if (firstChild != null) {
4402 ChildType child = firstChild!;
4403 int count = 1;
4404 while (true) {
4405 children.add(child.toDiagnosticsNode(name: 'child $count'));
4406 if (child == lastChild) {
4407 break;
4408 }
4409 count += 1;
4410 final ParentDataType childParentData = child.parentData! as ParentDataType;
4411 child = childParentData.nextSibling!;
4412 }
4413 }
4414 return children;
4415 }
4416}
4417
4418/// Mixin for [RenderObject] that will call [systemFontsDidChange] whenever the
4419/// system fonts change.
4420///
4421/// System fonts can change when the OS installs or removes a font. Use this
4422/// mixin if the [RenderObject] uses [TextPainter] or [Paragraph] to correctly
4423/// update the text when it happens.
4424mixin RelayoutWhenSystemFontsChangeMixin on RenderObject {
4425
4426 /// A callback that is called when system fonts have changed.
4427 ///
4428 /// The framework defers the invocation of the callback to the
4429 /// [SchedulerPhase.transientCallbacks] phase to ensure that the
4430 /// [RenderObject]'s text layout is still valid when user interactions are in
4431 /// progress (which usually take place during the [SchedulerPhase.idle] phase).
4432 ///
4433 /// By default, [markNeedsLayout] is called on the [RenderObject]
4434 /// implementing this mixin.
4435 ///
4436 /// Subclass should override this method to clear any extra cache that depend
4437 /// on font-related metrics.
4438 @protected
4439 @mustCallSuper
4440 void systemFontsDidChange() {
4441 markNeedsLayout();
4442 }
4443
4444 bool _hasPendingSystemFontsDidChangeCallBack = false;
4445 void _scheduleSystemFontsUpdate() {
4446 assert(
4447 SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle,
4448 '${objectRuntimeType(this, "RelayoutWhenSystemFontsChangeMixin")}._scheduleSystemFontsUpdate() '
4449 'called during ${SchedulerBinding.instance.schedulerPhase}.',
4450 );
4451 if (_hasPendingSystemFontsDidChangeCallBack) {
4452 return;
4453 }
4454 _hasPendingSystemFontsDidChangeCallBack = true;
4455 SchedulerBinding.instance.scheduleFrameCallback((Duration timeStamp) {
4456 assert(_hasPendingSystemFontsDidChangeCallBack);
4457 _hasPendingSystemFontsDidChangeCallBack = false;
4458 assert(
4459 attached || (debugDisposed ?? true),
4460 '$this is detached during ${SchedulerBinding.instance.schedulerPhase} but is not disposed.',
4461 );
4462 if (attached) {
4463 systemFontsDidChange();
4464 }
4465 });
4466 }
4467
4468 @override
4469 void attach(PipelineOwner owner) {
4470 super.attach(owner);
4471 // If there's a pending callback that would imply this node was detached
4472 // between the idle phase and the next transientCallbacks phase. The tree
4473 // can not be mutated between those two phases so that should never happen.
4474 assert(!_hasPendingSystemFontsDidChangeCallBack);
4475 PaintingBinding.instance.systemFonts.addListener(_scheduleSystemFontsUpdate);
4476 }
4477
4478 @override
4479 void detach() {
4480 assert(!_hasPendingSystemFontsDidChangeCallBack);
4481 PaintingBinding.instance.systemFonts.removeListener(_scheduleSystemFontsUpdate);
4482 super.detach();
4483 }
4484}
4485
4486/// Describes the semantics information a [RenderObject] wants to add to its
4487/// parent.
4488///
4489/// It has two notable subclasses:
4490/// * [_InterestingSemanticsFragment] describing actual semantic information to
4491/// be added to the parent.
4492/// * [_ContainerSemanticsFragment]: a container class to transport the semantic
4493/// information of multiple [_InterestingSemanticsFragment] to a parent.
4494abstract class _SemanticsFragment {
4495 _SemanticsFragment({
4496 required this.dropsSemanticsOfPreviousSiblings,
4497 });
4498
4499 /// Incorporate the fragments of children into this fragment.
4500 void addAll(Iterable<_InterestingSemanticsFragment> fragments);
4501
4502 /// Whether this fragment wants to make the semantics information of
4503 /// previously painted [RenderObject]s unreachable for accessibility purposes.
4504 ///
4505 /// See also:
4506 ///
4507 /// * [SemanticsConfiguration.isBlockingSemanticsOfPreviouslyPaintedNodes]
4508 /// describes what semantics are dropped in more detail.
4509 final bool dropsSemanticsOfPreviousSiblings;
4510
4511 /// Returns [_InterestingSemanticsFragment] describing the actual semantic
4512 /// information that this fragment wants to add to the parent.
4513 List<_InterestingSemanticsFragment> get mergeUpFragments;
4514}
4515
4516/// A container used when a [RenderObject] wants to add multiple independent
4517/// [_InterestingSemanticsFragment] to its parent.
4518///
4519/// The [_InterestingSemanticsFragment] to be added to the parent can be
4520/// obtained via [mergeUpFragments].
4521class _ContainerSemanticsFragment extends _SemanticsFragment {
4522 _ContainerSemanticsFragment({
4523 required super.dropsSemanticsOfPreviousSiblings,
4524 required this.siblingMergeGroups,
4525 });
4526
4527 final List<List<_InterestingSemanticsFragment>> siblingMergeGroups;
4528
4529 @override
4530 void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
4531 mergeUpFragments.addAll(fragments);
4532 }
4533
4534 @override
4535 final List<_InterestingSemanticsFragment> mergeUpFragments = <_InterestingSemanticsFragment>[];
4536}
4537
4538/// A [_SemanticsFragment] that describes which concrete semantic information
4539/// a [RenderObject] wants to add to the [SemanticsNode] of its parent.
4540///
4541/// Specifically, it describes which children (as returned by [compileChildren])
4542/// should be added to the parent's [SemanticsNode] and which [config] should be
4543/// merged into the parent's [SemanticsNode].
4544abstract class _InterestingSemanticsFragment extends _SemanticsFragment {
4545 _InterestingSemanticsFragment({
4546 required RenderObject owner,
4547 required super.dropsSemanticsOfPreviousSiblings,
4548 }) : _ancestorChain = <RenderObject>[owner];
4549
4550 /// The [RenderObject] that owns this fragment (and any new [SemanticsNode]
4551 /// introduced by it).
4552 RenderObject get owner => _ancestorChain.first;
4553
4554 final List<RenderObject> _ancestorChain;
4555
4556 /// The children to be added to the parent.
4557 ///
4558 /// See also:
4559 ///
4560 /// * [SemanticsNode.parentSemanticsClipRect] for the source and definition
4561 /// of the `parentSemanticsClipRect` argument.
4562 /// * [SemanticsNode.parentPaintClipRect] for the source and definition
4563 /// of the `parentPaintClipRect` argument.
4564 /// * [SemanticsNode.elevationAdjustment] for the source and definition
4565 /// of the `elevationAdjustment` argument.
4566 void compileChildren({
4567 required Rect? parentSemanticsClipRect,
4568 required Rect? parentPaintClipRect,
4569 required double elevationAdjustment,
4570 required List<SemanticsNode> result,
4571 required List<SemanticsNode> siblingNodes,
4572 });
4573
4574 /// The [SemanticsConfiguration] the child wants to merge into the parent's
4575 /// [SemanticsNode] or null if it doesn't want to merge anything.
4576 SemanticsConfiguration? get config;
4577
4578 /// Disallows this fragment to merge any configuration into its parent's
4579 /// [SemanticsNode].
4580 ///
4581 /// After calling this, the fragment will only produce children to be added
4582 /// to the parent and it will return null for [config].
4583 void markAsExplicit();
4584
4585 /// Consume the fragments of children.
4586 ///
4587 /// For each provided fragment it will add that fragment's children to
4588 /// this fragment's children (as returned by [compileChildren]) and merge that
4589 /// fragment's [config] into this fragment's [config].
4590 ///
4591 /// If a provided fragment should not merge anything into [config] call
4592 /// [markAsExplicit] before passing the fragment to this method.
4593 @override
4594 void addAll(Iterable<_InterestingSemanticsFragment> fragments);
4595
4596 /// Whether this fragment wants to add any semantic information to the parent
4597 /// [SemanticsNode].
4598 bool get hasConfigForParent => config != null;
4599
4600 @override
4601 List<_InterestingSemanticsFragment> get mergeUpFragments => <_InterestingSemanticsFragment>[this];
4602
4603 Set<SemanticsTag>? _tagsForChildren;
4604
4605 /// Tag all children produced by [compileChildren] with `tags`.
4606 ///
4607 /// `tags` must not be empty.
4608 void addTags(Iterable<SemanticsTag> tags) {
4609 assert(tags.isNotEmpty);
4610 _tagsForChildren ??= <SemanticsTag>{};
4611 _tagsForChildren!.addAll(tags);
4612 }
4613
4614 /// Adds the geometric information of `ancestor` to this object.
4615 ///
4616 /// Those information are required to properly compute the value for
4617 /// [SemanticsNode.transform], [SemanticsNode.clipRect], and
4618 /// [SemanticsNode.rect].
4619 ///
4620 /// Ancestors have to be added in order from [owner] up until the next
4621 /// [RenderObject] that owns a [SemanticsNode] is reached.
4622 void addAncestor(RenderObject ancestor) {
4623 _ancestorChain.add(ancestor);
4624 }
4625}
4626
4627/// An [_InterestingSemanticsFragment] that produces the root [SemanticsNode] of
4628/// the semantics tree.
4629///
4630/// The root node is available as the only element in the Iterable returned by
4631/// [children].
4632class _RootSemanticsFragment extends _InterestingSemanticsFragment {
4633 _RootSemanticsFragment({
4634 required super.owner,
4635 required super.dropsSemanticsOfPreviousSiblings,
4636 });
4637
4638 @override
4639 void compileChildren({
4640 Rect? parentSemanticsClipRect,
4641 Rect? parentPaintClipRect,
4642 required double elevationAdjustment,
4643 required List<SemanticsNode> result,
4644 required List<SemanticsNode> siblingNodes,
4645 }) {
4646 assert(_tagsForChildren == null || _tagsForChildren!.isEmpty);
4647 assert(parentSemanticsClipRect == null);
4648 assert(parentPaintClipRect == null);
4649 assert(_ancestorChain.length == 1);
4650 assert(elevationAdjustment == 0.0);
4651
4652 owner._semantics ??= SemanticsNode.root(
4653 showOnScreen: owner.showOnScreen,
4654 owner: owner.owner!.semanticsOwner!,
4655 );
4656 final SemanticsNode node = owner._semantics!;
4657 assert(MatrixUtils.matrixEquals(node.transform, Matrix4.identity()));
4658 assert(node.parentSemanticsClipRect == null);
4659 assert(node.parentPaintClipRect == null);
4660
4661 node.rect = owner.semanticBounds;
4662
4663 final List<SemanticsNode> children = <SemanticsNode>[];
4664 for (final _InterestingSemanticsFragment fragment in _children) {
4665 assert(fragment.config == null);
4666 fragment.compileChildren(
4667 parentSemanticsClipRect: parentSemanticsClipRect,
4668 parentPaintClipRect: parentPaintClipRect,
4669 elevationAdjustment: 0.0,
4670 result: children,
4671 siblingNodes: siblingNodes,
4672 );
4673 }
4674 // Root node does not have a parent and thus can't attach sibling nodes.
4675 assert(siblingNodes.isEmpty);
4676 node.updateWith(config: null, childrenInInversePaintOrder: children);
4677
4678 // The root node is the only semantics node allowed to be invisible. This
4679 // can happen when the canvas the app is drawn on has a size of 0 by 0
4680 // pixel. If this happens, the root node must not have any children (because
4681 // these would be invisible as well and are therefore excluded from the
4682 // tree).
4683 assert(!node.isInvisible || children.isEmpty);
4684 result.add(node);
4685 }
4686
4687 @override
4688 SemanticsConfiguration? get config => null;
4689
4690 final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[];
4691
4692 @override
4693 void markAsExplicit() {
4694 // nothing to do, we are always explicit.
4695 }
4696
4697 @override
4698 void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
4699 _children.addAll(fragments);
4700 }
4701}
4702
4703/// A fragment with partial information that must not form an explicit
4704/// semantics node without merging into another _SwitchableSemanticsFragment.
4705///
4706/// This fragment is generated from synthetic SemanticsConfiguration returned from
4707/// [SemanticsConfiguration.childConfigurationsDelegate].
4708class _IncompleteSemanticsFragment extends _InterestingSemanticsFragment {
4709 _IncompleteSemanticsFragment({
4710 required this.config,
4711 required super.owner,
4712 }) : super(dropsSemanticsOfPreviousSiblings: false);
4713
4714 @override
4715 void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
4716 assert(false, 'This fragment must be a leaf node');
4717 }
4718
4719 @override
4720 void compileChildren({
4721 required Rect? parentSemanticsClipRect,
4722 required Rect? parentPaintClipRect,
4723 required double elevationAdjustment,
4724 required List<SemanticsNode> result,
4725 required List<SemanticsNode> siblingNodes,
4726 }) {
4727 // There is nothing to do because this fragment must be a leaf node and
4728 // must not be explicit.
4729 }
4730
4731 @override
4732 final SemanticsConfiguration config;
4733
4734 @override
4735 void markAsExplicit() {
4736 assert(
4737 false,
4738 'SemanticsConfiguration created in '
4739 'SemanticsConfiguration.childConfigurationsDelegate must not produce '
4740 'its own semantics node'
4741 );
4742 }
4743}
4744
4745/// An [_InterestingSemanticsFragment] that can be told to only add explicit
4746/// [SemanticsNode]s to the parent.
4747///
4748/// If [markAsExplicit] was not called before this fragment is added to
4749/// another fragment it will merge [config] into the parent's [SemanticsNode]
4750/// and add its [children] to it.
4751///
4752/// If [markAsExplicit] was called before adding this fragment to another
4753/// fragment it will create a new [SemanticsNode]. The newly created node will
4754/// be annotated with the [SemanticsConfiguration] that - without the call to
4755/// [markAsExplicit] - would have been merged into the parent's [SemanticsNode].
4756/// Similarly, the new node will also take over the children that otherwise
4757/// would have been added to the parent's [SemanticsNode].
4758///
4759/// After a call to [markAsExplicit] the only element returned by [children]
4760/// is the newly created node and [config] will return null as the fragment
4761/// no longer wants to merge any semantic information into the parent's
4762/// [SemanticsNode].
4763class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
4764 _SwitchableSemanticsFragment({
4765 required bool mergeIntoParent,
4766 required bool blockUserActions,
4767 required SemanticsConfiguration config,
4768 required List<List<_InterestingSemanticsFragment>> siblingMergeGroups,
4769 required super.owner,
4770 required super.dropsSemanticsOfPreviousSiblings,
4771 }) : _siblingMergeGroups = siblingMergeGroups,
4772 _mergeIntoParent = mergeIntoParent,
4773 _config = config {
4774 if (blockUserActions && !_config.isBlockingUserActions) {
4775 _ensureConfigIsWritable();
4776 _config.isBlockingUserActions = true;
4777 }
4778 }
4779
4780 final bool _mergeIntoParent;
4781 SemanticsConfiguration _config;
4782 bool _isConfigWritable = false;
4783 bool _mergesToSibling = false;
4784
4785 final List<List<_InterestingSemanticsFragment>> _siblingMergeGroups;
4786
4787 void _mergeSiblingGroup(Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, List<SemanticsNode> result, Set<int> usedSemanticsIds) {
4788 for (final List<_InterestingSemanticsFragment> group in _siblingMergeGroups) {
4789 Rect? rect;
4790 Rect? semanticsClipRect;
4791 Rect? paintClipRect;
4792 SemanticsConfiguration? configuration;
4793 // Use empty set because the _tagsForChildren may not contains all of the
4794 // tags if this fragment is not explicit. The _tagsForChildren are added
4795 // to sibling nodes at the end of compileChildren if this fragment is
4796 // explicit.
4797 final Set<SemanticsTag> tags = <SemanticsTag>{};
4798 SemanticsNode? node;
4799 for (final _InterestingSemanticsFragment fragment in group) {
4800 if (fragment.config != null) {
4801 final _SwitchableSemanticsFragment switchableFragment = fragment as _SwitchableSemanticsFragment;
4802 switchableFragment._mergesToSibling = true;
4803 node ??= fragment.owner._semantics;
4804 configuration ??= SemanticsConfiguration();
4805 configuration.absorb(switchableFragment.config!);
4806 // It is a child fragment of a _SwitchableFragment, it must have a
4807 // geometry.
4808 final _SemanticsGeometry geometry = switchableFragment._computeSemanticsGeometry(
4809 parentSemanticsClipRect: parentSemanticsClipRect,
4810 parentPaintClipRect: parentPaintClipRect,
4811 )!;
4812 final Rect fragmentRect = MatrixUtils.transformRect(geometry.transform, geometry.rect);
4813 rect = rect?.expandToInclude(fragmentRect) ?? fragmentRect;
4814 if (geometry.semanticsClipRect != null) {
4815 final Rect rect = MatrixUtils.transformRect(geometry.transform, geometry.semanticsClipRect!);
4816 semanticsClipRect = semanticsClipRect?.intersect(rect) ?? rect;
4817 }
4818 if (geometry.paintClipRect != null) {
4819 final Rect rect = MatrixUtils.transformRect(geometry.transform, geometry.paintClipRect!);
4820 paintClipRect = paintClipRect?.intersect(rect) ?? rect;
4821 }
4822 if (switchableFragment._tagsForChildren != null) {
4823 tags.addAll(switchableFragment._tagsForChildren!);
4824 }
4825 }
4826 }
4827 // Can be null if all fragments in group are marked as explicit.
4828 if (configuration != null && !rect!.isEmpty) {
4829 if (node == null || usedSemanticsIds.contains(node.id)) {
4830 node = SemanticsNode(showOnScreen: owner.showOnScreen);
4831 }
4832 usedSemanticsIds.add(node.id);
4833 node
4834 ..tags = tags
4835 ..rect = rect
4836 ..transform = null // Will be set when compiling immediate parent node.
4837 ..parentSemanticsClipRect = semanticsClipRect
4838 ..parentPaintClipRect = paintClipRect;
4839 for (final _InterestingSemanticsFragment fragment in group) {
4840 if (fragment.config != null) {
4841 fragment.owner._semantics = node;
4842 }
4843 }
4844 node.updateWith(config: configuration);
4845 result.add(node);
4846 }
4847 }
4848 }
4849
4850 final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[];
4851
4852 @override
4853 void compileChildren({
4854 Rect? parentSemanticsClipRect,
4855 Rect? parentPaintClipRect,
4856 required double elevationAdjustment,
4857 required List<SemanticsNode> result,
4858 required List<SemanticsNode> siblingNodes,
4859 }) {
4860 final Set<int> usedSemanticsIds = <int>{};
4861 Iterable<_InterestingSemanticsFragment> compilingFragments = _children;
4862 for (final List<_InterestingSemanticsFragment> siblingGroup in _siblingMergeGroups) {
4863 compilingFragments = compilingFragments.followedBy(siblingGroup);
4864 }
4865 if (!_isExplicit) {
4866 if (!_mergesToSibling) {
4867 owner._semantics = null;
4868 }
4869 _mergeSiblingGroup(
4870 parentSemanticsClipRect,
4871 parentPaintClipRect,
4872 siblingNodes,
4873 usedSemanticsIds,
4874 );
4875 for (final _InterestingSemanticsFragment fragment in compilingFragments) {
4876 assert(_ancestorChain.first == fragment._ancestorChain.last);
4877 if (fragment is _SwitchableSemanticsFragment) {
4878 // Cached semantics node may be part of sibling merging group prior
4879 // to this update. In this case, the semantics node may continue to
4880 // be reused in that sibling merging group.
4881 if (fragment._isExplicit &&
4882 fragment.owner._semantics != null &&
4883 usedSemanticsIds.contains(fragment.owner._semantics!.id)) {
4884 fragment.owner._semantics = null;
4885 }
4886 }
4887 fragment._ancestorChain.addAll(_ancestorChain.skip(1));
4888 fragment.compileChildren(
4889 parentSemanticsClipRect: parentSemanticsClipRect,
4890 parentPaintClipRect: parentPaintClipRect,
4891 // The fragment is not explicit, its elevation has been absorbed by
4892 // the parent config (as thickness). We still need to make sure that
4893 // its children are placed at the elevation dictated by this config.
4894 elevationAdjustment: elevationAdjustment + _config.elevation,
4895 result: result,
4896 siblingNodes: siblingNodes,
4897 );
4898 }
4899 return;
4900 }
4901
4902 final _SemanticsGeometry? geometry = _computeSemanticsGeometry(
4903 parentSemanticsClipRect: parentSemanticsClipRect,
4904 parentPaintClipRect: parentPaintClipRect,
4905 );
4906
4907 if (!_mergeIntoParent && (geometry?.dropFromTree ?? false)) {
4908 return; // Drop the node, it's not going to be visible.
4909 }
4910
4911 final SemanticsNode node = (owner._semantics ??= SemanticsNode(showOnScreen: owner.showOnScreen))
4912 ..tags = _tagsForChildren;
4913
4914 node.elevationAdjustment = elevationAdjustment;
4915 if (elevationAdjustment != 0.0) {
4916 _ensureConfigIsWritable();
4917 _config.elevation += elevationAdjustment;
4918 }
4919
4920 if (geometry != null) {
4921 assert(_needsGeometryUpdate);
4922 node
4923 ..rect = geometry.rect
4924 ..transform = geometry.transform
4925 ..parentSemanticsClipRect = geometry.semanticsClipRect
4926 ..parentPaintClipRect = geometry.paintClipRect;
4927 if (!_mergeIntoParent && geometry.markAsHidden) {
4928 _ensureConfigIsWritable();
4929 _config.isHidden = true;
4930 }
4931 }
4932 final List<SemanticsNode> children = <SemanticsNode>[];
4933 _mergeSiblingGroup(
4934 node.parentSemanticsClipRect,
4935 node.parentPaintClipRect,
4936 siblingNodes,
4937 usedSemanticsIds,
4938 );
4939 for (final _InterestingSemanticsFragment fragment in compilingFragments) {
4940 if (fragment is _SwitchableSemanticsFragment) {
4941 // Cached semantics node may be part of sibling merging group prior
4942 // to this update. In this case, the semantics node may continue to
4943 // be reused in that sibling merging group.
4944 if (fragment._isExplicit &&
4945 fragment.owner._semantics != null &&
4946 usedSemanticsIds.contains(fragment.owner._semantics!.id)) {
4947 fragment.owner._semantics = null;
4948 }
4949 }
4950 final List<SemanticsNode> childSiblingNodes = <SemanticsNode>[];
4951 fragment.compileChildren(
4952 parentSemanticsClipRect: node.parentSemanticsClipRect,
4953 parentPaintClipRect: node.parentPaintClipRect,
4954 elevationAdjustment: 0.0,
4955 result: children,
4956 siblingNodes: childSiblingNodes,
4957 );
4958 siblingNodes.addAll(childSiblingNodes);
4959 }
4960
4961 if (_config.isSemanticBoundary) {
4962 owner.assembleSemanticsNode(node, _config, children);
4963 } else {
4964 node.updateWith(config: _config, childrenInInversePaintOrder: children);
4965 }
4966 result.add(node);
4967 // Sibling node needs to attach to the parent of an explicit node.
4968 for (final SemanticsNode siblingNode in siblingNodes) {
4969 // sibling nodes are in the same coordinate of the immediate explicit node.
4970 // They need to share the same transform if they are going to attach to the
4971 // parent of the immediate explicit node.
4972 assert(siblingNode.transform == null);
4973 siblingNode.transform = node.transform;
4974 if (_tagsForChildren != null) {
4975 siblingNode.tags ??= <SemanticsTag>{};
4976 siblingNode.tags!.addAll(_tagsForChildren!);
4977 }
4978 }
4979 result.addAll(siblingNodes);
4980 siblingNodes.clear();
4981 }
4982
4983 _SemanticsGeometry? _computeSemanticsGeometry({
4984 required Rect? parentSemanticsClipRect,
4985 required Rect? parentPaintClipRect,
4986 }) {
4987 return _needsGeometryUpdate
4988 ? _SemanticsGeometry(parentSemanticsClipRect: parentSemanticsClipRect, parentPaintClipRect: parentPaintClipRect, ancestors: _ancestorChain)
4989 : null;
4990 }
4991
4992 @override
4993 SemanticsConfiguration? get config {
4994 return _isExplicit ? null : _config;
4995 }
4996
4997 @override
4998 void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
4999 for (final _InterestingSemanticsFragment fragment in fragments) {
5000 _children.add(fragment);
5001 if (fragment.config == null) {
5002 continue;
5003 }
5004 _ensureConfigIsWritable();
5005 _config.absorb(fragment.config!);
5006 }
5007 }
5008
5009 @override
5010 void addTags(Iterable<SemanticsTag> tags) {
5011 super.addTags(tags);
5012 // _ContainerSemanticsFragments add their tags to child fragments through
5013 // this method. This fragment must make sure its _config is in sync.
5014 if (tags.isNotEmpty) {
5015 _ensureConfigIsWritable();
5016 tags.forEach(_config.addTagForChildren);
5017 }
5018 }
5019
5020 void _ensureConfigIsWritable() {
5021 if (!_isConfigWritable) {
5022 _config = _config.copy();
5023 _isConfigWritable = true;
5024 }
5025 }
5026
5027 bool _isExplicit = false;
5028
5029 @override
5030 void markAsExplicit() {
5031 _isExplicit = true;
5032 }
5033
5034 bool get _needsGeometryUpdate => _ancestorChain.length > 1;
5035}
5036
5037/// Helper class that keeps track of the geometry of a [SemanticsNode].
5038///
5039/// It is used to annotate a [SemanticsNode] with the current information for
5040/// [SemanticsNode.rect] and [SemanticsNode.transform].
5041class _SemanticsGeometry {
5042
5043 /// The `parentClippingRect` may be null if no clip is to be applied.
5044 ///
5045 /// The `ancestors` list has to include all [RenderObject] in order that are
5046 /// located between the [SemanticsNode] whose geometry is represented here
5047 /// (first [RenderObject] in the list) and its closest ancestor [RenderObject]
5048 /// that also owns its own [SemanticsNode] (last [RenderObject] in the list).
5049 _SemanticsGeometry({
5050 required Rect? parentSemanticsClipRect,
5051 required Rect? parentPaintClipRect,
5052 required List<RenderObject> ancestors,
5053 }) {
5054 _computeValues(parentSemanticsClipRect, parentPaintClipRect, ancestors);
5055 }
5056
5057 Rect? _paintClipRect;
5058 Rect? _semanticsClipRect;
5059 late Matrix4 _transform;
5060 late Rect _rect;
5061
5062 /// Value for [SemanticsNode.transform].
5063 Matrix4 get transform => _transform;
5064
5065 /// Value for [SemanticsNode.parentSemanticsClipRect].
5066 Rect? get semanticsClipRect => _semanticsClipRect;
5067
5068 /// Value for [SemanticsNode.parentPaintClipRect].
5069 Rect? get paintClipRect => _paintClipRect;
5070
5071 /// Value for [SemanticsNode.rect].
5072 Rect get rect => _rect;
5073
5074 /// Computes values, ensuring `rect` is properly bounded by ancestor clipping rects.
5075 ///
5076 /// See also:
5077 ///
5078 /// * [RenderObject.describeSemanticsClip], typically used to determine `parentSemanticsClipRect`.
5079 /// * [RenderObject.describeApproximatePaintClip], typically used to determine `parentPaintClipRect`.
5080 void _computeValues(Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, List<RenderObject> ancestors) {
5081 assert(ancestors.length > 1);
5082
5083 _transform = Matrix4.identity();
5084 _semanticsClipRect = parentSemanticsClipRect;
5085 _paintClipRect = parentPaintClipRect;
5086
5087 for (int index = ancestors.length-1; index > 0; index -= 1) {
5088 final RenderObject semanticsParent = ancestors[index];
5089 final RenderObject semanticsChild = ancestors[index-1];
5090 _applyIntermediatePaintTransforms(semanticsParent, semanticsChild, _transform);
5091
5092 if (identical(semanticsParent, semanticsChild.parent)) {
5093 // The easier and more common case: semanticsParent is directly
5094 // responsible for painting (and potentially clipping) the semanticsChild
5095 // RenderObject.
5096 _computeClipRect(semanticsParent, semanticsChild, _semanticsClipRect, _paintClipRect);
5097 } else {
5098 // Otherwise we have to find the closest ancestor RenderObject that
5099 // has up-to-date semantics geometry and compute the clip rects from there.
5100 //
5101 // Currently it can only happen when the subtree contains an OverlayPortal.
5102 final List<RenderObject> clipPath = <RenderObject>[semanticsChild];
5103
5104 RenderObject? ancestor = semanticsChild.parent;
5105 while (ancestor != null && ancestor._semantics == null) {
5106 clipPath.add(ancestor);
5107 ancestor = ancestor.parent;
5108 }
5109 _paintClipRect = ancestor?._semantics?.parentPaintClipRect;
5110 _semanticsClipRect = ancestor?._semantics?.parentSemanticsClipRect;
5111 if (ancestor != null) {
5112 assert(ancestor._semantics != null);
5113 assert(!ancestor._needsSemanticsUpdate);
5114 RenderObject parent = ancestor;
5115 for (int i = clipPath.length - 1; i >= 0; i -= 1) {
5116 _computeClipRect(parent, clipPath[i], _semanticsClipRect, _paintClipRect);
5117 parent = clipPath[i];
5118 }
5119 }
5120 }
5121 }
5122
5123 final RenderObject owner = ancestors.first;
5124 _rect = _semanticsClipRect?.intersect(owner.semanticBounds) ?? owner.semanticBounds;
5125 if (_paintClipRect != null) {
5126 final Rect paintRect = _paintClipRect!.intersect(_rect);
5127 _markAsHidden = paintRect.isEmpty && !_rect.isEmpty;
5128 if (!_markAsHidden) {
5129 _rect = paintRect;
5130 }
5131 }
5132 }
5133
5134 /// From parent to child coordinate system.
5135 static Rect? _transformRect(Rect? rect, Matrix4 transform) {
5136 if (rect == null) {
5137 return null;
5138 }
5139 if (rect.isEmpty || transform.isZero()) {
5140 return Rect.zero;
5141 }
5142 return MatrixUtils.inverseTransformRect(transform, rect);
5143 }
5144
5145 // Computes the paint transform from `childFragmentOwner` to
5146 // `parentFragmentOwner` and applies the paint transform to `transform` in
5147 // place.
5148 //
5149 // The `parentFragmentOwner` and `childFragmentOwner` [RenderObject]s must be
5150 // in the same render tree (so they have a common ancestor).
5151 static void _applyIntermediatePaintTransforms(
5152 RenderObject parentFragmentOwner,
5153 RenderObject childFragmentOwner,
5154 Matrix4 transform,
5155 ) {
5156 Matrix4? parentToCommonAncestorTransform;
5157 RenderObject from = childFragmentOwner;
5158 RenderObject to = parentFragmentOwner;
5159
5160 while (!identical(from, to)) {
5161 final int fromDepth = from.depth;
5162 final int toDepth = to.depth;
5163
5164 if (fromDepth >= toDepth) {
5165 assert(from.parent != null, '$parentFragmentOwner and $childFragmentOwner are not in the same render tree.');
5166 final RenderObject fromParent = from.parent!;
5167 fromParent.applyPaintTransform(from, transform);
5168 from = fromParent;
5169 }
5170 if (fromDepth <= toDepth) {
5171 assert(to.parent != null, '$parentFragmentOwner and $childFragmentOwner are not in the same render tree.');
5172 final RenderObject toParent = to.parent!;
5173 toParent.applyPaintTransform(to, parentToCommonAncestorTransform ??= Matrix4.identity());
5174 to = toParent;
5175 }
5176 }
5177
5178 if (parentToCommonAncestorTransform != null) {
5179 if (parentToCommonAncestorTransform.invert() != 0) {
5180 transform.multiply(parentToCommonAncestorTransform);
5181 } else {
5182 transform.setZero();
5183 }
5184 }
5185 }
5186
5187 // A matrix used to store transient transform data.
5188 //
5189 // Reusing this matrix avoids allocating a new matrix every time a temporary
5190 // matrix is needed.
5191 //
5192 // This instance should never be returned to the caller. Otherwise, the data
5193 // stored in it will be overwritten unpredictably by subsequent reuses.
5194 static final Matrix4 _temporaryTransformHolder = Matrix4.zero();
5195
5196 // Computes the semantics and painting clip rects for the given child and
5197 // assigns the rects to _semanticsClipRect and _paintClipRect respectively.
5198 //
5199 // The caller must guarantee that child.parent == parent. The resulting rects
5200 // are in `child`'s coordinate system.
5201 void _computeClipRect(RenderObject parent, RenderObject child, Rect? parentSemanticsClipRect, Rect? parentPaintClipRect) {
5202 assert(identical(child.parent, parent));
5203 // Computes the paint transform from child to parent. The _transformRect
5204 // method will compute the inverse.
5205 _temporaryTransformHolder.setIdentity(); // clears data from previous call(s)
5206 parent.applyPaintTransform(child, _temporaryTransformHolder);
5207
5208 final Rect? additionalPaintClip = parent.describeApproximatePaintClip(child);
5209 _paintClipRect = _transformRect(
5210 _intersectRects(additionalPaintClip, parentPaintClipRect),
5211 _temporaryTransformHolder,
5212 );
5213
5214 if (_paintClipRect == null) {
5215 _semanticsClipRect = null;
5216 } else {
5217 final Rect? semanticsClip = parent.describeSemanticsClip(child) ?? _intersectRects(parentSemanticsClipRect, additionalPaintClip);
5218 _semanticsClipRect = _transformRect(semanticsClip, _temporaryTransformHolder);
5219 }
5220 }
5221
5222 static Rect? _intersectRects(Rect? a, Rect? b) {
5223 if (b == null) {
5224 return a;
5225 }
5226 return a?.intersect(b) ?? b;
5227 }
5228
5229 /// Whether the [SemanticsNode] annotated with the geometric information tracked
5230 /// by this object can be dropped from the semantics tree without losing
5231 /// semantics information.
5232 bool get dropFromTree {
5233 return _rect.isEmpty || _transform.isZero();
5234 }
5235
5236 /// Whether the [SemanticsNode] annotated with the geometric information
5237 /// tracked by this object should be marked as hidden because it is not
5238 /// visible on screen.
5239 ///
5240 /// Hidden elements should still be included in the tree to work around
5241 /// platform limitations (e.g. accessibility scrolling on iOS).
5242 ///
5243 /// See also:
5244 ///
5245 /// * [SemanticsFlag.isHidden] for the purpose of marking a node as hidden.
5246 bool get markAsHidden => _markAsHidden;
5247 bool _markAsHidden = false;
5248}
5249
5250/// A class that creates [DiagnosticsNode] by wrapping [RenderObject.debugCreator].
5251///
5252/// Attach a [DiagnosticsDebugCreator] into [FlutterErrorDetails.informationCollector]
5253/// when a [RenderObject.debugCreator] is available. This will lead to improved
5254/// error message.
5255class DiagnosticsDebugCreator extends DiagnosticsProperty<Object> {
5256 /// Create a [DiagnosticsProperty] with its [value] initialized to input
5257 /// [RenderObject.debugCreator].
5258 DiagnosticsDebugCreator(Object value)
5259 : super(
5260 'debugCreator',
5261 value,
5262 level: DiagnosticLevel.hidden,
5263 );
5264}
5265