layer.dart 94.3 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:flutter/scheduler.dart';
11
import 'package:vector_math/vector_math_64.dart';
12

13 14
import 'debug.dart';

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

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

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

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

/// Information collected about a list of annotations that are found in the
/// layer tree.
///
/// See also:
///
///  * [AnnotationEntry], which are members of this class.
48 49
///  * [Layer.findAllAnnotations], and [Layer.findAnnotations], which create and
///    use an object of this class.
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.
71 72
  Iterable<T> get annotations {
    return _entries.map((AnnotationEntry<T> entry) => entry.annotation);
73 74 75
  }
}

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 1768 1769

    // Don't add this layer if there's no child.
    bool enabled = firstChild != null;
Dan Field's avatar
Dan Field committed
1770
    if (!enabled) {
1771 1772
      // Ensure the engineLayer is disposed.
      engineLayer = null;
Dan Field's avatar
Dan Field committed
1773 1774 1775
      // TODO(dnfield): Remove this if/when we can fix https://github.com/flutter/flutter/issues/90004
      return;
    }
1776

1777
    assert(() {
1778
      enabled = enabled && !debugDisableOpacityLayers;
1779 1780
      return true;
    }());
1781

Dan Field's avatar
Dan Field committed
1782 1783 1784 1785 1786
    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?);
1787
      engineLayer = builder.pushOpacity(
Dan Field's avatar
Dan Field committed
1788
        realizedAlpha,
1789
        offset: offset,
1790
        oldLayer: _engineLayer as ui.OpacityEngineLayer?,
1791
      );
Dan Field's avatar
Dan Field committed
1792 1793 1794
    } else {
      assert(_engineLayer is ui.OffsetEngineLayer?);
      engineLayer = builder.pushOffset(
1795 1796
        offset.dx,
        offset.dy,
Dan Field's avatar
Dan Field committed
1797 1798 1799
        oldLayer: _engineLayer as ui.OffsetEngineLayer?,
      );
    }
1800
    addChildrenToScene(builder);
Dan Field's avatar
Dan Field committed
1801
    builder.pop();
1802
  }
1803

1804
  @override
1805 1806
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1807
    properties.add(IntProperty('alpha', alpha));
1808
  }
1809
}
1810

1811
/// A composited layer that applies a shader to its children.
1812 1813 1814 1815 1816
///
/// 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.
1817
class ShaderMaskLayer extends ContainerLayer {
1818 1819
  /// Creates a shader mask layer.
  ///
1820
  /// The [shader], [maskRect], and [blendMode] properties must be non-null
1821
  /// before the compositing phase of the pipeline.
1822
  ShaderMaskLayer({
1823 1824 1825
    Shader? shader,
    Rect? maskRect,
    BlendMode? blendMode,
1826 1827 1828
  }) : _shader = shader,
       _maskRect = maskRect,
       _blendMode = blendMode;
1829 1830

  /// The shader to apply to the children.
1831
  ///
1832 1833 1834 1835
  /// 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].
  ///
1836 1837
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1838 1839 1840 1841
  ///
  /// See also:
  ///
  ///  * [ui.Gradient] and [ui.ImageShader], two shader types that can be used.
1842 1843 1844
  Shader? get shader => _shader;
  Shader? _shader;
  set shader(Shader? value) {
1845 1846 1847 1848 1849
    if (value != _shader) {
      _shader = value;
      markNeedsAddToScene();
    }
  }
1850

1851 1852 1853 1854
  /// 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.
1855 1856 1857
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
1858 1859 1860
  Rect? get maskRect => _maskRect;
  Rect? _maskRect;
  set maskRect(Rect? value) {
1861 1862 1863 1864 1865
    if (value != _maskRect) {
      _maskRect = value;
      markNeedsAddToScene();
    }
  }
1866

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

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

1895
  @override
1896 1897
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
1898 1899 1900
    properties.add(DiagnosticsProperty<Shader>('shader', shader));
    properties.add(DiagnosticsProperty<Rect>('maskRect', maskRect));
    properties.add(DiagnosticsProperty<BlendMode>('blendMode', blendMode));
1901 1902
  }
}
1903 1904 1905

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

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

1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947
  /// 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();
    }
  }

1948
  @override
1949
  void addToScene(ui.SceneBuilder builder) {
1950
    assert(filter != null);
1951
    engineLayer = builder.pushBackdropFilter(
1952
      filter!,
1953
      blendMode: blendMode,
1954
      oldLayer: _engineLayer as ui.BackdropFilterEngineLayer?,
1955
    );
1956
    addChildrenToScene(builder);
1957 1958 1959
    builder.pop();
  }
}
1960

1961 1962 1963
/// 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
1964
/// relative position of lights and other physically modeled objects in the
1965
/// scene.
1966 1967 1968 1969
///
/// 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.
1970
class PhysicalModelLayer extends ContainerLayer {
1971 1972 1973
  /// Creates a composited layer that uses a physical model to producing
  /// lighting effects.
  ///
1974 1975
  /// The [clipPath], [clipBehavior], [elevation], [color], and [shadowColor]
  /// arguments must be non-null before the compositing phase of the pipeline.
1976
  PhysicalModelLayer({
1977
    Path? clipPath,
1978
    Clip clipBehavior = Clip.none,
1979 1980 1981
    double? elevation,
    Color? color,
    Color? shadowColor,
1982
  }) : _clipPath = clipPath,
1983 1984 1985 1986
       _clipBehavior = clipBehavior,
       _elevation = elevation,
       _color = color,
       _shadowColor = shadowColor;
1987

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

2001
  /// {@macro flutter.material.Material.clipBehavior}
2002 2003 2004
  Clip get clipBehavior => _clipBehavior;
  Clip _clipBehavior;
  set clipBehavior(Clip value) {
2005
    assert(value != null);
2006 2007 2008 2009 2010
    if (value != _clipBehavior) {
      _clipBehavior = value;
      markNeedsAddToScene();
    }
  }
2011

2012
  /// The z-coordinate at which to place this physical object.
2013 2014 2015
  ///
  /// The scene must be explicitly recomposited after this property is changed
  /// (as described at [Layer]).
2016 2017 2018 2019 2020 2021
  ///
  /// 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.
2022 2023 2024
  double? get elevation => _elevation;
  double? _elevation;
  set elevation(double? value) {
2025 2026 2027 2028 2029
    if (value != _elevation) {
      _elevation = value;
      markNeedsAddToScene();
    }
  }
2030 2031

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

2044
  /// The shadow color.
2045 2046 2047
  Color? get shadowColor => _shadowColor;
  Color? _shadowColor;
  set shadowColor(Color? value) {
2048 2049 2050 2051 2052
    if (value != _shadowColor) {
      _shadowColor = value;
      markNeedsAddToScene();
    }
  }
2053

2054
  @override
2055 2056
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
    if (!clipPath!.contains(localPosition))
2057 2058
      return false;
    return super.findAnnotations<S>(result, localPosition, onlyFirst: onlyFirst);
2059 2060
  }

2061
  @override
2062
  void addToScene(ui.SceneBuilder builder) {
2063 2064 2065 2066 2067 2068
    assert(clipPath != null);
    assert(clipBehavior != null);
    assert(elevation != null);
    assert(color != null);
    assert(shadowColor != null);

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

  @override
2092 2093
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
2094
    properties.add(DoubleProperty('elevation', elevation));
2095
    properties.add(ColorProperty('color', color));
2096 2097
  }
}
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111

/// 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 {
2112 2113
  /// The [LeaderLayer] connected to this link.
  LeaderLayer? get leader => _leader;
2114
  LeaderLayer? _leader;
2115

2116 2117 2118 2119 2120 2121
  void _registerLeader(LeaderLayer leader) {
    assert(_leader != leader);
    assert((){
      if (_leader != null) {
        _debugPreviousLeaders ??= <LeaderLayer>{};
        _debugScheduleLeadersCleanUpCheck();
2122
        return _debugPreviousLeaders!.add(_leader!);
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132
      }
      return true;
    }());
    _leader = leader;
  }

  void _unregisterLeader(LeaderLayer leader) {
    if (_leader == leader) {
      _leader = null;
    } else {
2133
      assert(_debugPreviousLeaders!.remove(leader));
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
    }
  }

  /// Stores the previous leaders that were replaced by the current [_leader]
  /// in the current frame.
  ///
  /// These leaders need to give up their leaderships of this link by the end of
  /// the current frame.
  Set<LeaderLayer>? _debugPreviousLeaders;
  bool _debugLeaderCheckScheduled = false;

  /// Schedules the check as post frame callback to make sure the
  /// [_debugPreviousLeaders] is empty.
  void _debugScheduleLeadersCleanUpCheck() {
    assert(_debugPreviousLeaders != null);
    assert(() {
      if (_debugLeaderCheckScheduled)
        return true;
      _debugLeaderCheckScheduled = true;
2153
      SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
2154 2155 2156 2157 2158 2159 2160
        _debugLeaderCheckScheduled = false;
        assert(_debugPreviousLeaders!.isEmpty);
      });
      return true;
    }());
  }

2161
  /// The total size of the content of the connected [LeaderLayer].
2162 2163
  ///
  /// Generally this should be set by the [RenderObject] that paints on the
2164
  /// registered [LeaderLayer] (for instance a [RenderLeaderLayer] that shares
2165 2166 2167 2168
  /// this link with its followers). This size may be outdated before and during
  /// layout.
  Size? leaderSize;

2169
  @override
2170
  String toString() => '${describeIdentity(this)}(${ _leader != null ? "<linked>" : "<dangling>" })';
2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
}

/// 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.
2187
  LeaderLayer({ required LayerLink link, Offset offset = Offset.zero }) : assert(link != null), _link = link, _offset = offset;
2188 2189 2190 2191 2192

  /// 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.
2193
  LayerLink get link => _link;
2194
  LayerLink _link;
2195 2196
  set link(LayerLink value) {
    assert(value != null);
2197 2198 2199
    if (_link == value) {
      return;
    }
2200 2201 2202 2203
    if (attached) {
      _link._unregisterLeader(this);
      value._registerLeader(this);
    }
2204 2205
    _link = value;
  }
2206 2207 2208 2209 2210 2211 2212 2213

  /// 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.
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225
  Offset get offset => _offset;
  Offset _offset;
  set offset(Offset value) {
    assert(value != null);
    if (value == _offset) {
      return;
    }
    _offset = value;
    if (!alwaysNeedsAddToScene) {
      markNeedsAddToScene();
    }
  }
2226 2227 2228 2229

  @override
  void attach(Object owner) {
    super.attach(owner);
2230
    _link._registerLeader(this);
2231 2232 2233 2234
  }

  @override
  void detach() {
2235
    _link._unregisterLeader(this);
2236 2237 2238
    super.detach();
  }

2239
  @override
2240
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
2241 2242
    return super.findAnnotations<S>(result, localPosition - offset, onlyFirst: onlyFirst);
  }
2243

2244
  @override
2245
  void addToScene(ui.SceneBuilder builder) {
2246
    assert(offset != null);
2247
    if (offset != Offset.zero)
2248
      engineLayer = builder.pushTransform(
2249
        Matrix4.translationValues(offset.dx, offset.dy, 0.0).storage,
2250
        oldLayer: _engineLayer as ui.TransformEngineLayer?,
2251
      );
2252
    addChildrenToScene(builder);
2253
    if (offset != Offset.zero)
2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264
      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
2265
  void applyTransform(Layer? child, Matrix4 transform) {
2266 2267
    if (offset != Offset.zero)
      transform.translate(offset.dx, offset.dy);
2268 2269 2270
  }

  @override
2271 2272
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
2273 2274
    properties.add(DiagnosticsProperty<Offset>('offset', offset));
    properties.add(DiagnosticsProperty<LayerLink>('link', link));
2275 2276 2277 2278 2279 2280 2281 2282
  }
}

/// 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
2283
/// to the coordinate space of the [LeaderLayer].
2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295
///
/// 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({
2296
    required LayerLink link,
2297 2298 2299
    this.showWhenUnlinked = true,
    this.unlinkedOffset = Offset.zero,
    this.linkedOffset = Offset.zero,
2300
  }) : assert(link != null), _link = link;
2301 2302 2303 2304 2305 2306

  /// 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].
2307 2308 2309 2310 2311 2312
  LayerLink get link => _link;
  set link(LayerLink value) {
    assert(value != null);
    _link = value;
  }
  LayerLink _link;
2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325

  /// 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.
2326
  bool? showWhenUnlinked;
2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339

  /// 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.
2340
  Offset? unlinkedOffset;
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353

  /// 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.
2354
  Offset? linkedOffset;
2355

2356 2357 2358
  Offset? _lastOffset;
  Matrix4? _lastTransform;
  Matrix4? _invertedTransform;
2359
  bool _inverseDirty = true;
2360

2361
  Offset? _transformOffset(Offset localPosition) {
2362
    if (_inverseDirty) {
2363
      _invertedTransform = Matrix4.tryInvert(getLastTransform()!);
2364
      _inverseDirty = false;
2365
    }
2366 2367
    if (_invertedTransform == null)
      return null;
2368
    final Vector4 vector = Vector4(localPosition.dx, localPosition.dy, 0.0, 1.0);
2369 2370
    final Vector4 result = _invertedTransform!.transform(vector);
    return Offset(result[0] - linkedOffset!.dx, result[1] - linkedOffset!.dy);
2371 2372 2373
  }

  @override
2374
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
2375
    if (_link.leader == null) {
2376 2377
      if (showWhenUnlinked!) {
        return super.findAnnotations(result, localPosition - unlinkedOffset!, onlyFirst: onlyFirst);
2378 2379
      }
      return false;
2380
    }
2381
    final Offset? transformedOffset = _transformOffset(localPosition);
2382
    if (transformedOffset == null) {
2383
      return false;
2384
    }
2385
    return super.findAnnotations<S>(result, transformedOffset, onlyFirst: onlyFirst);
2386
  }
2387 2388 2389 2390

  /// The transform that was used during the last composition phase.
  ///
  /// If the [link] was not linked to a [LeaderLayer], or if this layer has
2391
  /// a degenerate matrix applied, then this will be null.
2392 2393
  ///
  /// This method returns a new [Matrix4] instance each time it is invoked.
2394
  Matrix4? getLastTransform() {
2395 2396
    if (_lastTransform == null)
      return null;
2397 2398
    final Matrix4 result = Matrix4.translationValues(-_lastOffset!.dx, -_lastOffset!.dy, 0.0);
    result.multiply(_lastTransform!);
2399 2400 2401 2402 2403 2404 2405 2406 2407
    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.
2408
  static Matrix4 _collectTransformForLayerChain(List<ContainerLayer?> layers) {
2409
    // Initialize our result matrix.
2410
    final Matrix4 result = Matrix4.identity();
2411 2412 2413
    // 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)
2414
      layers[index]?.applyTransform(layers[index - 1], result);
2415 2416 2417
    return result;
  }

2418 2419 2420 2421 2422 2423 2424
  /// 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(
2425 2426 2427 2428
    Layer? a,
    Layer? b,
    List<ContainerLayer?> ancestorsA,
    List<ContainerLayer?> ancestorsB,
2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439
  ) {
    // 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);
2440
    } else if (a.depth > b.depth) {
2441 2442 2443 2444 2445 2446 2447 2448 2449
      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);
  }

2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477
  bool _debugCheckLeaderBeforeFollower(
    List<ContainerLayer> leaderToCommonAncestor,
    List<ContainerLayer> followerToCommonAncestor,
  ) {
    if (followerToCommonAncestor.length <= 1) {
      // Follower is the common ancestor, ergo the leader must come AFTER the follower.
      return false;
    }
    if (leaderToCommonAncestor.length <= 1) {
      // Leader is the common ancestor, ergo the leader must come BEFORE the follower.
      return true;
    }

    // Common ancestor is neither the leader nor the follower.
    final ContainerLayer leaderSubtreeBelowAncestor = leaderToCommonAncestor[leaderToCommonAncestor.length - 2];
    final ContainerLayer followerSubtreeBelowAncestor = followerToCommonAncestor[followerToCommonAncestor.length - 2];

    Layer? sibling = leaderSubtreeBelowAncestor;
    while (sibling != null) {
      if (sibling == followerSubtreeBelowAncestor) {
        return true;
      }
      sibling = sibling.nextSibling;
    }
    // The follower subtree didn't come after the leader subtree.
    return false;
  }

2478 2479 2480 2481
  /// Populate [_lastTransform] given the current state of the tree.
  void _establishTransform() {
    assert(link != null);
    _lastTransform = null;
2482
    final LeaderLayer? leader = _link.leader;
2483
    // Check to see if we are linked.
2484
    if (leader == null)
2485 2486
      return;
    // If we're linked, check the link is valid.
2487 2488 2489 2490 2491 2492
    assert(
      leader.owner == owner,
      'Linked LeaderLayer anchor is not in the same layer tree as the FollowerLayer.',
    );

    // Stores [leader, ..., commonAncestor] after calling _pathsToCommonAncestor.
2493
    final List<ContainerLayer> forwardLayers = <ContainerLayer>[leader];
2494 2495
    // Stores [this (follower), ..., commonAncestor] after calling
    // _pathsToCommonAncestor.
2496
    final List<ContainerLayer> inverseLayers = <ContainerLayer>[this];
2497 2498 2499 2500 2501

    final Layer? ancestor = _pathsToCommonAncestor(
      leader, this,
      forwardLayers, inverseLayers,
    );
2502 2503 2504 2505 2506 2507 2508 2509
    assert(
      ancestor != null,
      'LeaderLayer and FollowerLayer do not have a common ancestor.',
    );
    assert(
      _debugCheckLeaderBeforeFollower(forwardLayers, inverseLayers),
      'LeaderLayer anchor must come before FollowerLayer in paint order, but the reverse was true.',
    );
2510

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

2518
    final Matrix4 inverseTransform = _collectTransformForLayerChain(inverseLayers);
2519

2520 2521 2522 2523 2524 2525 2526
    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;
2527
    _inverseDirty = true;
2528 2529
  }

2530
  /// {@template flutter.rendering.FollowerLayer.alwaysNeedsAddToScene}
2531
  /// This disables retained rendering.
2532
  ///
2533 2534 2535 2536 2537
  /// 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
2538 2539 2540 2541 2542
  /// as [alwaysNeedsAddToScene].
  /// {@endtemplate}
  @override
  bool get alwaysNeedsAddToScene => true;

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

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

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

2595 2596 2597 2598
/// 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
2599 2600 2601 2602
/// 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].
2603 2604 2605
///
/// 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
2606
/// layer's annotation if all of the following restrictions are met:
2607
///
2608
/// {@template flutter.rendering.AnnotatedRegionLayer.restrictions}
2609 2610 2611 2612
/// * 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}
2613
///
2614 2615
/// 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.
2616
class AnnotatedRegionLayer<T extends Object> extends ContainerLayer {
2617
  /// Creates a new layer that annotates its children with [value].
2618
  ///
2619
  /// The [value] provided cannot be null.
2620 2621 2622
  AnnotatedRegionLayer(
    this.value, {
    this.size,
2623
    Offset? offset,
2624 2625 2626 2627 2628 2629 2630
    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.
2631 2632
  final T value;

2633
  /// The size of the annotated object.
2634
  ///
2635
  /// If [size] is provided, then the annotation is found only if the target
2636 2637 2638
  /// 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.
2639
  final Size? size;
2640

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

2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674
  /// 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;
2675

2676 2677 2678 2679 2680 2681 2682 2683
  /// 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:
  ///
2684
  /// {@macro flutter.rendering.AnnotatedRegionLayer.restrictions}
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
  ///
  /// 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].
2696
  @override
2697
  bool findAnnotations<S extends Object>(AnnotationResult<S> result, Offset localPosition, { required bool onlyFirst }) {
2698 2699 2700
    bool isAbsorbed = super.findAnnotations(result, localPosition, onlyFirst: onlyFirst);
    if (result.entries.isNotEmpty && onlyFirst)
      return isAbsorbed;
2701
    if (size != null && !(offset & size!).contains(localPosition)) {
2702
      return isAbsorbed;
2703
    }
2704
    if (T == S) {
2705 2706
      isAbsorbed = isAbsorbed || opaque;
      final Object untypedValue = value;
2707
      final S typedValue = untypedValue as S;
2708 2709
      result.add(AnnotationEntry<S>(
        annotation: typedValue,
2710
        localPosition: localPosition - offset,
2711
      ));
2712
    }
2713
    return isAbsorbed;
2714 2715 2716 2717 2718
  }

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