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