layer.dart 94.2 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:ui' as ui;
6

7
import 'package:flutter/foundation.dart';
8
import 'package:flutter/gestures.dart';
9
import 'package:flutter/painting.dart';
10
import 'package:vector_math/vector_math_64.dart';
11

12 13
import 'debug.dart';

14 15 16 17
/// Information collected for an annotation that is found in the layer tree.
///
/// See also:
///
18
///  * [Layer.findAnnotations], which create and use objects of this class.
19 20
@immutable
class AnnotationEntry<T> {
21
  /// Create an entry of found annotation by providing the object and related
22 23
  /// information.
  const AnnotationEntry({
24 25
    required this.annotation,
    required this.localPosition,
26 27 28 29 30
  }) : assert(localPosition != null);

  /// The annotation object that is found.
  final T annotation;

31 32
  /// The target location described by the local coordinate space of the
  /// annotation object.
33 34 35 36
  final Offset localPosition;

  @override
  String toString() {
37
    return '${objectRuntimeType(this, 'AnnotationEntry')}(annotation: $annotation, localPosition: $localPosition)';
38 39 40 41 42 43 44 45 46
  }
}

/// Information collected about a list of annotations that are found in the
/// layer tree.
///
/// See also:
///
///  * [AnnotationEntry], which are members of this class.
47 48
///  * [Layer.findAllAnnotations], and [Layer.findAnnotations], which create and
///    use an object of this class.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
class AnnotationResult<T> {
  final List<AnnotationEntry<T>> _entries = <AnnotationEntry<T>>[];

  /// Add a new entry to the end of the result.
  ///
  /// Usually, entries should be added in order from most specific to least
  /// specific, typically during an upward walk of the tree.
  void add(AnnotationEntry<T> entry) => _entries.add(entry);

  /// An unmodifiable list of [AnnotationEntry] objects recorded.
  ///
  /// The first entry is the most specific, typically the one at the leaf of
  /// tree.
  Iterable<AnnotationEntry<T>> get entries => _entries;

  /// An unmodifiable list of annotations recorded.
  ///
  /// The first entry is the most specific, typically the one at the leaf of
  /// tree.
  ///
  /// It is similar to [entries] but does not contain other information.
  Iterable<T> get annotations sync* {
71
    for (final AnnotationEntry<T> entry in _entries)
72 73 74 75
      yield entry.annotation;
  }
}

76
/// A composited layer.
77 78 79 80
///
/// During painting, the render tree generates a tree of composited layers that
/// are uploaded into the engine and displayed by the compositor. This class is
/// the base class for all composited layers.
81 82 83 84 85
///
/// Most layers can have their properties mutated, and layers can be moved to
/// different parents. The scene must be explicitly recomposited after such
/// changes are made; the layer tree does not maintain its own dirty state.
///
86
/// To composite the tree, create a [SceneBuilder] object, pass it to the
87
/// root [Layer] object's [addToScene] method, and then call
88
/// [SceneBuilder.build] to obtain a [Scene]. A [Scene] can then be painted
89
/// using [dart:ui.FlutterView.render].
90
///
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/// ## Memory
///
/// Layers retain resources between frames to speed up rendering. A layer will
/// retain these resources until all [LayerHandle]s referring to the layer have
/// nulled out their references.
///
/// Layers must not be used after disposal. If a RenderObject needs to maintain
/// a layer for later usage, it must create a handle to that layer. This is
/// handled automatically for the [RenderObject.layer] property, but additional
/// layers must use their own [LayerHandle].
///
/// {@tool snippet}
///
/// This [RenderObject] is a repaint boundary that pushes an additional
/// [ClipRectLayer].
///
/// ```dart
/// class ClippingRenderObject extends RenderBox {
///   final LayerHandle<ClipRectLayer> _clipRectLayer = LayerHandle<ClipRectLayer>();
///
///   @override
///   bool get isRepaintBoundary => true; // The [layer] property will be used.
///
///   @override
///   void paint(PaintingContext context, Offset offset) {
///     _clipRectLayer.layer = context.pushClipRect(
///       needsCompositing,
///       offset,
///       Offset.zero & size,
///       super.paint,
///       clipBehavior: Clip.hardEdge,
///       oldLayer: _clipRectLayer.layer,
///     );
///   }
///
///   @override
///   void dispose() {
///     _clipRectLayer.layer = null;
///     super.dispose();
///   }
/// }
/// ```
/// {@end-tool}
134 135 136
/// See also:
///
///  * [RenderView.compositeFrame], which implements this recomposition protocol
137
///    for painting [RenderObject] trees on the display.
138
abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
139 140 141 142 143 144 145 146 147 148 149 150
  /// If asserts are enabled, returns whether [dispose] has
  /// been called since the last time any retained resources were created.
  ///
  /// Throws an exception if asserts are disabled.
  bool get debugDisposed {
    late bool disposed;
    assert(() {
      disposed = _debugDisposed;
      return true;
    }());
    return disposed;
  }
151
  bool _debugDisposed = false;
152 153 154 155 156 157 158 159 160 161 162

  /// Set when this layer is appended to a [ContainerLayer], and
  /// unset when it is removed.
  ///
  /// This cannot be set from [attach] or [detach] which is called when an
  /// entire subtree is attached to or detached from an owner. Layers may be
  /// appended to or removed from a [ContainerLayer] regardless of whether they
  /// are attached or detached, and detaching a layer from an owner does not
  /// imply that it has been removed from its parent.
  final LayerHandle<Layer> _parentHandle = LayerHandle<Layer>();

163
  /// Incremented by [LayerHandle].
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
  int _refCount = 0;

  /// Called by [LayerHandle].
  void _unref() {
    assert(_refCount > 0);
    _refCount -= 1;
    if (_refCount == 0) {
      dispose();
    }
  }

  /// Returns the number of objects holding a [LayerHandle] to this layer.
  ///
  /// This method throws if asserts are disabled.
  int get debugHandleCount {
    late int count;
    assert(() {
      count = _refCount;
      return true;
    }());
    return count;
  }

  /// Clears any retained resources that this layer holds.
  ///
  /// This method must dispose resources such as [EngineLayer] and [Picture]
  /// objects. The layer is still usable after this call, but any graphics
  /// related resources it holds will need to be recreated.
  ///
  /// This method _only_ disposes resources for this layer. For example, if it
  /// is a [ContainerLayer], it does not dispose resources of any children.
  /// However, [ContainerLayer]s do remove any children they have when
  /// this method is called, and if this layer was the last holder of a removed
  /// child handle, the child may recursively clean up its resources.
  ///
  /// This method automatically gets called when all outstanding [LayerHandle]s
  /// are disposed. [LayerHandle] objects are typically held by the [parent]
  /// layer of this layer and any [RenderObject]s that participated in creating
  /// it.
  ///
  /// After calling this method, the object is unusable.
  @mustCallSuper
  @protected
  @visibleForTesting
  void dispose() {
    assert(
      !_debugDisposed,
      'Layers must only be disposed once. This is typically handled by '
      'LayerHandle and createHandle. Subclasses should not directly call '
      'dispose, except to call super.dispose() in an overridden dispose  '
      'method. Tests must only call dispose once.',
    );
    assert(() {
      assert(
        _refCount == 0,
        'Do not directly call dispose on a $runtimeType. Instead, '
        'use createHandle and LayerHandle.dispose.',
      );
222
      _debugDisposed = true;
223 224 225 226 227 228
      return true;
    }());
    _engineLayer?.dispose();
    _engineLayer = null;
  }

229 230 231 232 233 234 235
  /// This layer's parent in the layer tree.
  ///
  /// The [parent] of the root node in the layer tree is null.
  ///
  /// Only subclasses of [ContainerLayer] can have children in the layer tree.
  /// All other layer classes are used for leaves in the layer tree.
  @override
236
  ContainerLayer? get parent => super.parent as ContainerLayer?;
237

238 239
  // Whether this layer has any changes since its last call to [addToScene].
  //
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
  // Initialized to true as a new layer has never called [addToScene], and is
  // set to false after calling [addToScene]. The value can become true again
  // if [markNeedsAddToScene] is called, or when [updateSubtreeNeedsAddToScene]
  // is called on this layer or on an ancestor layer.
  //
  // The values of [_needsAddToScene] in a tree of layers are said to be
  // _consistent_ if every layer in the tree satisfies the following:
  //
  // - If [alwaysNeedsAddToScene] is true, then [_needsAddToScene] is also true.
  // - If [_needsAddToScene] is true and [parent] is not null, then
  //   `parent._needsAddToScene` is true.
  //
  // Typically, this value is set during the paint phase and during compositing.
  // During the paint phase render objects create new layers and call
  // [markNeedsAddToScene] on existing layers, causing this value to become
  // true. After the paint phase the tree may be in an inconsistent state.
  // During compositing [ContainerLayer.buildScene] first calls
  // [updateSubtreeNeedsAddToScene] to bring this tree to a consistent state,
  // then it calls [addToScene], and finally sets this field to false.
259 260 261 262
  bool _needsAddToScene = true;

  /// Mark that this layer has changed and [addToScene] needs to be called.
  @protected
263
  @visibleForTesting
264
  void markNeedsAddToScene() {
265 266 267
    assert(
      !alwaysNeedsAddToScene,
      '$runtimeType with alwaysNeedsAddToScene set called markNeedsAddToScene.\n'
268
      "The layer's alwaysNeedsAddToScene is set to true, and therefore it should not call markNeedsAddToScene.",
269
    );
270
    assert(!_debugDisposed);
271 272 273 274 275 276

    // Already marked. Short-circuit.
    if (_needsAddToScene) {
      return;
    }

277 278 279 280 281
    _needsAddToScene = true;
  }

  /// Mark that this layer is in sync with engine.
  ///
282 283
  /// This is for debugging and testing purposes only. In release builds
  /// this method has no effect.
284 285
  @visibleForTesting
  void debugMarkClean() {
286
    assert(() {
287 288 289 290 291 292 293 294 295
      _needsAddToScene = false;
      return true;
    }());
  }

  /// Subclasses may override this to true to disable retained rendering.
  @protected
  bool get alwaysNeedsAddToScene => false;

296
  /// Whether this or any descendant layer in the subtree needs [addToScene].
297 298 299 300
  ///
  /// This is for debug and test purpose only. It only becomes valid after
  /// calling [updateSubtreeNeedsAddToScene].
  @visibleForTesting
301 302
  bool? get debugSubtreeNeedsAddToScene {
    bool? result;
303
    assert(() {
304
      result = _needsAddToScene;
305 306 307 308 309
      return true;
    }());
    return result;
  }

310 311 312 313 314 315 316 317 318 319 320 321 322 323
  /// Stores the engine layer created for this layer in order to reuse engine
  /// resources across frames for better app performance.
  ///
  /// This value may be passed to [ui.SceneBuilder.addRetained] to communicate
  /// to the engine that nothing in this layer or any of its descendants
  /// changed. The native engine could, for example, reuse the texture rendered
  /// in a previous frame. The web engine could, for example, reuse the HTML
  /// DOM nodes created for a previous frame.
  ///
  /// This value may be passed as `oldLayer` argument to a "push" method to
  /// communicate to the engine that a layer is updating a previously rendered
  /// layer. The web engine could, for example, update the properties of
  /// previously rendered HTML DOM nodes rather than creating new nodes.
  @protected
324
  @visibleForTesting
325
  ui.EngineLayer? get engineLayer => _engineLayer;
326 327 328 329 330 331 332

  /// Sets the engine layer used to render this layer.
  ///
  /// Typically this field is set to the value returned by [addToScene], which
  /// in turn returns the engine layer produced by one of [ui.SceneBuilder]'s
  /// "push" methods, such as [ui.SceneBuilder.pushOpacity].
  @protected
333
  @visibleForTesting
334
  set engineLayer(ui.EngineLayer? value) {
335 336 337
    assert(!_debugDisposed);

    _engineLayer?.dispose();
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
    _engineLayer = value;
    if (!alwaysNeedsAddToScene) {
      // The parent must construct a new engine layer to add this layer to, and
      // so we mark it as needing [addToScene].
      //
      // This is designed to handle two situations:
      //
      // 1. When rendering the complete layer tree as normal. In this case we
      // call child `addToScene` methods first, then we call `set engineLayer`
      // for the parent. The children will call `markNeedsAddToScene` on the
      // parent to signal that they produced new engine layers and therefore
      // the parent needs to update. In this case, the parent is already adding
      // itself to the scene via [addToScene], and so after it's done, its
      // `set engineLayer` is called and it clears the `_needsAddToScene` flag.
      //
      // 2. When rendering an interior layer (e.g. `OffsetLayer.toImage`). In
      // this case we call `addToScene` for one of the children but not the
      // parent, i.e. we produce new engine layers for children but not for the
      // parent. Here the children will mark the parent as needing
      // `addToScene`, but the parent does not clear the flag until some future
      // frame decides to render it, at which point the parent knows that it
      // cannot retain its engine layer and will call `addToScene` again.
360 361
      if (parent != null && !parent!.alwaysNeedsAddToScene) {
        parent!.markNeedsAddToScene();
362 363 364
      }
    }
  }
365
  ui.EngineLayer? _engineLayer;
366

367
  /// Traverses the layer subtree starting from this layer and determines whether it needs [addToScene].
368
  ///
369 370 371 372 373 374 375
  /// A layer needs [addToScene] if any of the following is true:
  ///
  /// - [alwaysNeedsAddToScene] is true.
  /// - [markNeedsAddToScene] has been called.
  /// - Any of its descendants need [addToScene].
  ///
  /// [ContainerLayer] overrides this method to recursively call it on its children.
376
  @protected
377
  @visibleForTesting
378
  void updateSubtreeNeedsAddToScene() {
379
    _needsAddToScene = _needsAddToScene || alwaysNeedsAddToScene;
380 381
  }

382
  /// This layer's next sibling in the parent layer's child list.
383 384
  Layer? get nextSibling => _nextSibling;
  Layer? _nextSibling;
385

386
  /// This layer's previous sibling in the parent layer's child list.
387 388
  Layer? get previousSibling => _previousSibling;
  Layer? _previousSibling;
389

390 391
  @override
  void dropChild(AbstractNode child) {
392 393 394
    if (!alwaysNeedsAddToScene) {
      markNeedsAddToScene();
    }
395 396 397 398 399
    super.dropChild(child);
  }

  @override
  void adoptChild(AbstractNode child) {
400 401 402
    if (!alwaysNeedsAddToScene) {
      markNeedsAddToScene();
    }
403 404 405
    super.adoptChild(child);
  }

406
  /// Removes this layer from its parent layer's child list.
407 408
  ///
  /// This has no effect if the layer's parent is already null.
409
  @mustCallSuper
410 411
  void remove() {
    parent?._removeChild(this);
412
  }
413

414 415 416 417
  /// Search this layer and its subtree for annotations of type `S` at the
  /// location described by `localPosition`.
  ///
  /// This method is called by the default implementation of [find] and
418 419 420 421 422 423 424
  /// [findAllAnnotations]. Override this method to customize how the layer
  /// should search for annotations, or if the layer has its own annotations to
  /// add.
  ///
  /// The default implementation simply returns `false`, which means neither
  /// the layer nor its children has annotations, and the annotation search
  /// is not absorbed either (see below for explanation).
425 426 427
  ///
  /// ## About layer annotations
  ///
428
  /// {@template flutter.rendering.Layer.findAnnotations.aboutAnnotations}
429
  /// An annotation is an optional object of any type that can be carried with a
430 431
  /// layer. An annotation can be found at a location as long as the owner layer
  /// contains the location and is walked to.
432
  ///
433 434 435
  /// The annotations are searched by first visiting each child recursively,
  /// then this layer, resulting in an order from visually front to back.
  /// Annotations must meet the given restrictions, such as type and position.
436
  ///
437 438
  /// The common way for a value to be found here is by pushing an
  /// [AnnotatedRegionLayer] into the layer tree, or by adding the desired
439
  /// annotation by overriding [findAnnotations].
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
  /// {@endtemplate}
  ///
  /// ## Parameters and return value
  ///
  /// The [result] parameter is where the method outputs the resulting
  /// annotations. New annotations found during the walk are added to the tail.
  ///
  /// The [onlyFirst] parameter indicates that, if true, the search will stop
  /// when it finds the first qualified annotation; otherwise, it will walk the
  /// entire subtree.
  ///
  /// The return value indicates the opacity of this layer and its subtree at
  /// this position. If it returns true, then this layer's parent should skip
  /// the children behind this layer. In other words, it is opaque to this type
  /// of annotation and has absorbed the search so that its siblings behind it
  /// are not aware of the search. If the return value is false, then the parent
  /// might continue with other siblings.
  ///
  /// The return value does not affect whether the parent adds its own
  /// annotations; in other words, if a layer is supposed to add an annotation,
  /// it will always add it even if its children are opaque to this type of
  /// annotation. However, the opacity that the parents return might be affected
  /// by their children, hence making all of its ancestors opaque to this type
  /// of annotation.
  @protected
465
  bool findAnnotations<S extends Object>(
466 467
    AnnotationResult<S> result,
    Offset localPosition, {
468
    required bool onlyFirst,
469 470 471
  }) {
    return false;
  }
472 473 474 475 476 477 478

  /// Search this layer and its subtree for the first annotation of type `S`
  /// under the point described by `localPosition`.
  ///
  /// Returns null if no matching annotations are found.
  ///
  /// By default this method simply calls [findAnnotations] with `onlyFirst:
479 480 481 482
  /// true` and returns the annotation of the first result. Prefer overriding
  /// [findAnnotations] instead of this method, because during an annotation
  /// search, only [findAnnotations] is recursively called, while custom
  /// behavior in this method is ignored.
483 484 485
  ///
  /// ## About layer annotations
  ///
486
  /// {@macro flutter.rendering.Layer.findAnnotations.aboutAnnotations}
487 488 489
  ///
  /// See also:
  ///
490 491
  ///  * [findAllAnnotations], which is similar but returns all annotations found
  ///    at the given position.
492
  ///  * [AnnotatedRegionLayer], for placing values in the layer tree.
493
  S? find<S extends Object>(Offset localPosition) {
494 495
    final AnnotationResult<S> result = AnnotationResult<S>();
    findAnnotations<S>(result, localPosition, onlyFirst: true);
496 497 498 499 500 501 502 503 504 505 506 507 508
    return result.entries.isEmpty ? null : result.entries.first.annotation;
  }

  /// Search this layer and its subtree for all annotations of type `S` under
  /// the point described by `localPosition`.
  ///
  /// Returns a result with empty entries if no matching annotations are found.
  ///
  /// By default this method simply calls [findAnnotations] with `onlyFirst:
  /// false` and returns the annotations of its result. Prefer overriding
  /// [findAnnotations] instead of this method, because during an annotation
  /// search, only [findAnnotations] is recursively called, while custom
  /// behavior in this method is ignored.
509 510 511
  ///
  /// ## About layer annotations
  ///
512
  /// {@macro flutter.rendering.Layer.findAnnotations.aboutAnnotations}
513 514 515
  ///
  /// See also:
  ///
516 517
  ///  * [find], which is similar but returns the first annotation found at the
  ///    given position.
518
  ///  * [AnnotatedRegionLayer], for placing values in the layer tree.
519
  AnnotationResult<S> findAllAnnotations<S extends Object>(Offset localPosition) {
520 521 522 523
    final AnnotationResult<S> result = AnnotationResult<S>();
    findAnnotations<S>(result, localPosition, onlyFirst: false);
    return result;
  }
524

525
  /// Override this method to upload this layer to the engine.
526 527 528 529
  ///
  /// Return the engine layer for retained rendering. When there's no
  /// corresponding engine layer, null is returned.
  @protected
530
  void addToScene(ui.SceneBuilder builder);
531 532 533

  void _addToSceneWithRetainedRendering(ui.SceneBuilder builder) {
    // There can't be a loop by adding a retained layer subtree whose
534
    // _needsAddToScene is false.
535 536 537 538
    //
    // Proof by contradiction:
    //
    // If we introduce a loop, this retained layer must be appended to one of
xster's avatar
xster committed
539
    // its descendant layers, say A. That means the child structure of A has
540
    // changed so A's _needsAddToScene is true. This contradicts
541 542
    // _needsAddToScene being false.
    if (!_needsAddToScene && _engineLayer != null) {
543
      builder.addRetained(_engineLayer!);
544 545
      return;
    }
546 547 548 549
    addToScene(builder);
    // Clearing the flag _after_ calling `addToScene`, not _before_. This is
    // because `addToScene` calls children's `addToScene` methods, which may
    // mark this layer as dirty.
550 551
    _needsAddToScene = false;
  }
552

553 554 555 556
  /// The object responsible for creating this layer.
  ///
  /// Defaults to the value of [RenderObject.debugCreator] for the render object
  /// that created this layer. Used in debug messages.
557
  Object? debugCreator;
558

559
  @override
560
  String toStringShort() => '${super.toStringShort()}${ owner == null ? " DETACHED" : ""}';
561

562
  @override
563 564
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
565
    properties.add(DiagnosticsProperty<Object>('owner', owner, level: parent != null ? DiagnosticLevel.hidden : DiagnosticLevel.info, defaultValue: null));
566 567 568 569 570
    properties.add(DiagnosticsProperty<Object?>('creator', debugCreator, defaultValue: null, level: DiagnosticLevel.debug));
    if (_engineLayer != null) {
      properties.add(DiagnosticsProperty<String>('engine layer', describeIdentity(_engineLayer)));
    }
    properties.add(DiagnosticsProperty<int>('handles', debugHandleCount));
571
  }
572 573
}

574 575 576
/// A handle to prevent a [Layer]'s platform graphics resources from being
/// disposed.
///
577
/// [Layer] objects retain native resources such as [EngineLayer]s and [Picture]
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
/// objects. These objects may in turn retain large chunks of texture memory,
/// either directly or indirectly.
///
/// The layer's native resources must be retained as long as there is some
/// object that can add it to a scene. Typically, this is either its
/// [Layer.parent] or an undisposed [RenderObject] that will append it to a
/// [ContainerLayer]. Layers automatically hold a handle to their children, and
/// RenderObjects automatically hold a handle to their [RenderObject.layer] as
/// well as any [PictureLayer]s that they paint into using the
/// [PaintingContext.canvas]. A layer automatically releases its resources once
/// at least one handle has been acquired and all handles have been disposed.
/// [RenderObject]s that create additional layer objects must manually manage
/// the handles for that layer similarly to the implementation of
/// [RenderObject.layer].
///
/// A handle is automatically managed for [RenderObject.layer].
///
/// If a [RenderObject] creates layers in addition to its [RenderObject.layer]
/// and it intends to reuse those layers separately from [RenderObject.layer],
/// it must create a handle to that layer and dispose of it when the layer is
/// no longer needed. For example, if it re-creates or nulls out an existing
/// layer in [RenderObject.paint], it should dispose of the handle to the
/// old layer. It should also dispose of any layer handles it holds in
/// [RenderObject.dispose].
class LayerHandle<T extends Layer> {
  /// Create a new layer handle, optionally referencing a [Layer].
  LayerHandle([this._layer]) {
    if (_layer != null) {
      _layer!._refCount += 1;
    }
  }

  T? _layer;

  /// The [Layer] whose resources this object keeps alive.
  ///
614
  /// Setting a new value or null will dispose the previously held layer if
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
  /// there are no other open handles to that layer.
  T? get layer => _layer;

  set layer(T? layer) {
    assert(
      layer?.debugDisposed != true,
      'Attempted to create a handle to an already disposed layer: $layer.',
    );
    if (identical(layer, _layer)) {
      return;
    }
    _layer?._unref();
    _layer = layer;
    if (_layer != null) {
      _layer!._refCount += 1;
    }
  }

  @override
  String toString() => 'LayerHandle(${_layer != null ? _layer.toString() : 'DISPOSED'})';
}

637 638
/// A composited layer containing a [Picture].
///
639 640 641 642
/// Picture layers are always leaves in the layer tree. They are also
/// responsible for disposing of the [Picture] object they hold. This is
/// typically done when their parent and all [RenderObject]s that participated
/// in painting the picture have been disposed.
643
class PictureLayer extends Layer {
644
  /// Creates a leaf layer for the layer tree.
645 646 647 648 649
  PictureLayer(this.canvasBounds);

  /// The bounds that were used for the canvas that drew this layer's [picture].
  ///
  /// This is purely advisory. It is included in the information dumped with
650
  /// [debugDumpLayerTree] (which can be triggered by pressing "L" when using
651 652 653 654
  /// "flutter run" at the console), which can help debug why certain drawing
  /// commands are being culled.
  final Rect canvasBounds;

655
  /// The picture recorded for this layer.
656
  ///
657
  /// The picture's coordinate system matches this layer's coordinate system.
658 659 660
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
661 662 663
  ui.Picture? get picture => _picture;
  ui.Picture? _picture;
  set picture(ui.Picture? picture) {
664
    assert(!_debugDisposed);
665
    markNeedsAddToScene();
666
    _picture?.dispose();
667 668
    _picture = picture;
  }
669

670 671 672 673 674
  /// Hints that the painting in this 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 this layer is complex enough to benefit from caching.
675 676 677
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
678 679 680 681 682 683 684 685
  bool get isComplexHint => _isComplexHint;
  bool _isComplexHint = false;
  set isComplexHint(bool value) {
    if (value != _isComplexHint) {
      _isComplexHint = value;
      markNeedsAddToScene();
    }
  }
686 687 688 689 690 691 692

  /// Hints that the painting in this layer is likely to change next frame.
  ///
  /// This hint tells the compositor not to cache this 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 this layer is likely to be
  /// reused in the future.
693 694 695
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
696 697 698 699 700 701 702 703
  bool get willChangeHint => _willChangeHint;
  bool _willChangeHint = false;
  set willChangeHint(bool value) {
    if (value != _willChangeHint) {
      _willChangeHint = value;
      markNeedsAddToScene();
    }
  }
704

705 706 707 708 709 710
  @override
  void dispose() {
    picture = null; // Will dispose _picture.
    super.dispose();
  }

711
  @override
712
  void addToScene(ui.SceneBuilder builder) {
713
    assert(picture != null);
714
    builder.addPicture(Offset.zero, picture!, isComplexHint: isComplexHint, willChangeHint: willChangeHint);
715
  }
716 717

  @override
718 719
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
720
    properties.add(DiagnosticsProperty<Rect>('paint bounds', canvasBounds));
721 722 723
    properties.add(DiagnosticsProperty<String>('picture', describeIdentity(_picture)));
    properties.add(DiagnosticsProperty<String>(
      'raster cache hints',
724 725
      'isComplex = $isComplexHint, willChange = $willChangeHint',
    ));
726
  }
727 728

  @override
729
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
730 731
    return false;
  }
732 733
}

734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
/// A composited layer that maps a backend texture to a rectangle.
///
/// Backend textures are images that can be applied (mapped) to an area of the
/// Flutter view. They are created, managed, and updated using a
/// platform-specific texture registry. This is typically done by a plugin
/// that integrates with host platform video player, camera, or OpenGL APIs,
/// or similar image sources.
///
/// A texture layer refers to its backend texture using an integer ID. Texture
/// IDs are obtained from the texture registry and are scoped to the Flutter
/// view. Texture IDs may be reused after deregistration, at the discretion
/// of the registry. The use of texture IDs currently unknown to the registry
/// will silently result in a blank rectangle.
///
/// Once inserted into the layer tree, texture layers are repainted autonomously
/// as dictated by the backend (e.g. on arrival of a video frame). Such
/// repainting generally does not involve executing Dart code.
///
/// Texture layers are always leaves in the layer tree.
///
/// See also:
///
756
///  * <https://api.flutter.dev/javadoc/io/flutter/view/TextureRegistry.html>
757
///    for how to create and manage backend textures on Android.
758
///  * <https://api.flutter.dev/objcdoc/Protocols/FlutterTextureRegistry.html>
759
///    for how to create and manage backend textures on iOS.
760 761
class TextureLayer extends Layer {
  /// Creates a texture layer bounded by [rect] and with backend texture
762
  /// identified by [textureId], if [freeze] is true new texture frames will not be
763
  /// populated to the texture, and use [filterQuality] to set layer's [FilterQuality].
764
  TextureLayer({
765 766
    required this.rect,
    required this.textureId,
767
    this.freeze = false,
768
    this.filterQuality = ui.FilterQuality.low,
769 770
  }) : assert(rect != null),
       assert(textureId != null);
771 772 773 774 775 776 777

  /// Bounding rectangle of this layer.
  final Rect rect;

  /// The identity of the backend texture.
  final int textureId;

778
  /// When true the texture will not be updated with new frames.
779
  ///
780
  /// This is used for resizing embedded Android views: when resizing there
781 782 783 784
  /// is a short period during which the framework cannot tell if the newest
  /// texture frame has the previous or new size, to workaround this the
  /// framework "freezes" the texture just before resizing the Android view and
  /// un-freezes it when it is certain that a frame with the new size is ready.
785 786
  final bool freeze;

787
  /// {@macro flutter.widgets.Texture.filterQuality}
788 789
  final ui.FilterQuality filterQuality;

790
  @override
791
  void addToScene(ui.SceneBuilder builder) {
792 793
    builder.addTexture(
      textureId,
794 795 796
      offset: rect.topLeft,
      width: rect.width,
      height: rect.height,
797
      freeze: freeze,
798
      filterQuality: filterQuality,
799 800
    );
  }
801 802

  @override
803
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
804 805
    return false;
  }
806 807
}

808 809 810 811 812 813 814
/// A layer that shows an embedded [UIView](https://developer.apple.com/documentation/uikit/uiview)
/// on iOS.
class PlatformViewLayer extends Layer {
  /// Creates a platform view layer.
  ///
  /// The `rect` and `viewId` parameters must not be null.
  PlatformViewLayer({
815 816
    required this.rect,
    required this.viewId,
817 818
  }) : assert(rect != null),
       assert(viewId != null);
819 820 821 822 823 824

  /// Bounding rectangle of this layer in the global coordinate space.
  final Rect rect;

  /// The unique identifier of the UIView displayed on this layer.
  ///
825
  /// A UIView with this identifier must have been created by [PlatformViewsService.initUiKitView].
826 827 828
  final int viewId;

  @override
829
  void addToScene(ui.SceneBuilder builder) {
830 831
    builder.addPlatformView(
      viewId,
832 833 834
      offset: rect.topLeft,
      width: rect.width,
      height: rect.height,
835 836 837 838
    );
  }
}

839
/// A layer that indicates to the compositor that it should display
840
/// certain performance statistics within it.
841 842
///
/// Performance overlay layers are always leaves in the layer tree.
843
class PerformanceOverlayLayer extends Layer {
844
  /// Creates a layer that displays a performance overlay.
845
  PerformanceOverlayLayer({
846 847 848 849 850
    required Rect overlayRect,
    required this.optionsMask,
    required this.rasterizerThreshold,
    required this.checkerboardRasterCacheImages,
    required this.checkerboardOffscreenLayers,
851
  }) : _overlayRect = overlayRect;
852

853
  /// The rectangle in this layer's coordinate system that the overlay should occupy.
854 855 856
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
857 858 859 860 861 862 863 864
  Rect get overlayRect => _overlayRect;
  Rect _overlayRect;
  set overlayRect(Rect value) {
    if (value != _overlayRect) {
      _overlayRect = value;
      markNeedsAddToScene();
    }
  }
865

866 867
  /// The mask is created by shifting 1 by the index of the specific
  /// [PerformanceOverlayOption] to enable.
868 869
  final int optionsMask;

870 871 872
  /// The rasterizer threshold is an integer specifying the number of frame
  /// intervals that the rasterizer must miss before it decides that the frame
  /// is suitable for capturing an SkPicture trace for further analysis.
873
  final int rasterizerThreshold;
874

875 876 877 878 879 880 881 882 883 884 885 886 887
  /// Whether the raster cache should checkerboard cached entries.
  ///
  /// The compositor can sometimes decide to cache certain portions of the
  /// widget hierarchy. Such portions typically don't change often from frame to
  /// frame and are expensive to render. This can speed up overall rendering. However,
  /// there is certain upfront cost to constructing these cache entries. And, if
  /// the cache entries are not used very often, this cost may not be worth the
  /// speedup in rendering of subsequent frames. If the developer wants to be certain
  /// that populating the raster cache is not causing stutters, this option can be
  /// set. Depending on the observations made, hints can be provided to the compositor
  /// that aid it in making better decisions about caching.
  final bool checkerboardRasterCacheImages;

888 889 890 891 892 893 894 895 896 897
  /// Whether the compositor should checkerboard layers that are rendered to offscreen
  /// bitmaps. This can be useful for debugging rendering performance.
  ///
  /// Render target switches are caused by using opacity layers (via a [FadeTransition] or
  /// [Opacity] widget), clips, shader mask layers, etc. Selecting a new render target
  /// and merging it with the rest of the scene has a performance cost. This can sometimes
  /// be avoided by using equivalent widgets that do not require these layers (for example,
  /// replacing an [Opacity] widget with an [widgets.Image] using a [BlendMode]).
  final bool checkerboardOffscreenLayers;

898
  @override
899
  void addToScene(ui.SceneBuilder builder) {
900
    assert(optionsMask != null);
901
    builder.addPerformanceOverlay(optionsMask, overlayRect);
902
    builder.setRasterizerTracingThreshold(rasterizerThreshold);
903
    builder.setCheckerboardRasterCacheImages(checkerboardRasterCacheImages);
904
    builder.setCheckerboardOffscreenLayers(checkerboardOffscreenLayers);
905
  }
906 907

  @override
908
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
909 910
    return false;
  }
911 912
}

913 914 915 916 917
/// A composited layer that has a list of children.
///
/// A [ContainerLayer] instance merely takes a list of children and inserts them
/// into the composited rendering in order. There are subclasses of
/// [ContainerLayer] which apply more elaborate effects in the process.
918
class ContainerLayer extends Layer {
919
  /// The first composited layer in this layer's child list.
920 921
  Layer? get firstChild => _firstChild;
  Layer? _firstChild;
922

923
  /// The last composited layer in this layer's child list.
924 925
  Layer? get lastChild => _lastChild;
  Layer? _lastChild;
926

927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
  /// Returns whether this layer has at least one child layer.
  bool get hasChildren => _firstChild != null;

  /// Consider this layer as the root and build a scene (a tree of layers)
  /// in the engine.
  // The reason this method is in the `ContainerLayer` class rather than
  // `PipelineOwner` or other singleton level is because this method can be used
  // both to render the whole layer tree (e.g. a normal application frame) and
  // to render a subtree (e.g. `OffsetLayer.toImage`).
  ui.Scene buildScene(ui.SceneBuilder builder) {
    updateSubtreeNeedsAddToScene();
    addToScene(builder);
    // Clearing the flag _after_ calling `addToScene`, not _before_. This is
    // because `addToScene` calls children's `addToScene` methods, which may
    // mark this layer as dirty.
    _needsAddToScene = false;
    final ui.Scene scene = builder.build();
    return scene;
  }

947
  bool _debugUltimatePreviousSiblingOf(Layer child, { Layer? equals }) {
948 949 950
    assert(child.attached == attached);
    while (child.previousSibling != null) {
      assert(child.previousSibling != child);
951
      child = child.previousSibling!;
952
      assert(child.attached == attached);
953 954 955 956
    }
    return child == equals;
  }

957
  bool _debugUltimateNextSiblingOf(Layer child, { Layer? equals }) {
958
    assert(child.attached == attached);
959 960
    while (child._nextSibling != null) {
      assert(child._nextSibling != child);
961
      child = child._nextSibling!;
962
      assert(child.attached == attached);
963 964 965 966
    }
    return child == equals;
  }

967 968 969 970 971 972
  @override
  void dispose() {
    removeAllChildren();
    super.dispose();
  }

973 974 975
  @override
  void updateSubtreeNeedsAddToScene() {
    super.updateSubtreeNeedsAddToScene();
976
    Layer? child = firstChild;
977 978
    while (child != null) {
      child.updateSubtreeNeedsAddToScene();
979
      _needsAddToScene = _needsAddToScene || child._needsAddToScene;
980 981 982 983
      child = child.nextSibling;
    }
  }

984
  @override
985 986
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    for (Layer? child = lastChild; child != null; child = child.previousSibling) {
987 988 989 990 991
      final bool isAbsorbed = child.findAnnotations<S>(result, localPosition, onlyFirst: onlyFirst);
      if (isAbsorbed)
        return true;
      if (onlyFirst && result.entries.isNotEmpty)
        return isAbsorbed;
992
    }
993
    return false;
994 995
  }

996 997 998
  @override
  void attach(Object owner) {
    super.attach(owner);
999
    Layer? child = firstChild;
1000 1001 1002 1003 1004 1005 1006 1007 1008
    while (child != null) {
      child.attach(owner);
      child = child.nextSibling;
    }
  }

  @override
  void detach() {
    super.detach();
1009
    Layer? child = firstChild;
1010 1011 1012 1013 1014 1015 1016
    while (child != null) {
      child.detach();
      child = child.nextSibling;
    }
  }

  /// Adds the given layer to the end of this layer's child list.
1017
  void append(Layer child) {
1018
    assert(child != this);
1019 1020 1021 1022 1023 1024
    assert(child != firstChild);
    assert(child != lastChild);
    assert(child.parent == null);
    assert(!child.attached);
    assert(child.nextSibling == null);
    assert(child.previousSibling == null);
1025
    assert(child._parentHandle.layer == null);
1026 1027 1028
    assert(() {
      Layer node = this;
      while (node.parent != null)
1029
        node = node.parent!;
1030 1031
      assert(node != child); // indicates we are about to create a cycle
      return true;
1032
    }());
1033 1034 1035
    adoptChild(child);
    child._previousSibling = lastChild;
    if (lastChild != null)
1036
      lastChild!._nextSibling = child;
1037
    _lastChild = child;
1038
    _firstChild ??= child;
1039
    child._parentHandle.layer = child;
1040
    assert(child.attached == attached);
1041 1042
  }

1043 1044 1045 1046 1047 1048
  // Implementation of [Layer.remove].
  void _removeChild(Layer child) {
    assert(child.parent == this);
    assert(child.attached == attached);
    assert(_debugUltimatePreviousSiblingOf(child, equals: firstChild));
    assert(_debugUltimateNextSiblingOf(child, equals: lastChild));
1049
    assert(child._parentHandle.layer != null);
1050 1051 1052 1053
    if (child._previousSibling == null) {
      assert(_firstChild == child);
      _firstChild = child._nextSibling;
    } else {
1054
      child._previousSibling!._nextSibling = child.nextSibling;
1055 1056
    }
    if (child._nextSibling == null) {
1057 1058
      assert(lastChild == child);
      _lastChild = child.previousSibling;
1059
    } else {
1060
      child.nextSibling!._previousSibling = child.previousSibling;
1061
    }
1062
    assert((firstChild == null) == (lastChild == null));
1063 1064 1065 1066
    assert(firstChild == null || firstChild!.attached == attached);
    assert(lastChild == null || lastChild!.attached == attached);
    assert(firstChild == null || _debugUltimateNextSiblingOf(firstChild!, equals: lastChild));
    assert(lastChild == null || _debugUltimatePreviousSiblingOf(lastChild!, equals: firstChild));
1067 1068
    child._previousSibling = null;
    child._nextSibling = null;
1069
    dropChild(child);
1070
    child._parentHandle.layer = null;
1071
    assert(!child.attached);
1072
  }
Hixie's avatar
Hixie committed
1073

1074
  /// Removes all of this layer's children from its child list.
1075
  void removeAllChildren() {
1076
    Layer? child = firstChild;
1077
    while (child != null) {
1078
      final Layer? next = child.nextSibling;
1079 1080
      child._previousSibling = null;
      child._nextSibling = null;
1081 1082
      assert(child.attached == attached);
      dropChild(child);
1083 1084
      assert(child._parentHandle != null);
      child._parentHandle.layer = null;
1085 1086 1087 1088 1089 1090
      child = next;
    }
    _firstChild = null;
    _lastChild = null;
  }

1091
  @override
1092 1093
  void addToScene(ui.SceneBuilder builder) {
    addChildrenToScene(builder);
Hixie's avatar
Hixie committed
1094 1095
  }

1096 1097 1098 1099
  /// Uploads all of this layer's children to the engine.
  ///
  /// This method is typically used by [addToScene] to insert the children into
  /// the scene. Subclasses of [ContainerLayer] typically override [addToScene]
1100
  /// to apply effects to the scene using the [SceneBuilder] API, then insert
1101 1102
  /// their children using [addChildrenToScene], then reverse the aforementioned
  /// effects before returning from [addToScene].
1103
  void addChildrenToScene(ui.SceneBuilder builder) {
1104
    Layer? child = firstChild;
Hixie's avatar
Hixie committed
1105
    while (child != null) {
1106
      child._addToSceneWithRetainedRendering(builder);
Hixie's avatar
Hixie committed
1107 1108 1109
      child = child.nextSibling;
    }
  }
1110

1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
  /// Applies the transform that would be applied when compositing the given
  /// child to the given matrix.
  ///
  /// Specifically, this should apply the transform that is applied to child's
  /// _origin_. When using [applyTransform] with a chain of layers, results will
  /// be unreliable unless the deepest layer in the chain collapses the
  /// `layerOffset` in [addToScene] to zero, meaning that it passes
  /// [Offset.zero] to its children, and bakes any incoming `layerOffset` into
  /// the [SceneBuilder] as (for instance) a transform (which is then also
  /// included in the transformation applied by [applyTransform]).
  ///
  /// For example, if [addToScene] applies the `layerOffset` and then
  /// passes [Offset.zero] to the children, then it should be included in the
  /// transform applied here, whereas if [addToScene] just passes the
  /// `layerOffset` to the child, then it should not be included in the
  /// transform applied here.
  ///
  /// This method is only valid immediately after [addToScene] has been called,
  /// before any of the properties have been changed.
  ///
  /// The default implementation does nothing, since [ContainerLayer], by
1132
  /// default, composites its children at the origin of the [ContainerLayer]
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
  /// itself.
  ///
  /// The `child` argument should generally not be null, since in principle a
  /// layer could transform each child independently. However, certain layers
  /// may explicitly allow null as a value, for example if they know that they
  /// transform all their children identically.
  ///
  /// The `transform` argument must not be null.
  ///
  /// Used by [FollowerLayer] to transform its child to a [LeaderLayer]'s
  /// position.
1144
  void applyTransform(Layer? child, Matrix4 transform) {
1145 1146 1147 1148
    assert(child != null);
    assert(transform != null);
  }

1149 1150 1151 1152 1153 1154
  /// Returns the descendants of this layer in depth first order.
  @visibleForTesting
  List<Layer> depthFirstIterateChildren() {
    if (firstChild == null)
      return <Layer>[];
    final List<Layer> children = <Layer>[];
1155
    Layer? child = firstChild;
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
    while(child != null) {
      children.add(child);
      if (child is ContainerLayer) {
        children.addAll(child.depthFirstIterateChildren());
      }
      child = child.nextSibling;
    }
    return children;
  }

1166
  @override
1167 1168
  List<DiagnosticsNode> debugDescribeChildren() {
    final List<DiagnosticsNode> children = <DiagnosticsNode>[];
1169
    if (firstChild == null)
1170
      return children;
1171
    Layer? child = firstChild;
1172
    int count = 1;
1173
    while (true) {
1174
      children.add(child!.toDiagnosticsNode(name: 'child $count'));
1175 1176
      if (child == lastChild)
        break;
1177 1178 1179
      count += 1;
      child = child.nextSibling;
    }
1180
    return children;
1181
  }
Hixie's avatar
Hixie committed
1182 1183
}

1184 1185 1186 1187 1188 1189 1190 1191 1192
/// A layer that is displayed at an offset from its parent layer.
///
/// Offset layers are key to efficient repainting because they are created by
/// repaint boundaries in the [RenderObject] tree (see
/// [RenderObject.isRepaintBoundary]). When a render object that is a repaint
/// boundary is asked to paint at given offset in a [PaintingContext], the
/// render object first checks whether it needs to repaint itself. If not, it
/// reuses its existing [OffsetLayer] (and its entire subtree) by mutating its
/// [offset] property, cutting off the paint walk.
1193
class OffsetLayer extends ContainerLayer {
1194 1195
  /// Creates an offset layer.
  ///
1196 1197
  /// By default, [offset] is zero. It must be non-null before the compositing
  /// phase of the pipeline.
1198
  OffsetLayer({ Offset offset = Offset.zero }) : _offset = offset;
1199 1200

  /// Offset from parent in the parent's coordinate system.
1201 1202 1203
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1204 1205 1206
  ///
  /// The [offset] property must be non-null before the compositing phase of the
  /// pipeline.
1207 1208 1209 1210 1211 1212 1213 1214
  Offset get offset => _offset;
  Offset _offset;
  set offset(Offset value) {
    if (value != _offset) {
      markNeedsAddToScene();
    }
    _offset = value;
  }
1215

1216
  @override
1217
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
1218
    return super.findAnnotations<S>(result, localPosition - offset, onlyFirst: onlyFirst);
1219 1220
  }

1221
  @override
1222
  void applyTransform(Layer? child, Matrix4 transform) {
1223 1224 1225 1226 1227 1228
    assert(child != null);
    assert(transform != null);
    transform.multiply(Matrix4.translationValues(offset.dx, offset.dy, 0.0));
  }

  @override
1229
  void addToScene(ui.SceneBuilder builder) {
1230 1231 1232 1233 1234
    // Skia has a fast path for concatenating scale/translation only matrices.
    // Hence pushing a translation-only transform layer should be fast. For
    // retained rendering, we don't want to push the offset down to each leaf
    // node. Otherwise, changing an offset layer on the very high level could
    // cascade the change to too many leaves.
1235
    engineLayer = builder.pushOffset(
1236 1237
      offset.dx,
      offset.dy,
1238
      oldLayer: _engineLayer as ui.OffsetEngineLayer?,
1239
    );
1240 1241
    addChildrenToScene(builder);
    builder.pop();
1242 1243
  }

1244
  @override
1245 1246
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1247
    properties.add(DiagnosticsProperty<Offset>('offset', offset));
1248
  }
1249 1250 1251

  /// Capture an image of the current state of this layer and its children.
  ///
1252 1253 1254
  /// The returned [ui.Image] has uncompressed raw RGBA bytes, will be offset
  /// by the top-left corner of [bounds], and have dimensions equal to the size
  /// of [bounds] multiplied by [pixelRatio].
1255 1256 1257
  ///
  /// The [pixelRatio] describes the scale between the logical pixels and the
  /// size of the output image. It is independent of the
1258 1259 1260
  /// [dart:ui.FlutterView.devicePixelRatio] for the device, so specifying 1.0
  /// (the default) will give you a 1:1 mapping between logical pixels and the
  /// output pixels in the image.
1261 1262 1263 1264 1265
  ///
  /// See also:
  ///
  ///  * [RenderRepaintBoundary.toImage] for a similar API at the render object level.
  ///  * [dart:ui.Scene.toImage] for more information about the image returned.
1266
  Future<ui.Image> toImage(Rect bounds, { double pixelRatio = 1.0 }) async {
1267
    assert(bounds != null);
1268
    assert(pixelRatio != null);
1269 1270
    final ui.SceneBuilder builder = ui.SceneBuilder();
    final Matrix4 transform = Matrix4.translationValues(
1271 1272 1273 1274
      (-bounds.left  - offset.dx) * pixelRatio,
      (-bounds.top - offset.dy) * pixelRatio,
      0.0,
    );
1275
    transform.scale(pixelRatio, pixelRatio);
1276
    builder.pushTransform(transform.storage);
1277
    final ui.Scene scene = buildScene(builder);
1278

1279 1280 1281 1282
    try {
      // Size is rounded up to the next pixel to make sure we don't clip off
      // anything.
      return await scene.toImage(
1283 1284
        (pixelRatio * bounds.width).ceil(),
        (pixelRatio * bounds.height).ceil(),
1285 1286 1287 1288 1289
      );
    } finally {
      scene.dispose();
    }
  }
1290 1291
}

1292
/// A composite layer that clips its children using a rectangle.
1293 1294 1295 1296
///
/// When debugging, setting [debugDisableClipLayers] to true will cause this
/// layer to be skipped (directly replaced by its children). This can be helpful
/// to track down the cause of performance problems.
Hixie's avatar
Hixie committed
1297
class ClipRectLayer extends ContainerLayer {
1298 1299
  /// Creates a layer with a rectangular clip.
  ///
1300 1301 1302 1303
  /// The [clipRect] argument must not be null before the compositing phase of
  /// the pipeline.
  ///
  /// The [clipBehavior] argument must not be null, and must not be [Clip.none].
1304
  ClipRectLayer({
1305
    Rect? clipRect,
1306 1307 1308 1309 1310
    Clip clipBehavior = Clip.hardEdge,
  }) : _clipRect = clipRect,
       _clipBehavior = clipBehavior,
       assert(clipBehavior != null),
       assert(clipBehavior != Clip.none);
Hixie's avatar
Hixie committed
1311

1312 1313 1314 1315
  /// The rectangle to clip in the parent's coordinate system.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1316 1317 1318
  Rect? get clipRect => _clipRect;
  Rect? _clipRect;
  set clipRect(Rect? value) {
1319 1320 1321 1322 1323
    if (value != _clipRect) {
      _clipRect = value;
      markNeedsAddToScene();
    }
  }
Hixie's avatar
Hixie committed
1324

1325
  /// {@template flutter.rendering.ClipRectLayer.clipBehavior}
1326
  /// Controls how to clip.
1327
  ///
1328
  /// Must not be set to null or [Clip.none].
1329
  /// {@endtemplate}
1330 1331
  ///
  /// Defaults to [Clip.hardEdge].
1332 1333 1334 1335 1336
  Clip get clipBehavior => _clipBehavior;
  Clip _clipBehavior;
  set clipBehavior(Clip value) {
    assert(value != null);
    assert(value != Clip.none);
1337 1338 1339 1340
    if (value != _clipBehavior) {
      _clipBehavior = value;
      markNeedsAddToScene();
    }
1341 1342
  }

1343
  @override
1344 1345
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    if (!clipRect!.contains(localPosition))
1346 1347
      return false;
    return super.findAnnotations<S>(result, localPosition, onlyFirst: onlyFirst);
1348 1349
  }

1350
  @override
1351
  void addToScene(ui.SceneBuilder builder) {
1352 1353
    assert(clipRect != null);
    assert(clipBehavior != null);
1354 1355 1356 1357 1358
    bool enabled = true;
    assert(() {
      enabled = !debugDisableClipLayers;
      return true;
    }());
1359
    if (enabled) {
1360
      engineLayer = builder.pushClipRect(
1361
        clipRect!,
1362
        clipBehavior: clipBehavior,
1363
        oldLayer: _engineLayer as ui.ClipRectEngineLayer?,
1364
      );
1365 1366
    } else {
      engineLayer = null;
1367
    }
1368
    addChildrenToScene(builder);
1369
    if (enabled)
1370
      builder.pop();
Hixie's avatar
Hixie committed
1371 1372
  }

1373
  @override
1374 1375
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1376
    properties.add(DiagnosticsProperty<Rect>('clipRect', clipRect));
1377
    properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior));
1378
  }
1379
}
Hixie's avatar
Hixie committed
1380

1381
/// A composite layer that clips its children using a rounded rectangle.
1382 1383 1384 1385
///
/// When debugging, setting [debugDisableClipLayers] to true will cause this
/// layer to be skipped (directly replaced by its children). This can be helpful
/// to track down the cause of performance problems.
Hixie's avatar
Hixie committed
1386
class ClipRRectLayer extends ContainerLayer {
1387 1388
  /// Creates a layer with a rounded-rectangular clip.
  ///
1389 1390
  /// The [clipRRect] and [clipBehavior] properties must be non-null before the
  /// compositing phase of the pipeline.
1391
  ClipRRectLayer({
1392
    RRect? clipRRect,
1393 1394 1395 1396 1397
    Clip clipBehavior = Clip.antiAlias,
  }) : _clipRRect = clipRRect,
       _clipBehavior = clipBehavior,
       assert(clipBehavior != null),
       assert(clipBehavior != Clip.none);
1398

1399 1400 1401 1402
  /// The rounded-rect to clip in the parent's coordinate system.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1403 1404 1405
  RRect? get clipRRect => _clipRRect;
  RRect? _clipRRect;
  set clipRRect(RRect? value) {
1406 1407 1408 1409 1410
    if (value != _clipRRect) {
      _clipRRect = value;
      markNeedsAddToScene();
    }
  }
Hixie's avatar
Hixie committed
1411

1412
  /// {@macro flutter.rendering.ClipRectLayer.clipBehavior}
1413 1414
  ///
  /// Defaults to [Clip.antiAlias].
1415 1416 1417 1418 1419
  Clip get clipBehavior => _clipBehavior;
  Clip _clipBehavior;
  set clipBehavior(Clip value) {
    assert(value != null);
    assert(value != Clip.none);
1420 1421 1422 1423
    if (value != _clipBehavior) {
      _clipBehavior = value;
      markNeedsAddToScene();
    }
1424 1425
  }

1426
  @override
1427 1428
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    if (!clipRRect!.contains(localPosition))
1429 1430
      return false;
    return super.findAnnotations<S>(result, localPosition, onlyFirst: onlyFirst);
1431 1432
  }

1433
  @override
1434
  void addToScene(ui.SceneBuilder builder) {
1435 1436
    assert(clipRRect != null);
    assert(clipBehavior != null);
1437 1438 1439 1440 1441
    bool enabled = true;
    assert(() {
      enabled = !debugDisableClipLayers;
      return true;
    }());
1442
    if (enabled) {
1443
      engineLayer = builder.pushClipRRect(
1444
        clipRRect!,
1445
        clipBehavior: clipBehavior,
1446
        oldLayer: _engineLayer as ui.ClipRRectEngineLayer?,
1447
      );
1448 1449
    } else {
      engineLayer = null;
1450
    }
1451
    addChildrenToScene(builder);
1452
    if (enabled)
1453
      builder.pop();
Hixie's avatar
Hixie committed
1454
  }
1455

1456
  @override
1457 1458
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1459
    properties.add(DiagnosticsProperty<RRect>('clipRRect', clipRRect));
1460
    properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior));
1461
  }
Hixie's avatar
Hixie committed
1462 1463
}

1464
/// A composite layer that clips its children using a path.
1465 1466 1467 1468
///
/// When debugging, setting [debugDisableClipLayers] to true will cause this
/// layer to be skipped (directly replaced by its children). This can be helpful
/// to track down the cause of performance problems.
Hixie's avatar
Hixie committed
1469
class ClipPathLayer extends ContainerLayer {
1470 1471
  /// Creates a layer with a path-based clip.
  ///
1472 1473
  /// The [clipPath] and [clipBehavior] properties must be non-null before the
  /// compositing phase of the pipeline.
1474
  ClipPathLayer({
1475
    Path? clipPath,
1476 1477 1478 1479 1480
    Clip clipBehavior = Clip.antiAlias,
  }) : _clipPath = clipPath,
       _clipBehavior = clipBehavior,
       assert(clipBehavior != null),
       assert(clipBehavior != Clip.none);
1481

1482 1483 1484 1485
  /// The path to clip in the parent's coordinate system.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1486 1487 1488
  Path? get clipPath => _clipPath;
  Path? _clipPath;
  set clipPath(Path? value) {
1489 1490 1491 1492 1493
    if (value != _clipPath) {
      _clipPath = value;
      markNeedsAddToScene();
    }
  }
Hixie's avatar
Hixie committed
1494

1495
  /// {@macro flutter.rendering.ClipRectLayer.clipBehavior}
1496 1497
  ///
  /// Defaults to [Clip.antiAlias].
1498 1499 1500 1501 1502
  Clip get clipBehavior => _clipBehavior;
  Clip _clipBehavior;
  set clipBehavior(Clip value) {
    assert(value != null);
    assert(value != Clip.none);
1503 1504 1505 1506
    if (value != _clipBehavior) {
      _clipBehavior = value;
      markNeedsAddToScene();
    }
1507 1508
  }

1509
  @override
1510 1511
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    if (!clipPath!.contains(localPosition))
1512 1513
      return false;
    return super.findAnnotations<S>(result, localPosition, onlyFirst: onlyFirst);
1514 1515
  }

1516
  @override
1517
  void addToScene(ui.SceneBuilder builder) {
1518 1519
    assert(clipPath != null);
    assert(clipBehavior != null);
1520 1521 1522 1523 1524
    bool enabled = true;
    assert(() {
      enabled = !debugDisableClipLayers;
      return true;
    }());
1525
    if (enabled) {
1526
      engineLayer = builder.pushClipPath(
1527
        clipPath!,
1528
        clipBehavior: clipBehavior,
1529
        oldLayer: _engineLayer as ui.ClipPathEngineLayer?,
1530
      );
1531 1532
    } else {
      engineLayer = null;
1533
    }
1534
    addChildrenToScene(builder);
1535
    if (enabled)
1536
      builder.pop();
Hixie's avatar
Hixie committed
1537
  }
1538 1539 1540 1541 1542 1543

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior));
  }
1544 1545
}

1546 1547 1548 1549
/// A composite layer that applies a [ColorFilter] to its children.
class ColorFilterLayer extends ContainerLayer {
  /// Creates a layer that applies a [ColorFilter] to its children.
  ///
1550
  /// The [colorFilter] property must be non-null before the compositing phase
1551 1552
  /// of the pipeline.
  ColorFilterLayer({
1553
    ColorFilter? colorFilter,
1554
  }) : _colorFilter = colorFilter;
1555 1556 1557 1558 1559

  /// The color filter to apply to children.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1560 1561 1562
  ColorFilter? get colorFilter => _colorFilter;
  ColorFilter? _colorFilter;
  set colorFilter(ColorFilter? value) {
1563
    assert(value != null);
1564 1565 1566 1567 1568 1569 1570
    if (value != _colorFilter) {
      _colorFilter = value;
      markNeedsAddToScene();
    }
  }

  @override
1571
  void addToScene(ui.SceneBuilder builder) {
1572
    assert(colorFilter != null);
1573
    engineLayer = builder.pushColorFilter(
1574 1575
      colorFilter!,
      oldLayer: _engineLayer as ui.ColorFilterEngineLayer?,
1576
    );
1577
    addChildrenToScene(builder);
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
    builder.pop();
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<ColorFilter>('colorFilter', colorFilter));
  }
}

1588 1589 1590 1591 1592 1593 1594
/// A composite layer that applies an [ImageFilter] to its children.
class ImageFilterLayer extends ContainerLayer {
  /// Creates a layer that applies an [ImageFilter] to its children.
  ///
  /// The [imageFilter] property must be non-null before the compositing phase
  /// of the pipeline.
  ImageFilterLayer({
1595
    ui.ImageFilter? imageFilter,
1596 1597 1598 1599 1600 1601
  }) : _imageFilter = imageFilter;

  /// The image filter to apply to children.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1602 1603 1604
  ui.ImageFilter? get imageFilter => _imageFilter;
  ui.ImageFilter? _imageFilter;
  set imageFilter(ui.ImageFilter? value) {
1605 1606 1607 1608 1609 1610 1611 1612
    assert(value != null);
    if (value != _imageFilter) {
      _imageFilter = value;
      markNeedsAddToScene();
    }
  }

  @override
1613
  void addToScene(ui.SceneBuilder builder) {
1614 1615
    assert(imageFilter != null);
    engineLayer = builder.pushImageFilter(
1616 1617
      imageFilter!,
      oldLayer: _engineLayer as ui.ImageFilterEngineLayer?,
1618
    );
1619
    addChildrenToScene(builder);
1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
    builder.pop();
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(DiagnosticsProperty<ui.ImageFilter>('imageFilter', imageFilter));
  }
}

1630 1631 1632 1633 1634
/// A composited layer that applies a given transformation matrix to its
/// children.
///
/// This class inherits from [OffsetLayer] to make it one of the layers that
/// can be used at the root of a [RenderObject] hierarchy.
1635
class TransformLayer extends OffsetLayer {
1636 1637
  /// Creates a transform layer.
  ///
1638 1639
  /// The [transform] and [offset] properties must be non-null before the
  /// compositing phase of the pipeline.
1640
  TransformLayer({ Matrix4? transform, Offset offset = Offset.zero })
1641
    : _transform = transform,
1642
      super(offset: offset);
1643

1644 1645 1646 1647
  /// The matrix to apply.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1648 1649 1650 1651 1652
  ///
  /// This transform is applied before [offset], if both are set.
  ///
  /// The [transform] property must be non-null before the compositing phase of
  /// the pipeline.
1653 1654 1655
  Matrix4? get transform => _transform;
  Matrix4? _transform;
  set transform(Matrix4? value) {
1656
    assert(value != null);
1657
    assert(value!.storage.every((double component) => component.isFinite));
1658 1659 1660
    if (value == _transform)
      return;
    _transform = value;
1661
    _inverseDirty = true;
1662
    markNeedsAddToScene();
1663
  }
1664

1665 1666
  Matrix4? _lastEffectiveTransform;
  Matrix4? _invertedTransform;
1667
  bool _inverseDirty = true;
1668

1669
  @override
1670
  void addToScene(ui.SceneBuilder builder) {
1671
    assert(transform != null);
1672
    _lastEffectiveTransform = transform;
1673 1674
    if (offset != Offset.zero) {
      _lastEffectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0)
1675
        ..multiply(_lastEffectiveTransform!);
1676
    }
1677
    engineLayer = builder.pushTransform(
1678 1679
      _lastEffectiveTransform!.storage,
      oldLayer: _engineLayer as ui.TransformEngineLayer?,
1680
    );
1681
    addChildrenToScene(builder);
1682
    builder.pop();
1683
  }
1684

1685
  Offset? _transformOffset(Offset localPosition) {
1686
    if (_inverseDirty) {
1687
      _invertedTransform = Matrix4.tryInvert(
1688
        PointerEvent.removePerspectiveTransform(transform!),
1689
      );
1690 1691 1692
      _inverseDirty = false;
    }
    if (_invertedTransform == null)
1693
      return null;
1694

1695
    return MatrixUtils.transformPoint(_invertedTransform!, localPosition);
1696 1697 1698
  }

  @override
1699 1700
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    final Offset? transformedOffset = _transformOffset(localPosition);
1701 1702 1703
    if (transformedOffset == null)
      return false;
    return super.findAnnotations<S>(result, transformedOffset, onlyFirst: onlyFirst);
1704 1705
  }

1706
  @override
1707
  void applyTransform(Layer? child, Matrix4 transform) {
1708 1709
    assert(child != null);
    assert(transform != null);
1710 1711
    assert(_lastEffectiveTransform != null || this.transform != null);
    if (_lastEffectiveTransform == null) {
1712
      transform.multiply(this.transform!);
1713
    } else {
1714
      transform.multiply(_lastEffectiveTransform!);
1715
    }
1716 1717
  }

1718
  @override
1719 1720
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1721
    properties.add(TransformProperty('transform', transform));
1722
  }
1723 1724
}

1725
/// A composited layer that makes its children partially transparent.
1726 1727 1728 1729
///
/// When debugging, setting [debugDisableOpacityLayers] to true will cause this
/// layer to be skipped (directly replaced by its children). This can be helpful
/// to track down the cause of performance problems.
1730 1731 1732
///
/// Try to avoid an [OpacityLayer] with no children. Remove that layer if
/// possible to save some tree walks.
Dan Field's avatar
Dan Field committed
1733
class OpacityLayer extends OffsetLayer {
1734 1735 1736 1737
  /// Creates an opacity layer.
  ///
  /// The [alpha] property must be non-null before the compositing phase of
  /// the pipeline.
1738
  OpacityLayer({
1739
    int? alpha,
1740 1741
    Offset offset = Offset.zero,
  }) : _alpha = alpha,
Dan Field's avatar
Dan Field committed
1742
       super(offset: offset);
1743

1744
  /// The amount to multiply into the alpha channel.
1745 1746 1747
  ///
  /// The opacity is expressed as an integer from 0 to 255, where 0 is fully
  /// transparent and 255 is fully opaque.
1748 1749 1750
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1751 1752 1753
  int? get alpha => _alpha;
  int? _alpha;
  set alpha(int? value) {
1754
    assert(value != null);
1755
    if (value != _alpha) {
Dan Field's avatar
Dan Field committed
1756 1757 1758
      if (value == 255 || _alpha == 255) {
        engineLayer = null;
      }
1759 1760 1761 1762 1763
      _alpha = value;
      markNeedsAddToScene();
    }
  }

1764
  @override
1765
  void addToScene(ui.SceneBuilder builder) {
1766
    assert(alpha != null);
1767
    bool enabled = firstChild != null;  // don't add this layer if there's no child
Dan Field's avatar
Dan Field committed
1768 1769 1770 1771
    if (!enabled) {
      // TODO(dnfield): Remove this if/when we can fix https://github.com/flutter/flutter/issues/90004
      return;
    }
1772
    assert(() {
1773
      enabled = enabled && !debugDisableOpacityLayers;
1774 1775
      return true;
    }());
1776

Dan Field's avatar
Dan Field committed
1777 1778 1779 1780 1781
    final int realizedAlpha = alpha!;
    // The type assertions work because the [alpha] setter nulls out the
    // engineLayer if it would have changed type (i.e. changed to or from 255).
    if (enabled && realizedAlpha < 255) {
      assert(_engineLayer is ui.OpacityEngineLayer?);
1782
      engineLayer = builder.pushOpacity(
Dan Field's avatar
Dan Field committed
1783
        realizedAlpha,
1784
        offset: offset,
1785
        oldLayer: _engineLayer as ui.OpacityEngineLayer?,
1786
      );
Dan Field's avatar
Dan Field committed
1787 1788 1789
    } else {
      assert(_engineLayer is ui.OffsetEngineLayer?);
      engineLayer = builder.pushOffset(
1790 1791
        offset.dx,
        offset.dy,
Dan Field's avatar
Dan Field committed
1792 1793 1794
        oldLayer: _engineLayer as ui.OffsetEngineLayer?,
      );
    }
1795
    addChildrenToScene(builder);
Dan Field's avatar
Dan Field committed
1796
    builder.pop();
1797
  }
1798

1799
  @override
1800 1801
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1802
    properties.add(IntProperty('alpha', alpha));
1803
  }
1804
}
1805

1806
/// A composited layer that applies a shader to its children.
1807 1808 1809 1810 1811
///
/// The shader is only applied inside the given [maskRect]. The shader itself
/// uses the top left of the [maskRect] as its origin.
///
/// The [maskRect] does not affect the positions of any child layers.
1812
class ShaderMaskLayer extends ContainerLayer {
1813 1814
  /// Creates a shader mask layer.
  ///
1815
  /// The [shader], [maskRect], and [blendMode] properties must be non-null
1816
  /// before the compositing phase of the pipeline.
1817
  ShaderMaskLayer({
1818 1819 1820
    Shader? shader,
    Rect? maskRect,
    BlendMode? blendMode,
1821 1822 1823
  }) : _shader = shader,
       _maskRect = maskRect,
       _blendMode = blendMode;
1824 1825

  /// The shader to apply to the children.
1826
  ///
1827 1828 1829 1830
  /// The origin of the shader (e.g. of the coordinate system used by the `from`
  /// and `to` arguments to [ui.Gradient.linear]) is at the top left of the
  /// [maskRect].
  ///
1831 1832
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1833 1834 1835 1836
  ///
  /// See also:
  ///
  ///  * [ui.Gradient] and [ui.ImageShader], two shader types that can be used.
1837 1838 1839
  Shader? get shader => _shader;
  Shader? _shader;
  set shader(Shader? value) {
1840 1841 1842 1843 1844
    if (value != _shader) {
      _shader = value;
      markNeedsAddToScene();
    }
  }
1845

1846 1847 1848 1849
  /// The position and size of the shader.
  ///
  /// The [shader] is only rendered inside this rectangle, using the top left of
  /// the rectangle as its origin.
1850 1851 1852
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1853 1854 1855
  Rect? get maskRect => _maskRect;
  Rect? _maskRect;
  set maskRect(Rect? value) {
1856 1857 1858 1859 1860
    if (value != _maskRect) {
      _maskRect = value;
      markNeedsAddToScene();
    }
  }
1861

1862
  /// The blend mode to apply when blending the shader with the children.
1863 1864 1865
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1866 1867 1868
  BlendMode? get blendMode => _blendMode;
  BlendMode? _blendMode;
  set blendMode(BlendMode? value) {
1869 1870 1871 1872 1873
    if (value != _blendMode) {
      _blendMode = value;
      markNeedsAddToScene();
    }
  }
1874

1875
  @override
1876
  void addToScene(ui.SceneBuilder builder) {
1877 1878 1879
    assert(shader != null);
    assert(maskRect != null);
    assert(blendMode != null);
1880
    engineLayer = builder.pushShaderMask(
1881
      shader!,
1882
      maskRect! ,
1883 1884
      blendMode!,
      oldLayer: _engineLayer as ui.ShaderMaskEngineLayer?,
1885
    );
1886
    addChildrenToScene(builder);
1887 1888 1889
    builder.pop();
  }

1890
  @override
1891 1892
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1893 1894 1895
    properties.add(DiagnosticsProperty<Shader>('shader', shader));
    properties.add(DiagnosticsProperty<Rect>('maskRect', maskRect));
    properties.add(DiagnosticsProperty<BlendMode>('blendMode', blendMode));
1896 1897
  }
}
1898 1899 1900

/// A composited layer that applies a filter to the existing contents of the scene.
class BackdropFilterLayer extends ContainerLayer {
1901 1902 1903 1904
  /// Creates a backdrop filter layer.
  ///
  /// The [filter] property must be non-null before the compositing phase of the
  /// pipeline.
1905 1906 1907 1908 1909 1910 1911
  ///
  /// The [blendMode] property defaults to [BlendMode.srcOver].
  BackdropFilterLayer({
    ui.ImageFilter? filter,
    BlendMode blendMode = BlendMode.srcOver,
  }) : _filter = filter,
       _blendMode = blendMode;
1912 1913

  /// The filter to apply to the existing contents of the scene.
1914 1915 1916
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1917 1918 1919
  ui.ImageFilter? get filter => _filter;
  ui.ImageFilter? _filter;
  set filter(ui.ImageFilter? value) {
1920 1921 1922 1923 1924
    if (value != _filter) {
      _filter = value;
      markNeedsAddToScene();
    }
  }
1925

1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
  /// The blend mode to use to apply the filtered background content onto the background
  /// surface.
  ///
  /// The default value of this property is [BlendMode.srcOver].
  /// {@macro flutter.widgets.BackdropFilter.blendMode}
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
  BlendMode get blendMode => _blendMode;
  BlendMode _blendMode;
  set blendMode(BlendMode value) {
    if (value != _blendMode) {
      _blendMode = value;
      markNeedsAddToScene();
    }
  }

1943
  @override
1944
  void addToScene(ui.SceneBuilder builder) {
1945
    assert(filter != null);
1946
    engineLayer = builder.pushBackdropFilter(
1947
      filter!,
1948
      blendMode: blendMode,
1949
      oldLayer: _engineLayer as ui.BackdropFilterEngineLayer?,
1950
    );
1951
    addChildrenToScene(builder);
1952 1953 1954
    builder.pop();
  }
}
1955

1956 1957 1958
/// A composited layer that uses a physical model to producing lighting effects.
///
/// For example, the layer casts a shadow according to its geometry and the
1959
/// relative position of lights and other physically modeled objects in the
1960
/// scene.
1961 1962 1963 1964
///
/// When debugging, setting [debugDisablePhysicalShapeLayers] to true will cause this
/// layer to be skipped (directly replaced by its children). This can be helpful
/// to track down the cause of performance problems.
1965
class PhysicalModelLayer extends ContainerLayer {
1966 1967 1968
  /// Creates a composited layer that uses a physical model to producing
  /// lighting effects.
  ///
1969 1970
  /// The [clipPath], [clipBehavior], [elevation], [color], and [shadowColor]
  /// arguments must be non-null before the compositing phase of the pipeline.
1971
  PhysicalModelLayer({
1972
    Path? clipPath,
1973
    Clip clipBehavior = Clip.none,
1974 1975 1976
    double? elevation,
    Color? color,
    Color? shadowColor,
1977
  }) : _clipPath = clipPath,
1978 1979 1980 1981
       _clipBehavior = clipBehavior,
       _elevation = elevation,
       _color = color,
       _shadowColor = shadowColor;
1982

1983
  /// The path to clip in the parent's coordinate system.
1984 1985 1986
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1987 1988 1989
  Path? get clipPath => _clipPath;
  Path? _clipPath;
  set clipPath(Path? value) {
1990 1991 1992 1993 1994
    if (value != _clipPath) {
      _clipPath = value;
      markNeedsAddToScene();
    }
  }
1995

1996
  /// {@macro flutter.material.Material.clipBehavior}
1997 1998 1999
  Clip get clipBehavior => _clipBehavior;
  Clip _clipBehavior;
  set clipBehavior(Clip value) {
2000
    assert(value != null);
2001 2002 2003 2004 2005
    if (value != _clipBehavior) {
      _clipBehavior = value;
      markNeedsAddToScene();
    }
  }
2006

2007
  /// The z-coordinate at which to place this physical object.
2008 2009 2010
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
2011 2012 2013 2014 2015 2016
  ///
  /// In tests, the [debugDisableShadows] flag is set to true by default.
  /// Several widgets and render objects force all elevations to zero when this
  /// flag is set. For this reason, this property will often be set to zero in
  /// tests even if the layer should be raised. To verify the actual value,
  /// consider setting [debugDisableShadows] to false in your test.
2017 2018 2019
  double? get elevation => _elevation;
  double? _elevation;
  set elevation(double? value) {
2020 2021 2022 2023 2024
    if (value != _elevation) {
      _elevation = value;
      markNeedsAddToScene();
    }
  }
2025 2026

  /// The background color.
2027 2028 2029
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
2030 2031 2032
  Color? get color => _color;
  Color? _color;
  set color(Color? value) {
2033 2034 2035 2036 2037
    if (value != _color) {
      _color = value;
      markNeedsAddToScene();
    }
  }
2038

2039
  /// The shadow color.
2040 2041 2042
  Color? get shadowColor => _shadowColor;
  Color? _shadowColor;
  set shadowColor(Color? value) {
2043 2044 2045 2046 2047
    if (value != _shadowColor) {
      _shadowColor = value;
      markNeedsAddToScene();
    }
  }
2048

2049
  @override
2050 2051
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    if (!clipPath!.contains(localPosition))
2052 2053
      return false;
    return super.findAnnotations<S>(result, localPosition, onlyFirst: onlyFirst);
2054 2055
  }

2056
  @override
2057
  void addToScene(ui.SceneBuilder builder) {
2058 2059 2060 2061 2062 2063
    assert(clipPath != null);
    assert(clipBehavior != null);
    assert(elevation != null);
    assert(color != null);
    assert(shadowColor != null);

2064 2065 2066 2067 2068 2069
    bool enabled = true;
    assert(() {
      enabled = !debugDisablePhysicalShapeLayers;
      return true;
    }());
    if (enabled) {
2070
      engineLayer = builder.pushPhysicalShape(
2071
        path: clipPath!,
2072 2073
        elevation: elevation!,
        color: color!,
2074
        shadowColor: shadowColor,
2075
        clipBehavior: clipBehavior,
2076
        oldLayer: _engineLayer as ui.PhysicalShapeEngineLayer?,
2077
      );
2078 2079
    } else {
      engineLayer = null;
2080
    }
2081
    addChildrenToScene(builder);
2082
    if (enabled)
2083
      builder.pop();
2084 2085 2086
  }

  @override
2087 2088
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
2089
    properties.add(DoubleProperty('elevation', elevation));
2090
    properties.add(ColorProperty('color', color));
2091 2092
  }
}
2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106

/// An object that a [LeaderLayer] can register with.
///
/// An instance of this class should be provided as the [LeaderLayer.link] and
/// the [FollowerLayer.link] properties to cause the [FollowerLayer] to follow
/// the [LeaderLayer].
///
/// See also:
///
///  * [CompositedTransformTarget], the widget that creates a [LeaderLayer].
///  * [CompositedTransformFollower], the widget that creates a [FollowerLayer].
///  * [RenderLeaderLayer] and [RenderFollowerLayer], the corresponding
///    render objects.
class LayerLink {
2107
  LeaderLayer? _leader;
2108

2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138
  int _connectedFollowers = 0;

  /// Whether a [LeaderLayer] is currently connected to this link.
  bool get leaderConnected => _leader != null;

  /// Called by the [FollowerLayer] to establish a link to a [LeaderLayer].
  ///
  /// The returned [LayerLinkHandle] provides access to the leader via
  /// [LayerLinkHandle.leader].
  ///
  /// When the [FollowerLayer] no longer wants to follow the [LeaderLayer],
  /// [LayerLinkHandle.dispose] must be called to disconnect the link.
  _LayerLinkHandle _registerFollower() {
    assert(_connectedFollowers >= 0);
    _connectedFollowers++;
    return _LayerLinkHandle(this);
  }

  /// Returns the [LeaderLayer] currently connected to this link.
  ///
  /// Valid in debug mode only. Returns null in all other modes.
  LeaderLayer? get debugLeader {
    LeaderLayer? result;
    if (kDebugMode) {
      result = _leader;
    }
    return result;
  }

  /// The total size of the content of the connected [LeaderLayer].
2139 2140
  ///
  /// Generally this should be set by the [RenderObject] that paints on the
2141
  /// registered [LeaderLayer] (for instance a [RenderLeaderLayer] that shares
2142 2143 2144 2145
  /// this link with its followers). This size may be outdated before and during
  /// layout.
  Size? leaderSize;

2146
  @override
2147
  String toString() => '${describeIdentity(this)}(${ _leader != null ? "<linked>" : "<dangling>" })';
2148 2149
}

2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173
/// A handle provided by [LayerLink.registerFollower] to a calling
/// [FollowerLayer] to establish a link between that [FollowerLayer] and a
/// [LeaderLayer].
///
/// If the link is no longer needed, [dispose] must be called to disconnect it.
class _LayerLinkHandle {
  _LayerLinkHandle(this._link);

  LayerLink? _link;

  /// The currently-registered [LeaderLayer], if any.
  LeaderLayer? get leader => _link!._leader;

  /// Disconnects the link between the [FollowerLayer] owning this handle and
  /// the [leader].
  ///
  /// The [LayerLinkHandle] becomes unusable after calling this method.
  void dispose() {
    assert(_link!._connectedFollowers > 0);
    _link!._connectedFollowers--;
    _link = null;
  }
}

2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
/// A composited layer that can be followed by a [FollowerLayer].
///
/// This layer collapses the accumulated offset into a transform and passes
/// [Offset.zero] to its child layers in the [addToScene]/[addChildrenToScene]
/// methods, so that [applyTransform] will work reliably.
class LeaderLayer extends ContainerLayer {
  /// Creates a leader layer.
  ///
  /// The [link] property must not be null, and must not have been provided to
  /// any other [LeaderLayer] layers that are [attached] to the layer tree at
  /// the same time.
  ///
  /// The [offset] property must be non-null before the compositing phase of the
  /// pipeline.
2188
  LeaderLayer({ required LayerLink link, Offset offset = Offset.zero }) : assert(link != null), _link = link, _offset = offset;
2189 2190 2191 2192 2193

  /// The object with which this layer should register.
  ///
  /// The link will be established when this layer is [attach]ed, and will be
  /// cleared when this layer is [detach]ed.
2194
  LayerLink get link => _link;
2195
  LayerLink _link;
2196 2197
  set link(LayerLink value) {
    assert(value != null);
2198 2199 2200 2201
    if (_link == value) {
      return;
    }
    _link._leader = null;
2202 2203
    _link = value;
  }
2204 2205 2206 2207 2208 2209 2210 2211

  /// Offset from parent in the parent's coordinate system.
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
  ///
  /// The [offset] property must be non-null before the compositing phase of the
  /// pipeline.
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223
  Offset get offset => _offset;
  Offset _offset;
  set offset(Offset value) {
    assert(value != null);
    if (value == _offset) {
      return;
    }
    _offset = value;
    if (!alwaysNeedsAddToScene) {
      markNeedsAddToScene();
    }
  }
2224

2225
  /// {@macro flutter.rendering.FollowerLayer.alwaysNeedsAddToScene}
2226
  @override
2227
  bool get alwaysNeedsAddToScene => _link._connectedFollowers > 0;
2228

2229 2230 2231
  @override
  void attach(Object owner) {
    super.attach(owner);
2232
    assert(link._leader == null);
2233 2234 2235 2236 2237 2238
    _lastOffset = null;
    link._leader = this;
  }

  @override
  void detach() {
2239
    assert(link._leader == this);
2240 2241 2242 2243 2244 2245 2246 2247 2248 2249
    link._leader = null;
    _lastOffset = null;
    super.detach();
  }

  /// The offset the last time this layer was composited.
  ///
  /// This is reset to null when the layer is attached or detached, to help
  /// catch cases where the follower layer ends up before the leader layer, but
  /// not every case can be detected.
2250
  Offset? _lastOffset;
2251

2252
  @override
2253
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
2254 2255
    return super.findAnnotations<S>(result, localPosition - offset, onlyFirst: onlyFirst);
  }
2256

2257
  @override
2258
  void addToScene(ui.SceneBuilder builder) {
2259
    assert(offset != null);
2260
    _lastOffset = offset;
2261
    if (_lastOffset != Offset.zero)
2262
      engineLayer = builder.pushTransform(
2263 2264
        Matrix4.translationValues(_lastOffset!.dx, _lastOffset!.dy, 0.0).storage,
        oldLayer: _engineLayer as ui.TransformEngineLayer?,
2265
      );
2266
    addChildrenToScene(builder);
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278
    if (_lastOffset != Offset.zero)
      builder.pop();
  }

  /// Applies the transform that would be applied when compositing the given
  /// child to the given matrix.
  ///
  /// See [ContainerLayer.applyTransform] for details.
  ///
  /// The `child` argument may be null, as the same transform is applied to all
  /// children.
  @override
2279
  void applyTransform(Layer? child, Matrix4 transform) {
2280 2281
    assert(_lastOffset != null);
    if (_lastOffset != Offset.zero)
2282
      transform.translate(_lastOffset!.dx, _lastOffset!.dy);
2283 2284 2285
  }

  @override
2286 2287
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
2288 2289
    properties.add(DiagnosticsProperty<Offset>('offset', offset));
    properties.add(DiagnosticsProperty<LayerLink>('link', link));
2290 2291 2292 2293 2294 2295 2296 2297
  }
}

/// A composited layer that applies a transformation matrix to its children such
/// that they are positioned to match a [LeaderLayer].
///
/// If any of the ancestors of this layer have a degenerate matrix (e.g. scaling
/// by zero), then the [FollowerLayer] will not be able to transform its child
2298
/// to the coordinate space of the [LeaderLayer].
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310
///
/// A [linkedOffset] property can be provided to further offset the child layer
/// from the leader layer, for example if the child is to follow the linked
/// layer at a distance rather than directly overlapping it.
class FollowerLayer extends ContainerLayer {
  /// Creates a follower layer.
  ///
  /// The [link] property must not be null.
  ///
  /// The [unlinkedOffset], [linkedOffset], and [showWhenUnlinked] properties
  /// must be non-null before the compositing phase of the pipeline.
  FollowerLayer({
2311
    required LayerLink link,
2312 2313 2314
    this.showWhenUnlinked = true,
    this.unlinkedOffset = Offset.zero,
    this.linkedOffset = Offset.zero,
2315
  }) : assert(link != null), _link = link;
2316 2317 2318 2319 2320 2321

  /// The link to the [LeaderLayer].
  ///
  /// The same object should be provided to a [LeaderLayer] that is earlier in
  /// the layer tree. When this layer is composited, it will apply a transform
  /// that moves its children to match the position of the [LeaderLayer].
2322 2323 2324
  LayerLink get link => _link;
  set link(LayerLink value) {
    assert(value != null);
2325 2326 2327 2328
    if (value != _link && _leaderHandle != null) {
      _leaderHandle!.dispose();
      _leaderHandle = value._registerFollower();
    }
2329 2330 2331
    _link = value;
  }
  LayerLink _link;
2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344

  /// Whether to show the layer's contents when the [link] does not point to a
  /// [LeaderLayer].
  ///
  /// When the layer is linked, children layers are positioned such that they
  /// have the same global position as the linked [LeaderLayer].
  ///
  /// When the layer is not linked, then: if [showWhenUnlinked] is true,
  /// children are positioned as if the [FollowerLayer] was a [ContainerLayer];
  /// if it is false, then children are hidden.
  ///
  /// The [showWhenUnlinked] property must be non-null before the compositing
  /// phase of the pipeline.
2345
  bool? showWhenUnlinked;
2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358

  /// Offset from parent in the parent's coordinate system, used when the layer
  /// is not linked to a [LeaderLayer].
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
  ///
  /// The [unlinkedOffset] property must be non-null before the compositing
  /// phase of the pipeline.
  ///
  /// See also:
  ///
  ///  * [linkedOffset], for when the layers are linked.
2359
  Offset? unlinkedOffset;
2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372

  /// Offset from the origin of the leader layer to the origin of the child
  /// layers, used when the layer is linked to a [LeaderLayer].
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
  ///
  /// The [linkedOffset] property must be non-null before the compositing phase
  /// of the pipeline.
  ///
  /// See also:
  ///
  ///  * [unlinkedOffset], for when the layer is not linked.
2373
  Offset? linkedOffset;
2374

2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389
  _LayerLinkHandle? _leaderHandle;

  @override
  void attach(Object owner) {
    super.attach(owner);
    _leaderHandle = _link._registerFollower();
  }

  @override
  void detach() {
    super.detach();
    _leaderHandle?.dispose();
    _leaderHandle = null;
  }

2390 2391 2392
  Offset? _lastOffset;
  Matrix4? _lastTransform;
  Matrix4? _invertedTransform;
2393
  bool _inverseDirty = true;
2394

2395
  Offset? _transformOffset(Offset localPosition) {
2396
    if (_inverseDirty) {
2397
      _invertedTransform = Matrix4.tryInvert(getLastTransform()!);
2398
      _inverseDirty = false;
2399
    }
2400 2401
    if (_invertedTransform == null)
      return null;
2402
    final Vector4 vector = Vector4(localPosition.dx, localPosition.dy, 0.0, 1.0);
2403 2404
    final Vector4 result = _invertedTransform!.transform(vector);
    return Offset(result[0] - linkedOffset!.dx, result[1] - linkedOffset!.dy);
2405 2406 2407
  }

  @override
2408
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
2409
    if (_leaderHandle!.leader == null) {
2410 2411
      if (showWhenUnlinked!) {
        return super.findAnnotations(result, localPosition - unlinkedOffset!, onlyFirst: onlyFirst);
2412 2413
      }
      return false;
2414
    }
2415
    final Offset? transformedOffset = _transformOffset(localPosition);
2416
    if (transformedOffset == null) {
2417
      return false;
2418
    }
2419
    return super.findAnnotations<S>(result, transformedOffset, onlyFirst: onlyFirst);
2420
  }
2421 2422 2423 2424

  /// The transform that was used during the last composition phase.
  ///
  /// If the [link] was not linked to a [LeaderLayer], or if this layer has
2425
  /// a degenerate matrix applied, then this will be null.
2426 2427
  ///
  /// This method returns a new [Matrix4] instance each time it is invoked.
2428
  Matrix4? getLastTransform() {
2429 2430
    if (_lastTransform == null)
      return null;
2431 2432
    final Matrix4 result = Matrix4.translationValues(-_lastOffset!.dx, -_lastOffset!.dy, 0.0);
    result.multiply(_lastTransform!);
2433 2434 2435 2436 2437 2438 2439 2440 2441
    return result;
  }

  /// Call [applyTransform] for each layer in the provided list.
  ///
  /// The list is in reverse order (deepest first). The first layer will be
  /// treated as the child of the second, and so forth. The first layer in the
  /// list won't have [applyTransform] called on it. The first layer may be
  /// null.
2442
  static Matrix4 _collectTransformForLayerChain(List<ContainerLayer?> layers) {
2443
    // Initialize our result matrix.
2444
    final Matrix4 result = Matrix4.identity();
2445 2446 2447
    // Apply each layer to the matrix in turn, starting from the last layer,
    // and providing the previous layer as the child.
    for (int index = layers.length - 1; index > 0; index -= 1)
2448
      layers[index]?.applyTransform(layers[index - 1], result);
2449 2450 2451
    return result;
  }

2452 2453 2454 2455 2456 2457 2458
  /// Find the common ancestor of two layers [a] and [b] by searching towards
  /// the root of the tree, and append each ancestor of [a] or [b] visited along
  /// the path to [ancestorsA] and [ancestorsB] respectively.
  ///
  /// Returns null if [a] [b] do not share a common ancestor, in which case the
  /// results in [ancestorsA] and [ancestorsB] are undefined.
  static Layer? _pathsToCommonAncestor(
2459 2460 2461 2462
    Layer? a,
    Layer? b,
    List<ContainerLayer?> ancestorsA,
    List<ContainerLayer?> ancestorsB,
2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473
  ) {
    // No common ancestor found.
    if (a == null || b == null)
      return null;

    if (identical(a, b))
      return a;

    if (a.depth < b.depth) {
      ancestorsB.add(b.parent);
      return _pathsToCommonAncestor(a, b.parent, ancestorsA, ancestorsB);
2474
    } else if (a.depth > b.depth) {
2475 2476 2477 2478 2479 2480 2481 2482 2483
      ancestorsA.add(a.parent);
      return _pathsToCommonAncestor(a.parent, b, ancestorsA, ancestorsB);
    }

    ancestorsA.add(a.parent);
    ancestorsB.add(b.parent);
    return _pathsToCommonAncestor(a.parent, b.parent, ancestorsA, ancestorsB);
  }

2484 2485 2486 2487
  /// Populate [_lastTransform] given the current state of the tree.
  void _establishTransform() {
    assert(link != null);
    _lastTransform = null;
2488
    final LeaderLayer? leader = _leaderHandle!.leader;
2489
    // Check to see if we are linked.
2490
    if (leader == null)
2491 2492
      return;
    // If we're linked, check the link is valid.
2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513
    assert(
      leader.owner == owner,
      'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.',
    );
    assert(
      leader._lastOffset != null,
      'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.',
    );

    // Stores [leader, ..., commonAncestor] after calling _pathsToCommonAncestor.
    final List<ContainerLayer?> forwardLayers = <ContainerLayer>[leader];
    // Stores [this (follower), ..., commonAncestor] after calling
    // _pathsToCommonAncestor.
    final List<ContainerLayer?> inverseLayers = <ContainerLayer>[this];

    final Layer? ancestor = _pathsToCommonAncestor(
      leader, this,
      forwardLayers, inverseLayers,
    );
    assert(ancestor != null);

2514
    final Matrix4 forwardTransform = _collectTransformForLayerChain(forwardLayers);
2515 2516 2517 2518 2519 2520
    // Further transforms the coordinate system to a hypothetical child (null)
    // of the leader layer, to account for the leader's additional paint offset
    // and layer offset (LeaderLayer._lastOffset).
    leader.applyTransform(null, forwardTransform);
    forwardTransform.translate(linkedOffset!.dx, linkedOffset!.dy);

2521
    final Matrix4 inverseTransform = _collectTransformForLayerChain(inverseLayers);
2522

2523 2524 2525 2526 2527 2528 2529
    if (inverseTransform.invert() == 0.0) {
      // We are in a degenerate transform, so there's not much we can do.
      return;
    }
    // Combine the matrices and store the result.
    inverseTransform.multiply(forwardTransform);
    _lastTransform = inverseTransform;
2530
    _inverseDirty = true;
2531 2532
  }

2533
  /// {@template flutter.rendering.FollowerLayer.alwaysNeedsAddToScene}
2534
  /// This disables retained rendering.
2535
  ///
2536 2537 2538 2539 2540
  /// A [FollowerLayer] copies changes from a [LeaderLayer] that could be anywhere
  /// in the Layer tree, and that leader layer could change without notifying the
  /// follower layer. Therefore we have to always call a follower layer's
  /// [addToScene]. In order to call follower layer's [addToScene], leader layer's
  /// [addToScene] must be called first so leader layer must also be considered
2541 2542 2543 2544 2545
  /// as [alwaysNeedsAddToScene].
  /// {@endtemplate}
  @override
  bool get alwaysNeedsAddToScene => true;

2546
  @override
2547
  void addToScene(ui.SceneBuilder builder) {
2548 2549
    assert(link != null);
    assert(showWhenUnlinked != null);
2550
    if (_leaderHandle!.leader == null && !showWhenUnlinked!) {
2551 2552
      _lastTransform = null;
      _lastOffset = null;
2553
      _inverseDirty = true;
2554 2555
      engineLayer = null;
      return;
2556 2557 2558
    }
    _establishTransform();
    if (_lastTransform != null) {
2559
      engineLayer = builder.pushTransform(
2560
        _lastTransform!.storage,
2561
        oldLayer: _engineLayer as ui.TransformEngineLayer?,
2562
      );
2563
      addChildrenToScene(builder);
2564
      builder.pop();
2565
      _lastOffset = unlinkedOffset;
2566 2567
    } else {
      _lastOffset = null;
2568
      final Matrix4 matrix = Matrix4.translationValues(unlinkedOffset!.dx, unlinkedOffset!.dy, .0);
2569 2570
      engineLayer = builder.pushTransform(
        matrix.storage,
2571
        oldLayer: _engineLayer as ui.TransformEngineLayer?,
2572
      );
2573 2574
      addChildrenToScene(builder);
      builder.pop();
2575
    }
2576
    _inverseDirty = true;
2577 2578 2579
  }

  @override
2580
  void applyTransform(Layer? child, Matrix4 transform) {
2581 2582
    assert(child != null);
    assert(transform != null);
2583
    if (_lastTransform != null) {
2584
      transform.multiply(_lastTransform!);
2585
    } else {
2586
      transform.multiply(Matrix4.translationValues(unlinkedOffset!.dx, unlinkedOffset!.dy, 0));
2587
    }
2588 2589 2590
  }

  @override
2591 2592
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
2593 2594
    properties.add(DiagnosticsProperty<LayerLink>('link', link));
    properties.add(TransformProperty('transform', getLastTransform(), defaultValue: null));
2595 2596
  }
}
2597

2598 2599 2600 2601
/// A composited layer which annotates its children with a value. Pushing this
/// layer to the tree is the common way of adding an annotation.
///
/// An annotation is an optional object of any type that, when attached with a
2602 2603 2604 2605
/// layer, can be retrieved using [Layer.find] or [Layer.findAllAnnotations]
/// with a position. The search process is done recursively, controlled by a
/// concept of being opaque to a type of annotation, explained in the document
/// of [Layer.findAnnotations].
2606 2607 2608
///
/// When an annotation search arrives, this layer defers the same search to each
/// of this layer's children, respecting their opacity. Then it adds this
2609
/// layer's annotation if all of the following restrictions are met:
2610
///
2611
/// {@template flutter.rendering.AnnotatedRegionLayer.restrictions}
2612 2613 2614 2615
/// * The target type must be identical to the annotated type `T`.
/// * If [size] is provided, the target position must be contained within the
///   rectangle formed by [size] and [offset].
/// {@endtemplate}
2616
///
2617 2618
/// This layer is opaque to a type of annotation if any child is also opaque, or
/// if [opaque] is true and the layer's annotation is added.
2619
class AnnotatedRegionLayer<T extends Object> extends ContainerLayer {
2620
  /// Creates a new layer that annotates its children with [value].
2621
  ///
2622
  /// The [value] provided cannot be null.
2623 2624 2625
  AnnotatedRegionLayer(
    this.value, {
    this.size,
2626
    Offset? offset,
2627 2628 2629 2630 2631 2632 2633
    this.opaque = false,
  }) : assert(value != null),
       assert(opaque != null),
       offset = offset ?? Offset.zero;

  /// The annotated object, which is added to the result if all restrictions are
  /// met.
2634 2635
  final T value;

2636
  /// The size of the annotated object.
2637
  ///
2638
  /// If [size] is provided, then the annotation is found only if the target
2639 2640 2641
  /// position is contained by the rectangle formed by [size] and [offset].
  /// Otherwise no such restriction is applied, and clipping can only be done by
  /// the ancestor layers.
2642
  final Size? size;
2643

2644
  /// The position of the annotated object.
2645
  ///
2646 2647
  /// The [offset] defaults to [Offset.zero] if not provided, and is ignored if
  /// [size] is not set.
2648
  ///
2649
  /// The [offset] only offsets the clipping rectangle, and does not affect
2650
  /// how the painting or annotation search is propagated to its children.
2651 2652
  final Offset offset;

2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677
  /// Whether the annotation of this layer should be opaque during an annotation
  /// search of type `T`, preventing siblings visually behind it from being
  /// searched.
  ///
  /// If [opaque] is true, and this layer does add its annotation [value],
  /// then the layer will always be opaque during the search.
  ///
  /// If [opaque] is false, or if this layer does not add its annotation,
  /// then the opacity of this layer will be the one returned by the children,
  /// meaning that it will be opaque if any child is opaque.
  ///
  /// The [opaque] defaults to false.
  ///
  /// The [opaque] is effectively useless during [Layer.find] (more
  /// specifically, [Layer.findAnnotations] with `onlyFirst: true`), since the
  /// search process then skips the remaining tree after finding the first
  /// annotation.
  ///
  /// See also:
  ///
  ///  * [Layer.findAnnotations], which explains the concept of being opaque
  ///    to a type of annotation as the return value.
  ///  * [HitTestBehavior], which controls similar logic when hit-testing in the
  ///    render tree.
  final bool opaque;
2678

2679 2680 2681 2682 2683 2684 2685 2686
  /// Searches the subtree for annotations of type `S` at the location
  /// `localPosition`, then adds the annotation [value] if applicable.
  ///
  /// This method always searches its children, and if any child returns `true`,
  /// the remaining children are skipped. Regardless of what the children
  /// return, this method then adds this layer's annotation if all of the
  /// following restrictions are met:
  ///
2687
  /// {@macro flutter.rendering.AnnotatedRegionLayer.restrictions}
2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698
  ///
  /// This search process respects `onlyFirst`, meaning that when `onlyFirst` is
  /// true, the search will stop when it finds the first annotation from the
  /// children, and the layer's own annotation is checked only when none is
  /// given by the children.
  ///
  /// The return value is true if any child returns `true`, or if [opaque] is
  /// true and the layer's annotation is added.
  ///
  /// For explanation of layer annotations, parameters and return value, refer
  /// to [Layer.findAnnotations].
2699
  @override
2700
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
2701 2702 2703
    bool isAbsorbed = super.findAnnotations(result, localPosition, onlyFirst: onlyFirst);
    if (result.entries.isNotEmpty && onlyFirst)
      return isAbsorbed;
2704
    if (size != null && !(offset & size!).contains(localPosition)) {
2705
      return isAbsorbed;
2706
    }
2707
    if (T == S) {
2708 2709
      isAbsorbed = isAbsorbed || opaque;
      final Object untypedValue = value;
2710
      final S typedValue = untypedValue as S;
2711 2712
      result.add(AnnotationEntry<S>(
        annotation: typedValue,
2713
        localPosition: localPosition - offset,
2714
      ));
2715
    }
2716
    return isAbsorbed;
2717 2718 2719 2720 2721
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
2722 2723
    properties.add(DiagnosticsProperty<T>('value', value));
    properties.add(DiagnosticsProperty<Size>('size', size, defaultValue: null));
2724
    properties.add(DiagnosticsProperty<Offset>('offset', offset, defaultValue: null));
2725
    properties.add(DiagnosticsProperty<bool>('opaque', opaque, defaultValue: false));
2726 2727
  }
}