未验证 提交 94bb7a7f 编写于 作者: Y Yegor 提交者: GitHub

Adds API for retaining intermediate engine layers (#9461)

Add new optional named oldLayer arguments to all push* methods of the SceneBuilder class.

When not null oldLayer signals to the engine that the intent is to update a layer rendered in a previous frame. The engine may optionally use that signal to reuse the resources allocated for that layer in the previous frame. For example, on the Web we can reuse existing DOM nodes and some of their properties and move fewer nodes around the tree.

The return type of each push method has been tightened up. Instead of having all methods return the same EngineLayer type, each method has its own unique layer type, e.g. OffsetEngineLayer. oldLayer parameters match the returned type. This prevents the framework (and other developers using dart:ui directly) from accidentally supplying an engine layer of the wrong type.
上级 7d1508d9
......@@ -8,7 +8,7 @@ part of engine;
///
/// A layer is the lowest-level rendering primitive. It represents an atomic
/// painting command.
abstract class Layer {
abstract class Layer implements ui.EngineLayer {
/// The layer that contains us as a child.
ContainerLayer parent;
......@@ -173,7 +173,7 @@ class ClipRRectLayer extends ContainerLayer {
}
/// A layer that transforms its child layers by the given transform matrix.
class TransformLayer extends ContainerLayer {
class TransformLayer extends ContainerLayer implements ui.OffsetEngineLayer, ui.TransformEngineLayer {
/// The matrix with which to transform the child layers.
final Matrix4 _transform;
......@@ -287,7 +287,7 @@ class PictureLayer extends Layer {
///
/// The shape clips its children to a given [Path], and casts a shadow based
/// on the given elevation.
class PhysicalShapeLayer extends ContainerLayer {
class PhysicalShapeLayer extends ContainerLayer implements ui.PhysicalShapeEngineLayer {
final double _elevation;
final ui.Color _color;
final ui.Color _shadowColor;
......
......@@ -4,12 +4,6 @@
part of engine;
class EngineLayerImpl extends ui.EngineLayer {
final ContainerLayer _layer;
EngineLayerImpl(this._layer);
}
class LayerScene implements ui.Scene {
final LayerTree layerTree;
......@@ -60,7 +54,7 @@ class LayerSceneBuilder implements ui.SceneBuilder {
@override
void addRetained(ui.EngineLayer retainedLayer) {
if (currentLayer == null) return;
currentLayer.add((retainedLayer as EngineLayerImpl)._layer);
currentLayer.add(retainedLayer);
}
@override
......@@ -95,80 +89,81 @@ class LayerSceneBuilder implements ui.SceneBuilder {
}
@override
ui.EngineLayer pushBackdropFilter(ui.ImageFilter filter,
{Object webOnlyPaintedBy}) {
ui.BackdropFilterEngineLayer pushBackdropFilter(ui.ImageFilter filter,
{ui.BackdropFilterEngineLayer oldLayer}) {
throw new UnimplementedError();
}
@override
ui.EngineLayer pushClipPath(ui.Path path,
{ui.Clip clipBehavior = ui.Clip.antiAlias, Object webOnlyPaintedBy}) {
ui.ClipPathEngineLayer pushClipPath(ui.Path path,
{ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipPathEngineLayer oldLayer}) {
pushLayer(ClipPathLayer(path));
return null;
}
@override
ui.EngineLayer pushClipRRect(ui.RRect rrect,
{ui.Clip clipBehavior, Object webOnlyPaintedBy}) {
ui.ClipRRectEngineLayer pushClipRRect(ui.RRect rrect,
{ui.Clip clipBehavior, ui.ClipRRectEngineLayer oldLayer}) {
pushLayer(ClipRRectLayer(rrect));
return null;
}
@override
ui.EngineLayer pushClipRect(ui.Rect rect,
{ui.Clip clipBehavior = ui.Clip.antiAlias, Object webOnlyPaintedBy}) {
ui.ClipRectEngineLayer pushClipRect(ui.Rect rect,
{ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipRectEngineLayer oldLayer}) {
pushLayer(ClipRectLayer(rect));
return null;
}
@override
ui.EngineLayer pushColorFilter(ui.Color color, ui.BlendMode blendMode,
{Object webOnlyPaintedBy}) {
ui.ColorFilterEngineLayer pushColorFilter(ui.Color color, ui.BlendMode blendMode,
{ui.ColorFilterEngineLayer oldLayer}) {
throw new UnimplementedError();
}
@override
ui.EngineLayer pushOffset(double dx, double dy, {Object webOnlyPaintedBy}) {
ui.OffsetEngineLayer pushOffset(double dx, double dy, {ui.OffsetEngineLayer oldLayer}) {
final matrix = Matrix4.translationValues(dx, dy, 0.0);
final layer = TransformLayer(matrix);
pushLayer(layer);
return EngineLayerImpl(layer);
return layer;
}
@override
ui.EngineLayer pushOpacity(int alpha,
{Object webOnlyPaintedBy, ui.Offset offset = ui.Offset.zero}) {
ui.OpacityEngineLayer pushOpacity(int alpha,
{ui.OpacityEngineLayer oldLayer, ui.Offset offset = ui.Offset.zero}) {
// TODO(het): Implement opacity
pushOffset(0.0, 0.0);
return null;
}
@override
ui.EngineLayer pushPhysicalShape(
ui.PhysicalShapeEngineLayer pushPhysicalShape(
{ui.Path path,
double elevation,
ui.Color color,
ui.Color shadowColor,
ui.Clip clipBehavior = ui.Clip.none,
Object webOnlyPaintedBy}) {
ui.PhysicalShapeEngineLayer oldLayer}) {
final layer =
PhysicalShapeLayer(elevation, color, shadowColor, path, clipBehavior);
pushLayer(layer);
return EngineLayerImpl(layer);
return layer;
}
@override
ui.EngineLayer pushShaderMask(
ui.ShaderMaskEngineLayer pushShaderMask(
ui.Shader shader, ui.Rect maskRect, ui.BlendMode blendMode,
{Object webOnlyPaintedBy}) {
{ui.ShaderMaskEngineLayer oldLayer}) {
throw new UnimplementedError();
}
@override
ui.EngineLayer pushTransform(Float64List matrix4, {Object webOnlyPaintedBy}) {
final matrix = Matrix4.fromList(matrix4);
pushLayer(TransformLayer(matrix));
return null;
ui.TransformEngineLayer pushTransform(Float64List matrix4, {ui.TransformEngineLayer oldLayer}) {
final Matrix4 matrix = Matrix4.fromList(matrix4);
final TransformLayer layer = TransformLayer(matrix);
pushLayer(layer);
return layer;
}
@override
......
......@@ -56,7 +56,7 @@ mixin _DomClip on PersistedContainerSurface {
}
/// A surface that creates a rectangular clip.
class PersistedClipRect extends PersistedContainerSurface with _DomClip {
class PersistedClipRect extends PersistedContainerSurface with _DomClip implements ui.ClipRectEngineLayer {
PersistedClipRect(Object paintedBy, this.rect) : super(paintedBy);
final ui.Rect rect;
......@@ -99,7 +99,7 @@ class PersistedClipRect extends PersistedContainerSurface with _DomClip {
}
/// A surface that creates a rounded rectangular clip.
class PersistedClipRRect extends PersistedContainerSurface with _DomClip {
class PersistedClipRRect extends PersistedContainerSurface with _DomClip implements ui.ClipRRectEngineLayer {
PersistedClipRRect(Object paintedBy, this.rrect, this.clipBehavior)
: super(paintedBy);
......@@ -148,7 +148,7 @@ class PersistedClipRRect extends PersistedContainerSurface with _DomClip {
}
}
class PersistedPhysicalShape extends PersistedContainerSurface with _DomClip {
class PersistedPhysicalShape extends PersistedContainerSurface with _DomClip implements ui.PhysicalShapeEngineLayer {
PersistedPhysicalShape(Object paintedBy, this.path, this.elevation, int color,
int shadowColor, this.clipBehavior)
: this.color = ui.Color(color),
......@@ -313,7 +313,7 @@ class PersistedPhysicalShape extends PersistedContainerSurface with _DomClip {
}
/// A surface that clips it's children.
class PersistedClipPath extends PersistedContainerSurface {
class PersistedClipPath extends PersistedContainerSurface implements ui.ClipPathEngineLayer {
PersistedClipPath(Object paintedBy, this.clipPath, this.clipBehavior)
: super(paintedBy);
......
......@@ -5,7 +5,7 @@
part of engine;
/// A surface that translates its children using CSS transform and translate.
class PersistedOffset extends PersistedContainerSurface {
class PersistedOffset extends PersistedContainerSurface implements ui.OffsetEngineLayer {
PersistedOffset(Object paintedBy, this.dx, this.dy) : super(paintedBy);
/// Horizontal displacement.
......
......@@ -5,7 +5,7 @@
part of engine;
/// A surface that makes its children transparent.
class PersistedOpacity extends PersistedContainerSurface {
class PersistedOpacity extends PersistedContainerSurface implements ui.OpacityEngineLayer {
PersistedOpacity(Object paintedBy, this.alpha, this.offset)
: super(paintedBy);
......
......@@ -5,7 +5,7 @@
part of engine;
/// A surface that transforms its children using CSS transform.
class PersistedTransform extends PersistedContainerSurface {
class PersistedTransform extends PersistedContainerSurface implements ui.TransformEngineLayer {
PersistedTransform(Object paintedBy, this.matrix4) : super(paintedBy);
final Float64List matrix4;
......
......@@ -39,6 +39,80 @@ class Scene {
void dispose() {}
}
/// 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}
abstract class TransformEngineLayer implements EngineLayer {}
/// An opaque handle to an offset engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushOffset].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class OffsetEngineLayer implements EngineLayer {}
/// An opaque handle to a clip rect engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushClipRect].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class ClipRectEngineLayer implements EngineLayer {}
/// An opaque handle to a clip rounded rect engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushClipRRect].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class ClipRRectEngineLayer implements EngineLayer {}
/// An opaque handle to a clip path engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushClipPath].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class ClipPathEngineLayer implements EngineLayer {}
/// An opaque handle to an opacity engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushOpacity].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class OpacityEngineLayer implements EngineLayer {}
/// An opaque handle to a color filter engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushColorFilter].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class ColorFilterEngineLayer implements EngineLayer {}
/// An opaque handle to a backdrop filter engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushBackdropFilter].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class BackdropFilterEngineLayer implements EngineLayer {}
/// An opaque handle to a shader mask engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushShaderMask].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class ShaderMaskEngineLayer implements EngineLayer {}
/// An opaque handle to a physical shape engine layer.
///
/// Instances of this class are created by [SceneBuilder.pushPhysicalShape].
///
/// {@macro dart.ui.sceneBuilder.oldLayerCompatibility}
abstract class PhysicalShapeEngineLayer implements EngineLayer {}
/// Builds a [Scene] containing the given visuals.
///
/// A [Scene] can then be rendered using [Window.render].
......@@ -108,7 +182,7 @@ class SceneBuilder {
/// This is equivalent to [pushTransform] with a matrix with only translation.
///
/// See [pop] for details about the operation stack.
EngineLayer pushOffset(double dx, double dy) {
OffsetEngineLayer pushOffset(double dx, double dy, { OffsetEngineLayer oldLayer }) {
return _pushSurface(engine.PersistedOffset(null, dx, dy));
}
......@@ -117,7 +191,7 @@ class SceneBuilder {
/// The objects are transformed by the given matrix before rasterization.
///
/// See [pop] for details about the operation stack.
EngineLayer pushTransform(Float64List matrix4) {
TransformEngineLayer pushTransform(Float64List matrix4, { TransformEngineLayer oldLayer }) {
if (matrix4 == null) {
throw new ArgumentError('"matrix4" argument cannot be null');
}
......@@ -133,8 +207,8 @@ class SceneBuilder {
///
/// 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]).
EngineLayer pushClipRect(Rect rect,
{Clip clipBehavior = Clip.antiAlias}) {
ClipRectEngineLayer pushClipRect(Rect rect,
{Clip clipBehavior = Clip.antiAlias, ClipRectEngineLayer oldLayer }) {
assert(clipBehavior != null);
assert(clipBehavior != Clip.none);
return _pushSurface(engine.PersistedClipRect(null, rect));
......@@ -145,8 +219,8 @@ class SceneBuilder {
/// Rasterization outside the given rounded rectangle is discarded.
///
/// See [pop] for details about the operation stack.
EngineLayer pushClipRRect(RRect rrect,
{Clip clipBehavior}) {
ClipRRectEngineLayer pushClipRRect(RRect rrect,
{Clip clipBehavior, ClipRRectEngineLayer oldLayer }) {
return _pushSurface(
engine.PersistedClipRRect(null, rrect, clipBehavior));
}
......@@ -156,8 +230,8 @@ class SceneBuilder {
/// Rasterization outside the given path is discarded.
///
/// See [pop] for details about the operation stack.
EngineLayer pushClipPath(Path path,
{Clip clipBehavior = Clip.antiAlias}) {
ClipPathEngineLayer pushClipPath(Path path,
{Clip clipBehavior = Clip.antiAlias, ClipPathEngineLayer oldLayer }) {
assert(clipBehavior != null);
assert(clipBehavior != Clip.none);
return _pushSurface(
......@@ -172,10 +246,9 @@ class SceneBuilder {
/// opacity).
///
/// See [pop] for details about the operation stack.
EngineLayer pushOpacity(int alpha,
{Offset offset = Offset.zero}) {
return _pushSurface(
engine.PersistedOpacity(null, alpha, offset));
OpacityEngineLayer pushOpacity(int alpha,
{Offset offset = Offset.zero, OpacityEngineLayer oldLayer}) {
return _pushSurface(engine.PersistedOpacity(null, alpha, offset));
}
/// Pushes a color filter operation onto the operation stack.
......@@ -184,7 +257,7 @@ class SceneBuilder {
/// blend mode.
///
/// See [pop] for details about the operation stack.
EngineLayer pushColorFilter(Color color, BlendMode blendMode) {
ColorFilterEngineLayer pushColorFilter(Color color, BlendMode blendMode, { ColorFilterEngineLayer oldLayer }) {
throw new UnimplementedError();
}
......@@ -194,7 +267,7 @@ class SceneBuilder {
/// rasterizing the given objects.
///
/// See [pop] for details about the operation stack.
EngineLayer pushBackdropFilter(ImageFilter filter) {
BackdropFilterEngineLayer pushBackdropFilter(ImageFilter filter, { BackdropFilterEngineLayer oldLayer }) {
throw new UnimplementedError();
}
......@@ -204,7 +277,7 @@ class SceneBuilder {
/// rectangle using the given blend mode.
///
/// See [pop] for details about the operation stack.
EngineLayer pushShaderMask(Shader shader, Rect maskRect, BlendMode blendMode) {
ShaderMaskEngineLayer pushShaderMask(Shader shader, Rect maskRect, BlendMode blendMode, { ShaderMaskEngineLayer oldLayer }) {
throw new UnimplementedError();
}
......@@ -220,12 +293,13 @@ class SceneBuilder {
/// color of the layer background.
///
/// See [pop] for details about the operation stack, and [Clip] for different clip modes.
EngineLayer pushPhysicalShape({
PhysicalShapeEngineLayer pushPhysicalShape({
Path path,
double elevation,
Color color,
Color shadowColor,
Clip clipBehavior = Clip.none,
PhysicalShapeEngineLayer oldLayer,
}) {
return _pushSurface(engine.PersistedPhysicalShape(
null,
......
此差异已折叠。
......@@ -51,4 +51,250 @@ void main() {
throwsA(const TypeMatcher<AssertionError>()),
);
});
test('SceneBuilder accepts typed layers', () {
final SceneBuilder builder1 = SceneBuilder();
final OpacityEngineLayer opacity1 = builder1.pushOpacity(100);
expect(opacity1, isNotNull);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
final OpacityEngineLayer opacity2 = builder2.pushOpacity(200, oldLayer: opacity1);
expect(opacity2, isNotNull);
builder2.pop();
builder2.build();
});
// Attempts to use the same layer first as `oldLayer` then in `addRetained`.
void testPushThenIllegalRetain(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
pushFunction(builder2, layer);
builder2.pop();
try {
builder2.addRetained(layer);
fail('Expected addRetained to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('The layer is already being used'));
}
builder2.build();
}
// Attempts to use the same layer first in `addRetained` then as `oldLayer`.
void testAddRetainedThenIllegalPush(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
builder2.addRetained(layer);
try {
pushFunction(builder2, layer);
fail('Expected push to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('The layer is already being used'));
}
builder2.build();
}
// Attempts to retain the same layer twice in the same scene.
void testDoubleAddRetained(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
builder2.addRetained(layer);
try {
builder2.addRetained(layer);
fail('Expected second addRetained to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('The layer is already being used'));
}
builder2.build();
}
// Attempts to use the same layer as `oldLayer` twice in the same scene.
void testPushOldLayerTwice(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
pushFunction(builder2, layer);
try {
pushFunction(builder2, layer);
fail('Expected push to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('was previously used as oldLayer'));
}
builder2.build();
}
// Attempts to use a child of a retained layer as an `oldLayer`.
void testPushChildLayerOfRetainedLayer(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
final EngineLayer childLayer = builder1.pushOpacity(123);
builder1.pop();
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
builder2.addRetained(layer);
try {
builder2.pushOpacity(321, oldLayer: childLayer);
fail('Expected pushOpacity to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('The layer is already being used'));
}
builder2.build();
}
// Attempts to retain a layer whose child is already used as `oldLayer` elsewhere in the scene.
void testRetainParentLayerOfPushedChild(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
final EngineLayer childLayer = builder1.pushOpacity(123);
builder1.pop();
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
builder2.pushOpacity(234, oldLayer: childLayer);
builder2.pop();
try {
builder2.addRetained(layer);
fail('Expected addRetained to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('The layer is already being used'));
}
builder2.build();
}
// Attempts to retain a layer that has been used as `oldLayer` in a previous frame.
void testRetainOldLayer(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
pushFunction(builder2, layer);
builder2.pop();
try {
final SceneBuilder builder3 = SceneBuilder();
builder3.addRetained(layer);
fail('Expected addRetained to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('was previously used as oldLayer'));
}
builder2.build();
}
// Attempts to pass layer as `oldLayer` that has been used as `oldLayer` in a previous frame.
void testPushOldLayer(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer layer = pushFunction(builder1, null);
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
pushFunction(builder2, layer);
builder2.pop();
try {
final SceneBuilder builder3 = SceneBuilder();
pushFunction(builder3, layer);
fail('Expected addRetained to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('was previously used as oldLayer'));
}
builder2.build();
}
// Attempts to retain a parent of a layer used as `oldLayer` in a previous frame.
void testRetainsParentOfOldLayer(_TestNoSharingFunction pushFunction) {
final SceneBuilder builder1 = SceneBuilder();
final EngineLayer parentLayer = pushFunction(builder1, null);
final OpacityEngineLayer childLayer = builder1.pushOpacity(123);
builder1.pop();
builder1.pop();
builder1.build();
final SceneBuilder builder2 = SceneBuilder();
builder2.pushOpacity(321, oldLayer: childLayer);
builder2.pop();
try {
final SceneBuilder builder3 = SceneBuilder();
builder3.addRetained(parentLayer);
fail('Expected addRetained to throw AssertionError but it returned successully');
} on AssertionError catch (error) {
expect(error.toString(), contains('was previously used as oldLayer'));
}
builder2.build();
}
void testNoSharing(_TestNoSharingFunction pushFunction) {
testPushThenIllegalRetain(pushFunction);
testAddRetainedThenIllegalPush(pushFunction);
testDoubleAddRetained(pushFunction);
testPushOldLayerTwice(pushFunction);
testPushChildLayerOfRetainedLayer(pushFunction);
testRetainParentLayerOfPushedChild(pushFunction);
testRetainOldLayer(pushFunction);
testPushOldLayer(pushFunction);
testRetainsParentOfOldLayer(pushFunction);
}
test('SceneBuilder does not share a layer between addRetained and push*', () {
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushOffset(0, 0, oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushTransform(Float64List(16), oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushClipRect(Rect.zero, oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushClipRRect(RRect.zero, oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushClipPath(Path(), oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushOpacity(100, oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushColorFilter(const Color.fromARGB(0, 0, 0, 0), BlendMode.color, oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushBackdropFilter(ImageFilter.blur(), oldLayer: oldLayer);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushShaderMask(
Gradient.radial(
const Offset(0, 0),
10,
const <Color>[Color.fromARGB(0, 0, 0, 0), Color.fromARGB(0, 255, 255, 255)],
),
Rect.zero,
BlendMode.color,
oldLayer: oldLayer,
);
});
testNoSharing((SceneBuilder builder, EngineLayer oldLayer) {
return builder.pushPhysicalShape(path: Path(), color: const Color.fromARGB(0, 0, 0, 0), oldLayer: oldLayer);
});
});
}
typedef _TestNoSharingFunction = EngineLayer Function(SceneBuilder builder, EngineLayer oldLayer);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册