object.dart 153 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:developer';
6
import 'dart:ui' as ui show PictureRecorder;
7

8
import 'package:flutter/animation.dart';
9
import 'package:flutter/foundation.dart';
10
import 'package:flutter/gestures.dart';
Hixie's avatar
Hixie committed
11
import 'package:flutter/painting.dart';
12
import 'package:flutter/semantics.dart';
13
import 'package:vector_math/vector_math_64.dart';
14

15
import 'binding.dart';
16 17 18
import 'debug.dart';
import 'layer.dart';

19
export 'package:flutter/foundation.dart' show FlutterError, InformationCollector, DiagnosticsNode, ErrorSummary, ErrorDescription, ErrorHint, DiagnosticsProperty, StringProperty, DoubleProperty, EnumProperty, FlagProperty, IntProperty, DiagnosticPropertiesBuilder;
Ian Hickson's avatar
Ian Hickson committed
20
export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
21
export 'package:flutter/painting.dart';
22

23
/// Base class for data associated with a [RenderObject] by its parent.
24
///
25 26 27 28 29 30 31 32
/// Some render objects wish to store data on their children, such as the
/// children's input parameters to the parent's layout algorithm or the
/// children's position relative to other children.
///
/// See also:
///
///  * [RenderObject.setupParentData], which [RenderObject] subclasses may
///    override to attach specific types of parent data to children.
33
class ParentData {
34
  /// Called when the RenderObject is removed from the tree.
35
  @protected
36
  @mustCallSuper
37
  void detach() { }
38

39
  @override
40 41 42
  String toString() => '<none>';
}

43 44 45 46
/// Signature for painting into a [PaintingContext].
///
/// The `offset` argument is the offset from the origin of the coordinate system
/// of the [PaintingContext.canvas] to the coordinate system of the callee.
47 48
///
/// Used by many of the methods of [PaintingContext].
49
typedef PaintingContextCallback = void Function(PaintingContext context, Offset offset);
Adam Barth's avatar
Adam Barth committed
50 51

/// A place to paint.
52
///
53 54
/// Rather than holding a canvas directly, [RenderObject]s paint using a painting
/// context. The painting context has a [Canvas], which receives the
55 56 57 58 59 60 61 62
/// individual draw operations, and also has functions for painting child
/// render objects.
///
/// When painting a child render object, the canvas held by the painting context
/// can change because the draw operations issued before and after painting the
/// child might be recorded in separate compositing layers. For this reason, do
/// not hold a reference to the canvas across operations that might paint
/// child render objects.
63 64 65
///
/// New [PaintingContext] objects are created automatically when using
/// [PaintingContext.repaintCompositedChild] and [pushLayer].
66
class PaintingContext extends ClipContext {
67 68 69 70 71 72 73

  /// Creates a painting context.
  ///
  /// Typically only called by [PaintingContext.repaintCompositedChild]
  /// and [pushLayer].
  @protected
  PaintingContext(this._containerLayer, this.estimatedBounds)
74
    : assert(_containerLayer != null),
75
      assert(estimatedBounds != null);
Adam Barth's avatar
Adam Barth committed
76 77

  final ContainerLayer _containerLayer;
78

79
  /// An estimate of the bounds within which the painting context's [canvas]
80
  /// will record painting commands. This can be useful for debugging.
81
  ///
82
  /// The canvas will allow painting outside these bounds.
83
  ///
84 85
  /// The [estimatedBounds] rectangle is in the [canvas] coordinate system.
  final Rect estimatedBounds;
Adam Barth's avatar
Adam Barth committed
86 87 88

  /// Repaint the given render object.
  ///
89 90 91 92
  /// The render object must be attached to a [PipelineOwner], must have a
  /// composited layer, and must be in need of painting. The render object's
  /// layer, if any, is re-used, along with any layers in the subtree that don't
  /// need to be repainted.
93 94 95 96 97
  ///
  /// See also:
  ///
  ///  * [RenderObject.isRepaintBoundary], which determines if a [RenderObject]
  ///    has a composited layer.
98
  static void repaintCompositedChild(RenderObject child, { bool debugAlsoPaintedParent = false }) {
99
    assert(child._needsPaint);
100 101 102 103 104 105 106 107 108
    _repaintCompositedChild(
      child,
      debugAlsoPaintedParent: debugAlsoPaintedParent,
    );
  }

  static void _repaintCompositedChild(
    RenderObject child, {
    bool debugAlsoPaintedParent = false,
109
    PaintingContext? childContext,
110 111
  }) {
    assert(child.isRepaintBoundary);
112
    assert(() {
113 114 115 116 117
      // register the call for RepaintBoundary metrics
      child.debugRegisterRepaintBoundaryPaint(
        includedParent: debugAlsoPaintedParent,
        includedChild: true,
      );
118
      return true;
119
    }());
120
    OffsetLayer? childLayer = child._layer as OffsetLayer?;
121
    if (childLayer == null) {
122
      assert(debugAlsoPaintedParent);
123 124 125 126 127
      // Not using the `layer` setter because the setter asserts that we not
      // replace the layer for repaint boundaries. That assertion does not
      // apply here because this is exactly the place designed to create a
      // layer for repaint boundaries.
      child._layer = childLayer = OffsetLayer();
128
    } else {
129 130 131
      assert(childLayer is OffsetLayer);
      assert(debugAlsoPaintedParent || childLayer.attached);
      childLayer.removeAllChildren();
132
    }
133 134
    assert(identical(childLayer, child._layer));
    assert(child._layer is OffsetLayer);
135
    assert(() {
136
      child._layer!.debugCreator = child.debugCreator ?? child.runtimeType;
137
      return true;
138
    }());
139
    childContext ??= PaintingContext(child._layer!, child.paintBounds);
Adam Barth's avatar
Adam Barth committed
140
    child._paintWithContext(childContext, Offset.zero);
141 142 143 144

    // Double-check that the paint method did not replace the layer (the first
    // check is done in the [layer] setter itself).
    assert(identical(childLayer, child._layer));
145 146 147 148 149 150 151 152 153 154 155 156 157 158
    childContext.stopRecordingIfNeeded();
  }

  /// In debug mode, repaint the given render object using a custom painting
  /// context that can record the results of the painting operation in addition
  /// to performing the regular paint of the child.
  ///
  /// See also:
  ///
  ///  * [repaintCompositedChild], for repainting a composited child without
  ///    instrumentation.
  static void debugInstrumentRepaintCompositedChild(
    RenderObject child, {
    bool debugAlsoPaintedParent = false,
159
    required PaintingContext customContext,
160 161 162 163 164 165 166 167 168
  }) {
    assert(() {
      _repaintCompositedChild(
        child,
        debugAlsoPaintedParent: debugAlsoPaintedParent,
        childContext: customContext,
      );
      return true;
    }());
Adam Barth's avatar
Adam Barth committed
169 170
  }

171
  /// Paint a child [RenderObject].
Adam Barth's avatar
Adam Barth committed
172 173 174 175 176
  ///
  /// If the child has its own composited layer, the child will be composited
  /// into the layer subtree associated with this painting context. Otherwise,
  /// the child will be painted into the current PictureLayer for this context.
  void paintChild(RenderObject child, Offset offset) {
177 178
    assert(() {
      if (debugProfilePaintsEnabled)
179
        Timeline.startSync('${child.runtimeType}', arguments: timelineArgumentsIndicatingLandmarkEvent);
180
      if (debugOnProfilePaint != null)
181
        debugOnProfilePaint!(child);
182
      return true;
183
    }());
184

185
    if (child.isRepaintBoundary) {
186
      stopRecordingIfNeeded();
Adam Barth's avatar
Adam Barth committed
187 188 189 190
      _compositeChild(child, offset);
    } else {
      child._paintWithContext(this, offset);
    }
191 192 193 194 195

    assert(() {
      if (debugProfilePaintsEnabled)
        Timeline.finishSync();
      return true;
196
    }());
197 198
  }

Adam Barth's avatar
Adam Barth committed
199 200
  void _compositeChild(RenderObject child, Offset offset) {
    assert(!_isRecording);
201
    assert(child.isRepaintBoundary);
202
    assert(_canvas == null || _canvas!.getSaveCount() == 1);
Adam Barth's avatar
Adam Barth committed
203 204

    // Create a layer for our child, and paint the child into it.
205
    if (child._needsPaint) {
206
      repaintCompositedChild(child, debugAlsoPaintedParent: true);
Adam Barth's avatar
Adam Barth committed
207
    } else {
208
      assert(() {
209 210 211 212 213
        // register the call for RepaintBoundary metrics
        child.debugRegisterRepaintBoundaryPaint(
          includedParent: true,
          includedChild: false,
        );
214
        child._layer!.debugCreator = child.debugCreator ?? child;
215
        return true;
216
      }());
Adam Barth's avatar
Adam Barth committed
217
    }
218
    assert(child._layer is OffsetLayer);
219
    final OffsetLayer childOffsetLayer = child._layer! as OffsetLayer;
220
    childOffsetLayer.offset = offset;
221
    appendLayer(child._layer!);
Hixie's avatar
Hixie committed
222
  }
223

224 225 226 227 228 229 230 231 232 233 234
  /// Adds a layer to the recording requiring that the recording is already
  /// stopped.
  ///
  /// Do not call this function directly: call [addLayer] or [pushLayer]
  /// instead. This function is called internally when all layers not
  /// generated from the [canvas] are added.
  ///
  /// Subclasses that need to customize how layers are added should override
  /// this method.
  @protected
  void appendLayer(Layer layer) {
Adam Barth's avatar
Adam Barth committed
235
    assert(!_isRecording);
236
    layer.remove();
Adam Barth's avatar
Adam Barth committed
237 238
    _containerLayer.append(layer);
  }
239

Adam Barth's avatar
Adam Barth committed
240
  bool get _isRecording {
241
    final bool hasCanvas = _canvas != null;
Adam Barth's avatar
Adam Barth committed
242 243 244 245 246 247 248 249 250 251 252
    assert(() {
      if (hasCanvas) {
        assert(_currentLayer != null);
        assert(_recorder != null);
        assert(_canvas != null);
      } else {
        assert(_currentLayer == null);
        assert(_recorder == null);
        assert(_canvas == null);
      }
      return true;
253
    }());
Adam Barth's avatar
Adam Barth committed
254 255
    return hasCanvas;
  }
Hixie's avatar
Hixie committed
256

Adam Barth's avatar
Adam Barth committed
257
  // Recording state
258 259 260
  PictureLayer? _currentLayer;
  ui.PictureRecorder? _recorder;
  Canvas? _canvas;
Adam Barth's avatar
Adam Barth committed
261 262 263 264 265 266

  /// The canvas on which to paint.
  ///
  /// The current canvas can change whenever you paint a child using this
  /// context, which means it's fragile to hold a reference to the canvas
  /// returned by this getter.
267
  @override
Adam Barth's avatar
Adam Barth committed
268
  Canvas get canvas {
Adam Barth's avatar
Adam Barth committed
269 270
    if (_canvas == null)
      _startRecording();
271
    return _canvas!;
Adam Barth's avatar
Adam Barth committed
272 273 274 275
  }

  void _startRecording() {
    assert(!_isRecording);
276 277
    _currentLayer = PictureLayer(estimatedBounds);
    _recorder = ui.PictureRecorder();
278 279
    _canvas = Canvas(_recorder!);
    _containerLayer.append(_currentLayer!);
280 281
  }

282 283 284 285 286 287 288 289 290 291 292 293 294
  /// Stop recording to a canvas if recording has started.
  ///
  /// Do not call this function directly: functions in this class will call
  /// this method as needed. This function is called internally to ensure that
  /// recording is stopped before adding layers or finalizing the results of a
  /// paint.
  ///
  /// Subclasses that need to customize how recording to a canvas is performed
  /// should override this method to save the results of the custom canvas
  /// recordings.
  @protected
  @mustCallSuper
  void stopRecordingIfNeeded() {
Adam Barth's avatar
Adam Barth committed
295 296
    if (!_isRecording)
      return;
297
    assert(() {
298
      if (debugRepaintRainbowEnabled) {
299
        final Paint paint = Paint()
300 301 302
          ..style = PaintingStyle.stroke
          ..strokeWidth = 6.0
          ..color = debugCurrentRepaintColor.toColor();
303
        canvas.drawRect(estimatedBounds.deflate(3.0), paint);
304
      }
305
      if (debugPaintLayerBordersEnabled) {
306
        final Paint paint = Paint()
307
          ..style = PaintingStyle.stroke
308
          ..strokeWidth = 1.0
309
          ..color = const Color(0xFFFF9800);
310
        canvas.drawRect(estimatedBounds, paint);
311 312
      }
      return true;
313
    }());
314
    _currentLayer!.picture = _recorder!.endRecording();
Hixie's avatar
Hixie committed
315
    _currentLayer = null;
316 317 318 319
    _recorder = null;
    _canvas = null;
  }

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
  /// Hints that the painting in the current layer is complex and would benefit
  /// from caching.
  ///
  /// If this hint is not set, the compositor will apply its own heuristics to
  /// decide whether the current layer is complex enough to benefit from
  /// caching.
  void setIsComplexHint() {
    _currentLayer?.isComplexHint = true;
  }

  /// Hints that the painting in the current layer is likely to change next frame.
  ///
  /// This hint tells the compositor not to cache the current layer because the
  /// cache will not be used in the future. If this hint is not set, the
  /// compositor will apply its own heuristics to decide whether the current
  /// layer is likely to be reused in the future.
  void setWillChangeHint() {
    _currentLayer?.willChangeHint = true;
  }

340
  /// Adds a composited leaf layer to the recording.
341
  ///
342 343
  /// After calling this function, the [canvas] property will change to refer to
  /// a new [Canvas] that draws on top of the given layer.
344
  ///
345
  /// A [RenderObject] that uses this function is very likely to require its
346
  /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs
347
  /// ancestor render objects that this render object will include a composited
348 349 350 351
  /// layer, which, for example, causes them to use composited clips.
  ///
  /// See also:
  ///
352 353
  ///  * [pushLayer], for adding a layer and painting further contents within
  ///    it.
354
  void addLayer(Layer layer) {
355 356
    stopRecordingIfNeeded();
    appendLayer(layer);
Adam Barth's avatar
Adam Barth committed
357 358
  }

359
  /// Appends the given layer to the recording, and calls the `painter` callback
360
  /// with that layer, providing the `childPaintBounds` as the estimated paint
361
  /// bounds of the child. The `childPaintBounds` can be used for debugging but
362
  /// have no effect on painting.
363 364 365 366 367
  ///
  /// The given layer must be an unattached orphan. (Providing a newly created
  /// object, rather than reusing an existing layer, satisfies that
  /// requirement.)
  ///
368
  /// {@template flutter.rendering.PaintingContext.pushLayer.offset}
369 370 371 372 373
  /// The `offset` is the offset to pass to the `painter`. In particular, it is
  /// not an offset applied to the layer itself. Layers conceptually by default
  /// have no position or size, though they can transform their contents. For
  /// example, an [OffsetLayer] applies an offset to its children.
  /// {@endtemplate}
374
  ///
375
  /// If the `childPaintBounds` are not specified then the current layer's paint
376
  /// bounds are used. This is appropriate if the child layer does not apply any
377
  /// transformation or clipping to its contents. The `childPaintBounds`, if
378 379 380
  /// specified, must be in the coordinate system of the new layer (i.e. as seen
  /// by its children after it applies whatever transform to its contents), and
  /// should not go outside the current layer's paint bounds.
381 382 383
  ///
  /// See also:
  ///
384 385
  ///  * [addLayer], for pushing a layer without painting further contents
  ///    within it.
386
  void pushLayer(ContainerLayer childLayer, PaintingContextCallback painter, Offset offset, { Rect? childPaintBounds }) {
387
    assert(painter != null);
388 389 390 391 392
    // If a layer is being reused, it may already contain children. We remove
    // them so that `painter` can add children that are relevant for this frame.
    if (childLayer.hasChildren) {
      childLayer.removeAllChildren();
    }
393 394 395
    stopRecordingIfNeeded();
    appendLayer(childLayer);
    final PaintingContext childContext = createChildContext(childLayer, childPaintBounds ?? estimatedBounds);
396
    painter(childContext, offset);
397 398 399
    childContext.stopRecordingIfNeeded();
  }

400 401 402
  /// Creates a painting context configured to paint into [childLayer].
  ///
  /// The `bounds` are estimated paint bounds for debugging purposes.
403 404
  @protected
  PaintingContext createChildContext(ContainerLayer childLayer, Rect bounds) {
405
    return PaintingContext(childLayer, bounds);
406 407
  }

408
  /// Clip further painting using a rectangle.
Adam Barth's avatar
Adam Barth committed
409
  ///
410
  /// {@template flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
411 412 413 414 415 416 417 418 419 420 421
  /// The `needsCompositing` argument specifies whether the child needs
  /// compositing. Typically this matches the value of
  /// [RenderObject.needsCompositing] for the caller. If false, this method
  /// returns null, indicating that a layer is no longer necessary. If a render
  /// object calling this method stores the `oldLayer` in its
  /// [RenderObject.layer] field, it should set that field to null.
  ///
  /// When `needsCompositing` is false, this method will use a more efficient
  /// way to apply the layer effect than actually creating a layer.
  /// {@endtemplate}
  ///
422
  /// {@template flutter.rendering.PaintingContext.pushClipRect.offset}
423 424 425 426 427 428 429 430 431 432 433 434 435
  /// The `offset` argument is the offset from the origin of the canvas'
  /// coordinate system to the origin of the caller's coordinate system.
  /// {@endtemplate}
  ///
  /// The `clipRect` is the rectangle (in the caller's coordinate system) to use
  /// to clip the painting done by [painter]. It should not include the
  /// `offset`.
  ///
  /// The `painter` callback will be called while the `clipRect` is applied. It
  /// is called synchronously during the call to [pushClipRect].
  ///
  /// The `clipBehavior` argument controls how the rectangle is clipped.
  ///
436
  /// {@template flutter.rendering.PaintingContext.pushClipRect.oldLayer}
437 438 439 440 441 442 443 444
  /// For the `oldLayer` argument, specify the layer created in the previous
  /// frame. This gives the engine more information for performance
  /// optimizations. Typically this is the value of [RenderObject.layer] that a
  /// render object creates once, then reuses for all subsequent frames until a
  /// layer is no longer needed (e.g. the render object no longer needs
  /// compositing) or until the render object changes the type of the layer
  /// (e.g. from opacity layer to a clip rect layer).
  /// {@endtemplate}
445
  ClipRectLayer? pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.hardEdge, ClipRectLayer? oldLayer }) {
446
    final Rect offsetClipRect = clipRect.shift(offset);
Adam Barth's avatar
Adam Barth committed
447
    if (needsCompositing) {
448 449 450 451 452 453
      final ClipRectLayer layer = oldLayer ?? ClipRectLayer();
      layer
        ..clipRect = offsetClipRect
        ..clipBehavior = clipBehavior;
      pushLayer(layer, painter, offset, childPaintBounds: offsetClipRect);
      return layer;
Adam Barth's avatar
Adam Barth committed
454
    } else {
455
      clipRectAndPaint(offsetClipRect, clipBehavior, offsetClipRect, () => painter(this, offset));
456
      return null;
Hixie's avatar
Hixie committed
457 458 459
    }
  }

460
  /// Clip further painting using a rounded rectangle.
461
  ///
462
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
463
  ///
464
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.offset}
465 466 467 468 469 470 471 472 473 474 475 476 477
  ///
  /// The `bounds` argument is used to specify the region of the canvas (in the
  /// caller's coordinate system) into which `painter` will paint.
  ///
  /// The `clipRRect` argument specifies the rounded-rectangle (in the caller's
  /// coordinate system) to use to clip the painting done by `painter`. It
  /// should not include the `offset`.
  ///
  /// The `painter` callback will be called while the `clipRRect` is applied. It
  /// is called synchronously during the call to [pushClipRRect].
  ///
  /// The `clipBehavior` argument controls how the rounded rectangle is clipped.
  ///
478
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
479
  ClipRRectLayer? pushClipRRect(bool needsCompositing, Offset offset, Rect bounds, RRect clipRRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.antiAlias, ClipRRectLayer? oldLayer }) {
480
    assert(clipBehavior != null);
481 482
    final Rect offsetBounds = bounds.shift(offset);
    final RRect offsetClipRRect = clipRRect.shift(offset);
Adam Barth's avatar
Adam Barth committed
483
    if (needsCompositing) {
484 485 486 487 488 489
      final ClipRRectLayer layer = oldLayer ?? ClipRRectLayer();
      layer
        ..clipRRect = offsetClipRRect
        ..clipBehavior = clipBehavior;
      pushLayer(layer, painter, offset, childPaintBounds: offsetBounds);
      return layer;
Adam Barth's avatar
Adam Barth committed
490
    } else {
491
      clipRRectAndPaint(offsetClipRRect, clipBehavior, offsetBounds, () => painter(this, offset));
492
      return null;
Hixie's avatar
Hixie committed
493 494 495
    }
  }

496
  /// Clip further painting using a path.
497
  ///
498
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
499
  ///
500
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.offset}
501 502 503 504 505 506 507 508 509 510 511 512 513
  ///
  /// The `bounds` argument is used to specify the region of the canvas (in the
  /// caller's coordinate system) into which `painter` will paint.
  ///
  /// The `clipPath` argument specifies the [Path] (in the caller's coordinate
  /// system) to use to clip the painting done by `painter`. It should not
  /// include the `offset`.
  ///
  /// The `painter` callback will be called while the `clipPath` is applied. It
  /// is called synchronously during the call to [pushClipPath].
  ///
  /// The `clipBehavior` argument controls how the path is clipped.
  ///
514
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
515
  ClipPathLayer? pushClipPath(bool needsCompositing, Offset offset, Rect bounds, Path clipPath, PaintingContextCallback painter, { Clip clipBehavior = Clip.antiAlias, ClipPathLayer? oldLayer }) {
516
    assert(clipBehavior != null);
517 518
    final Rect offsetBounds = bounds.shift(offset);
    final Path offsetClipPath = clipPath.shift(offset);
Adam Barth's avatar
Adam Barth committed
519
    if (needsCompositing) {
520 521 522 523 524 525
      final ClipPathLayer layer = oldLayer ?? ClipPathLayer();
      layer
        ..clipPath = offsetClipPath
        ..clipBehavior = clipBehavior;
      pushLayer(layer, painter, offset, childPaintBounds: offsetBounds);
      return layer;
526
    } else {
527
      clipPathAndPaint(offsetClipPath, clipBehavior, offsetBounds, () => painter(this, offset));
528
      return null;
529 530
    }
  }
531

532 533
  /// Blend further painting with a color filter.
  ///
534
  /// {@macro flutter.rendering.PaintingContext.pushLayer.offset}
535 536 537 538 539 540 541
  ///
  /// The `colorFilter` argument is the [ColorFilter] value to use when blending
  /// the painting done by `painter`.
  ///
  /// The `painter` callback will be called while the `colorFilter` is applied.
  /// It is called synchronously during the call to [pushColorFilter].
  ///
542
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
543 544 545 546 547
  ///
  /// A [RenderObject] that uses this function is very likely to require its
  /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs
  /// ancestor render objects that this render object will include a composited
  /// layer, which, for example, causes them to use composited clips.
548
  ColorFilterLayer pushColorFilter(Offset offset, ColorFilter colorFilter, PaintingContextCallback painter, { ColorFilterLayer? oldLayer }) {
549
    assert(colorFilter != null);
550 551 552 553
    final ColorFilterLayer layer = oldLayer ?? ColorFilterLayer();
    layer.colorFilter = colorFilter;
    pushLayer(layer, painter, offset);
    return layer;
554 555
  }

556
  /// Transform further painting using a matrix.
557
  ///
558
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.needsCompositing}
559 560 561 562 563 564 565 566 567 568 569
  ///
  /// The `offset` argument is the offset to pass to `painter` and the offset to
  /// the origin used by `transform`.
  ///
  /// The `transform` argument is the [Matrix4] with which to transform the
  /// coordinate system while calling `painter`. It should not include `offset`.
  /// It is applied effectively after applying `offset`.
  ///
  /// The `painter` callback will be called while the `transform` is applied. It
  /// is called synchronously during the call to [pushTransform].
  ///
570
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
571
  TransformLayer? pushTransform(bool needsCompositing, Offset offset, Matrix4 transform, PaintingContextCallback painter, { TransformLayer? oldLayer }) {
572
    final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0)
573
      ..multiply(transform)..translate(-offset.dx, -offset.dy);
Adam Barth's avatar
Adam Barth committed
574
    if (needsCompositing) {
575 576
      final TransformLayer layer = oldLayer ?? TransformLayer();
      layer.transform = effectiveTransform;
577
      pushLayer(
578
        layer,
579 580
        painter,
        offset,
581
        childPaintBounds: MatrixUtils.inverseTransformRect(effectiveTransform, estimatedBounds),
582
      );
583
      return layer;
Adam Barth's avatar
Adam Barth committed
584
    } else {
585 586 587
      canvas
        ..save()
        ..transform(effectiveTransform.storage);
588
      painter(this, offset);
589
      canvas.restore();
590
      return null;
591
    }
592
  }
593

594
  /// Blend further painting with an alpha value.
Adam Barth's avatar
Adam Barth committed
595
  ///
596 597 598 599 600 601 602 603 604 605
  /// The `offset` argument indicates an offset to apply to all the children
  /// (the rendering created by `painter`).
  ///
  /// The `alpha` argument is the alpha value to use when blending the painting
  /// done by `painter`. An alpha value of 0 means the painting is fully
  /// transparent and an alpha value of 255 means the painting is fully opaque.
  ///
  /// The `painter` callback will be called while the `alpha` is applied. It
  /// is called synchronously during the call to [pushOpacity].
  ///
606
  /// {@macro flutter.rendering.PaintingContext.pushClipRect.oldLayer}
607 608 609 610
  ///
  /// A [RenderObject] that uses this function is very likely to require its
  /// [RenderObject.alwaysNeedsCompositing] property to return true. That informs
  /// ancestor render objects that this render object will include a composited
611
  /// layer, which, for example, causes them to use composited clips.
612
  OpacityLayer pushOpacity(Offset offset, int alpha, PaintingContextCallback painter, { OpacityLayer? oldLayer }) {
613 614 615 616 617 618
    final OpacityLayer layer = oldLayer ?? OpacityLayer();
    layer
      ..alpha = alpha
      ..offset = offset;
    pushLayer(layer, painter, Offset.zero);
    return layer;
619
  }
620 621

  @override
622
  String toString() => '${objectRuntimeType(this, 'PaintingContext')}#$hashCode(layer: $_containerLayer, canvas bounds: $estimatedBounds)';
623 624
}

625
/// An abstract set of layout constraints.
626 627 628
///
/// Concrete layout models (such as box) will create concrete subclasses to
/// communicate layout constraints between parents and children.
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
///
/// ## Writing a Constraints subclass
///
/// When creating a new [RenderObject] subclass with a new layout protocol, one
/// will usually need to create a new [Constraints] subclass to express the
/// input to the layout algorithms.
///
/// A [Constraints] subclass should be immutable (all fields final). There are
/// several members to implement, in addition to whatever fields, constructors,
/// and helper methods one may find useful for a particular layout protocol:
///
/// * The [isTight] getter, which should return true if the object represents a
///   case where the [RenderObject] class has no choice for how to lay itself
///   out. For example, [BoxConstraints] returns true for [isTight] when both
///   the minimum and maximum widths and the minimum and maximum heights are
///   equal.
///
/// * The [isNormalized] getter, which should return true if the object
///   represents its data in its canonical form. Sometimes, it is possible for
///   fields to be redundant with each other, such that several different
///   representations have the same implications. For example, a
///   [BoxConstraints] instance with its minimum width greater than its maximum
///   width is equivalent to one where the maximum width is set to that minimum
///   width (`2<w<1` is equivalent to `2<w<2`, since minimum constraints have
///   priority). This getter is used by the default implementation of
///   [debugAssertIsValid].
///
/// * The [debugAssertIsValid] method, which should assert if there's anything
///   wrong with the constraints object. (We use this approach rather than
///   asserting in constructors so that our constructors can be `const` and so
///   that it is possible to create invalid constraints temporarily while
///   building valid ones.) See the implementation of
///   [BoxConstraints.debugAssertIsValid] for an example of the detailed checks
///   that can be made.
///
Ian Hickson's avatar
Ian Hickson committed
664
/// * The [==] operator and the [hashCode] getter, so that constraints can be
665 666 667 668 669 670
///   compared for equality. If a render object is given constraints that are
///   equal, then the rendering library will avoid laying the object out again
///   if it is not dirty.
///
/// * The [toString] method, which should describe the constraints so that they
///   appear in a usefully readable form in the output of [debugDumpRenderTree].
671
@immutable
672
abstract class Constraints {
673 674
  /// Abstract const constructor. This constructor enables subclasses to provide
  /// const constructors so that they can be used in const expressions.
675
  const Constraints();
676

677
  /// Whether there is exactly one size possible given these constraints.
678
  bool get isTight;
679 680 681

  /// Whether the constraint is expressed in a consistent manner.
  bool get isNormalized;
682

683 684 685 686
  /// Asserts that the constraints are valid.
  ///
  /// This might involve checks more detailed than [isNormalized].
  ///
687
  /// For example, the [BoxConstraints] subclass verifies that the constraints
688
  /// are not [double.nan].
689 690 691 692 693 694 695 696 697 698 699 700 701
  ///
  /// If the `isAppliedConstraint` argument is true, then even stricter rules
  /// are enforced. This argument is set to true when checking constraints that
  /// are about to be applied to a [RenderObject] during layout, as opposed to
  /// constraints that may be further affected by other constraints. For
  /// example, the asserts for verifying the validity of
  /// [RenderConstrainedBox.additionalConstraints] do not set this argument, but
  /// the asserts for verifying the argument passed to the [RenderObject.layout]
  /// method do.
  ///
  /// The `informationCollector` argument takes an optional callback which is
  /// called when an exception is to be thrown. The collected information is
  /// then included in the message after the error line.
702
  ///
703
  /// Returns the same as [isNormalized] if asserts are disabled.
704
  bool debugAssertIsValid({
705
    bool isAppliedConstraint = false,
706
    InformationCollector? informationCollector,
707 708 709 710
  }) {
    assert(isNormalized);
    return isNormalized;
  }
711 712
}

713
/// Signature for a function that is called for each [RenderObject].
714 715
///
/// Used by [RenderObject.visitChildren] and [RenderObject.visitChildrenForSemantics].
716 717
///
/// The `child` argument must not be null.
718
typedef RenderObjectVisitor = void Function(RenderObject child);
719 720

/// Signature for a function that is called during layout.
721 722
///
/// Used by [RenderObject.invokeLayoutCallback].
723
typedef LayoutCallback<T extends Constraints> = void Function(T constraints);
724

Adam Barth's avatar
Adam Barth committed
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
/// A reference to the semantics tree.
///
/// The framework maintains the semantics tree (used for accessibility and
/// indexing) only when there is at least one client holding an open
/// [SemanticsHandle].
///
/// The framework notifies the client that it has updated the semantics tree by
/// calling the [listener] callback. When the client no longer needs the
/// semantics tree, the client can call [dispose] on the [SemanticsHandle],
/// which stops these callbacks and closes the [SemanticsHandle]. When all the
/// outstanding [SemanticsHandle] objects are closed, the framework stops
/// updating the semantics tree.
///
/// To obtain a [SemanticsHandle], call [PipelineOwner.ensureSemantics] on the
/// [PipelineOwner] for the render tree from which you wish to read semantics.
/// You can obtain the [PipelineOwner] using the [RenderObject.owner] property.
741
class SemanticsHandle {
742 743 744
  SemanticsHandle._(PipelineOwner owner, this.listener)
      : assert(owner != null),
        _owner = owner {
745
    if (listener != null)
746
      _owner.semanticsOwner!.addListener(listener!);
747 748
  }

749
  final PipelineOwner _owner;
Adam Barth's avatar
Adam Barth committed
750 751

  /// The callback that will be notified when the semantics tree updates.
752
  final VoidCallback? listener;
753

Adam Barth's avatar
Adam Barth committed
754 755 756 757 758 759
  /// Closes the semantics handle and stops calling [listener] when the
  /// semantics updates.
  ///
  /// When all the outstanding [SemanticsHandle] objects for a given
  /// [PipelineOwner] are closed, the [PipelineOwner] will stop updating the
  /// semantics tree.
760 761
  @mustCallSuper
  void dispose() {
762 763 764
    if (listener != null)
      _owner.semanticsOwner!.removeListener(listener!);
    _owner._didDisposeSemanticsHandle();
765 766 767
  }
}

768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
/// The pipeline owner manages the rendering pipeline.
///
/// The pipeline owner provides an interface for driving the rendering pipeline
/// and stores the state about which render objects have requested to be visited
/// in each stage of the pipeline. To flush the pipeline, call the following
/// functions in order:
///
/// 1. [flushLayout] updates any render objects that need to compute their
///    layout. During this phase, the size and position of each render
///    object is calculated. Render objects might dirty their painting or
///    compositing state during this phase.
/// 2. [flushCompositingBits] updates any render objects that have dirty
///    compositing bits. During this phase, each render object learns whether
///    any of its children require compositing. This information is used during
///    the painting phase when selecting how to implement visual effects such as
///    clipping. If a render object has a composited child, its needs to use a
///    [Layer] to create the clip in order for the clip to apply to the
///    composited child (which will be painted into its own [Layer]).
786
/// 3. [flushPaint] visits any render objects that need to paint. During this
787 788
///    phase, render objects get a chance to record painting commands into
///    [PictureLayer]s and construct other composited [Layer]s.
789 790 791
/// 4. Finally, if semantics are enabled, [flushSemantics] will compile the
///    semantics for the render objects. This semantic information is used by
///    assistive technology to improve the accessibility of the render tree.
792 793 794 795 796
///
/// The [RendererBinding] holds the pipeline owner for the render objects that
/// are visible on screen. You can create other pipeline owners to manage
/// off-screen objects, which can flush their pipelines independently of the
/// on-screen render objects.
797
class PipelineOwner {
798 799 800 801 802
  /// Creates a pipeline owner.
  ///
  /// Typically created by the binding (e.g., [RendererBinding]), but can be
  /// created separately from the binding to drive off-screen render objects
  /// through the rendering pipeline.
803 804
  PipelineOwner({
    this.onNeedVisualUpdate,
805 806
    this.onSemanticsOwnerCreated,
    this.onSemanticsOwnerDisposed,
807
  });
808 809 810 811 812 813 814 815

  /// Called when a render object associated with this pipeline owner wishes to
  /// update its visual appearance.
  ///
  /// Typical implementations of this function will schedule a task to flush the
  /// various stages of the pipeline. This function might be called multiple
  /// times in quick succession. Implementations should take care to discard
  /// duplicate calls quickly.
816
  final VoidCallback? onNeedVisualUpdate;
817

818
  /// Called whenever this pipeline owner creates a semantics object.
819
  ///
820 821
  /// Typical implementations will schedule the creation of the initial
  /// semantics tree.
822
  final VoidCallback? onSemanticsOwnerCreated;
823

824
  /// Called whenever this pipeline owner disposes its semantics owner.
825
  ///
826
  /// Typical implementations will tear down the semantics tree.
827
  final VoidCallback? onSemanticsOwnerDisposed;
828

829 830 831 832
  /// Calls [onNeedVisualUpdate] if [onNeedVisualUpdate] is not null.
  ///
  /// Used to notify the pipeline owner that an associated render object wishes
  /// to update its visual appearance.
833 834
  void requestVisualUpdate() {
    if (onNeedVisualUpdate != null)
835
      onNeedVisualUpdate!();
836
  }
837

838 839 840
  /// The unique object managed by this pipeline that has no parent.
  ///
  /// This object does not have to be a [RenderObject].
841 842 843
  AbstractNode? get rootNode => _rootNode;
  AbstractNode? _rootNode;
  set rootNode(AbstractNode? value) {
844
    if (_rootNode == value)
845
      return;
846 847 848
    _rootNode?.detach();
    _rootNode = value;
    _rootNode?.attach(this);
849 850
  }

851
  List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
852 853 854 855 856

  /// Whether this pipeline is currently in the layout phase.
  ///
  /// Specifically, whether [flushLayout] is currently running.
  ///
857 858
  /// Only valid when asserts are enabled; in release builds, this
  /// always returns false.
859
  bool get debugDoingLayout => _debugDoingLayout;
860 861
  bool _debugDoingLayout = false;

862 863 864 865 866 867
  /// Update the layout information for all dirty render objects.
  ///
  /// This function is one of the core stages of the rendering pipeline. Layout
  /// information is cleaned prior to painting so that render objects will
  /// appear on screen in their up-to-date locations.
  ///
868
  /// See [RendererBinding] for an example of how this function is used.
869
  void flushLayout() {
870
    if (!kReleaseMode) {
871
      Timeline.startSync('Layout', arguments: timelineArgumentsIndicatingLandmarkEvent);
872
    }
873 874 875 876
    assert(() {
      _debugDoingLayout = true;
      return true;
    }());
877
    try {
878
      // TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themselves
879
      while (_nodesNeedingLayout.isNotEmpty) {
880
        final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
881
        _nodesNeedingLayout = <RenderObject>[];
882
        for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
883 884 885 886 887
          if (node._needsLayout && node.owner == this)
            node._layoutWithoutResize();
        }
      }
    } finally {
888 889 890 891
      assert(() {
        _debugDoingLayout = false;
        return true;
      }());
892
      if (!kReleaseMode) {
893
        Timeline.finishSync();
894
      }
895 896 897
    }
  }

898 899 900 901 902 903 904 905 906 907
  // This flag is used to allow the kinds of mutations performed by GlobalKey
  // reparenting while a LayoutBuilder is being rebuilt and in so doing tries to
  // move a node from another LayoutBuilder subtree that hasn't been updated
  // yet. To set this, call [_enableMutationsToDirtySubtrees], which is called
  // by [RenderObject.invokeLayoutCallback].
  bool _debugAllowMutationsToDirtySubtrees = false;

  // See [RenderObject.invokeLayoutCallback].
  void _enableMutationsToDirtySubtrees(VoidCallback callback) {
    assert(_debugDoingLayout);
908
    bool? oldState;
909 910 911 912 913
    assert(() {
      oldState = _debugAllowMutationsToDirtySubtrees;
      _debugAllowMutationsToDirtySubtrees = true;
      return true;
    }());
914 915 916
    try {
      callback();
    } finally {
917
      assert(() {
918
        _debugAllowMutationsToDirtySubtrees = oldState!;
919 920
        return true;
      }());
921 922 923
    }
  }

924
  final List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[];
925
  /// Updates the [RenderObject.needsCompositing] bits.
926 927 928 929
  ///
  /// Called as part of the rendering pipeline after [flushLayout] and before
  /// [flushPaint].
  void flushCompositingBits() {
930 931 932
    if (!kReleaseMode) {
      Timeline.startSync('Compositing bits');
    }
933
    _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
934
    for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) {
935
      if (node._needsCompositingBitsUpdate && node.owner == this)
936 937 938
        node._updateCompositingBits();
    }
    _nodesNeedingCompositingBitsUpdate.clear();
939 940 941
    if (!kReleaseMode) {
      Timeline.finishSync();
    }
942 943 944
  }

  List<RenderObject> _nodesNeedingPaint = <RenderObject>[];
945 946 947 948 949

  /// Whether this pipeline is currently in the paint phase.
  ///
  /// Specifically, whether [flushPaint] is currently running.
  ///
950 951
  /// Only valid when asserts are enabled. In release builds,
  /// this always returns false.
952
  bool get debugDoingPaint => _debugDoingPaint;
953 954
  bool _debugDoingPaint = false;

955 956 957 958 959 960
  /// Update the display lists for all render objects.
  ///
  /// This function is one of the core stages of the rendering pipeline.
  /// Painting occurs after layout and before the scene is recomposited so that
  /// scene is composited with up-to-date display lists for every render object.
  ///
961
  /// See [RendererBinding] for an example of how this function is used.
962
  void flushPaint() {
963
    if (!kReleaseMode) {
964
      Timeline.startSync('Paint', arguments: timelineArgumentsIndicatingLandmarkEvent);
965
    }
966 967 968 969
    assert(() {
      _debugDoingPaint = true;
      return true;
    }());
970
    try {
971
      final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
972 973
      _nodesNeedingPaint = <RenderObject>[];
      // Sort the dirty nodes in reverse order (deepest first).
974
      for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
975 976
        assert(node._layer != null);
        if (node._needsPaint && node.owner == this) {
977
          if (node._layer!.attached) {
978 979 980 981 982
            PaintingContext.repaintCompositedChild(node);
          } else {
            node._skippedPaintingOnLayer();
          }
        }
pq's avatar
pq committed
983
      }
984
      assert(_nodesNeedingPaint.isEmpty);
985
    } finally {
986 987 988 989
      assert(() {
        _debugDoingPaint = false;
        return true;
      }());
990 991 992
      if (!kReleaseMode) {
        Timeline.finishSync();
      }
993 994 995
    }
  }

996 997
  /// The object that is managing semantics for this pipeline owner, if any.
  ///
998
  /// An owner is created by [ensureSemantics]. The owner is valid for as long
999 1000
  /// there are [SemanticsHandle]s returned by [ensureSemantics] that have not
  /// yet been disposed. Once the last handle has been disposed, the
1001 1002
  /// [semanticsOwner] field will revert to null, and the previous owner will be
  /// disposed.
1003 1004 1005
  ///
  /// When [semanticsOwner] is null, the [PipelineOwner] skips all steps
  /// relating to semantics.
1006 1007
  SemanticsOwner? get semanticsOwner => _semanticsOwner;
  SemanticsOwner? _semanticsOwner;
1008

1009 1010 1011 1012 1013 1014
  /// The number of clients registered to listen for semantics.
  ///
  /// The number is increased whenever [ensureSemantics] is called and decreased
  /// when [SemanticsHandle.dispose] is called.
  int get debugOutstandingSemanticsHandles => _outstandingSemanticsHandles;
  int _outstandingSemanticsHandles = 0;
1015

Adam Barth's avatar
Adam Barth committed
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
  /// Opens a [SemanticsHandle] and calls [listener] whenever the semantics tree
  /// updates.
  ///
  /// The [PipelineOwner] updates the semantics tree only when there are clients
  /// that wish to use the semantics tree. These clients express their interest
  /// by holding [SemanticsHandle] objects that notify them whenever the
  /// semantics tree updates.
  ///
  /// Clients can close their [SemanticsHandle] by calling
  /// [SemanticsHandle.dispose]. Once all the outstanding [SemanticsHandle]
  /// objects for a given [PipelineOwner] are closed, the [PipelineOwner] stops
  /// maintaining the semantics tree.
1028
  SemanticsHandle ensureSemantics({ VoidCallback? listener }) {
1029 1030
    _outstandingSemanticsHandles += 1;
    if (_outstandingSemanticsHandles == 1) {
1031
      assert(_semanticsOwner == null);
1032
      _semanticsOwner = SemanticsOwner();
1033
      if (onSemanticsOwnerCreated != null)
1034
        onSemanticsOwnerCreated!();
1035
    }
1036
    return SemanticsHandle._(this, listener);
1037 1038 1039 1040
  }

  void _didDisposeSemanticsHandle() {
    assert(_semanticsOwner != null);
1041 1042
    _outstandingSemanticsHandles -= 1;
    if (_outstandingSemanticsHandles == 0) {
1043
      _semanticsOwner!.dispose();
1044 1045
      _semanticsOwner = null;
      if (onSemanticsOwnerDisposed != null)
1046
        onSemanticsOwnerDisposed!();
1047 1048 1049
    }
  }

1050
  bool _debugDoingSemantics = false;
1051
  final Set<RenderObject> _nodesNeedingSemantics = <RenderObject>{};
1052

1053 1054 1055
  /// Update the semantics for render objects marked as needing a semantics
  /// update.
  ///
1056
  /// Initially, only the root node, as scheduled by
1057
  /// [RenderObject.scheduleInitialSemantics], needs a semantics update.
1058 1059 1060 1061 1062
  ///
  /// This function is one of the core stages of the rendering pipeline. The
  /// semantics are compiled after painting and only after
  /// [RenderObject.scheduleInitialSemantics] has been called.
  ///
1063
  /// See [RendererBinding] for an example of how this function is used.
1064
  void flushSemantics() {
1065 1066
    if (_semanticsOwner == null)
      return;
1067 1068 1069
    if (!kReleaseMode) {
      Timeline.startSync('Semantics');
    }
1070
    assert(_semanticsOwner != null);
1071 1072 1073 1074
    assert(() {
      _debugDoingSemantics = true;
      return true;
    }());
1075
    try {
1076 1077 1078
      final List<RenderObject> nodesToProcess = _nodesNeedingSemantics.toList()
        ..sort((RenderObject a, RenderObject b) => a.depth - b.depth);
      _nodesNeedingSemantics.clear();
1079
      for (final RenderObject node in nodesToProcess) {
1080 1081 1082
        if (node._needsSemanticsUpdate && node.owner == this)
          node._updateSemantics();
      }
1083
      _semanticsOwner!.sendSemanticsUpdate();
1084
    } finally {
1085
      assert(_nodesNeedingSemantics.isEmpty);
1086 1087 1088 1089
      assert(() {
        _debugDoingSemantics = false;
        return true;
      }());
1090 1091 1092
      if (!kReleaseMode) {
        Timeline.finishSync();
      }
1093 1094 1095 1096
    }
  }
}

1097
/// An object in the render tree.
1098
///
1099 1100 1101
/// The [RenderObject] class hierarchy is the core of the rendering
/// library's reason for being.
///
1102 1103 1104 1105
/// [RenderObject]s have a [parent], and have a slot called [parentData] in
/// which the parent [RenderObject] can store child-specific data, for example,
/// the child position. The [RenderObject] class also implements the basic
/// layout and paint protocols.
1106
///
1107 1108
/// The [RenderObject] class, however, does not define a child model (e.g.
/// whether a node has zero, one, or more children). It also doesn't define a
1109
/// coordinate system (e.g. whether children are positioned in Cartesian
1110 1111 1112 1113 1114
/// coordinates, in polar coordinates, etc) or a specific layout protocol (e.g.
/// whether the layout is width-in-height-out, or constraint-in-size-out, or
/// whether the parent sets the size and position of the child before or after
/// the child lays out, etc; or indeed whether the children are allowed to read
/// their parent's [parentData] slot).
1115 1116
///
/// The [RenderBox] subclass introduces the opinion that the layout
1117
/// system uses Cartesian coordinates.
1118 1119 1120 1121 1122
///
/// ## Writing a RenderObject subclass
///
/// In most cases, subclassing [RenderObject] itself is overkill, and
/// [RenderBox] would be a better starting point. However, if a render object
1123
/// doesn't want to use a Cartesian coordinate system, then it should indeed
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
/// inherit from [RenderObject] directly. This allows it to define its own
/// layout protocol by using a new subclass of [Constraints] rather than using
/// [BoxConstraints], and by potentially using an entirely new set of objects
/// and values to represent the result of the output rather than just a [Size].
/// This increased flexibility comes at the cost of not being able to rely on
/// the features of [RenderBox]. For example, [RenderBox] implements an
/// intrinsic sizing protocol that allows you to measure a child without fully
/// laying it out, in such a way that if that child changes size, the parent
/// will be laid out again (to take into account the new dimensions of the
/// child). This is a subtle and bug-prone feature to get right.
///
/// Most aspects of writing a [RenderBox] apply to writing a [RenderObject] as
/// well, and therefore the discussion at [RenderBox] is recommended background
/// reading. The main differences are around layout and hit testing, since those
/// are the aspects that [RenderBox] primarily specializes.
///
/// ### Layout
///
/// A layout protocol begins with a subclass of [Constraints]. See the
/// discussion at [Constraints] for more information on how to write a
/// [Constraints] subclass.
///
/// The [performLayout] method should take the [constraints], and apply them.
/// The output of the layout algorithm is fields set on the object that describe
/// the geometry of the object for the purposes of the parent's layout. For
/// example, with [RenderBox] the output is the [RenderBox.size] field. This
/// output should only be read by the parent if the parent specified
/// `parentUsesSize` as true when calling [layout] on the child.
///
/// Anytime anything changes on a render object that would affect the layout of
/// that object, it should call [markNeedsLayout].
///
/// ### Hit Testing
///
/// Hit testing is even more open-ended than layout. There is no method to
/// override, you are expected to provide one.
///
Ian Hickson's avatar
Ian Hickson committed
1161
/// The general behavior of your hit-testing method should be similar to the
1162
/// behavior described for [RenderBox]. The main difference is that the input
1163
/// need not be an [Offset]. You are also allowed to use a different subclass of
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
/// [HitTestEntry] when adding entries to the [HitTestResult]. When the
/// [handleEvent] method is called, the same object that was added to the
/// [HitTestResult] will be passed in, so it can be used to track information
/// like the precise coordinate of the hit, in whatever coordinate system is
/// used by the new layout protocol.
///
/// ### Adapting from one protocol to another
///
/// In general, the root of a Flutter render object tree is a [RenderView]. This
/// object has a single child, which must be a [RenderBox]. Thus, if you want to
/// have a custom [RenderObject] subclass in the render tree, you have two
/// choices: you either need to replace the [RenderView] itself, or you need to
/// have a [RenderBox] that has your class as its child. (The latter is the much
/// more common case.)
///
/// This [RenderBox] subclass converts from the box protocol to the protocol of
/// your class.
///
/// In particular, this means that for hit testing it overrides
/// [RenderBox.hitTest], and calls whatever method you have in your class for
/// hit testing.
///
/// Similarly, it overrides [performLayout] to create a [Constraints] object
/// appropriate for your class and passes that to the child's [layout] method.
///
/// ### Layout interactions between render objects
///
1191
/// In general, the layout of a render object should only depend on the output of
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
/// its child's layout, and then only if `parentUsesSize` is set to true in the
/// [layout] call. Furthermore, if it is set to true, the parent must call the
/// child's [layout] if the child is to be rendered, because otherwise the
/// parent will not be notified when the child changes its layout outputs.
///
/// It is possible to set up render object protocols that transfer additional
/// information. For example, in the [RenderBox] protocol you can query your
/// children's intrinsic dimensions and baseline geometry. However, if this is
/// done then it is imperative that the child call [markNeedsLayout] on the
/// parent any time that additional information changes, if the parent used it
/// in the last layout phase. For an example of how to implement this, see the
/// [RenderBox.markNeedsLayout] method. It overrides
/// [RenderObject.markNeedsLayout] so that if a parent has queried the intrinsic
/// or baseline information, it gets marked dirty whenever the child's geometry
/// changes.
1207
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
1208
  /// Initializes internal fields for subclasses.
1209
  RenderObject() {
1210
    _needsCompositing = isRepaintBoundary || alwaysNeedsCompositing;
1211 1212
  }

1213
  /// Cause the entire subtree rooted at the given [RenderObject] to be marked
1214 1215 1216 1217 1218 1219 1220 1221
  /// dirty for layout, paint, etc, so that the effects of a hot reload can be
  /// seen, or so that the effect of changing a global debug flag (such as
  /// [debugPaintSizeEnabled]) can be applied.
  ///
  /// This is called by the [RendererBinding] in response to the
  /// `ext.flutter.reassemble` hook, which is used by development tools when the
  /// application code has changed, to cause the widget tree to pick up any
  /// changed implementations.
1222 1223 1224 1225 1226
  ///
  /// This is expensive and should not be called except during development.
  ///
  /// See also:
  ///
1227
  ///  * [BindingBase.reassembleApplication]
1228
  void reassemble() {
1229 1230 1231 1232 1233
    markNeedsLayout();
    markNeedsCompositingBitsUpdate();
    markNeedsPaint();
    markNeedsSemanticsUpdate();
    visitChildren((RenderObject child) {
1234
      child.reassemble();
1235 1236 1237
    });
  }

1238 1239
  // LAYOUT

1240
  /// Data for use by the parent render object.
1241 1242 1243 1244 1245 1246
  ///
  /// The parent data is used by the render object that lays out this object
  /// (typically this object's parent in the render tree) to store information
  /// relevant to itself and to any other nodes who happen to know exactly what
  /// the data means. The parent data is opaque to the child.
  ///
1247 1248 1249 1250 1251 1252 1253 1254
  ///  * The parent data field must not be directly set, except by calling
  ///    [setupParentData] on the parent node.
  ///  * The parent data can be set before the child is added to the parent, by
  ///    calling [setupParentData] on the future parent node.
  ///  * The conventions for using the parent data depend on the layout protocol
  ///    used between the parent and child. For example, in box layout, the
  ///    parent data is completely opaque but in sector layout the child is
  ///    permitted to read some fields of the parent data.
1255
  ParentData? parentData;
1256

1257
  /// Override to setup parent data correctly for your children.
1258 1259 1260
  ///
  /// You can call this function to set up the parent data for child before the
  /// child is added to the parent's child list.
1261
  void setupParentData(covariant RenderObject child) {
1262
    assert(_debugCanPerformMutations);
1263
    if (child.parentData is! ParentData)
1264
      child.parentData = ParentData();
1265 1266
  }

1267
  /// Called by subclasses when they decide a render object is a child.
1268 1269 1270
  ///
  /// Only for use by subclasses when changing their child lists. Calling this
  /// in other cases will lead to an inconsistent tree and probably cause crashes.
1271
  @override
1272
  void adoptChild(RenderObject child) {
1273
    assert(_debugCanPerformMutations);
1274 1275 1276
    assert(child != null);
    setupParentData(child);
    markNeedsLayout();
1277
    markNeedsCompositingBitsUpdate();
1278
    markNeedsSemanticsUpdate();
1279
    super.adoptChild(child);
1280
  }
1281

1282
  /// Called by subclasses when they decide a render object is no longer a child.
1283 1284 1285
  ///
  /// Only for use by subclasses when changing their child lists. Calling this
  /// in other cases will lead to an inconsistent tree and probably cause crashes.
1286
  @override
1287
  void dropChild(RenderObject child) {
1288
    assert(_debugCanPerformMutations);
1289 1290
    assert(child != null);
    assert(child.parentData != null);
1291
    child._cleanRelayoutBoundary();
1292
    child.parentData!.detach();
1293
    child.parentData = null;
1294 1295
    super.dropChild(child);
    markNeedsLayout();
1296
    markNeedsCompositingBitsUpdate();
1297
    markNeedsSemanticsUpdate();
1298 1299
  }

1300
  /// Calls visitor for each immediate child of this render object.
1301
  ///
1302
  /// Override in subclasses with children and call the visitor for each child.
1303 1304
  void visitChildren(RenderObjectVisitor visitor) { }

1305 1306 1307
  /// The object responsible for creating this render object.
  ///
  /// Used in debug messages.
1308
  Object? debugCreator;
1309

1310
  void _debugReportException(String method, Object exception, StackTrace stack) {
1311
    FlutterError.reportError(FlutterErrorDetails(
1312 1313 1314
      exception: exception,
      stack: stack,
      library: 'rendering library',
1315 1316
      context: ErrorDescription('during $method()'),
      informationCollector: () sync* {
1317
        if (debugCreator != null)
1318
          yield DiagnosticsDebugCreator(debugCreator!);
1319 1320 1321 1322 1323
        yield describeForError('The following RenderObject was being processed when the exception was fired');
        // TODO(jacobr): this error message has a code smell. Consider whether
        // displaying the truncated children is really useful for command line
        // users. Inspector users can see the full tree by clicking on the
        // render object so this may not be that useful.
1324
        yield describeForError('RenderObject', style: DiagnosticsTreeStyle.truncateChildren);
1325
      },
1326
    ));
1327 1328
  }

1329 1330 1331 1332
  /// Whether [performResize] for this render object is currently running.
  ///
  /// Only valid when asserts are enabled. In release builds, always returns
  /// false.
1333
  bool get debugDoingThisResize => _debugDoingThisResize;
1334 1335 1336 1337 1338 1339
  bool _debugDoingThisResize = false;

  /// Whether [performLayout] for this render object is currently running.
  ///
  /// Only valid when asserts are enabled. In release builds, always returns
  /// false.
1340
  bool get debugDoingThisLayout => _debugDoingThisLayout;
1341 1342 1343 1344 1345 1346
  bool _debugDoingThisLayout = false;

  /// The render object that is actively computing layout.
  ///
  /// Only valid when asserts are enabled. In release builds, always returns
  /// null.
1347 1348
  static RenderObject? get debugActiveLayout => _debugActiveLayout;
  static RenderObject? _debugActiveLayout;
1349 1350 1351 1352 1353 1354

  /// Whether the parent render object is permitted to use this render object's
  /// size.
  ///
  /// Determined by the `parentUsesSize` parameter to [layout].
  ///
1355 1356 1357
  /// Only valid when asserts are enabled. In release builds, throws.
  bool get debugCanParentUseSize => _debugCanParentUseSize!;
  bool? _debugCanParentUseSize;
1358 1359 1360 1361 1362 1363 1364 1365

  bool _debugMutationsLocked = false;

  /// Whether tree mutations are currently permitted.
  ///
  /// Only valid when asserts are enabled. In release builds, always returns
  /// null.
  bool get _debugCanPerformMutations {
1366
    late bool result;
1367 1368 1369 1370 1371 1372 1373
    assert(() {
      RenderObject node = this;
      while (true) {
        if (node._doingThisLayoutWithCallback) {
          result = true;
          break;
        }
1374
        if (owner != null && owner!._debugAllowMutationsToDirtySubtrees && node._needsLayout) {
1375 1376 1377
          result = true;
          break;
        }
1378 1379 1380 1381 1382 1383 1384 1385
        if (node._debugMutationsLocked) {
          result = false;
          break;
        }
        if (node.parent is! RenderObject) {
          result = true;
          break;
        }
1386
        node = node.parent! as RenderObject;
1387 1388
      }
      return true;
1389
    }());
1390
    return result;
1391 1392
  }

1393
  @override
1394
  PipelineOwner? get owner => super.owner as PipelineOwner?;
1395

1396 1397 1398
  @override
  void attach(PipelineOwner owner) {
    super.attach(owner);
1399 1400
    // If the node was dirtied in some way while unattached, make sure to add
    // it to the appropriate dirty list now that an owner is available
1401
    if (_needsLayout && _relayoutBoundary != null) {
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
      // Don't enter this block if we've never laid out at all;
      // scheduleInitialLayout() will handle it
      _needsLayout = false;
      markNeedsLayout();
    }
    if (_needsCompositingBitsUpdate) {
      _needsCompositingBitsUpdate = false;
      markNeedsCompositingBitsUpdate();
    }
    if (_needsPaint && _layer != null) {
      // Don't enter this block if we've never painted at all;
      // scheduleInitialPaint() will handle it
      _needsPaint = false;
      markNeedsPaint();
    }
1417
    if (_needsSemanticsUpdate && _semanticsConfiguration.isSemanticBoundary) {
1418 1419 1420 1421 1422
      // Don't enter this block if we've never updated semantics at all;
      // scheduleInitialSemantics() will handle it
      _needsSemanticsUpdate = false;
      markNeedsSemanticsUpdate();
    }
1423 1424
  }

1425
  /// Whether this render object's layout information is dirty.
1426 1427 1428 1429
  ///
  /// This is only set in debug mode. In general, render objects should not need
  /// to condition their runtime behavior on whether they are dirty or not,
  /// since they should only be marked dirty immediately prior to being laid
1430
  /// out and painted. In release builds, this throws.
1431 1432
  ///
  /// It is intended to be used by tests and asserts.
1433
  bool get debugNeedsLayout {
1434
    late bool result;
1435 1436 1437
    assert(() {
      result = _needsLayout;
      return true;
1438
    }());
1439 1440
    return result;
  }
1441 1442
  bool _needsLayout = true;

1443
  RenderObject? _relayoutBoundary;
1444
  bool _doingThisLayoutWithCallback = false;
1445

1446
  /// The layout constraints most recently supplied by the parent.
1447 1448 1449
  ///
  /// If layout has not yet happened, accessing this getter will
  /// throw a [StateError] exception.
1450
  @protected
1451
  Constraints get constraints {
1452 1453
    if (_constraints == null)
      throw StateError('A RenderObject does not have any constraints before it has been laid out.');
1454
    return _constraints!;
1455
  }
1456
  Constraints? _constraints;
1457

1458 1459 1460
  /// Verify that the object's constraints are being met. Override
  /// this function in a subclass to verify that your state matches
  /// the constraints object. This function is only called in checked
1461 1462
  /// mode and only when needsLayout is false. If the constraints are
  /// not met, it should assert or throw an exception.
1463
  @protected
1464 1465 1466
  void debugAssertDoesMeetConstraints();

  /// When true, debugAssertDoesMeetConstraints() is currently
1467
  /// executing asserts for verifying the consistent behavior of
1468 1469 1470 1471 1472 1473 1474 1475
  /// intrinsic dimensions methods.
  ///
  /// This should only be set by debugAssertDoesMeetConstraints()
  /// implementations. It is used by tests to selectively ignore
  /// custom layout callbacks. It should not be set outside of
  /// debugAssertDoesMeetConstraints(), and should not be checked in
  /// release mode (where it will always be false).
  static bool debugCheckingIntrinsics = false;
1476
  bool _debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout() {
1477
    if (_relayoutBoundary == null)
1478
      return true; // we don't know where our relayout boundary is yet
1479
    RenderObject node = this;
1480 1481
    while (node != _relayoutBoundary) {
      assert(node._relayoutBoundary == _relayoutBoundary);
1482
      assert(node.parent != null);
1483
      node = node.parent! as RenderObject;
1484
      if ((!node._needsLayout) && (!node._debugDoingThisLayout))
1485 1486
        return false;
    }
1487
    assert(node._relayoutBoundary == node);
1488 1489
    return true;
  }
1490

1491 1492 1493 1494 1495
  /// Mark this render object's layout information as dirty, and either register
  /// this object with its [PipelineOwner], or defer to the parent, depending on
  /// whether this object is a relayout boundary or not respectively.
  ///
  /// ## Background
1496 1497
  ///
  /// Rather than eagerly updating layout information in response to writes into
1498
  /// a render object, we instead mark the layout information as dirty, which
1499
  /// schedules a visual update. As part of the visual update, the rendering
1500
  /// pipeline updates the render object's layout information.
1501 1502 1503 1504
  ///
  /// This mechanism batches the layout work so that multiple sequential writes
  /// are coalesced, removing redundant computation.
  ///
1505 1506 1507 1508 1509 1510 1511 1512
  /// If a render object's parent indicates that it uses the size of one of its
  /// render object children when computing its layout information, this
  /// function, when called for the child, will also mark the parent as needing
  /// layout. In that case, since both the parent and the child need to have
  /// their layout recomputed, the pipeline owner is only notified about the
  /// parent; when the parent is laid out, it will call the child's [layout]
  /// method and thus the child will be laid out as well.
  ///
1513 1514 1515
  /// Once [markNeedsLayout] has been called on a render object,
  /// [debugNeedsLayout] returns true for that render object until just after
  /// the pipeline owner has called [layout] on the render object.
1516 1517 1518 1519 1520
  ///
  /// ## Special cases
  ///
  /// Some subclasses of [RenderObject], notably [RenderBox], have other
  /// situations in which the parent needs to be notified if the child is
1521 1522
  /// dirtied (e.g., if the child's intrinsic dimensions or baseline changes).
  /// Such subclasses override markNeedsLayout and either call
1523
  /// `super.markNeedsLayout()`, in the normal case, or call
1524
  /// [markParentNeedsLayout], in the case where the parent needs to be laid out
1525
  /// as well as the child.
1526
  ///
1527
  /// If [sizedByParent] has changed, calls
1528
  /// [markNeedsLayoutForSizedByParentChange] instead of [markNeedsLayout].
1529
  void markNeedsLayout() {
1530
    assert(_debugCanPerformMutations);
1531
    if (_needsLayout) {
1532
      assert(_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout());
1533 1534
      return;
    }
1535 1536
    assert(_relayoutBoundary != null);
    if (_relayoutBoundary != this) {
1537
      markParentNeedsLayout();
1538
    } else {
1539
      _needsLayout = true;
1540
      if (owner != null) {
1541 1542
        assert(() {
          if (debugPrintMarkNeedsLayoutStacks)
1543
            debugPrintStack(label: 'markNeedsLayout() called for $this');
1544
          return true;
1545
        }());
1546 1547
        owner!._nodesNeedingLayout.add(this);
        owner!.requestVisualUpdate();
1548
      }
1549 1550
    }
  }
1551

1552 1553 1554
  /// Mark this render object's layout information as dirty, and then defer to
  /// the parent.
  ///
1555 1556 1557 1558
  /// This function should only be called from [markNeedsLayout] or
  /// [markNeedsLayoutForSizedByParentChange] implementations of subclasses that
  /// introduce more reasons for deferring the handling of dirty layout to the
  /// parent. See [markNeedsLayout] for details.
1559 1560 1561 1562 1563
  ///
  /// Only call this if [parent] is not null.
  @protected
  void markParentNeedsLayout() {
    _needsLayout = true;
1564 1565
    assert(this.parent != null);
    final RenderObject parent = this.parent! as RenderObject;
1566 1567 1568 1569 1570 1571 1572 1573
    if (!_doingThisLayoutWithCallback) {
      parent.markNeedsLayout();
    } else {
      assert(parent._debugDoingThisLayout);
    }
    assert(parent == this.parent);
  }

1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
  /// Mark this render object's layout information as dirty (like
  /// [markNeedsLayout]), and additionally also handle any necessary work to
  /// handle the case where [sizedByParent] has changed value.
  ///
  /// This should be called whenever [sizedByParent] might have changed.
  ///
  /// Only call this if [parent] is not null.
  void markNeedsLayoutForSizedByParentChange() {
    markNeedsLayout();
    markParentNeedsLayout();
  }

1586 1587 1588
  void _cleanRelayoutBoundary() {
    if (_relayoutBoundary != this) {
      _relayoutBoundary = null;
1589
      _needsLayout = true;
1590
      visitChildren(_cleanChildRelayoutBoundary);
1591 1592
    }
  }
1593

1594 1595 1596 1597 1598
  // Reduces closure allocation for visitChildren use cases.
  static void _cleanChildRelayoutBoundary(RenderObject child) {
    child._cleanRelayoutBoundary();
  }

1599
  /// Bootstrap the rendering pipeline by scheduling the very first layout.
1600 1601 1602 1603 1604
  ///
  /// Requires this render object to be attached and that this render object
  /// is the root of the render tree.
  ///
  /// See [RenderView] for an example of how this function is used.
1605 1606
  void scheduleInitialLayout() {
    assert(attached);
Hixie's avatar
Hixie committed
1607
    assert(parent is! RenderObject);
1608
    assert(!owner!._debugDoingLayout);
1609 1610
    assert(_relayoutBoundary == null);
    _relayoutBoundary = this;
1611 1612 1613
    assert(() {
      _debugCanParentUseSize = false;
      return true;
1614
    }());
1615
    owner!._nodesNeedingLayout.add(this);
1616
  }
1617 1618

  void _layoutWithoutResize() {
1619
    assert(_relayoutBoundary == this);
1620
    RenderObject? debugPreviousActiveLayout;
1621 1622 1623 1624 1625 1626 1627 1628
    assert(!_debugMutationsLocked);
    assert(!_doingThisLayoutWithCallback);
    assert(_debugCanParentUseSize != null);
    assert(() {
      _debugMutationsLocked = true;
      _debugDoingThisLayout = true;
      debugPreviousActiveLayout = _debugActiveLayout;
      _debugActiveLayout = this;
1629 1630
      if (debugPrintLayouts)
        debugPrint('Laying out (without resize) $this');
1631
      return true;
1632
    }());
1633
    try {
1634
      performLayout();
Hixie's avatar
Hixie committed
1635
      markNeedsSemanticsUpdate();
1636 1637
    } catch (e, stack) {
      _debugReportException('performLayout', e, stack);
1638
    }
1639 1640 1641 1642 1643
    assert(() {
      _debugActiveLayout = debugPreviousActiveLayout;
      _debugDoingThisLayout = false;
      _debugMutationsLocked = false;
      return true;
1644
    }());
1645 1646 1647
    _needsLayout = false;
    markNeedsPaint();
  }
1648

1649
  /// Compute the layout for this render object.
1650
  ///
1651
  /// This method is the main entry point for parents to ask their children to
1652
  /// update their layout information. The parent passes a constraints object,
1653
  /// which informs the child as to which layouts are permissible. The child is
1654 1655 1656
  /// required to obey the given constraints.
  ///
  /// If the parent reads information computed during the child's layout, the
1657 1658
  /// parent must pass true for `parentUsesSize`. In that case, the parent will
  /// be marked as needing layout whenever the child is marked as needing layout
1659 1660
  /// because the parent's layout information depends on the child's layout
  /// information. If the parent uses the default value (false) for
1661
  /// `parentUsesSize`, the child can change its layout information (subject to
1662 1663
  /// the given constraints) without informing the parent.
  ///
1664 1665 1666
  /// Subclasses should not override [layout] directly. Instead, they should
  /// override [performResize] and/or [performLayout]. The [layout] method
  /// delegates the actual work to [performResize] and [performLayout].
1667
  ///
1668
  /// The parent's [performLayout] method should call the [layout] of all its
1669
  /// children unconditionally. It is the [layout] method's responsibility (as
1670 1671
  /// implemented here) to return early if the child does not need to do any
  /// work to update its layout information.
1672
  void layout(Constraints constraints, { bool parentUsesSize = false }) {
1673 1674 1675
    if (!kReleaseMode && debugProfileLayoutsEnabled)
      Timeline.startSync('$runtimeType',  arguments: timelineArgumentsIndicatingLandmarkEvent);

1676
    assert(constraints != null);
1677 1678
    assert(constraints.debugAssertIsValid(
      isAppliedConstraint: true,
1679
      informationCollector: () sync* {
1680
        final List<String> stack = StackTrace.current.toString().split('\n');
1681
        int? targetFrame;
1682
        final Pattern layoutFramePattern = RegExp(r'^#[0-9]+ +RenderObject.layout \(');
1683 1684 1685 1686 1687 1688 1689
        for (int i = 0; i < stack.length; i += 1) {
          if (layoutFramePattern.matchAsPrefix(stack[i]) != null) {
            targetFrame = i + 1;
            break;
          }
        }
        if (targetFrame != null && targetFrame < stack.length) {
1690
          final Pattern targetFramePattern = RegExp(r'^#[0-9]+ +(.+)$');
1691 1692
          final Match? targetFrameMatch = targetFramePattern.matchAsPrefix(stack[targetFrame]);
          final String? problemFunction = (targetFrameMatch != null && targetFrameMatch.groupCount > 0) ? targetFrameMatch.group(1) : stack[targetFrame].trim();
1693 1694
          // TODO(jacobr): this case is similar to displaying a single stack frame.
          yield ErrorDescription(
1695
            "These invalid constraints were provided to $runtimeType's layout() "
1696
            'function by the following function, which probably computed the '
1697 1698
            'invalid constraints in question:\n'
            '  $problemFunction'
1699 1700
          );
        }
1701
      },
1702
    ));
Hixie's avatar
Hixie committed
1703 1704
    assert(!_debugDoingThisResize);
    assert(!_debugDoingThisLayout);
1705
    RenderObject? relayoutBoundary;
1706
    if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
1707
      relayoutBoundary = this;
1708
    } else {
1709
      relayoutBoundary = (parent! as RenderObject)._relayoutBoundary;
1710
    }
1711 1712 1713
    assert(() {
      _debugCanParentUseSize = parentUsesSize;
      return true;
1714
    }());
1715
    if (!_needsLayout && constraints == _constraints && relayoutBoundary == _relayoutBoundary) {
1716 1717 1718
      assert(() {
        // in case parentUsesSize changed since the last invocation, set size
        // to itself, so it has the right internal debug values.
Hixie's avatar
Hixie committed
1719 1720
        _debugDoingThisResize = sizedByParent;
        _debugDoingThisLayout = !sizedByParent;
1721
        final RenderObject? debugPreviousActiveLayout = _debugActiveLayout;
1722 1723 1724 1725
        _debugActiveLayout = this;
        debugResetSize();
        _debugActiveLayout = debugPreviousActiveLayout;
        _debugDoingThisLayout = false;
Hixie's avatar
Hixie committed
1726
        _debugDoingThisResize = false;
1727
        return true;
1728
      }());
1729 1730 1731

      if (!kReleaseMode && debugProfileLayoutsEnabled)
        Timeline.finishSync();
1732
      return;
1733
    }
1734
    _constraints = constraints;
1735 1736 1737 1738
    if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) {
      // The local relayout boundary has changed, must notify children in case
      // they also need updating. Otherwise, they will be confused about what
      // their actual relayout boundary is later.
1739
      visitChildren(_cleanChildRelayoutBoundary);
1740
    }
1741
    _relayoutBoundary = relayoutBoundary;
1742
    assert(!_debugMutationsLocked);
1743
    assert(!_doingThisLayoutWithCallback);
1744 1745
    assert(() {
      _debugMutationsLocked = true;
1746 1747
      if (debugPrintLayouts)
        debugPrint('Laying out (${sizedByParent ? "with separate resize" : "with resize allowed"}) $this');
1748
      return true;
1749
    }());
1750
    if (sizedByParent) {
1751 1752 1753 1754
      assert(() {
        _debugDoingThisResize = true;
        return true;
      }());
1755 1756
      try {
        performResize();
1757 1758 1759 1760
        assert(() {
          debugAssertDoesMeetConstraints();
          return true;
        }());
1761 1762 1763
      } catch (e, stack) {
        _debugReportException('performResize', e, stack);
      }
1764 1765 1766 1767
      assert(() {
        _debugDoingThisResize = false;
        return true;
      }());
1768
    }
1769
    RenderObject? debugPreviousActiveLayout;
1770 1771 1772 1773 1774
    assert(() {
      _debugDoingThisLayout = true;
      debugPreviousActiveLayout = _debugActiveLayout;
      _debugActiveLayout = this;
      return true;
1775
    }());
1776
    try {
1777
      performLayout();
Hixie's avatar
Hixie committed
1778
      markNeedsSemanticsUpdate();
1779 1780 1781 1782
      assert(() {
        debugAssertDoesMeetConstraints();
        return true;
      }());
1783 1784
    } catch (e, stack) {
      _debugReportException('performLayout', e, stack);
1785
    }
1786 1787 1788 1789 1790
    assert(() {
      _debugActiveLayout = debugPreviousActiveLayout;
      _debugDoingThisLayout = false;
      _debugMutationsLocked = false;
      return true;
1791
    }());
1792 1793
    _needsLayout = false;
    markNeedsPaint();
1794 1795 1796

    if (!kReleaseMode && debugProfileLayoutsEnabled)
      Timeline.finishSync();
1797
  }
1798

1799 1800 1801 1802 1803 1804
  /// If a subclass has a "size" (the state controlled by `parentUsesSize`,
  /// whatever it is in the subclass, e.g. the actual `size` property of
  /// [RenderBox]), and the subclass verifies that in checked mode this "size"
  /// property isn't used when [debugCanParentUseSize] isn't set, then that
  /// subclass should override [debugResetSize] to reapply the current values of
  /// [debugCanParentUseSize] to that state.
1805
  @protected
1806 1807
  void debugResetSize() { }

1808
  /// Whether the constraints are the only input to the sizing algorithm (in
1809
  /// particular, child nodes have no impact).
1810 1811 1812 1813
  ///
  /// Returning false is always correct, but returning true can be more
  /// efficient when computing the size of this render object because we don't
  /// need to recompute the size if the constraints don't change.
1814 1815 1816 1817
  ///
  /// Typically, subclasses will always return the same value. If the value can
  /// change, then, when it does change, the subclass should make sure to call
  /// [markNeedsLayoutForSizedByParentChange].
1818 1819 1820
  ///
  /// Subclasses that return true must not change the dimensions of this render
  /// object in [performLayout]. Instead, that work should be done by
1821 1822
  /// [performResize] or - for subclasses of [RenderBox] - in
  /// [RenderBox.computeDryLayout].
1823
  @protected
1824 1825
  bool get sizedByParent => false;

1826
  /// {@template flutter.rendering.RenderObject.performResize}
1827
  /// Updates the render objects size using only the constraints.
1828 1829 1830 1831 1832 1833
  ///
  /// Do not call this function directly: call [layout] instead. This function
  /// is called by [layout] when there is actually work to be done by this
  /// render object during layout. The layout constraints provided by your
  /// parent are available via the [constraints] getter.
  ///
1834
  /// This function is called only if [sizedByParent] is true.
1835 1836 1837 1838 1839
  /// {@endtemplate}
  ///
  /// Subclasses that set [sizedByParent] to true should override this method to
  /// compute their size. Subclasses of [RenderBox] should consider overriding
  /// [RenderBox.computeDryLayout] instead.
1840
  @protected
1841 1842
  void performResize();

1843
  /// Do the work of computing the layout for this render object.
1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
  ///
  /// Do not call this function directly: call [layout] instead. This function
  /// is called by [layout] when there is actually work to be done by this
  /// render object during layout. The layout constraints provided by your
  /// parent are available via the [constraints] getter.
  ///
  /// If [sizedByParent] is true, then this function should not actually change
  /// the dimensions of this render object. Instead, that work should be done by
  /// [performResize]. If [sizedByParent] is false, then this function should
  /// both change the dimensions of this render object and instruct its children
  /// to layout.
  ///
  /// In implementing this function, you must call [layout] on each of your
  /// children, passing true for parentUsesSize if your layout information is
  /// dependent on your child's layout information. Passing true for
  /// parentUsesSize ensures that this render object will undergo layout if the
1860
  /// child undergoes layout. Otherwise, the child can change its layout
1861
  /// information without informing this render object.
1862
  @protected
1863
  void performLayout();
1864

1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879
  /// Allows mutations to be made to this object's child list (and any
  /// descendants) as well as to any other dirty nodes in the render tree owned
  /// by the same [PipelineOwner] as this object. The `callback` argument is
  /// invoked synchronously, and the mutations are allowed only during that
  /// callback's execution.
  ///
  /// This exists to allow child lists to be built on-demand during layout (e.g.
  /// based on the object's size), and to enable nodes to be moved around the
  /// tree as this happens (e.g. to handle [GlobalKey] reparenting), while still
  /// ensuring that any particular node is only laid out once per frame.
  ///
  /// Calling this function disables a number of assertions that are intended to
  /// catch likely bugs. As such, using this function is generally discouraged.
  ///
  /// This function can only be called during layout.
1880
  @protected
1881
  void invokeLayoutCallback<T extends Constraints>(LayoutCallback<T> callback) {
1882 1883
    assert(_debugMutationsLocked);
    assert(_debugDoingThisLayout);
1884 1885 1886
    assert(!_doingThisLayoutWithCallback);
    _doingThisLayoutWithCallback = true;
    try {
1887
      owner!._enableMutationsToDirtySubtrees(() { callback(constraints as T); });
1888 1889 1890
    } finally {
      _doingThisLayoutWithCallback = false;
    }
1891 1892
  }

1893
  /// Rotate this render object (not yet implemented).
1894
  void rotate({
1895 1896 1897
    int? oldAngle, // 0..3
    int? newAngle, // 0..3
    Duration? time,
1898 1899
  }) { }

1900 1901 1902 1903 1904 1905 1906 1907
  // when the parent has rotated (e.g. when the screen has been turned
  // 90 degrees), immediately prior to layout() being called for the
  // new dimensions, rotate() is called with the old and new angles.
  // The next time paint() is called, the coordinate space will have
  // been rotated N quarter-turns clockwise, where:
  //    N = newAngle-oldAngle
  // ...but the rendering is expected to remain the same, pixel for
  // pixel, on the output device. Then, the layout() method or
1908
  // equivalent will be called.
1909 1910 1911 1912


  // PAINTING

1913 1914 1915 1916
  /// Whether [paint] for this render object is currently running.
  ///
  /// Only valid when asserts are enabled. In release builds, always returns
  /// false.
1917
  bool get debugDoingThisPaint => _debugDoingThisPaint;
1918 1919 1920 1921 1922 1923
  bool _debugDoingThisPaint = false;

  /// The render object that is actively painting.
  ///
  /// Only valid when asserts are enabled. In release builds, always returns
  /// null.
1924 1925
  static RenderObject? get debugActivePaint => _debugActivePaint;
  static RenderObject? _debugActivePaint;
1926

1927
  /// Whether this render object repaints separately from its parent.
1928
  ///
1929 1930 1931 1932 1933
  /// Override this in subclasses to indicate that instances of your class ought
  /// to repaint independently. For example, render objects that repaint
  /// frequently might want to repaint themselves without requiring their parent
  /// to repaint.
  ///
1934
  /// If this getter returns true, the [paintBounds] are applied to this object
1935 1936 1937 1938
  /// and all descendants. The framework automatically creates an [OffsetLayer]
  /// and assigns it to the [layer] field. Render objects that declare
  /// themselves as repaint boundaries must not replace the layer created by
  /// the framework.
1939
  ///
1940
  /// Warning: This getter must not change value over the lifetime of this object.
1941 1942
  ///
  /// See [RepaintBoundary] for more information about how repaint boundaries function.
1943 1944
  bool get isRepaintBoundary => false;

1945 1946 1947 1948 1949
  /// Called, in checked mode, if [isRepaintBoundary] is true, when either the
  /// this render object or its parent attempt to paint.
  ///
  /// This can be used to record metrics about whether the node should actually
  /// be a repaint boundary.
1950
  void debugRegisterRepaintBoundaryPaint({ bool includedParent = true, bool includedChild = false }) { }
1951

1952 1953 1954 1955
  /// Whether this render object always needs compositing.
  ///
  /// Override this in subclasses to indicate that your paint function always
  /// creates at least one composited layer. For example, videos should return
1956 1957
  /// true if they use hardware decoders.
  ///
1958 1959
  /// You must call [markNeedsCompositingBitsUpdate] if the value of this getter
  /// changes. (This is implied when [adoptChild] or [dropChild] are called.)
1960
  @protected
1961
  bool get alwaysNeedsCompositing => false;
1962

1963
  /// The compositing layer that this render object uses to repaint.
1964
  ///
1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
  /// If this render object is not a repaint boundary, it is the responsibility
  /// of the [paint] method to populate this field. If [needsCompositing] is
  /// true, this field may be populated with the root-most layer used by the
  /// render object implementation. When repainting, instead of creating a new
  /// layer the render object may update the layer stored in this field for better
  /// performance. It is also OK to leave this field as null and create a new
  /// layer on every repaint, but without the performance benefit. If
  /// [needsCompositing] is false, this field must be set to null either by
  /// never populating this field, or by setting it to null when the value of
  /// [needsCompositing] changes from true to false.
  ///
  /// If this render object is a repaint boundary, the framework automatically
  /// creates an [OffsetLayer] and populates this field prior to calling the
  /// [paint] method. The [paint] method must not replace the value of this
  /// field.
  @protected
1981
  ContainerLayer? get layer {
1982
    assert(!isRepaintBoundary || (_layer == null || _layer is OffsetLayer));
Hixie's avatar
Hixie committed
1983
    return _layer;
1984
  }
1985 1986

  @protected
1987
  set layer(ContainerLayer? newLayer) {
1988 1989 1990 1991 1992 1993 1994 1995
    assert(
      !isRepaintBoundary,
      'Attempted to set a layer to a repaint boundary render object.\n'
      'The framework creates and assigns an OffsetLayer to a repaint '
      'boundary automatically.',
    );
    _layer = newLayer;
  }
1996
  ContainerLayer? _layer;
1997

1998 1999 2000 2001 2002 2003 2004
  /// In debug mode, the compositing layer that this render object uses to repaint.
  ///
  /// This getter is intended for debugging purposes only. In release builds, it
  /// always returns null. In debug builds, it returns the layer even if the layer
  /// is dirty.
  ///
  /// For production code, consider [layer].
2005 2006
  ContainerLayer? get debugLayer {
    ContainerLayer? result;
2007 2008 2009
    assert(() {
      result = _layer;
      return true;
2010
    }());
2011 2012
    return result;
  }
2013

2014
  bool _needsCompositingBitsUpdate = false; // set to true when a child is added
2015
  /// Mark the compositing state for this render object as dirty.
2016
  ///
2017
  /// This is called to indicate that the value for [needsCompositing] needs to
2018 2019
  /// be recomputed during the next [PipelineOwner.flushCompositingBits] engine
  /// phase.
2020
  ///
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
  /// When the subtree is mutated, we need to recompute our
  /// [needsCompositing] bit, and some of our ancestors need to do the
  /// same (in case ours changed in a way that will change theirs). To
  /// this end, [adoptChild] and [dropChild] call this method, and, as
  /// necessary, this method calls the parent's, etc, walking up the
  /// tree to mark all the nodes that need updating.
  ///
  /// This method does not schedule a rendering frame, because since
  /// it cannot be the case that _only_ the compositing bits changed,
  /// something else will have scheduled a frame for us.
2031
  void markNeedsCompositingBitsUpdate() {
Hixie's avatar
Hixie committed
2032
    if (_needsCompositingBitsUpdate)
2033
      return;
Hixie's avatar
Hixie committed
2034
    _needsCompositingBitsUpdate = true;
2035
    if (parent is RenderObject) {
2036
      final RenderObject parent = this.parent! as RenderObject;
2037 2038
      if (parent._needsCompositingBitsUpdate)
        return;
2039
      if (!isRepaintBoundary && !parent.isRepaintBoundary) {
2040
        parent.markNeedsCompositingBitsUpdate();
2041 2042 2043 2044
        return;
      }
    }
    assert(() {
2045
      final AbstractNode? parent = this.parent;
2046 2047 2048
      if (parent is RenderObject)
        return parent._needsCompositing;
      return true;
2049
    }());
2050
    // parent is fine (or there isn't one), but we are dirty
2051
    if (owner != null)
2052
      owner!._nodesNeedingCompositingBitsUpdate.add(this);
2053 2054
  }

2055
  late bool _needsCompositing; // initialized in the constructor
2056
  /// Whether we or one of our descendants has a compositing layer.
2057
  ///
2058 2059 2060
  /// If this node needs compositing as indicated by this bit, then all ancestor
  /// nodes will also need compositing.
  ///
2061 2062
  /// Only legal to call after [PipelineOwner.flushLayout] and
  /// [PipelineOwner.flushCompositingBits] have been called.
Hixie's avatar
Hixie committed
2063 2064 2065 2066
  bool get needsCompositing {
    assert(!_needsCompositingBitsUpdate); // make sure we don't use this bit when it is dirty
    return _needsCompositing;
  }
2067

2068
  void _updateCompositingBits() {
Hixie's avatar
Hixie committed
2069
    if (!_needsCompositingBitsUpdate)
2070
      return;
2071
    final bool oldNeedsCompositing = _needsCompositing;
2072
    _needsCompositing = false;
2073
    visitChildren((RenderObject child) {
2074
      child._updateCompositingBits();
Hixie's avatar
Hixie committed
2075 2076
      if (child.needsCompositing)
        _needsCompositing = true;
2077
    });
2078
    if (isRepaintBoundary || alwaysNeedsCompositing)
Hixie's avatar
Hixie committed
2079
      _needsCompositing = true;
2080
    if (oldNeedsCompositing != _needsCompositing)
Hixie's avatar
Hixie committed
2081 2082
      markNeedsPaint();
    _needsCompositingBitsUpdate = false;
2083 2084
  }

2085 2086 2087 2088 2089
  /// Whether this render object's paint information is dirty.
  ///
  /// This is only set in debug mode. In general, render objects should not need
  /// to condition their runtime behavior on whether they are dirty or not,
  /// since they should only be marked dirty immediately prior to being laid
2090
  /// out and painted. (In release builds, this throws.)
2091 2092 2093 2094 2095 2096 2097 2098 2099
  ///
  /// It is intended to be used by tests and asserts.
  ///
  /// It is possible (and indeed, quite common) for [debugNeedsPaint] to be
  /// false and [debugNeedsLayout] to be true. The render object will still be
  /// repainted in the next frame when this is the case, because the
  /// [markNeedsPaint] method is implicitly called by the framework after a
  /// render object is laid out, prior to the paint phase.
  bool get debugNeedsPaint {
2100
    late bool result;
2101 2102 2103
    assert(() {
      result = _needsPaint;
      return true;
2104
    }());
2105 2106
    return result;
  }
2107
  bool _needsPaint = true;
2108

2109
  /// Mark this render object as having changed its visual appearance.
2110 2111
  ///
  /// Rather than eagerly updating this render object's display list
2112
  /// in response to writes, we instead mark the render object as needing to
2113 2114 2115 2116 2117 2118
  /// paint, which schedules a visual update. As part of the visual update, the
  /// rendering pipeline will give this render object an opportunity to update
  /// its display list.
  ///
  /// This mechanism batches the painting work so that multiple sequential
  /// writes are coalesced, removing redundant computation.
2119 2120 2121 2122
  ///
  /// Once [markNeedsPaint] has been called on a render object,
  /// [debugNeedsPaint] returns true for that render object until just after
  /// the pipeline owner has called [paint] on the render object.
2123 2124 2125 2126 2127 2128
  ///
  /// See also:
  ///
  ///  * [RepaintBoundary], to scope a subtree of render objects to their own
  ///    layer, thus limiting the number of nodes that [markNeedsPaint] must mark
  ///    dirty.
2129
  void markNeedsPaint() {
2130
    assert(owner == null || !owner!.debugDoingPaint);
2131 2132 2133
    if (_needsPaint)
      return;
    _needsPaint = true;
2134
    if (isRepaintBoundary) {
2135 2136
      assert(() {
        if (debugPrintMarkNeedsPaintStacks)
2137
          debugPrintStack(label: 'markNeedsPaint() called for $this');
2138
        return true;
2139
      }());
Hixie's avatar
Hixie committed
2140 2141
      // If we always have our own layer, then we can just repaint
      // ourselves without involving any other nodes.
2142
      assert(_layer is OffsetLayer);
2143
      if (owner != null) {
2144 2145
        owner!._nodesNeedingPaint.add(this);
        owner!.requestVisualUpdate();
2146
      }
Hixie's avatar
Hixie committed
2147
    } else if (parent is RenderObject) {
2148
      final RenderObject parent = this.parent! as RenderObject;
Hixie's avatar
Hixie committed
2149 2150
      parent.markNeedsPaint();
      assert(parent == this.parent);
Hixie's avatar
Hixie committed
2151
    } else {
2152 2153 2154 2155
      assert(() {
        if (debugPrintMarkNeedsPaintStacks)
          debugPrintStack(label: 'markNeedsPaint() called for $this (root of render tree)');
        return true;
2156
      }());
Hixie's avatar
Hixie committed
2157 2158 2159 2160
      // If we're the root of the render tree (probably a RenderView),
      // then we have to paint ourselves, since nobody else can paint
      // us. We don't add ourselves to _nodesNeedingPaint in this
      // case, because the root is always told to paint regardless.
2161
      if (owner != null)
2162
        owner!.requestVisualUpdate();
2163 2164
    }
  }
2165

2166 2167 2168 2169 2170 2171 2172 2173 2174 2175
  // Called when flushPaint() tries to make us paint but our layer is detached.
  // To make sure that our subtree is repainted when it's finally reattached,
  // even in the case where some ancestor layer is itself never marked dirty, we
  // have to mark our entire detached subtree as dirty and needing to be
  // repainted. That way, we'll eventually be repainted.
  void _skippedPaintingOnLayer() {
    assert(attached);
    assert(isRepaintBoundary);
    assert(_needsPaint);
    assert(_layer != null);
2176 2177 2178
    assert(!_layer!.attached);
    AbstractNode? node = parent;
    while (node is RenderObject) {
2179 2180 2181
      if (node.isRepaintBoundary) {
        if (node._layer == null)
          break; // looks like the subtree here has never been painted. let it handle itself.
2182
        if (node._layer!.attached)
2183 2184 2185
          break; // it's the one that detached us, so it's the one that will decide to repaint us.
        node._needsPaint = true;
      }
2186
      node = node.parent;
2187 2188 2189
    }
  }

2190
  /// Bootstrap the rendering pipeline by scheduling the very first paint.
2191 2192 2193 2194 2195
  ///
  /// Requires that this render object is attached, is the root of the render
  /// tree, and has a composited layer.
  ///
  /// See [RenderView] for an example of how this function is used.
2196
  void scheduleInitialPaint(ContainerLayer rootLayer) {
2197
    assert(rootLayer.attached);
Hixie's avatar
Hixie committed
2198 2199
    assert(attached);
    assert(parent is! RenderObject);
2200
    assert(!owner!._debugDoingPaint);
2201
    assert(isRepaintBoundary);
2202
    assert(_layer == null);
2203 2204
    _layer = rootLayer;
    assert(_needsPaint);
2205
    owner!._nodesNeedingPaint.add(this);
Hixie's avatar
Hixie committed
2206
  }
2207 2208 2209 2210 2211 2212

  /// Replace the layer. This is only valid for the root of a render
  /// object subtree (whatever object [scheduleInitialPaint] was
  /// called on).
  ///
  /// This might be called if, e.g., the device pixel ratio changed.
2213
  void replaceRootLayer(OffsetLayer rootLayer) {
2214
    assert(rootLayer.attached);
2215 2216
    assert(attached);
    assert(parent is! RenderObject);
2217
    assert(!owner!._debugDoingPaint);
2218 2219
    assert(isRepaintBoundary);
    assert(_layer != null); // use scheduleInitialPaint the first time
2220
    _layer!.detach();
2221 2222 2223 2224
    _layer = rootLayer;
    markNeedsPaint();
  }

2225
  void _paintWithContext(PaintingContext context, Offset offset) {
2226 2227
    assert(() {
      if (_debugDoingThisPaint) {
2228 2229 2230 2231 2232 2233 2234 2235 2236
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('Tried to paint a RenderObject reentrantly.'),
          describeForError(
            'The following RenderObject was already being painted when it was '
            'painted again'
          ),
          ErrorDescription(
            'Since this typically indicates an infinite recursion, it is '
            'disallowed.'
2237
          ),
2238
        ]);
2239
      }
2240
      return true;
2241
    }());
2242 2243 2244 2245 2246
    // If we still need layout, then that means that we were skipped in the
    // layout phase and therefore don't need painting. We might not know that
    // yet (that is, our layer might not have been detached yet), because the
    // same node that skipped us in layout is above us in the tree (obviously)
    // and therefore may not have had a chance to paint yet (since the tree
2247
    // paints in reverse order). In particular this will happen if they have
2248 2249 2250 2251
    // a different layer, because there's a repaint boundary between us.
    if (_needsLayout)
      return;
    assert(() {
2252
      if (_needsCompositingBitsUpdate) {
2253
        if (parent is RenderObject) {
2254
          final RenderObject parent = this.parent! as RenderObject;
2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283
          bool visitedByParent = false;
          parent.visitChildren((RenderObject child) {
            if (child == this) {
              visitedByParent = true;
            }
          });
          if (!visitedByParent) {
            throw FlutterError.fromParts(<DiagnosticsNode>[
              ErrorSummary(
                "A RenderObject was not visited by the parent's visitChildren "
                'during paint.',
              ),
              parent.describeForError(
                'The parent was',
              ),
              describeForError(
                'The child that was not visited was'
              ),
              ErrorDescription(
                'A RenderObject with children must implement visitChildren and '
                'call the visitor exactly once for each child; it also should not '
                'paint children that were removed with dropChild.'
              ),
              ErrorHint(
                'This usually indicates an error in the Flutter framework itself.'
              ),
            ]);
          }
        }
2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary(
            'Tried to paint a RenderObject before its compositing bits were '
            'updated.'
          ),
          describeForError(
            'The following RenderObject was marked as having dirty compositing '
            'bits at the time that it was painted',
          ),
          ErrorDescription(
            'A RenderObject that still has dirty compositing bits cannot be '
            'painted because this indicates that the tree has not yet been '
            'properly configured for creating the layer tree.'
          ),
          ErrorHint(
            'This usually indicates an error in the Flutter framework itself.'
2300
          ),
2301
        ]);
2302 2303
      }
      return true;
2304
    }());
2305
    RenderObject? debugLastActivePaint;
2306 2307 2308 2309
    assert(() {
      _debugDoingThisPaint = true;
      debugLastActivePaint = _debugActivePaint;
      _debugActivePaint = this;
2310
      assert(!isRepaintBoundary || _layer != null);
2311
      return true;
2312
    }());
Hixie's avatar
Hixie committed
2313
    _needsPaint = false;
2314 2315 2316 2317 2318 2319 2320
    try {
      paint(context, offset);
      assert(!_needsLayout); // check that the paint() method didn't mark us dirty again
      assert(!_needsPaint); // check that the paint() method didn't mark us dirty again
    } catch (e, stack) {
      _debugReportException('paint', e, stack);
    }
2321
    assert(() {
2322
      debugPaint(context, offset);
2323 2324 2325
      _debugActivePaint = debugLastActivePaint;
      _debugDoingThisPaint = false;
      return true;
2326
    }());
2327 2328
  }

2329 2330
  /// An estimate of the bounds within which this render object will paint.
  /// Useful for debugging flags such as [debugPaintLayerBordersEnabled].
2331 2332 2333
  ///
  /// These are also the bounds used by [showOnScreen] to make a [RenderObject]
  /// visible on screen.
2334
  Rect get paintBounds;
2335

2336
  /// Override this method to paint debugging information.
2337
  void debugPaint(PaintingContext context, Offset offset) { }
2338

2339
  /// Paint this render object into the given context at the given offset.
2340
  ///
2341
  /// Subclasses should override this method to provide a visual appearance
2342 2343 2344 2345 2346 2347 2348
  /// for themselves. The render object's local coordinate system is
  /// axis-aligned with the coordinate system of the context's canvas and the
  /// render object's local origin (i.e, x=0 and y=0) is placed at the given
  /// offset in the context's canvas.
  ///
  /// Do not call this function directly. If you wish to paint yourself, call
  /// [markNeedsPaint] instead to schedule a call to this function. If you wish
2349 2350
  /// to paint one of your children, call [PaintingContext.paintChild] on the
  /// given `context`.
2351 2352 2353 2354 2355
  ///
  /// When painting one of your children (via a paint child function on the
  /// given context), the current canvas held by the context might change
  /// because draw operations before and after painting children might need to
  /// be recorded on separate compositing layers.
2356
  void paint(PaintingContext context, Offset offset) { }
2357

2358 2359
  /// Applies the transform that would be applied when painting the given child
  /// to the given matrix.
2360
  ///
2361
  /// Used by coordinate conversion functions to translate coordinates local to
2362
  /// one render object into coordinates local to another render object.
2363
  void applyPaintTransform(covariant RenderObject child, Matrix4 transform) {
2364 2365
    assert(child.parent == this);
  }
2366

2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
  /// Applies the paint transform up the tree to `ancestor`.
  ///
  /// Returns a matrix that maps the local paint coordinate system to the
  /// coordinate system of `ancestor`.
  ///
  /// If `ancestor` is null, this method returns a matrix that maps from the
  /// local paint coordinate system to the coordinate system of the
  /// [PipelineOwner.rootNode]. For the render tree owner by the
  /// [RendererBinding] (i.e. for the main render tree displayed on the device)
  /// this means that this method maps to the global coordinate system in
  /// logical pixels. To get physical pixels, use [applyPaintTransform] from the
  /// [RenderView] to further transform the coordinate.
2379
  Matrix4 getTransformTo(RenderObject? ancestor) {
2380
    final bool ancestorSpecified = ancestor != null;
2381 2382
    assert(attached);
    if (ancestor == null) {
2383
      final AbstractNode? rootNode = owner!.rootNode;
2384 2385 2386 2387
      if (rootNode is RenderObject)
        ancestor = rootNode;
    }
    final List<RenderObject> renderers = <RenderObject>[];
2388
    for (RenderObject renderer = this; renderer != ancestor; renderer = renderer.parent! as RenderObject) {
2389 2390 2391
      assert(renderer != null); // Failed to find ancestor in parent chain.
      renderers.add(renderer);
    }
2392
    if (ancestorSpecified)
2393
      renderers.add(ancestor!);
2394
    final Matrix4 transform = Matrix4.identity();
2395
    for (int index = renderers.length - 1; index > 0; index -= 1) {
2396
      renderers[index].applyPaintTransform(renderers[index - 1], transform);
2397
    }
2398 2399 2400 2401
    return transform;
  }


Hixie's avatar
Hixie committed
2402 2403 2404 2405
  /// Returns a rect in this object's coordinate system that describes
  /// the approximate bounding box of the clip rect that would be
  /// applied to the given child during the paint phase, if any.
  ///
2406
  /// Returns null if the child would not be clipped.
Hixie's avatar
Hixie committed
2407 2408 2409
  ///
  /// This is used in the semantics phase to avoid including children
  /// that are not physically visible.
2410
  Rect? describeApproximatePaintClip(covariant RenderObject child) => null;
Hixie's avatar
Hixie committed
2411

2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431
  /// Returns a rect in this object's coordinate system that describes
  /// which [SemanticsNode]s produced by the `child` should be included in the
  /// semantics tree. [SemanticsNode]s from the `child` that are positioned
  /// outside of this rect will be dropped. Child [SemanticsNode]s that are
  /// positioned inside this rect, but outside of [describeApproximatePaintClip]
  /// will be included in the tree marked as hidden. Child [SemanticsNode]s
  /// that are inside of both rect will be included in the tree as regular
  /// nodes.
  ///
  /// This method only returns a non-null value if the semantics clip rect
  /// is different from the rect returned by [describeApproximatePaintClip].
  /// If the semantics clip rect and the paint clip rect are the same, this
  /// method returns null.
  ///
  /// A viewport would typically implement this method to include semantic nodes
  /// in the semantics tree that are currently hidden just before the leading
  /// or just after the trailing edge. These nodes have to be included in the
  /// semantics tree to implement implicit accessibility scrolling on iOS where
  /// the viewport scrolls implicitly when moving the accessibility focus from
  /// a the last visible node in the viewport to the first hidden one.
2432 2433 2434 2435 2436
  ///
  /// See also:
  ///
  /// * [RenderViewportBase.cacheExtent], used by viewports to extend their
  ///   semantics clip beyond their approximate paint clip.
2437
  Rect? describeSemanticsClip(covariant RenderObject? child) => null;
Hixie's avatar
Hixie committed
2438 2439 2440 2441 2442 2443 2444 2445 2446

  // SEMANTICS

  /// Bootstrap the semantics reporting mechanism by marking this node
  /// as needing a semantics update.
  ///
  /// Requires that this render object is attached, and is the root of
  /// the render tree.
  ///
2447
  /// See [RendererBinding] for an example of how this function is used.
Hixie's avatar
Hixie committed
2448 2449 2450
  void scheduleInitialSemantics() {
    assert(attached);
    assert(parent is! RenderObject);
2451
    assert(!owner!._debugDoingSemantics);
Hixie's avatar
Hixie committed
2452 2453
    assert(_semantics == null);
    assert(_needsSemanticsUpdate);
2454 2455 2456
    assert(owner!._semanticsOwner != null);
    owner!._nodesNeedingSemantics.add(this);
    owner!.requestVisualUpdate();
Hixie's avatar
Hixie committed
2457 2458
  }

2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
  /// Report the semantics of this node, for example for accessibility purposes.
  ///
  /// This method should be overridden by subclasses that have interesting
  /// semantic information.
  ///
  /// The given [SemanticsConfiguration] object is mutable and should be
  /// annotated in a manner that describes the current state. No reference
  /// should be kept to that object; mutating it outside of the context of the
  /// [describeSemanticsConfiguration] call (for example as a result of
  /// asynchronous computation) will at best have no useful effect and at worse
  /// will cause crashes as the data will be in an inconsistent state.
2470
  ///
2471
  /// {@tool snippet}
2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
  ///
  /// The following snippet will describe the node as a button that responds to
  /// tap actions.
  ///
  /// ```dart
  /// abstract class SemanticButtonRenderObject extends RenderObject {
  ///   @override
  ///   void describeSemanticsConfiguration(SemanticsConfiguration config) {
  ///     super.describeSemanticsConfiguration(config);
  ///     config
2482
  ///       ..onTap = _handleTap
2483 2484 2485 2486 2487 2488 2489 2490 2491
  ///       ..label = 'I am a button'
  ///       ..isButton = true;
  ///   }
  ///
  ///   void _handleTap() {
  ///     // Do something.
  ///   }
  /// }
  /// ```
2492
  /// {@end-tool}
2493
  @protected
2494
  void describeSemanticsConfiguration(SemanticsConfiguration config) {
2495 2496
    // Nothing to do by default.
  }
Hixie's avatar
Hixie committed
2497

2498 2499 2500 2501 2502 2503 2504 2505 2506
  /// Sends a [SemanticsEvent] associated with this render object's [SemanticsNode].
  ///
  /// If this render object has no semantics information, the first parent
  /// render object with a non-null semantic node is used.
  ///
  /// If semantics are disabled, no events are dispatched.
  ///
  /// See [SemanticsNode.sendEvent] for a full description of the behavior.
  void sendSemanticsEvent(SemanticsEvent semanticsEvent) {
2507
    if (owner!.semanticsOwner == null)
2508
      return;
2509 2510
    if (_semantics != null && !_semantics!.isMergedIntoParent) {
      _semantics!.sendEvent(semanticsEvent);
2511
    } else if (parent != null) {
2512
      final RenderObject renderParent = parent! as RenderObject;
2513 2514 2515 2516
      renderParent.sendSemanticsEvent(semanticsEvent);
    }
  }

2517
  // Use [_semanticsConfiguration] to access.
2518
  SemanticsConfiguration? _cachedSemanticsConfiguration;
2519

2520 2521
  SemanticsConfiguration get _semanticsConfiguration {
    if (_cachedSemanticsConfiguration == null) {
2522
      _cachedSemanticsConfiguration = SemanticsConfiguration();
2523
      describeSemanticsConfiguration(_cachedSemanticsConfiguration!);
2524
    }
2525
    return _cachedSemanticsConfiguration!;
2526
  }
2527

Hixie's avatar
Hixie committed
2528 2529 2530 2531 2532
  /// The bounding box, in the local coordinate system, of this
  /// object, for accessibility purposes.
  Rect get semanticBounds;

  bool _needsSemanticsUpdate = true;
2533
  SemanticsNode? _semantics;
Hixie's avatar
Hixie committed
2534

2535 2536 2537
  /// The semantics of this render object.
  ///
  /// Exposed only for testing and debugging. To learn about the semantics of
2538 2539
  /// render objects in production, obtain a [SemanticsHandle] from
  /// [PipelineOwner.ensureSemantics].
2540
  ///
2541
  /// Only valid in debug and profile mode. In release builds, always returns
2542
  /// null.
2543
  SemanticsNode? get debugSemantics {
2544 2545 2546 2547
    if (!kReleaseMode) {
      return _semantics;
    }
    return null;
Hixie's avatar
Hixie committed
2548 2549
  }

2550
  /// Removes all semantics from this render object and its descendants.
2551 2552
  ///
  /// Should only be called on objects whose [parent] is not a [RenderObject].
2553 2554 2555 2556
  ///
  /// Override this method if you instantiate new [SemanticsNode]s in an
  /// overridden [assembleSemanticsNode] method, to dispose of those nodes.
  @mustCallSuper
2557
  void clearSemantics() {
2558 2559 2560
    _needsSemanticsUpdate = true;
    _semantics = null;
    visitChildren((RenderObject child) {
2561
      child.clearSemantics();
2562 2563 2564
    });
  }

2565 2566
  /// Mark this node as needing an update to its semantics description.
  ///
2567 2568 2569 2570
  /// This must be called whenever the semantics configuration of this
  /// [RenderObject] as annotated by [describeSemanticsConfiguration] changes in
  /// any way to update the semantics tree.
  void markNeedsSemanticsUpdate() {
2571 2572
    assert(!attached || !owner!._debugDoingSemantics);
    if (!attached || owner!._semanticsOwner == null) {
2573
      _cachedSemanticsConfiguration = null;
Hixie's avatar
Hixie committed
2574
      return;
2575
    }
2576 2577 2578 2579

    // Dirty the semantics tree starting at `this` until we have reached a
    // RenderObject that is a semantics boundary. All semantics past this
    // RenderObject are still up-to date. Therefore, we will later only rebuild
2580
    // the semantics subtree starting at the identified semantics boundary.
2581

2582
    final bool wasSemanticsBoundary = _semantics != null && _cachedSemanticsConfiguration?.isSemanticBoundary == true;
2583 2584 2585 2586 2587 2588 2589 2590 2591
    _cachedSemanticsConfiguration = null;
    bool isEffectiveSemanticsBoundary = _semanticsConfiguration.isSemanticBoundary && wasSemanticsBoundary;
    RenderObject node = this;

    while (!isEffectiveSemanticsBoundary && node.parent is RenderObject) {
      if (node != this && node._needsSemanticsUpdate)
        break;
      node._needsSemanticsUpdate = true;

2592
      node = node.parent! as RenderObject;
2593
      isEffectiveSemanticsBoundary = node._semanticsConfiguration.isSemanticBoundary;
2594 2595 2596 2597 2598 2599
      if (isEffectiveSemanticsBoundary && node._semantics == null) {
        // We have reached a semantics boundary that doesn't own a semantics node.
        // That means the semantics of this branch are currently blocked and will
        // not appear in the semantics tree. We can abort the walk here.
        return;
      }
2600 2601 2602 2603 2604 2605
    }
    if (node != this && _semantics != null && _needsSemanticsUpdate) {
      // If `this` node has already been added to [owner._nodesNeedingSemantics]
      // remove it as it is no longer guaranteed that its semantics
      // node will continue to be in the tree. If it still is in the tree, the
      // ancestor `node` added to [owner._nodesNeedingSemantics] at the end of
2606
      // this block will ensure that the semantics of `this` node actually gets
2607 2608
      // updated.
      // (See semantics_10_test.dart for an example why this is required).
2609
      owner!._nodesNeedingSemantics.remove(this);
2610 2611 2612 2613 2614
    }
    if (!node._needsSemanticsUpdate) {
      node._needsSemanticsUpdate = true;
      if (owner != null) {
        assert(node._semanticsConfiguration.isSemanticBoundary || node.parent is! RenderObject);
2615 2616
        owner!._nodesNeedingSemantics.add(node);
        owner!.requestVisualUpdate();
2617
      }
Hixie's avatar
Hixie committed
2618 2619 2620
    }
  }

2621
  /// Updates the semantic information of the render object.
Hixie's avatar
Hixie committed
2622
  void _updateSemantics() {
2623
    assert(_semanticsConfiguration.isSemanticBoundary || parent is! RenderObject);
2624 2625 2626 2627 2628
    if (_needsLayout) {
      // There's not enough information in this subtree to compute semantics.
      // The subtree is probably being kept alive by a viewport but not laid out.
      return;
    }
2629 2630 2631 2632
    final _SemanticsFragment fragment = _getSemanticsForParent(
      mergeIntoParent: _semantics?.parent?.isPartOfNodeMerging ?? false,
    );
    assert(fragment is _InterestingSemanticsFragment);
2633
    final _InterestingSemanticsFragment interestingFragment = fragment as _InterestingSemanticsFragment;
2634 2635
    final List<SemanticsNode> result = <SemanticsNode>[];
    interestingFragment.compileChildren(
2636 2637
      parentSemanticsClipRect: _semantics?.parentSemanticsClipRect,
      parentPaintClipRect: _semantics?.parentPaintClipRect,
2638
      elevationAdjustment: _semantics?.elevationAdjustment ?? 0.0,
2639 2640 2641
      result: result,
    );
    final SemanticsNode node = result.single;
2642 2643
    // Fragment only wants to add this node's SemanticsNode to the parent.
    assert(interestingFragment.config == null && node == _semantics);
Hixie's avatar
Hixie committed
2644 2645
  }

2646 2647
  /// Returns the semantics that this node would like to add to its parent.
  _SemanticsFragment _getSemanticsForParent({
2648
    required bool mergeIntoParent,
2649 2650
  }) {
    assert(mergeIntoParent != null);
2651
    assert(!_needsLayout, 'Updated layout information required for $this to calculate semantics.');
2652 2653 2654 2655 2656 2657

    final SemanticsConfiguration config = _semanticsConfiguration;
    bool dropSemanticsOfPreviousSiblings = config.isBlockingSemanticsOfPreviouslyPaintedNodes;

    final bool producesForkingFragment = !config.hasBeenAnnotated && !config.isSemanticBoundary;
    final List<_InterestingSemanticsFragment> fragments = <_InterestingSemanticsFragment>[];
2658
    final Set<_InterestingSemanticsFragment> toBeMarkedExplicit = <_InterestingSemanticsFragment>{};
2659 2660
    final bool childrenMergeIntoParent = mergeIntoParent || config.isMergingSemanticsOfDescendants;

2661 2662 2663 2664 2665 2666 2667
    // When set to true there's currently not enough information in this subtree
    // to compute semantics. In this case the walk needs to be aborted and no
    // SemanticsNodes in the subtree should be updated.
    // This will be true for subtrees that are currently kept alive by a
    // viewport but not laid out.
    bool abortWalk = false;

2668
    visitChildrenForSemantics((RenderObject renderChild) {
2669 2670 2671 2672
      if (abortWalk || _needsLayout) {
        abortWalk = true;
        return;
      }
2673
      final _SemanticsFragment parentFragment = renderChild._getSemanticsForParent(
2674 2675
        mergeIntoParent: childrenMergeIntoParent,
      );
2676 2677 2678 2679
      if (parentFragment.abortsWalk) {
        abortWalk = true;
        return;
      }
2680
      if (parentFragment.dropsSemanticsOfPreviousSiblings) {
2681 2682 2683 2684
        fragments.clear();
        toBeMarkedExplicit.clear();
        if (!config.isSemanticBoundary)
          dropSemanticsOfPreviousSiblings = true;
2685
      }
2686
      // Figure out which child fragments are to be made explicit.
2687
      for (final _InterestingSemanticsFragment fragment in parentFragment.interestingFragments) {
2688
        fragments.add(fragment);
2689
        fragment.addAncestor(this);
2690 2691 2692 2693 2694 2695 2696 2697 2698
        fragment.addTags(config.tagsForChildren);
        if (config.explicitChildNodes || parent is! RenderObject) {
          fragment.markAsExplicit();
          continue;
        }
        if (!fragment.hasConfigForParent || producesForkingFragment)
          continue;
        if (!config.isCompatibleWith(fragment.config))
          toBeMarkedExplicit.add(fragment);
2699 2700 2701
        final int siblingLength = fragments.length - 1;
        for (int i = 0; i < siblingLength; i += 1) {
          final _InterestingSemanticsFragment siblingFragment = fragments[i];
2702
          if (!fragment.config!.isCompatibleWith(siblingFragment.config)) {
2703 2704 2705 2706
            toBeMarkedExplicit.add(fragment);
            toBeMarkedExplicit.add(siblingFragment);
          }
        }
Hixie's avatar
Hixie committed
2707 2708
      }
    });
2709

2710 2711 2712 2713
    if (abortWalk) {
      return _AbortingSemanticsFragment(owner: this);
    }

2714
    for (final _InterestingSemanticsFragment fragment in toBeMarkedExplicit)
2715 2716
      fragment.markAsExplicit();

Hixie's avatar
Hixie committed
2717
    _needsSemanticsUpdate = false;
2718 2719

    _SemanticsFragment result;
2720
    if (parent is! RenderObject) {
2721
      assert(!config.hasBeenAnnotated);
2722
      assert(!mergeIntoParent);
2723
      result = _RootSemanticsFragment(
2724 2725
        owner: this,
        dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
2726
      );
2727
    } else if (producesForkingFragment) {
2728
      result = _ContainerSemanticsFragment(
2729
        dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
2730
      );
2731
    } else {
2732
      result = _SwitchableSemanticsFragment(
2733 2734 2735 2736
        config: config,
        mergeIntoParent: mergeIntoParent,
        owner: this,
        dropsSemanticsOfPreviousSiblings: dropSemanticsOfPreviousSiblings,
2737
      );
2738
      if (config.isSemanticBoundary) {
2739
        final _SwitchableSemanticsFragment fragment = result as _SwitchableSemanticsFragment;
2740 2741
        fragment.markAsExplicit();
      }
2742
    }
2743 2744 2745 2746

    result.addAll(fragments);

    return result;
Hixie's avatar
Hixie committed
2747 2748
  }

2749 2750 2751 2752 2753
  /// Called when collecting the semantics of this node.
  ///
  /// The implementation has to return the children in paint order skipping all
  /// children that are not semantically relevant (e.g. because they are
  /// invisible).
Hixie's avatar
Hixie committed
2754 2755
  ///
  /// The default implementation mirrors the behavior of
2756
  /// [visitChildren] (which is supposed to walk all the children).
Hixie's avatar
Hixie committed
2757 2758 2759 2760
  void visitChildrenForSemantics(RenderObjectVisitor visitor) {
    visitChildren(visitor);
  }

2761 2762
  /// Assemble the [SemanticsNode] for this [RenderObject].
  ///
2763 2764 2765 2766 2767
  /// If [describeSemanticsConfiguration] sets
  /// [SemanticsConfiguration.isSemanticBoundary] to true, this method is called
  /// with the `node` created for this [RenderObject], the `config` to be
  /// applied to that node and the `children` [SemanticsNode]s that descendants
  /// of this RenderObject have generated.
2768 2769 2770
  ///
  /// By default, the method will annotate `node` with `config` and add the
  /// `children` to it.
2771
  ///
2772
  /// Subclasses can override this method to add additional [SemanticsNode]s
2773 2774
  /// to the tree. If new [SemanticsNode]s are instantiated in this method
  /// they must be disposed in [clearSemantics].
2775
  void assembleSemanticsNode(
2776 2777 2778
    SemanticsNode node,
    SemanticsConfiguration config,
    Iterable<SemanticsNode> children,
2779
  ) {
2780
    assert(node == _semantics);
2781 2782
    // TODO(a14n): remove the following cast by updating type of parameter in either updateWith or assembleSemanticsNode
    node.updateWith(config: config, childrenInInversePaintOrder: children as List<SemanticsNode>);
2783
  }
2784 2785 2786

  // EVENTS

2787
  /// Override this method to handle pointer events that hit this render object.
2788
  @override
2789
  void handleEvent(PointerEvent event, covariant HitTestEntry entry) { }
2790 2791 2792 2793


  // HIT TESTING

2794 2795 2796 2797
  // RenderObject subclasses are expected to have a method like the following
  // (with the signature being whatever passes for coordinates for this
  // particular class):
  //
2798
  // bool hitTest(HitTestResult result, { Offset position }) {
2799
  //   // If the given position is not inside this node, then return false.
2800
  //   // Otherwise:
2801 2802 2803 2804
  //   // For each child that intersects the position, in z-order starting from
  //   // the top, call hitTest() for that child, passing it /result/, and the
  //   // coordinates converted to the child's coordinate origin, and stop at
  //   // the first child that returns true.
2805 2806
  //   // Then, add yourself to /result/, and return true.
  // }
2807 2808 2809
  //
  // If you add yourself to /result/ and still return false, then that means you
  // will see events but so will objects below you.
2810 2811


2812
  /// Returns a human understandable name.
2813
  @override
2814
  String toStringShort() {
2815
    String header = describeIdentity(this);
2816
    if (_relayoutBoundary != null && _relayoutBoundary != this) {
2817
      int count = 1;
2818
      RenderObject? target = parent as RenderObject?;
2819
      while (target != null && target != _relayoutBoundary) {
2820
        target = target.parent as RenderObject?;
2821 2822
        count += 1;
      }
2823
      header += ' relayoutBoundary=up$count';
2824 2825 2826
    }
    if (_needsLayout)
      header += ' NEEDS-LAYOUT';
2827 2828
    if (_needsPaint)
      header += ' NEEDS-PAINT';
2829 2830
    if (_needsCompositingBitsUpdate)
      header += ' NEEDS-COMPOSITING-BITS-UPDATE';
2831 2832
    if (!attached)
      header += ' DETACHED';
2833
    return header;
2834
  }
2835

2836
  @override
2837
  String toString({ DiagnosticLevel minLevel = DiagnosticLevel.info }) => toStringShort();
2838

2839 2840 2841
  /// Returns a description of the tree rooted at this node.
  /// If the prefix argument is provided, then every line in the output
  /// will be prefixed by that string.
2842
  @override
2843
  String toStringDeep({
2844
    String prefixLineOne = '',
2845
    String? prefixOtherLines = '',
2846
    DiagnosticLevel minLevel = DiagnosticLevel.debug,
2847
  }) {
2848
    RenderObject? debugPreviousActiveLayout;
2849 2850 2851 2852 2853
    assert(() {
      debugPreviousActiveLayout = _debugActiveLayout;
      _debugActiveLayout = null;
      return true;
    }());
2854 2855 2856 2857 2858
    final String result = super.toStringDeep(
      prefixLineOne: prefixLineOne,
      prefixOtherLines: prefixOtherLines,
      minLevel: minLevel,
    );
2859 2860 2861 2862
    assert(() {
      _debugActiveLayout = debugPreviousActiveLayout;
      return true;
    }());
2863 2864 2865
    return result;
  }

2866 2867 2868 2869
  /// Returns a one-line detailed description of the render object.
  /// This description is often somewhat long.
  ///
  /// This includes the same information for this RenderObject as given by
2870
  /// [toStringDeep], but does not recurse to any children.
2871
  @override
2872
  String toStringShallow({
2873
    String joiner = ', ',
2874
    DiagnosticLevel minLevel = DiagnosticLevel.debug,
2875
  }) {
2876
    RenderObject? debugPreviousActiveLayout;
2877 2878 2879 2880 2881
    assert(() {
      debugPreviousActiveLayout = _debugActiveLayout;
      _debugActiveLayout = null;
      return true;
    }());
2882
    final String result = super.toStringShallow(joiner: joiner, minLevel: minLevel);
2883 2884 2885 2886
    assert(() {
      _debugActiveLayout = debugPreviousActiveLayout;
      return true;
    }());
2887
    return result;
2888 2889
  }

2890
  @protected
2891
  @override
2892
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2893
    super.debugFillProperties(properties);
2894
    properties.add(FlagProperty('needsCompositing', value: _needsCompositing, ifTrue: 'needs compositing'));
2895
    properties.add(DiagnosticsProperty<Object?>('creator', debugCreator, defaultValue: null, level: DiagnosticLevel.debug));
2896
    properties.add(DiagnosticsProperty<ParentData>('parentData', parentData, tooltip: _debugCanParentUseSize == true ? 'can use size' : null, missingIfNull: true));
2897
    properties.add(DiagnosticsProperty<Constraints>('constraints', _constraints, missingIfNull: true));
2898
    // don't access it via the "layer" getter since that's only valid when we don't need paint
2899
    properties.add(DiagnosticsProperty<ContainerLayer>('layer', _layer, defaultValue: null));
2900 2901
    properties.add(DiagnosticsProperty<SemanticsNode>('semantics node', _semantics, defaultValue: null));
    properties.add(FlagProperty(
2902
      'isBlockingSemanticsOfPreviouslyPaintedNodes',
2903
      value: _semanticsConfiguration.isBlockingSemanticsOfPreviouslyPaintedNodes,
2904 2905
      ifTrue: 'blocks semantics of earlier render objects below the common boundary',
    ));
2906
    properties.add(FlagProperty('isSemanticBoundary', value: _semanticsConfiguration.isSemanticBoundary, ifTrue: 'semantic boundary'));
2907
  }
2908

2909 2910
  @override
  List<DiagnosticsNode> debugDescribeChildren() => <DiagnosticsNode>[];
2911

2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926
  /// Attempt to make (a portion of) this or a descendant [RenderObject] visible
  /// on screen.
  ///
  /// If `descendant` is provided, that [RenderObject] is made visible. If
  /// `descendant` is omitted, this [RenderObject] is made visible.
  ///
  /// The optional `rect` parameter describes which area of that [RenderObject]
  /// should be shown on screen. If `rect` is null, the entire
  /// [RenderObject] (as defined by its [paintBounds]) will be revealed. The
  /// `rect` parameter is interpreted relative to the coordinate system of
  /// `descendant` if that argument is provided and relative to this
  /// [RenderObject] otherwise.
  ///
  /// The `duration` parameter can be set to a non-zero value to bring the
  /// target object on screen in an animation defined by `curve`.
2927 2928 2929 2930 2931
  ///
  /// See also:
  ///
  /// * [RenderViewportBase.showInViewport], which [RenderViewportBase] and
  ///   [SingleChildScrollView] delegate this method to.
2932
  void showOnScreen({
2933 2934
    RenderObject? descendant,
    Rect? rect,
2935 2936 2937
    Duration duration = Duration.zero,
    Curve curve = Curves.ease,
  }) {
2938
    if (parent is RenderObject) {
2939
      final RenderObject renderParent = parent! as RenderObject;
2940 2941 2942 2943 2944 2945
      renderParent.showOnScreen(
        descendant: descendant ?? this,
        rect: rect,
        duration: duration,
        curve: curve,
      );
2946 2947
    }
  }
2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960

  /// Adds a debug representation of a [RenderObject] optimized for including in
  /// error messages.
  ///
  /// The default [style] of [DiagnosticsTreeStyle.shallow] ensures that all of
  /// the properties of the render object are included in the error output but
  /// none of the children of the object are.
  ///
  /// You should always include a RenderObject in an error message if it is the
  /// [RenderObject] causing the failure or contract violation of the error.
  DiagnosticsNode describeForError(String name, { DiagnosticsTreeStyle style = DiagnosticsTreeStyle.shallow }) {
    return toDiagnosticsNode(name: name, style: style);
  }
2961 2962
}

2963
/// Generic mixin for render objects with one child.
2964
///
2965 2966 2967 2968 2969
/// Provides a child model for a render object subclass that has
/// a unique child, which is accessible via the [child] getter.
///
/// This mixin is typically used to implement render objects created
/// in a [SingleChildRenderObjectWidget].
2970
mixin RenderObjectWithChildMixin<ChildType extends RenderObject> on RenderObject {
2971

2972 2973 2974 2975 2976 2977
  /// Checks whether the given render object has the correct [runtimeType] to be
  /// a child of this render object.
  ///
  /// Does nothing if assertions are disabled.
  ///
  /// Always returns true.
2978 2979 2980
  bool debugValidateChild(RenderObject child) {
    assert(() {
      if (child is! ChildType) {
2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary(
            'A $runtimeType expected a child of type $ChildType but received a '
            'child of type ${child.runtimeType}.'
          ),
          ErrorDescription(
            'RenderObjects expect specific types of children because they '
            'coordinate with their children during layout and paint. For '
            'example, a RenderSliver cannot be the child of a RenderBox because '
            'a RenderSliver does not understand the RenderBox layout protocol.',
          ),
          ErrorSpacer(),
2993
          DiagnosticsProperty<Object?>(
2994 2995 2996 2997 2998
            'The $runtimeType that expected a $ChildType child was created by',
            debugCreator,
            style: DiagnosticsTreeStyle.errorProperty,
          ),
          ErrorSpacer(),
2999
          DiagnosticsProperty<Object?>(
3000 3001 3002 3003
            'The ${child.runtimeType} that did not match the expected child type '
            'was created by',
            child.debugCreator,
            style: DiagnosticsTreeStyle.errorProperty,
3004
          ),
3005
        ]);
3006 3007
      }
      return true;
3008
    }());
3009 3010 3011
    return true;
  }

3012
  ChildType? _child;
3013
  /// The render object's unique child.
3014 3015
  ChildType? get child => _child;
  set child(ChildType? value) {
3016
    if (_child != null)
3017
      dropChild(_child!);
3018 3019
    _child = value;
    if (_child != null)
3020
      adoptChild(_child!);
3021
  }
3022 3023

  @override
3024 3025
  void attach(PipelineOwner owner) {
    super.attach(owner);
3026
    if (_child != null)
3027
      _child!.attach(owner);
3028
  }
3029 3030

  @override
3031 3032
  void detach() {
    super.detach();
3033
    if (_child != null)
3034
      _child!.detach();
3035
  }
3036

3037 3038 3039
  @override
  void redepthChildren() {
    if (_child != null)
3040
      redepthChild(_child!);
3041 3042
  }

3043
  @override
3044
  void visitChildren(RenderObjectVisitor visitor) {
3045
    if (_child != null)
3046
      visitor(_child!);
3047
  }
3048 3049

  @override
3050
  List<DiagnosticsNode> debugDescribeChildren() {
3051
    return child != null ? <DiagnosticsNode>[child!.toDiagnosticsNode(name: 'child')] : <DiagnosticsNode>[];
3052 3053 3054
  }
}

3055
/// Parent data to support a doubly-linked list of children.
3056 3057 3058 3059 3060
///
/// The children can be traversed using [nextSibling] or [previousSibling],
/// which can be called on the parent data of the render objects
/// obtained via [ContainerRenderObjectMixin.firstChild] or
/// [ContainerRenderObjectMixin.lastChild].
3061
mixin ContainerParentDataMixin<ChildType extends RenderObject> on ParentData {
3062
  /// The previous sibling in the parent's child list.
3063
  ChildType? previousSibling;
3064
  /// The next sibling in the parent's child list.
3065
  ChildType? nextSibling;
3066 3067

  /// Clear the sibling pointers.
3068
  @override
3069
  void detach() {
3070 3071
    assert(previousSibling == null, 'Pointers to siblings must be nulled before detaching ParentData.');
    assert(nextSibling == null, 'Pointers to siblings must be nulled before detaching ParentData.');
3072
    super.detach();
3073 3074 3075
  }
}

3076
/// Generic mixin for render objects with a list of children.
3077 3078 3079
///
/// Provides a child model for a render object subclass that has a doubly-linked
/// list of children.
3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093
///
/// The [ChildType] specifies the type of the children (extending [RenderObject]),
/// e.g. [RenderBox].
///
/// [ParentDataType] stores parent container data on its child render objects.
/// It must extend [ContainerParentDataMixin], which provides the interface
/// for visiting children. This data is populated by
/// [RenderObject.setupParentData] implemented by the class using this mixin.
///
/// When using [RenderBox] as the child type, you will usually want to make use of
/// [RenderBoxContainerDefaultsMixin] and extend [ContainerBoxParentData] for the
/// parent data.
///
/// Moreover, this is a required mixin for render objects returned to [MultiChildRenderObjectWidget].
3094
mixin ContainerRenderObjectMixin<ChildType extends RenderObject, ParentDataType extends ContainerParentDataMixin<ChildType>> on RenderObject {
3095
  bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType? equals }) {
3096
    ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3097 3098
    while (childParentData.previousSibling != null) {
      assert(childParentData.previousSibling != child);
3099
      child = childParentData.previousSibling!;
3100
      childParentData = child.parentData! as ParentDataType;
3101 3102 3103
    }
    return child == equals;
  }
3104
  bool _debugUltimateNextSiblingOf(ChildType child, { ChildType? equals }) {
3105
    ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3106 3107
    while (childParentData.nextSibling != null) {
      assert(childParentData.nextSibling != child);
3108
      child = childParentData.nextSibling!;
3109
      childParentData = child.parentData! as ParentDataType;
3110 3111 3112 3113 3114
    }
    return child == equals;
  }

  int _childCount = 0;
3115
  /// The number of children.
3116 3117
  int get childCount => _childCount;

3118 3119 3120 3121 3122 3123
  /// Checks whether the given render object has the correct [runtimeType] to be
  /// a child of this render object.
  ///
  /// Does nothing if assertions are disabled.
  ///
  /// Always returns true.
3124 3125 3126
  bool debugValidateChild(RenderObject child) {
    assert(() {
      if (child is! ChildType) {
3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary(
            'A $runtimeType expected a child of type $ChildType but received a '
            'child of type ${child.runtimeType}.'
          ),
          ErrorDescription(
            'RenderObjects expect specific types of children because they '
            'coordinate with their children during layout and paint. For '
            'example, a RenderSliver cannot be the child of a RenderBox because '
            'a RenderSliver does not understand the RenderBox layout protocol.'
          ),
          ErrorSpacer(),
3139
          DiagnosticsProperty<Object?>(
3140 3141 3142 3143 3144
            'The $runtimeType that expected a $ChildType child was created by',
            debugCreator,
            style: DiagnosticsTreeStyle.errorProperty,
          ),
          ErrorSpacer(),
3145
          DiagnosticsProperty<Object?>(
3146 3147 3148 3149 3150 3151
            'The ${child.runtimeType} that did not match the expected child type '
            'was created by',
            child.debugCreator,
            style: DiagnosticsTreeStyle.errorProperty,
          ),
        ]);
3152 3153
      }
      return true;
3154
    }());
3155 3156 3157
    return true;
  }

3158 3159 3160
  ChildType? _firstChild;
  ChildType? _lastChild;
  void _insertIntoChildList(ChildType child, { ChildType? after }) {
3161
    final ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3162 3163
    assert(childParentData.nextSibling == null);
    assert(childParentData.previousSibling == null);
3164 3165
    _childCount += 1;
    assert(_childCount > 0);
3166 3167 3168 3169
    if (after == null) {
      // insert at the start (_firstChild)
      childParentData.nextSibling = _firstChild;
      if (_firstChild != null) {
3170
        final ParentDataType _firstChildParentData = _firstChild!.parentData! as ParentDataType;
3171
        _firstChildParentData.previousSibling = child;
3172
      }
3173
      _firstChild = child;
3174
      _lastChild ??= child;
3175 3176 3177
    } else {
      assert(_firstChild != null);
      assert(_lastChild != null);
3178 3179
      assert(_debugUltimatePreviousSiblingOf(after, equals: _firstChild));
      assert(_debugUltimateNextSiblingOf(after, equals: _lastChild));
3180
      final ParentDataType afterParentData = after.parentData! as ParentDataType;
3181 3182 3183 3184 3185 3186
      if (afterParentData.nextSibling == null) {
        // insert at the end (_lastChild); we'll end up with two or more children
        assert(after == _lastChild);
        childParentData.previousSibling = after;
        afterParentData.nextSibling = child;
        _lastChild = child;
3187 3188 3189
      } else {
        // insert in the middle; we'll end up with three or more children
        // set up links from child to siblings
3190 3191
        childParentData.nextSibling = afterParentData.nextSibling;
        childParentData.previousSibling = after;
3192
        // set up links from siblings to child
3193 3194
        final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling!.parentData! as ParentDataType;
        final ParentDataType childNextSiblingParentData = childParentData.nextSibling!.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3195 3196
        childPreviousSiblingParentData.nextSibling = child;
        childNextSiblingParentData.previousSibling = child;
3197
        assert(afterParentData.nextSibling == child);
3198 3199 3200
      }
    }
  }
3201
  /// Insert child into this render object's child list after the given child.
3202 3203 3204
  ///
  /// If `after` is null, then this inserts the child at the start of the list,
  /// and the child becomes the new [firstChild].
3205
  void insert(ChildType child, { ChildType? after }) {
3206 3207 3208
    assert(child != this, 'A RenderObject cannot be inserted into itself.');
    assert(after != this, 'A RenderObject cannot simultaneously be both the parent and the sibling of another RenderObject.');
    assert(child != after, 'A RenderObject cannot be inserted after itself.');
3209 3210 3211
    assert(child != _firstChild);
    assert(child != _lastChild);
    adoptChild(child);
3212 3213 3214 3215 3216 3217
    _insertIntoChildList(child, after: after);
  }

  /// Append child to the end of this render object's child list.
  void add(ChildType child) {
    insert(child, after: _lastChild);
3218
  }
3219

3220
  /// Add all the children to the end of this render object's child list.
3221
  void addAll(List<ChildType>? children) {
3222
    children?.forEach(add);
3223
  }
3224

3225
  void _removeFromChildList(ChildType child) {
3226
    final ParentDataType childParentData = child.parentData! as ParentDataType;
3227 3228 3229
    assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
    assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
    assert(_childCount >= 0);
Hixie's avatar
Hixie committed
3230
    if (childParentData.previousSibling == null) {
3231
      assert(_firstChild == child);
Hixie's avatar
Hixie committed
3232
      _firstChild = childParentData.nextSibling;
3233
    } else {
3234
      final ParentDataType childPreviousSiblingParentData = childParentData.previousSibling!.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3235
      childPreviousSiblingParentData.nextSibling = childParentData.nextSibling;
3236
    }
Hixie's avatar
Hixie committed
3237
    if (childParentData.nextSibling == null) {
3238
      assert(_lastChild == child);
Hixie's avatar
Hixie committed
3239
      _lastChild = childParentData.previousSibling;
3240
    } else {
3241
      final ParentDataType childNextSiblingParentData = childParentData.nextSibling!.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3242
      childNextSiblingParentData.previousSibling = childParentData.previousSibling;
3243
    }
Hixie's avatar
Hixie committed
3244 3245
    childParentData.previousSibling = null;
    childParentData.nextSibling = null;
3246 3247
    _childCount -= 1;
  }
3248

3249
  /// Remove this child from the child list.
3250 3251
  ///
  /// Requires the child to be present in the child list.
3252 3253 3254 3255
  void remove(ChildType child) {
    _removeFromChildList(child);
    dropChild(child);
  }
3256

3257
  /// Remove all their children from this render object's child list.
3258 3259
  ///
  /// More efficient than removing them individually.
3260
  void removeAll() {
3261
    ChildType? child = _firstChild;
3262
    while (child != null) {
3263
      final ParentDataType childParentData = child.parentData! as ParentDataType;
3264
      final ChildType? next = childParentData.nextSibling;
Hixie's avatar
Hixie committed
3265 3266
      childParentData.previousSibling = null;
      childParentData.nextSibling = null;
3267 3268 3269 3270 3271 3272 3273
      dropChild(child);
      child = next;
    }
    _firstChild = null;
    _lastChild = null;
    _childCount = 0;
  }
3274

3275
  /// Move the given `child` in the child list to be after another child.
3276 3277
  ///
  /// More efficient than removing and re-adding the child. Requires the child
3278 3279
  /// to already be in the child list at some position. Pass null for `after` to
  /// move the child to the start of the child list.
3280
  void move(ChildType child, { ChildType? after }) {
3281
    assert(child != this);
3282 3283
    assert(after != this);
    assert(child != after);
3284
    assert(child.parent == this);
3285
    final ParentDataType childParentData = child.parentData! as ParentDataType;
3286
    if (childParentData.previousSibling == after)
3287 3288
      return;
    _removeFromChildList(child);
3289
    _insertIntoChildList(child, after: after);
3290
    markNeedsLayout();
3291
  }
3292

3293
  @override
3294 3295
  void attach(PipelineOwner owner) {
    super.attach(owner);
3296
    ChildType? child = _firstChild;
3297
    while (child != null) {
3298
      child.attach(owner);
3299
      final ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3300
      child = childParentData.nextSibling;
3301 3302
    }
  }
3303

3304
  @override
3305 3306
  void detach() {
    super.detach();
3307
    ChildType? child = _firstChild;
3308
    while (child != null) {
3309
      child.detach();
3310
      final ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3311
      child = childParentData.nextSibling;
3312 3313
    }
  }
3314

3315
  @override
3316
  void redepthChildren() {
3317
    ChildType? child = _firstChild;
3318
    while (child != null) {
3319
      redepthChild(child);
3320
      final ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3321
      child = childParentData.nextSibling;
3322 3323
    }
  }
3324

3325
  @override
3326
  void visitChildren(RenderObjectVisitor visitor) {
3327
    ChildType? child = _firstChild;
3328
    while (child != null) {
3329
      visitor(child);
3330
      final ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3331
      child = childParentData.nextSibling;
3332 3333 3334
    }
  }

3335
  /// The first child in the child list.
3336
  ChildType? get firstChild => _firstChild;
3337

3338
  /// The last child in the child list.
3339
  ChildType? get lastChild => _lastChild;
3340

3341
  /// The previous child before the given child in the child list.
3342
  ChildType? childBefore(ChildType child) {
3343 3344
    assert(child != null);
    assert(child.parent == this);
3345
    final ParentDataType childParentData = child.parentData! as ParentDataType;
3346 3347 3348
    return childParentData.previousSibling;
  }

3349
  /// The next child after the given child in the child list.
3350
  ChildType? childAfter(ChildType child) {
3351 3352
    assert(child != null);
    assert(child.parent == this);
3353
    final ParentDataType childParentData = child.parentData! as ParentDataType;
Hixie's avatar
Hixie committed
3354
    return childParentData.nextSibling;
3355 3356
  }

3357
  @override
3358 3359
  List<DiagnosticsNode> debugDescribeChildren() {
    final List<DiagnosticsNode> children = <DiagnosticsNode>[];
3360
    if (firstChild != null) {
3361
      ChildType child = firstChild!;
Hixie's avatar
Hixie committed
3362
      int count = 1;
3363 3364 3365 3366
      while (true) {
        children.add(child.toDiagnosticsNode(name: 'child $count'));
        if (child == lastChild)
          break;
Hixie's avatar
Hixie committed
3367
        count += 1;
3368
        final ParentDataType childParentData = child.parentData! as ParentDataType;
3369
        child = childParentData.nextSibling!;
Hixie's avatar
Hixie committed
3370
      }
3371
    }
3372
    return children;
3373 3374
  }
}
3375

3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397
/// Mixin for [RenderObject] that will call [systemFontsDidChange] whenever the
/// system fonts change.
///
/// System fonts can change when the OS install or remove a font. Use this mixin if
/// the [RenderObject] uses [TextPainter] or [Paragraph] to correctly update the
/// text when it happens.
mixin RelayoutWhenSystemFontsChangeMixin on RenderObject {

  /// A callback that is called when system fonts have changed.
  ///
  /// By default, [markNeedsLayout] is called on the [RenderObject]
  /// implementing this mixin.
  ///
  /// Subclass should override this method to clear any extra cache that depend
  /// on font-related metrics.
  @protected
  @mustCallSuper
  void systemFontsDidChange() {
    markNeedsLayout();
  }

  @override
3398
  void attach(covariant PipelineOwner owner) {
3399
    super.attach(owner);
3400
    PaintingBinding.instance!.systemFonts.addListener(systemFontsDidChange);
3401 3402 3403 3404
  }

  @override
  void detach() {
3405
    PaintingBinding.instance!.systemFonts.removeListener(systemFontsDidChange);
3406 3407 3408 3409
    super.detach();
  }
}

3410 3411
/// Describes the semantics information a [RenderObject] wants to add to its
/// parent.
3412
///
3413 3414 3415 3416 3417 3418
/// It has two notable subclasses:
///  * [_InterestingSemanticsFragment] describing actual semantic information to
///    be added to the parent.
///  * [_ContainerSemanticsFragment]: a container class to transport the semantic
///    information of multiple [_InterestingSemanticsFragment] to a parent.
abstract class _SemanticsFragment {
3419
  _SemanticsFragment({ required this.dropsSemanticsOfPreviousSiblings })
3420
    : assert (dropsSemanticsOfPreviousSiblings != null);
3421 3422 3423 3424 3425 3426 3427 3428

  /// Incorporate the fragments of children into this fragment.
  void addAll(Iterable<_InterestingSemanticsFragment> fragments);

  /// Whether this fragment wants to make the semantics information of
  /// previously painted [RenderObject]s unreachable for accessibility purposes.
  ///
  /// See also:
3429
  ///
3430 3431 3432 3433 3434 3435
  ///  * [SemanticsConfiguration.isBlockingSemanticsOfPreviouslyPaintedNodes]
  ///    describes what semantics are dropped in more detail.
  final bool dropsSemanticsOfPreviousSiblings;

  /// Returns [_InterestingSemanticsFragment] describing the actual semantic
  /// information that this fragment wants to add to the parent.
3436
  List<_InterestingSemanticsFragment> get interestingFragments;
3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447

  /// Whether this fragment wants to abort the semantics walk because the
  /// information in the tree are not sufficient to calculate semantics.
  ///
  /// This happens for subtrees that are currently kept alive by a viewport but
  /// not laid out.
  ///
  /// See also:
  ///
  ///  * [_AbortingSemanticsFragment], which sets this to true.
  bool get abortsWalk => false;
3448 3449 3450 3451 3452 3453 3454 3455 3456
}

/// A container used when a [RenderObject] wants to add multiple independent
/// [_InterestingSemanticsFragment] to its parent.
///
/// The [_InterestingSemanticsFragment] to be added to the parent can be
/// obtained via [interestingFragments].
class _ContainerSemanticsFragment extends _SemanticsFragment {

3457
  _ContainerSemanticsFragment({ required bool dropsSemanticsOfPreviousSiblings })
3458
    : super(dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings);
3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471

  @override
  void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
    interestingFragments.addAll(fragments);
  }

  @override
  final List<_InterestingSemanticsFragment> interestingFragments = <_InterestingSemanticsFragment>[];
}

/// A [_SemanticsFragment] that describes which concrete semantic information
/// a [RenderObject] wants to add to the [SemanticsNode] of its parent.
///
3472 3473
/// Specifically, it describes which children (as returned by [compileChildren])
/// should be added to the parent's [SemanticsNode] and which [config] should be
3474 3475 3476
/// merged into the parent's [SemanticsNode].
abstract class _InterestingSemanticsFragment extends _SemanticsFragment {
  _InterestingSemanticsFragment({
3477 3478
    required RenderObject owner,
    required bool dropsSemanticsOfPreviousSiblings,
3479
  }) : assert(owner != null),
3480
       _ancestorChain = <RenderObject>[owner],
3481 3482
       super(dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings);

Dan Field's avatar
Dan Field committed
3483
  /// The [RenderObject] that owns this fragment (and any new [SemanticsNode]
3484
  /// introduced by it).
3485 3486 3487
  RenderObject get owner => _ancestorChain.first;

  final List<RenderObject> _ancestorChain;
3488 3489

  /// The children to be added to the parent.
3490 3491 3492 3493 3494 3495
  ///
  /// See also:
  ///
  ///  * [SemanticsNode.parentSemanticsClipRect] for the source and definition
  ///    of the `parentSemanticsClipRect` argument.
  ///  * [SemanticsNode.parentPaintClipRect] for the source and definition
3496
  ///    of the `parentPaintClipRect` argument.
3497
  ///  * [SemanticsNode.elevationAdjustment] for the source and definition
3498
  ///    of the `elevationAdjustment` argument.
3499
  void compileChildren({
3500 3501 3502
    required Rect? parentSemanticsClipRect,
    required Rect? parentPaintClipRect,
    required double elevationAdjustment,
3503
    required List<SemanticsNode> result,
3504
  });
3505 3506 3507

  /// The [SemanticsConfiguration] the child wants to merge into the parent's
  /// [SemanticsNode] or null if it doesn't want to merge anything.
3508
  SemanticsConfiguration? get config;
3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532

  /// Disallows this fragment to merge any configuration into its parent's
  /// [SemanticsNode].
  ///
  /// After calling this the fragment will only produce children to be added
  /// to the parent and it will return null for [config].
  void markAsExplicit();

  /// Consume the fragments of children.
  ///
  /// For each provided fragment it will add that fragment's children to
  /// this fragment's children (as returned by [compileChildren]) and merge that
  /// fragment's [config] into this fragment's [config].
  ///
  /// If a provided fragment should not merge anything into [config] call
  /// [markAsExplicit] before passing the fragment to this method.
  @override
  void addAll(Iterable<_InterestingSemanticsFragment> fragments);

  /// Whether this fragment wants to add any semantic information to the parent
  /// [SemanticsNode].
  bool get hasConfigForParent => config != null;

  @override
3533
  List<_InterestingSemanticsFragment> get interestingFragments => <_InterestingSemanticsFragment>[this];
3534

3535
  Set<SemanticsTag>? _tagsForChildren;
3536 3537

  /// Tag all children produced by [compileChildren] with `tags`.
3538
  void addTags(Iterable<SemanticsTag>? tags) {
3539 3540
    if (tags == null || tags.isEmpty)
      return;
3541
    _tagsForChildren ??= <SemanticsTag>{};
3542
    _tagsForChildren!.addAll(tags);
3543
  }
3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555

  /// Adds the geometric information of `ancestor` to this object.
  ///
  /// Those information are required to properly compute the value for
  /// [SemanticsNode.transform], [SemanticsNode.clipRect], and
  /// [SemanticsNode.rect].
  ///
  /// Ancestors have to be added in order from [owner] up until the next
  /// [RenderObject] that owns a [SemanticsNode] is reached.
  void addAncestor(RenderObject ancestor) {
    _ancestorChain.add(ancestor);
  }
3556 3557
}

Ian Hickson's avatar
Ian Hickson committed
3558
/// An [_InterestingSemanticsFragment] that produces the root [SemanticsNode] of
3559 3560
/// the semantics tree.
///
3561
/// The root node is available as the only element in the Iterable returned by
3562 3563 3564
/// [children].
class _RootSemanticsFragment extends _InterestingSemanticsFragment {
  _RootSemanticsFragment({
3565 3566
    required RenderObject owner,
    required bool dropsSemanticsOfPreviousSiblings,
3567 3568 3569
  }) : super(owner: owner, dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings);

  @override
3570
  void compileChildren({ Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, required double elevationAdjustment, required List<SemanticsNode> result }) {
3571
    assert(_tagsForChildren == null || _tagsForChildren!.isEmpty);
3572 3573
    assert(parentSemanticsClipRect == null);
    assert(parentPaintClipRect == null);
3574
    assert(_ancestorChain.length == 1);
3575
    assert(elevationAdjustment == 0.0);
3576

3577
    owner._semantics ??= SemanticsNode.root(
3578
      showOnScreen: owner.showOnScreen,
3579
      owner: owner.owner!.semanticsOwner!,
3580
    );
3581
    final SemanticsNode node = owner._semantics!;
3582
    assert(MatrixUtils.matrixEquals(node.transform, Matrix4.identity()));
3583 3584
    assert(node.parentSemanticsClipRect == null);
    assert(node.parentPaintClipRect == null);
3585

3586
    node.rect = owner.semanticBounds;
3587

3588 3589 3590 3591 3592 3593 3594 3595 3596 3597
    final List<SemanticsNode> children = <SemanticsNode>[];
    for (final _InterestingSemanticsFragment fragment in _children) {
      assert(fragment.config == null);
      fragment.compileChildren(
        parentSemanticsClipRect: parentSemanticsClipRect,
        parentPaintClipRect: parentPaintClipRect,
        elevationAdjustment: 0.0,
        result: children,
      );
    }
3598 3599
    node.updateWith(config: null, childrenInInversePaintOrder: children);

3600 3601 3602 3603 3604 3605
    // The root node is the only semantics node allowed to be invisible. This
    // can happen when the canvas the app is drawn on has a size of 0 by 0
    // pixel. If this happens, the root node must not have any children (because
    // these would be invisible as well and are therefore excluded from the
    // tree).
    assert(!node.isInvisible || children.isEmpty);
3606
    result.add(node);
3607 3608 3609
  }

  @override
3610
  SemanticsConfiguration? get config => null;
3611

3612 3613
  final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[];

3614 3615 3616 3617 3618 3619 3620
  @override
  void markAsExplicit() {
    // nothing to do, we are always explicit.
  }

  @override
  void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
3621
    _children.addAll(fragments);
3622 3623 3624
  }
}

Ian Hickson's avatar
Ian Hickson committed
3625
/// An [_InterestingSemanticsFragment] that can be told to only add explicit
3626 3627 3628 3629 3630 3631 3632 3633 3634 3635
/// [SemanticsNode]s to the parent.
///
/// If [markAsExplicit] was not called before this fragment is added to
/// another fragment it will merge [config] into the parent's [SemanticsNode]
/// and add its [children] to it.
///
/// If [markAsExplicit] was called before adding this fragment to another
/// fragment it will create a new [SemanticsNode]. The newly created node will
/// be annotated with the [SemanticsConfiguration] that - without the call to
/// [markAsExplicit] - would have been merged into the parent's [SemanticsNode].
3636
/// Similarly, the new node will also take over the children that otherwise
3637 3638 3639 3640 3641 3642 3643 3644
/// would have been added to the parent's [SemanticsNode].
///
/// After a call to [markAsExplicit] the only element returned by [children]
/// is the newly created node and [config] will return null as the fragment
/// no longer wants to merge any semantic information into the parent's
/// [SemanticsNode].
class _SwitchableSemanticsFragment extends _InterestingSemanticsFragment {
  _SwitchableSemanticsFragment({
3645 3646 3647 3648
    required bool mergeIntoParent,
    required SemanticsConfiguration config,
    required RenderObject owner,
    required bool dropsSemanticsOfPreviousSiblings,
3649 3650 3651 3652
  }) : _mergeIntoParent = mergeIntoParent,
       _config = config,
       assert(mergeIntoParent != null),
       assert(config != null),
3653
       super(owner: owner, dropsSemanticsOfPreviousSiblings: dropsSemanticsOfPreviousSiblings);
3654 3655 3656 3657

  final bool _mergeIntoParent;
  SemanticsConfiguration _config;
  bool _isConfigWritable = false;
3658
  final List<_InterestingSemanticsFragment> _children = <_InterestingSemanticsFragment>[];
3659 3660

  @override
3661
  void compileChildren({ Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, required double elevationAdjustment, required List<SemanticsNode> result }) {
3662 3663
    if (!_isExplicit) {
      owner._semantics = null;
3664
      for (final _InterestingSemanticsFragment fragment in _children) {
3665
        assert(_ancestorChain.first == fragment._ancestorChain.last);
3666 3667
        fragment._ancestorChain.addAll(_ancestorChain.skip(1));
        fragment.compileChildren(
3668 3669 3670 3671 3672 3673
          parentSemanticsClipRect: parentSemanticsClipRect,
          parentPaintClipRect: parentPaintClipRect,
          // The fragment is not explicit, its elevation has been absorbed by
          // the parent config (as thickness). We still need to make sure that
          // its children are placed at the elevation dictated by this config.
          elevationAdjustment: elevationAdjustment + _config.elevation,
3674
          result: result,
3675
        );
3676
      }
3677 3678
      return;
    }
3679

3680
    final _SemanticsGeometry? geometry = _needsGeometryUpdate
3681
        ? _SemanticsGeometry(parentSemanticsClipRect: parentSemanticsClipRect, parentPaintClipRect: parentPaintClipRect, ancestors: _ancestorChain)
3682 3683
        : null;

3684
    if (!_mergeIntoParent && (geometry?.dropFromTree == true))
3685
      return;  // Drop the node, it's not going to be visible.
3686

3687
    owner._semantics ??= SemanticsNode(showOnScreen: owner.showOnScreen);
3688
    final SemanticsNode node = owner._semantics!
3689 3690 3691
      ..isMergedIntoParent = _mergeIntoParent
      ..tags = _tagsForChildren;

3692 3693 3694 3695 3696 3697
    node.elevationAdjustment = elevationAdjustment;
    if (elevationAdjustment != 0.0) {
      _ensureConfigIsWritable();
      _config.elevation += elevationAdjustment;
    }

3698 3699 3700 3701 3702
    if (geometry != null) {
      assert(_needsGeometryUpdate);
      node
        ..rect = geometry.rect
        ..transform = geometry.transform
3703 3704 3705 3706 3707 3708
        ..parentSemanticsClipRect = geometry.semanticsClipRect
        ..parentPaintClipRect = geometry.paintClipRect;
      if (!_mergeIntoParent && geometry.markAsHidden) {
        _ensureConfigIsWritable();
        _config.isHidden = true;
      }
3709 3710
    }

3711 3712 3713
    final List<SemanticsNode> children = <SemanticsNode>[];
    for (final _InterestingSemanticsFragment fragment in _children) {
      fragment.compileChildren(
3714 3715 3716
        parentSemanticsClipRect: node.parentSemanticsClipRect,
        parentPaintClipRect: node.parentPaintClipRect,
        elevationAdjustment: 0.0,
3717 3718 3719
        result: children,
      );
    }
3720
    if (_config.isSemanticBoundary) {
3721
      owner.assembleSemanticsNode(node, _config, children);
3722
    } else {
3723
      node.updateWith(config: _config, childrenInInversePaintOrder: children);
3724
    }
3725
    result.add(node);
3726 3727 3728
  }

  @override
3729
  SemanticsConfiguration? get config {
3730 3731 3732 3733 3734
    return _isExplicit ? null : _config;
  }

  @override
  void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
3735
    for (final _InterestingSemanticsFragment fragment in fragments) {
3736
      _children.add(fragment);
3737 3738
      if (fragment.config == null)
        continue;
3739
      _ensureConfigIsWritable();
3740
      _config.absorb(fragment.config!);
3741 3742 3743
    }
  }

3744 3745 3746 3747 3748 3749 3750
  void _ensureConfigIsWritable() {
    if (!_isConfigWritable) {
      _config = _config.copy();
      _isConfigWritable = true;
    }
  }

3751 3752 3753 3754 3755 3756
  bool _isExplicit = false;

  @override
  void markAsExplicit() {
    _isExplicit = true;
  }
3757 3758

  bool get _needsGeometryUpdate => _ancestorChain.length > 1;
3759 3760
}

3761 3762 3763 3764 3765 3766 3767 3768 3769

/// [_SemanticsFragment] used to indicate that the current information in this
/// subtree is not sufficient to update semantics.
///
/// Anybody processing this [_SemanticsFragment] should abort the walk of the
/// current subtree without updating any [SemanticsNode]s as there is no semantic
/// information to compute. As a result, this fragment also doesn't carry any
/// semantics information either.
class _AbortingSemanticsFragment extends _InterestingSemanticsFragment {
3770
  _AbortingSemanticsFragment({required RenderObject owner}) : super(owner: owner, dropsSemanticsOfPreviousSiblings: false);
3771 3772 3773 3774 3775

  @override
  bool get abortsWalk => true;

  @override
3776
  SemanticsConfiguration? get config => null;
3777 3778 3779 3780 3781 3782 3783

  @override
  void addAll(Iterable<_InterestingSemanticsFragment> fragments) {
    assert(false);
  }

  @override
3784 3785
  void compileChildren({ Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, required double elevationAdjustment, required List<SemanticsNode> result }) {
    result.add(owner._semantics!);
3786 3787 3788 3789 3790 3791 3792 3793
  }

  @override
  void markAsExplicit() {
    // Is never explicit.
  }
}

3794 3795 3796 3797 3798 3799
/// Helper class that keeps track of the geometry of a [SemanticsNode].
///
/// It is used to annotate a [SemanticsNode] with the current information for
/// [SemanticsNode.rect] and [SemanticsNode.transform].
class _SemanticsGeometry {

3800 3801 3802 3803 3804 3805
  /// The `parentClippingRect` may be null if no clip is to be applied.
  ///
  /// The `ancestors` list has to include all [RenderObject] in order that are
  /// located between the [SemanticsNode] whose geometry is represented here
  /// (first [RenderObject] in the list) and its closest ancestor [RenderObject]
  /// that also owns its own [SemanticsNode] (last [RenderObject] in the list).
3806
  _SemanticsGeometry({
3807 3808 3809
    required Rect? parentSemanticsClipRect,
    required Rect? parentPaintClipRect,
    required List<RenderObject> ancestors,
3810
  }) {
3811
    _computeValues(parentSemanticsClipRect, parentPaintClipRect, ancestors);
3812
  }
3813

3814 3815 3816 3817
  Rect? _paintClipRect;
  Rect? _semanticsClipRect;
  late Matrix4 _transform;
  late Rect _rect;
3818

3819 3820
  /// Value for [SemanticsNode.transform].
  Matrix4 get transform => _transform;
3821

3822
  /// Value for [SemanticsNode.parentSemanticsClipRect].
3823
  Rect? get semanticsClipRect => _semanticsClipRect;
3824 3825

  /// Value for [SemanticsNode.parentPaintClipRect].
3826
  Rect? get paintClipRect => _paintClipRect;
3827

3828 3829
  /// Value for [SemanticsNode.rect].
  Rect get rect => _rect;
3830

3831 3832 3833 3834 3835 3836
  /// Computes values, ensuring `rect` is properly bounded by ancestor clipping rects.
  ///
  /// See also:
  ///
  /// * [RenderObject.describeSemanticsClip], typically used to determine `parentSemanticsClipRect`.
  /// * [RenderObject.describeApproximatePaintClip], typically used to determine `parentPaintClipRect`.
3837
  void _computeValues(Rect? parentSemanticsClipRect, Rect? parentPaintClipRect, List<RenderObject> ancestors) {
3838
    assert(ancestors.length > 1);
3839

3840
    _transform = Matrix4.identity();
3841 3842
    _semanticsClipRect = parentSemanticsClipRect;
    _paintClipRect = parentPaintClipRect;
3843 3844 3845
    for (int index = ancestors.length-1; index > 0; index -= 1) {
      final RenderObject parent = ancestors[index];
      final RenderObject child = ancestors[index-1];
3846
      final Rect? parentSemanticsClipRect = parent.describeSemanticsClip(child);
3847 3848 3849 3850 3851
      if (parentSemanticsClipRect != null) {
        _semanticsClipRect = parentSemanticsClipRect;
        _paintClipRect = _intersectRects(_paintClipRect, parent.describeApproximatePaintClip(child));
      } else {
        _semanticsClipRect = _intersectRects(_semanticsClipRect, parent.describeApproximatePaintClip(child));
3852
      }
3853 3854 3855 3856
      _temporaryTransformHolder.setIdentity(); // clears data from previous call(s)
      _applyIntermediatePaintTransforms(parent, child, _transform, _temporaryTransformHolder);
      _semanticsClipRect = _transformRect(_semanticsClipRect, _temporaryTransformHolder);
      _paintClipRect = _transformRect(_paintClipRect, _temporaryTransformHolder);
3857 3858
    }

3859
    final RenderObject owner = ancestors.first;
3860
    _rect = _semanticsClipRect == null ? owner.semanticBounds : _semanticsClipRect!.intersect(owner.semanticBounds);
3861
    if (_paintClipRect != null) {
3862
      final Rect paintRect = _paintClipRect!.intersect(_rect);
3863 3864 3865 3866 3867 3868
      _markAsHidden = paintRect.isEmpty && !_rect.isEmpty;
      if (!_markAsHidden)
        _rect = paintRect;
    }
  }

3869 3870 3871 3872 3873 3874 3875 3876 3877
  // A matrix used to store transient transform data.
  //
  // Reusing this matrix avoids allocating a new matrix every time a temporary
  // matrix is needed.
  //
  // This instance should never be returned to the caller. Otherwise, the data
  // stored in it will be overwritten unpredictably by subsequent reuses.
  static final Matrix4 _temporaryTransformHolder = Matrix4.zero();

3878
  /// From parent to child coordinate system.
3879
  static Rect? _transformRect(Rect? rect, Matrix4 transform) {
3880
    assert(transform != null);
3881 3882
    if (rect == null)
      return null;
3883
    if (rect.isEmpty || transform.isZero())
3884
      return Rect.zero;
3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903
    return MatrixUtils.inverseTransformRect(transform, rect);
  }

  // Calls applyPaintTransform on all of the render objects between [child] and
  // [ancestor]. This method handles cases where the immediate semantic parent
  // is not the immediate render object parent of the child.
  //
  // It will mutate both transform and clipRectTransform.
  static void _applyIntermediatePaintTransforms(
    RenderObject ancestor,
    RenderObject child,
    Matrix4 transform,
    Matrix4 clipRectTransform,
  ) {
    assert(ancestor != null);
    assert(child != null);
    assert(transform != null);
    assert(clipRectTransform != null);
    assert(clipRectTransform.isIdentity());
3904
    RenderObject intermediateParent = child.parent! as RenderObject;
3905 3906 3907
    assert(intermediateParent != null);
    while (intermediateParent != ancestor) {
      intermediateParent.applyPaintTransform(child, transform);
3908 3909
      intermediateParent = intermediateParent.parent! as RenderObject;
      child = child.parent! as RenderObject;
3910 3911 3912 3913
      assert(intermediateParent != null);
    }
    ancestor.applyPaintTransform(child, transform);
    ancestor.applyPaintTransform(child, clipRectTransform);
3914 3915
  }

3916
  static Rect? _intersectRects(Rect? a, Rect? b) {
3917 3918 3919 3920 3921
    if (a == null)
      return b;
    if (b == null)
      return a;
    return a.intersect(b);
3922 3923
  }

3924 3925 3926 3927
  /// Whether the [SemanticsNode] annotated with the geometric information tracked
  /// by this object can be dropped from the semantics tree without losing
  /// semantics information.
  bool get dropFromTree {
3928
    return _rect.isEmpty;
3929
  }
3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942

  /// Whether the [SemanticsNode] annotated with the geometric information
  /// tracked by this object should be marked as hidden because it is not
  /// visible on screen.
  ///
  /// Hidden elements should still be included in the tree to work around
  /// platform limitations (e.g. accessibility scrolling on iOS).
  ///
  /// See also:
  ///
  ///  * [SemanticsFlag.isHidden] for the purpose of marking a node as hidden.
  bool get markAsHidden => _markAsHidden;
  bool _markAsHidden = false;
3943
}
3944 3945 3946 3947 3948 3949 3950 3951 3952

/// A class that creates [DiagnosticsNode] by wrapping [RenderObject.debugCreator].
///
/// Attach a [DiagnosticsDebugCreator] into [FlutterErrorDetails.informationCollector]
/// when a [RenderObject.debugCreator] is available. This will lead to improved
/// error message.
class DiagnosticsDebugCreator extends DiagnosticsProperty<Object> {
  /// Create a [DiagnosticsProperty] with its [value] initialized to input
  /// [RenderObject.debugCreator].
3953 3954 3955 3956 3957 3958 3959
  DiagnosticsDebugCreator(Object value)
    : assert(value != null),
      super(
        'debugCreator',
        value,
        level: DiagnosticLevel.hidden,
      );
3960
}