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

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com