compositing.dart 32.5 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 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 6
// @dart = 2.9

A
Adam Barth 已提交
7
part of dart.ui;
8

A
Adam Barth 已提交
9
/// An opaque object representing a composited scene.
H
Hixie 已提交
10 11 12 13 14
///
/// To create a Scene object, use a [SceneBuilder].
///
/// Scene objects can be displayed on the screen using the
/// [Window.render] method.
S
sjindel-google 已提交
15
@pragma('vm:entry-point')
H
Hixie 已提交
16
class Scene extends NativeFieldWrapperClass2 {
17 18
  /// This class is created by the engine, and should not be instantiated
  /// or extended directly.
H
Hixie 已提交
19
  ///
20
  /// To create a Scene object, use a [SceneBuilder].
21
  @pragma('vm:entry-point')
22
  Scene._();
H
Hixie 已提交
23

24 25
  /// Creates a raster image representation of the current state of the scene.
  /// This is a slow operation that is performed on a background thread.
26
  Future<Image> toImage(int width, int height) {
27
    if (width <= 0 || height <= 0) {
D
Dan Field 已提交
28
      throw Exception('Invalid image dimensions.');
29
    }
30
    return _futurize((_Callback<Image> callback) => _toImage(width, height, callback));
31 32
  }

33
  String _toImage(int width, int height, _Callback<Image> callback) native 'Scene_toImage';
34

A
Adam Barth 已提交
35 36 37
  /// Releases the resources used by this scene.
  ///
  /// After calling this function, the scene is cannot be used further.
38
  void dispose() native 'Scene_dispose';
39 40
}

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
// Lightweight wrapper of a native layer object.
//
// This is used to provide a typed API for engine layers to prevent
// incompatible layers from being passed to [SceneBuilder]'s push methods.
// For example, this prevents a layer returned from `pushOpacity` from being
// passed as `oldLayer` to `pushTransform`. This is achieved by having one
// concrete subclass of this class per push method.
abstract class _EngineLayerWrapper implements EngineLayer {
  _EngineLayerWrapper._(this._nativeLayer);

  EngineLayer _nativeLayer;

  // Children of this layer.
  //
  // Null if this layer has no children. This field is populated only in debug
  // mode.
57
  List<_EngineLayerWrapper>? _debugChildren;
58 59 60 61 62 63 64 65 66

  // Whether this layer was used as `oldLayer` in a past frame.
  //
  // It is illegal to use a layer object again after it is passed as an
  // `oldLayer` argument.
  bool _debugWasUsedAsOldLayer = false;

  bool _debugCheckNotUsedAsOldLayer() {
    assert(
67 68 69 70 71 72
        !_debugWasUsedAsOldLayer,
        'Layer $runtimeType was previously used as oldLayer.\n'
        'Once a layer is used as oldLayer, it may not be used again. Instead, '
        'after calling one of the SceneBuilder.push* methods and passing an oldLayer '
        'to it, use the layer returned by the method as oldLayer in subsequent '
        'frames.');
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 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 134 135 136 137 138 139 140 141 142 143
    return true;
  }
}

/// An opaque handle to a transform engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushTransform].
///
/// {@template dart.ui.sceneBuilder.oldLayerCompatibility}
/// `oldLayer` parameter in [SceneBuilder] methods only accepts objects created
/// by the engine. [SceneBuilder] will throw an [AssertionError] if you pass it
/// a custom implementation of this class.
/// {@endtemplate}
class TransformEngineLayer extends _EngineLayerWrapper {
  TransformEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to an offset engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushOffset].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class OffsetEngineLayer extends _EngineLayerWrapper {
  OffsetEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to a clip rect engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushClipRect].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class ClipRectEngineLayer extends _EngineLayerWrapper {
  ClipRectEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to a clip rounded rect engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushClipRRect].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class ClipRRectEngineLayer extends _EngineLayerWrapper {
  ClipRRectEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to a clip path engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushClipPath].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class ClipPathEngineLayer extends _EngineLayerWrapper {
  ClipPathEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to an opacity engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushOpacity].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class OpacityEngineLayer extends _EngineLayerWrapper {
  OpacityEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to a color filter engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushColorFilter].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class ColorFilterEngineLayer extends _EngineLayerWrapper {
  ColorFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

144 145 146 147 148 149 150 151 152
/// An opaque handle to an image filter engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushImageFilter].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class ImageFilterEngineLayer extends _EngineLayerWrapper {
  ImageFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/// An opaque handle to a backdrop filter engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushBackdropFilter].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class BackdropFilterEngineLayer extends _EngineLayerWrapper {
  BackdropFilterEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to a shader mask engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushShaderMask].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class ShaderMaskEngineLayer extends _EngineLayerWrapper {
  ShaderMaskEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

/// An opaque handle to a physical shape engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushPhysicalShape].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
class PhysicalShapeEngineLayer extends _EngineLayerWrapper {
  PhysicalShapeEngineLayer._(EngineLayer nativeLayer) : super._(nativeLayer);
}

A
Adam Barth 已提交
180
/// Builds a [Scene] containing the given visuals.
H
Hixie 已提交
181 182 183 184 185 186
///
/// A [Scene] can then be rendered using [Window.render].
///
/// To draw graphical operations onto a [Scene], first create a
/// [Picture] using a [PictureRecorder] and a [Canvas], and then add
/// it to the scene using [addPicture].
187
class SceneBuilder extends NativeFieldWrapperClass2 {
H
Hixie 已提交
188
  /// Creates an empty [SceneBuilder] object.
189
  @pragma('vm:entry-point')
190 191 192
  SceneBuilder() {
    _constructor();
  }
193
  void _constructor() native 'SceneBuilder_constructor';
194

195 196 197 198 199 200 201 202 203 204
  // Layers used in this scene.
  //
  // The key is the layer used. The value is the description of what the layer
  // is used for, e.g. "pushOpacity" or "addRetained".
  Map<EngineLayer, String> _usedLayers = <EngineLayer, String>{};

  // In debug mode checks that the `layer` is only used once in a given scene.
  bool _debugCheckUsedOnce(EngineLayer layer, String usage) {
    assert(() {
      assert(
205 206 207 208
          !_usedLayers.containsKey(layer),
          'Layer ${layer.runtimeType} already used.\n'
          'The layer is already being used as ${_usedLayers[layer]} in this scene.\n'
          'A layer may only be used once in a given scene.');
209 210 211 212 213 214 215 216

      _usedLayers[layer] = usage;
      return true;
    }());

    return true;
  }

217
  bool _debugCheckCanBeUsedAsOldLayer(_EngineLayerWrapper? layer, String methodName) {
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    assert(() {
      if (layer == null) {
        return true;
      }
      layer._debugCheckNotUsedAsOldLayer();
      assert(_debugCheckUsedOnce(layer, 'oldLayer in $methodName'));
      layer._debugWasUsedAsOldLayer = true;
      return true;
    }());
    return true;
  }

  final List<_EngineLayerWrapper> _layerStack = <_EngineLayerWrapper>[];

  // Pushes the `newLayer` onto the `_layerStack` and adds it to the
  // `_debugChildren` of the current layer in the stack, if any.
  bool _debugPushLayer(_EngineLayerWrapper newLayer) {
    assert(() {
      if (_layerStack.isNotEmpty) {
        final _EngineLayerWrapper currentLayer = _layerStack.last;
        currentLayer._debugChildren ??= <_EngineLayerWrapper>[];
239
        currentLayer._debugChildren!.add(newLayer);
240 241 242 243 244 245 246
      }
      _layerStack.add(newLayer);
      return true;
    }());
    return true;
  }

A
Adam Barth 已提交
247 248 249 250
  /// Pushes a transform operation onto the operation stack.
  ///
  /// The objects are transformed by the given matrix before rasterization.
  ///
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
  /// {@template dart.ui.sceneBuilder.oldLayer}
  /// If `oldLayer` is not null the engine will attempt to reuse the resources
  /// allocated for the old layer when rendering the new layer. This is purely
  /// an optimization. It has no effect on the correctness of rendering.
  /// {@endtemplate}
  ///
  /// {@template dart.ui.sceneBuilder.oldLayerVsRetained}
  /// Passing a layer to [addRetained] or as `oldLayer` argument to a push
  /// method counts as _usage_. A layer can be used no more than once in a scene.
  /// For example, it may not be passed simultaneously to two push methods, or
  /// to a push method and to `addRetained`.
  ///
  /// When a layer is passed to [addRetained] all descendant layers are also
  /// considered as used in this scene. The same single-usage restriction
  /// applies to descendants.
  ///
  /// When a layer is passed as an `oldLayer` argument to a push method, it may
  /// no longer be used in subsequent frames. If you would like to continue
  /// reusing the resources associated with the layer, store the layer object
  /// returned by the push method and use that in the next frame instead of the
  /// original object.
  /// {@endtemplate}
  ///
A
Adam Barth 已提交
274
  /// See [pop] for details about the operation stack.
275 276 277
  TransformEngineLayer? pushTransform(
    Float64List matrix4, {
    TransformEngineLayer? oldLayer,
278
  }) {
279
    assert(_matrix4IsValid(matrix4));
280
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushTransform'));
281 282 283
    final EngineLayer engineLayer = EngineLayer._();
    _pushTransform(engineLayer, matrix4);
    final TransformEngineLayer layer = TransformEngineLayer._(engineLayer);
284 285
    assert(_debugPushLayer(layer));
    return layer;
286
  }
287

288
  void _pushTransform(EngineLayer layer, Float64List matrix4) native 'SceneBuilder_pushTransform';
A
Adam Barth 已提交
289

290 291 292 293
  /// Pushes an offset operation onto the operation stack.
  ///
  /// This is equivalent to [pushTransform] with a matrix with only translation.
  ///
294 295 296 297
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
298
  /// See [pop] for details about the operation stack.
299 300 301 302
  OffsetEngineLayer? pushOffset(
    double dx,
    double dy, {
    OffsetEngineLayer? oldLayer,
303
  }) {
304
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOffset'));
305 306 307
    final EngineLayer engineLayer = EngineLayer._();
    _pushOffset(engineLayer, dx, dy);
    final OffsetEngineLayer layer = OffsetEngineLayer._(engineLayer);
308 309 310
    assert(_debugPushLayer(layer));
    return layer;
  }
311

312
  void _pushOffset(EngineLayer layer, double dx, double dy) native 'SceneBuilder_pushOffset';
313

A
Adam Barth 已提交
314 315 316 317
  /// Pushes a rectangular clip operation onto the operation stack.
  ///
  /// Rasterization outside the given rectangle is discarded.
  ///
318 319 320 321
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
322 323
  /// See [pop] for details about the operation stack, and [Clip] for different clip modes.
  /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]).
324 325 326 327
  ClipRectEngineLayer? pushClipRect(
    Rect rect, {
    Clip clipBehavior = Clip.antiAlias,
    ClipRectEngineLayer? oldLayer,
328
  }) {
329
    assert(clipBehavior != null); // ignore: unnecessary_null_comparison
330
    assert(clipBehavior != Clip.none);
331
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipRect'));
332 333 334
    final EngineLayer engineLayer = EngineLayer._();
    _pushClipRect(engineLayer, rect.left, rect.right, rect.top, rect.bottom, clipBehavior.index);
    final ClipRectEngineLayer layer = ClipRectEngineLayer._(engineLayer);
335 336
    assert(_debugPushLayer(layer));
    return layer;
337
  }
338

339
  void _pushClipRect(EngineLayer outEngineLayer, double left, double right, double top, double bottom, int clipBehavior)
340
      native 'SceneBuilder_pushClipRect';
A
Adam Barth 已提交
341 342 343 344 345

  /// Pushes a rounded-rectangular clip operation onto the operation stack.
  ///
  /// Rasterization outside the given rounded rectangle is discarded.
  ///
346 347 348 349
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
350 351
  /// See [pop] for details about the operation stack, and [Clip] for different clip modes.
  /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]).
352 353 354 355
  ClipRRectEngineLayer? pushClipRRect(
    RRect rrect, {
    Clip clipBehavior = Clip.antiAlias,
    ClipRRectEngineLayer? oldLayer,
356
  }) {
357
    assert(clipBehavior != null); // ignore: unnecessary_null_comparison
358
    assert(clipBehavior != Clip.none);
359
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipRRect'));
360 361 362
    final EngineLayer engineLayer = EngineLayer._();
    _pushClipRRect(engineLayer, rrect._value32, clipBehavior.index);
    final ClipRRectEngineLayer layer = ClipRRectEngineLayer._(engineLayer);
363 364
    assert(_debugPushLayer(layer));
    return layer;
365
  }
366

367
  void _pushClipRRect(EngineLayer layer, Float32List rrect, int clipBehavior)
368
      native 'SceneBuilder_pushClipRRect';
A
Adam Barth 已提交
369 370 371 372 373

  /// Pushes a path clip operation onto the operation stack.
  ///
  /// Rasterization outside the given path is discarded.
  ///
374 375 376 377
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
378 379
  /// See [pop] for details about the operation stack. See [Clip] for different clip modes.
  /// By default, the clip will be anti-aliased (clip = [Clip.antiAlias]).
380 381 382 383
  ClipPathEngineLayer? pushClipPath(
    Path path, {
    Clip clipBehavior = Clip.antiAlias,
    ClipPathEngineLayer? oldLayer,
384
  }) {
385
    assert(clipBehavior != null); // ignore: unnecessary_null_comparison
386
    assert(clipBehavior != Clip.none);
387
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushClipPath'));
388 389 390
    final EngineLayer engineLayer = EngineLayer._();
    _pushClipPath(engineLayer, path, clipBehavior.index);
    final ClipPathEngineLayer layer = ClipPathEngineLayer._(engineLayer);
391 392
    assert(_debugPushLayer(layer));
    return layer;
393
  }
394

395
  void _pushClipPath(EngineLayer layer, Path path, int clipBehavior) native 'SceneBuilder_pushClipPath';
A
Adam Barth 已提交
396 397 398 399 400 401 402 403

  /// Pushes an opacity operation onto the operation stack.
  ///
  /// The given alpha value is blended into the alpha value of the objects'
  /// rasterization. An alpha value of 0 makes the objects entirely invisible.
  /// An alpha value of 255 has no effect (i.e., the objects retain the current
  /// opacity).
  ///
404 405 406 407
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
A
Adam Barth 已提交
408
  /// See [pop] for details about the operation stack.
409 410 411 412
  OpacityEngineLayer? pushOpacity(
    int alpha, {
    Offset? offset = Offset.zero,
    OpacityEngineLayer? oldLayer,
413
  }) {
414
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOpacity'));
415
    final EngineLayer engineLayer = EngineLayer._();
416
    _pushOpacity(engineLayer, alpha, offset!.dx, offset.dy);
417
    final OpacityEngineLayer layer = OpacityEngineLayer._(engineLayer);
418 419
    assert(_debugPushLayer(layer));
    return layer;
420
  }
421

422
  void _pushOpacity(EngineLayer layer, int alpha, double dx, double dy) native 'SceneBuilder_pushOpacity';
A
Adam Barth 已提交
423 424 425 426

  /// Pushes a color filter operation onto the operation stack.
  ///
  /// The given color is applied to the objects' rasterization using the given
427
  /// blend mode.
A
Adam Barth 已提交
428
  ///
429 430 431 432
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
A
Adam Barth 已提交
433
  /// See [pop] for details about the operation stack.
434 435 436
  ColorFilterEngineLayer? pushColorFilter(
    ColorFilter filter, {
    ColorFilterEngineLayer? oldLayer,
437
  }) {
438
    assert(filter != null); // ignore: unnecessary_null_comparison
439
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushColorFilter'));
440 441
    final _ColorFilter nativeFilter = filter._toNativeColorFilter()!;
    assert(nativeFilter != null); // ignore: unnecessary_null_comparison
442 443 444
    final EngineLayer engineLayer = EngineLayer._();
    _pushColorFilter(engineLayer, nativeFilter);
    final ColorFilterEngineLayer layer = ColorFilterEngineLayer._(engineLayer);
445 446
    assert(_debugPushLayer(layer));
    return layer;
447
  }
448

449
  void _pushColorFilter(EngineLayer layer, _ColorFilter filter) native 'SceneBuilder_pushColorFilter';
450 451 452 453 454 455 456 457 458 459 460

  /// Pushes an image filter operation onto the operation stack.
  ///
  /// The given filter is applied to the children's rasterization before compositing them into
  /// the scene.
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
  /// See [pop] for details about the operation stack.
461 462 463
  ImageFilterEngineLayer? pushImageFilter(
    ImageFilter filter, {
    ImageFilterEngineLayer? oldLayer,
464
  }) {
465
    assert(filter != null); // ignore: unnecessary_null_comparison
466 467
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushImageFilter'));
    final _ImageFilter nativeFilter = filter._toNativeImageFilter();
468
    assert(nativeFilter != null); // ignore: unnecessary_null_comparison
469 470 471
    final EngineLayer engineLayer = EngineLayer._();
    _pushImageFilter(engineLayer, nativeFilter);
    final ImageFilterEngineLayer layer = ImageFilterEngineLayer._(engineLayer);
472 473 474 475
    assert(_debugPushLayer(layer));
    return layer;
  }

476
  void _pushImageFilter(EngineLayer outEngineLayer, _ImageFilter filter) native 'SceneBuilder_pushImageFilter';
A
Adam Barth 已提交
477

478 479 480 481 482
  /// Pushes a backdrop filter operation onto the operation stack.
  ///
  /// The given filter is applied to the current contents of the scene prior to
  /// rasterizing the given objects.
  ///
483 484 485 486
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
487
  /// See [pop] for details about the operation stack.
488 489 490
  BackdropFilterEngineLayer? pushBackdropFilter(
    ImageFilter filter, {
    BackdropFilterEngineLayer? oldLayer,
491
  }) {
492
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushBackdropFilter'));
493 494 495
    final EngineLayer engineLayer = EngineLayer._();
    _pushBackdropFilter(engineLayer, filter._toNativeImageFilter());
    final BackdropFilterEngineLayer layer = BackdropFilterEngineLayer._(engineLayer);
496 497 498
    assert(_debugPushLayer(layer));
    return layer;
  }
499

500
  void _pushBackdropFilter(EngineLayer outEngineLayer, _ImageFilter filter) native 'SceneBuilder_pushBackdropFilter';
501

A
Adam Barth 已提交
502 503 504
  /// Pushes a shader mask operation onto the operation stack.
  ///
  /// The given shader is applied to the object's rasterization in the given
505
  /// rectangle using the given blend mode.
A
Adam Barth 已提交
506
  ///
507 508 509 510
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
A
Adam Barth 已提交
511
  /// See [pop] for details about the operation stack.
512 513 514 515 516
  ShaderMaskEngineLayer? pushShaderMask(
    Shader shader,
    Rect maskRect,
    BlendMode blendMode, {
    ShaderMaskEngineLayer? oldLayer,
517
  }) {
518
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushShaderMask'));
519 520 521 522 523 524 525 526 527 528 529
    final EngineLayer engineLayer = EngineLayer._();
    _pushShaderMask(
      engineLayer,
      shader,
      maskRect.left,
      maskRect.right,
      maskRect.top,
      maskRect.bottom,
      blendMode.index,
    );
    final ShaderMaskEngineLayer layer = ShaderMaskEngineLayer._(engineLayer);
530 531
    assert(_debugPushLayer(layer));
    return layer;
532
  }
533 534

  EngineLayer _pushShaderMask(
535
      EngineLayer engineLayer,
536 537 538 539 540 541
      Shader shader,
      double maskRectLeft,
      double maskRectRight,
      double maskRectTop,
      double maskRectBottom,
      int blendMode) native 'SceneBuilder_pushShaderMask';
542

543
  /// Pushes a physical layer operation for an arbitrary shape onto the
544 545
  /// operation stack.
  ///
546 547 548 549 550
  /// By default, the layer's content will not be clipped (clip = [Clip.none]).
  /// If clip equals [Clip.hardEdge], [Clip.antiAlias], or [Clip.antiAliasWithSaveLayer],
  /// then the content is clipped to the given shape defined by [path].
  ///
  /// If [elevation] is greater than 0.0, then a shadow is drawn around the layer.
L
liyuqian 已提交
551
  /// [shadowColor] defines the color of the shadow if present and [color] defines the
552
  /// color of the layer background.
553
  ///
554 555 556 557
  /// {@macro dart.ui.sceneBuilder.oldLayer}
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
  ///
558 559
  /// See [pop] for details about the operation stack, and [Clip] for different clip modes.
  // ignore: deprecated_member_use
560 561 562 563 564 565 566
  PhysicalShapeEngineLayer? pushPhysicalShape({
    required Path path,
    required double elevation,
    required Color color,
    Color? shadowColor,
    Clip clipBehavior = Clip.none,
    PhysicalShapeEngineLayer? oldLayer,
567
  }) {
568
    assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushPhysicalShape'));
569 570 571 572 573 574 575 576 577 578
    final EngineLayer engineLayer = EngineLayer._();
    _pushPhysicalShape(
      engineLayer,
      path,
      elevation,
      color.value,
      shadowColor?.value ?? 0xFF000000,
      clipBehavior.index,
    );
    final PhysicalShapeEngineLayer layer = PhysicalShapeEngineLayer._(engineLayer);
579 580
    assert(_debugPushLayer(layer));
    return layer;
581
  }
582

583
  EngineLayer _pushPhysicalShape(EngineLayer outEngineLayer, Path path, double elevation, int color, int shadowColor,
584
      int clipBehavior) native 'SceneBuilder_pushPhysicalShape';
585

A
Adam Barth 已提交
586 587 588 589 590 591
  /// Ends the effect of the most recently pushed operation.
  ///
  /// Internally the scene builder maintains a stack of operations. Each of the
  /// operations in the stack applies to each of the objects added to the scene.
  /// Calling this function removes the most recently added operation from the
  /// stack.
592 593 594 595 596 597
  void pop() {
    if (_layerStack.isNotEmpty) {
      _layerStack.removeLast();
    }
    _pop();
  }
598

599
  void _pop() native 'SceneBuilder_pop';
600

601 602 603 604 605
  /// Add a retained engine layer subtree from previous frames.
  ///
  /// All the engine layers that are in the subtree of the retained layer will
  /// be automatically appended to the current engine layer tree.
  ///
L
liyuqian 已提交
606
  /// Therefore, when implementing a subclass of the [Layer] concept defined in
607 608
  /// the rendering layer of Flutter's framework, once this is called, there's
  /// no need to call [addToScene] for its children layers.
609 610
  ///
  /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
611
  void addRetained(EngineLayer retainedLayer) {
612 613
    assert(retainedLayer is _EngineLayerWrapper);
    assert(() {
614
      final _EngineLayerWrapper layer = retainedLayer as _EngineLayerWrapper;
615 616 617 618 619

      void recursivelyCheckChildrenUsedOnce(_EngineLayerWrapper parentLayer) {
        _debugCheckUsedOnce(parentLayer, 'retained layer');
        parentLayer._debugCheckNotUsedAsOldLayer();

620 621
        final List<_EngineLayerWrapper>? children = parentLayer._debugChildren;
        if (children == null || children.isEmpty) {
622 623
          return;
        }
624
        children.forEach(recursivelyCheckChildrenUsedOnce);
625 626 627 628 629 630 631
      }

      recursivelyCheckChildrenUsedOnce(layer);

      return true;
    }());

632
    final _EngineLayerWrapper wrapper = retainedLayer as _EngineLayerWrapper;
633 634
    _addRetained(wrapper._nativeLayer);
  }
635

636
  void _addRetained(EngineLayer retainedLayer) native 'SceneBuilder_addRetained';
637

A
Adam Barth 已提交
638 639 640 641 642
  /// Adds an object to the scene that displays performance statistics.
  ///
  /// Useful during development to assess the performance of the application.
  /// The enabledOptions controls which statistics are displayed. The bounds
  /// controls where the statistics are displayed.
H
Hixie 已提交
643 644
  ///
  /// enabledOptions is a bit field with the following bits defined:
645 646
  ///  - 0x01: displayRasterizerStatistics - show raster thread frame time
  ///  - 0x02: visualizeRasterizerStatistics - graph raster thread frame times
H
Hixie 已提交
647 648
  ///  - 0x04: displayEngineStatistics - show UI thread frame time
  ///  - 0x08: visualizeEngineStatistics - graph UI thread frame times
H
Hixie 已提交
649 650 651 652 653
  /// Set enabledOptions to 0x0F to enable all the currently defined features.
  ///
  /// The "UI thread" is the thread that includes all the execution of
  /// the main Dart isolate (the isolate that can call
  /// [Window.render]). The UI thread frame time is the total time
654
  /// spent executing the [Window.onBeginFrame] callback. The "raster
H
Hixie 已提交
655 656 657 658 659 660 661
  /// thread" is the thread (running on the CPU) that subsequently
  /// processes the [Scene] provided by the Dart code to turn it into
  /// GPU commands and send it to the GPU.
  ///
  /// See also the [PerformanceOverlayOption] enum in the rendering library.
  /// for more details.
  // Values above must match constants in //engine/src/sky/compositor/performance_overlay_layer.h
662
  void addPerformanceOverlay(int enabledOptions, Rect bounds) {
663
    _addPerformanceOverlay(enabledOptions, bounds.left, bounds.right, bounds.top, bounds.bottom);
664
  }
665 666 667 668 669 670 671 672

  void _addPerformanceOverlay(
    int enabledOptions,
    double left,
    double right,
    double top,
    double bottom,
  ) native 'SceneBuilder_addPerformanceOverlay';
A
Adam Barth 已提交
673

H
Hixie 已提交
674
  /// Adds a [Picture] to the scene.
A
Adam Barth 已提交
675 676
  ///
  /// The picture is rasterized at the given offset.
677
  void addPicture(
678 679 680 681
    Offset offset,
    Picture picture, {
    bool isComplexHint = false,
    bool willChangeHint = false,
682 683
  }) {
    final int hints = (isComplexHint ? 1 : 0) | (willChangeHint ? 2 : 0);
684
    _addPicture(offset.dx, offset.dy, picture, hints);
685
  }
686 687 688

  void _addPicture(double dx, double dy, Picture picture, int hints)
      native 'SceneBuilder_addPicture';
A
Adam Barth 已提交
689

690 691 692
  /// Adds a backend texture to the scene.
  ///
  /// The texture is scaled to the given size and rasterized at the given offset.
A
amirh 已提交
693 694 695 696 697 698
  ///
  /// If `freeze` is true the texture that is added to the scene will not
  /// be updated with new frames. `freeze` is used when resizing an embedded
  /// Android view: When resizing an Android view there 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
699
  /// texture just before resizing the Android view and un-freezes it when it is
A
amirh 已提交
700
  /// certain that a frame with the new size is ready.
701
  void addTexture(
702 703 704 705 706 707
    int/*!*/ textureId, {
    Offset/*!*/ offset = Offset.zero,
    double/*!*/ width = 0.0,
    double/*!*/ height = 0.0,
    bool/*!*/ freeze = false,
    FilterQuality/*!*/ filterQuality = FilterQuality.low,
708
  }) {
709
    assert(offset != null, 'Offset argument was null'); // ignore: unnecessary_null_comparison
710
    _addTexture(offset.dx, offset.dy, width, height, textureId, freeze, filterQuality.index);
711
  }
712

713 714
  void _addTexture(double dx, double dy, double width, double height, int textureId, bool freeze,
      int filterQuality) native 'SceneBuilder_addTexture';
715

716 717
  /// Adds a platform view (e.g an iOS UIView) to the scene.
  ///
718 719 720 721 722 723 724 725 726 727 728 729 730 731
  /// Only supported on iOS, this is currently a no-op on other platforms.
  ///
  /// On iOS this layer splits the current output surface into two surfaces, one for the scene nodes
  /// preceding the platform view, and one for the scene nodes following the platform view.
  ///
  /// ## Performance impact
  ///
  /// Adding an additional surface doubles the amount of graphics memory directly used by Flutter
  /// for output buffers. Quartz might allocated extra buffers for compositing the Flutter surfaces
  /// and the platform view.
  ///
  /// With a platform view in the scene, Quartz has to composite the two Flutter surfaces and the
  /// embedded UIView. In addition to that, on iOS versions greater than 9, the Flutter frames are
  /// synchronized with the UIView frames adding additional performance overhead.
732
  void addPlatformView(
733 734 735 736
    int viewId, {
    Offset offset = Offset.zero,
    double width = 0.0,
    double height = 0.0,
737
  }) {
738
    assert(offset != null, 'Offset argument was null'); // ignore: unnecessary_null_comparison
739 740
    _addPlatformView(offset.dx, offset.dy, width, height, viewId);
  }
741 742 743

  void _addPlatformView(double dx, double dy, double width, double height, int viewId)
      native 'SceneBuilder_addPlatformView';
744

745 746
  /// (Fuchsia-only) Adds a scene rendered by another application to the scene
  /// for this application.
747
  void addChildScene({
748 749 750 751 752
    Offset offset = Offset.zero,
    double width = 0.0,
    double height = 0.0,
    required SceneHost sceneHost,
    bool hitTestable = true,
753
  }) {
754
    _addChildScene(offset.dx, offset.dy, width, height, sceneHost, hitTestable);
755
  }
756 757 758

  void _addChildScene(double dx, double dy, double width, double height, SceneHost sceneHost,
      bool hitTestable) native 'SceneBuilder_addChildScene';
A
Adam Barth 已提交
759 760 761 762 763 764 765

  /// Sets a threshold after which additional debugging information should be recorded.
  ///
  /// Currently this interface is difficult to use by end-developers. If you're
  /// interested in using this feature, please contact [flutter-dev](https://groups.google.com/forum/#!forum/flutter-dev).
  /// We'll hopefully be able to figure out how to make this feature more useful
  /// to you.
766
  void setRasterizerTracingThreshold(int frameInterval)
767
      native 'SceneBuilder_setRasterizerTracingThreshold';
768

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
  /// Sets whether the raster cache should checkerboard cached entries. This is
  /// only useful for debugging purposes.
  ///
  /// 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.
  ///
  /// Currently this interface is difficult to use by end-developers. If you're
  /// interested in using this feature, please contact [flutter-dev](https://groups.google.com/forum/#!forum/flutter-dev).
784
  void setCheckerboardRasterCacheImages(bool checkerboard)
785
      native 'SceneBuilder_setCheckerboardRasterCacheImages';
786

787 788 789 790
  /// Sets whether the compositor should checkerboard layers that are rendered
  /// to offscreen bitmaps.
  ///
  /// This is only useful for debugging purposes.
791
  void setCheckerboardOffscreenLayers(bool checkerboard)
792
      native 'SceneBuilder_setCheckerboardOffscreenLayers';
793

A
Adam Barth 已提交
794 795
  /// Finishes building the scene.
  ///
H
Hixie 已提交
796 797 798
  /// Returns a [Scene] containing the objects that have been added to
  /// this scene builder. The [Scene] can then be displayed on the
  /// screen with [Window.render].
A
Adam Barth 已提交
799 800 801
  ///
  /// After calling this function, the scene builder object is invalid and
  /// cannot be used further.
802
  Scene build() {
803 804 805 806 807 808
    final Scene scene = Scene._();
    _build(scene);
    return scene;
  }

  void _build(Scene outScene) native 'SceneBuilder_build';
809
}
810 811 812

/// (Fuchsia-only) Hosts content provided by another application.
class SceneHost extends NativeFieldWrapperClass2 {
813
  /// Creates a host for a child scene's content.
814
  ///
815 816 817
  /// The ViewHolder token is bound to a ViewHolder scene graph node which acts
  /// as a container for the child's content.  The creator of the SceneHost is
  /// responsible for sending the corresponding ViewToken to the child.
818
  ///
819
  /// The ViewHolder token is a dart:zircon Handle, but that type isn't
820
  /// available here. This is called by ChildViewConnection in
821
  /// //topaz/public/dart/fuchsia_scenic_flutter/.
822
  ///
823 824
  /// The SceneHost takes ownership of the provided ViewHolder token.
  SceneHost(
825
    dynamic viewHolderToken,
826 827 828
    void Function()? viewConnectedCallback,
    void Function()? viewDisconnectedCallback,
    void Function(bool)? viewStateChangedCallback,
829 830 831
  ) {
    _constructor(
        viewHolderToken, viewConnectedCallback, viewDisconnectedCallback, viewStateChangedCallback);
832
  }
833

834 835
  void _constructor(
    dynamic viewHolderToken,
836 837 838
    void Function()? viewConnectedCallback,
    void Function()? viewDisconnectedCallback,
    void Function(bool)? viewStateChangedCallbac,
839
  ) native 'SceneHost_constructor';
840

841
  /// Releases the resources associated with the SceneHost.
842
  ///
843
  /// After calling this function, the SceneHost cannot be used further.
844
  void dispose() native 'SceneHost_dispose';
845 846 847 848

  /// Set properties on the linked scene.  These properties include its bounds,
  /// as well as whether it can be the target of focus events or not.
  void setProperties(
849 850 851 852 853 854 855
    double width,
    double height,
    double insetTop,
    double insetRight,
    double insetBottom,
    double insetLeft,
    bool focusable,
856
  ) native 'SceneHost_setProperties';
857
}