未验证 提交 5fe6083d 编写于 作者: Y Yegor 提交者: GitHub

Move surface-based SceneBuilder implementation under surface/ (#13159)

Move surface-based SceneBuilder implementation under surface/
上级 c979817b
......@@ -415,6 +415,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/opacity.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/picture.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/platform_view.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/scene.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/scene_builder.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/surface.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/surface/transform.dart
FILE: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart
......
......@@ -82,6 +82,7 @@ part 'engine/surface/opacity.dart';
part 'engine/surface/picture.dart';
part 'engine/surface/platform_view.dart';
part 'engine/surface/scene.dart';
part 'engine/surface/scene_builder.dart';
part 'engine/surface/surface.dart';
part 'engine/surface/transform.dart';
part 'engine/test_embedding.dart';
......
......@@ -4,6 +4,27 @@
part of engine;
class SurfaceScene implements ui.Scene {
/// This class is created by the engine, and should not be instantiated
/// or extended directly.
///
/// To create a Scene object, use a [SceneBuilder].
SurfaceScene(this.webOnlyRootElement);
final html.Element webOnlyRootElement;
/// Creates a raster image representation of the current state of the scene.
/// This is a slow operation that is performed on a background thread.
Future<ui.Image> toImage(int width, int height) {
throw UnsupportedError('toImage is not supported on the Web');
}
/// Releases the resources used by this scene.
///
/// After calling this function, the scene is cannot be used further.
void dispose() {}
}
/// A surface that creates a DOM element for whole app.
class PersistedScene extends PersistedContainerSurface {
PersistedScene(PersistedScene oldLayer) : super(oldLayer) {
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of engine;
class SurfaceSceneBuilder implements ui.SceneBuilder {
SurfaceSceneBuilder() {
_surfaceStack.add(PersistedScene(_lastFrameScene));
}
final List<PersistedContainerSurface> _surfaceStack =
<PersistedContainerSurface>[];
/// The scene built by this scene builder.
///
/// This getter should only be called after all surfaces are built.
PersistedScene get _persistedScene {
assert(() {
if (_surfaceStack.length != 1) {
final String surfacePrintout = _surfaceStack
.map<Type>((PersistedContainerSurface surface) =>
surface.runtimeType)
.toList()
.join(', ');
throw Exception('Incorrect sequence of push/pop operations while '
'building scene surfaces. After building the scene the persisted '
'surface stack must contain a single element which corresponds '
'to the scene itself (_PersistedScene). All other surfaces '
'should have been popped off the stack. Found the following '
'surfaces in the stack:\n$surfacePrintout');
}
return true;
}());
return _surfaceStack.first;
}
/// The surface currently being built.
PersistedContainerSurface get _currentSurface => _surfaceStack.last;
ui.EngineLayer _pushSurface(PersistedContainerSurface surface) {
// Only attempt to update if the update is requested and the surface is in
// the live tree.
if (surface.oldLayer != null) {
assert(surface.oldLayer.runtimeType == surface.runtimeType);
assert(surface.oldLayer.isActive);
surface.oldLayer.state = PersistedSurfaceState.pendingUpdate;
}
_adoptSurface(surface);
_surfaceStack.add(surface);
return surface;
}
void _addSurface(PersistedSurface surface) {
_adoptSurface(surface);
}
void _adoptSurface(PersistedSurface surface) {
_currentSurface.appendChild(surface);
}
/// Pushes an offset operation onto the operation stack.
///
/// This is equivalent to [pushTransform] with a matrix with only translation.
///
/// See [pop] for details about the operation stack.
@override
ui.OffsetEngineLayer pushOffset(double dx, double dy,
{ui.OffsetEngineLayer oldLayer}) {
return _pushSurface(PersistedOffset(oldLayer, dx, dy));
}
/// Pushes a transform operation onto the operation stack.
///
/// The objects are transformed by the given matrix before rasterization.
///
/// See [pop] for details about the operation stack.
@override
ui.TransformEngineLayer pushTransform(Float64List matrix4,
{ui.TransformEngineLayer oldLayer}) {
if (matrix4 == null) {
throw ArgumentError('"matrix4" argument cannot be null');
}
if (matrix4.length != 16) {
throw ArgumentError('"matrix4" must have 16 entries.');
}
return _pushSurface(PersistedTransform(oldLayer, matrix4));
}
/// Pushes a rectangular clip operation onto the operation stack.
///
/// Rasterization outside the given rectangle is discarded.
///
/// 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]).
@override
ui.ClipRectEngineLayer pushClipRect(ui.Rect rect,
{ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipRectEngineLayer oldLayer}) {
assert(clipBehavior != null);
assert(clipBehavior != ui.Clip.none);
return _pushSurface(PersistedClipRect(oldLayer, rect));
}
/// Pushes a rounded-rectangular clip operation onto the operation stack.
///
/// Rasterization outside the given rounded rectangle is discarded.
///
/// See [pop] for details about the operation stack.
@override
ui.ClipRRectEngineLayer pushClipRRect(ui.RRect rrect,
{ui.Clip clipBehavior, ui.ClipRRectEngineLayer oldLayer}) {
return _pushSurface(
PersistedClipRRect(oldLayer, rrect, clipBehavior));
}
/// Pushes a path clip operation onto the operation stack.
///
/// Rasterization outside the given path is discarded.
///
/// See [pop] for details about the operation stack.
@override
ui.ClipPathEngineLayer pushClipPath(ui.Path path,
{ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipPathEngineLayer oldLayer}) {
assert(clipBehavior != null);
assert(clipBehavior != ui.Clip.none);
return _pushSurface(PersistedClipPath(oldLayer, path, clipBehavior));
}
/// 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).
///
/// See [pop] for details about the operation stack.
@override
ui.OpacityEngineLayer pushOpacity(int alpha,
{ui.Offset offset = ui.Offset.zero, ui.OpacityEngineLayer oldLayer}) {
return _pushSurface(PersistedOpacity(oldLayer, alpha, offset));
}
/// Pushes a color filter operation onto the operation stack.
///
/// The given color is applied to the objects' rasterization using the given
/// blend mode.
///
/// {@macro dart.ui.sceneBuilder.oldLayer}
///
/// {@macro dart.ui.sceneBuilder.oldLayerVsRetained}
///
/// See [pop] for details about the operation stack.
@override
ui.ColorFilterEngineLayer pushColorFilter(ui.ColorFilter filter,
{ui.ColorFilterEngineLayer oldLayer}) {
assert(filter != null);
throw UnimplementedError();
}
/// 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.
///
/// See [pop] for details about the operation stack.
@override
ui.BackdropFilterEngineLayer pushBackdropFilter(ui.ImageFilter filter,
{ui.BackdropFilterEngineLayer oldLayer}) {
return _pushSurface(PersistedBackdropFilter(oldLayer, filter));
}
/// Pushes a shader mask operation onto the operation stack.
///
/// The given shader is applied to the object's rasterization in the given
/// rectangle using the given blend mode.
///
/// See [pop] for details about the operation stack.
@override
ui.ShaderMaskEngineLayer pushShaderMask(
ui.Shader shader, ui.Rect maskRect, ui.BlendMode blendMode,
{ui.ShaderMaskEngineLayer oldLayer}) {
throw UnimplementedError();
}
/// Pushes a physical layer operation for an arbitrary shape onto the
/// operation stack.
///
/// 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.
/// [shadowColor] defines the color of the shadow if present and [color] defines the
/// color of the layer background.
///
/// See [pop] for details about the operation stack, and [Clip] for different clip modes.
@override
ui.PhysicalShapeEngineLayer pushPhysicalShape({
ui.Path path,
double elevation,
ui.Color color,
ui.Color shadowColor,
ui.Clip clipBehavior = ui.Clip.none,
ui.PhysicalShapeEngineLayer oldLayer,
}) {
return _pushSurface(PersistedPhysicalShape(
oldLayer,
path,
elevation,
color.value,
shadowColor?.value ?? 0xFF000000,
clipBehavior,
));
}
/// 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.
///
/// Therefore, when implementing a subclass of the [Layer] concept defined in
/// the rendering layer of Flutter's framework, once this is called, there's
/// no need to call [addToScene] for its children layers.
@override
void addRetained(ui.EngineLayer retainedLayer) {
final PersistedContainerSurface retainedSurface = retainedLayer;
assert(retainedSurface.isActive || retainedSurface.isReleased);
retainedSurface.tryRetain();
_adoptSurface(retainedSurface);
}
/// 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.
@override
void pop() {
assert(_surfaceStack.isNotEmpty);
_surfaceStack.removeLast();
}
/// 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.
///
/// enabledOptions is a bit field with the following bits defined:
/// - 0x01: displayRasterizerStatistics - show GPU thread frame time
/// - 0x02: visualizeRasterizerStatistics - graph GPU thread frame times
/// - 0x04: displayEngineStatistics - show UI thread frame time
/// - 0x08: visualizeEngineStatistics - graph UI thread frame times
/// 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
/// spent executing the [Window.onBeginFrame] callback. The "GPU
/// 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.
@override
void addPerformanceOverlay(int enabledOptions, ui.Rect bounds) {
_addPerformanceOverlay(
enabledOptions, bounds.left, bounds.right, bounds.top, bounds.bottom);
}
/// Whether we've already warned the user about the lack of the performance
/// overlay or not.
///
/// We use this to avoid spamming the console with redundant warning messages.
static bool _webOnlyDidWarnAboutPerformanceOverlay = false;
void _addPerformanceOverlay(int enabledOptions, double left, double right,
double top, double bottom) {
if (!_webOnlyDidWarnAboutPerformanceOverlay) {
_webOnlyDidWarnAboutPerformanceOverlay = true;
html.window.console
.warn('The performance overlay isn\'t supported on the web');
}
}
/// Adds a [Picture] to the scene.
///
/// The picture is rasterized at the given offset.
@override
void addPicture(
ui.Offset offset,
ui.Picture picture, {
bool isComplexHint = false,
bool willChangeHint = false,
}) {
int hints = 0;
if (isComplexHint) {
hints |= 1;
}
if (willChangeHint) {
hints |= 2;
}
_addSurface(
persistedPictureFactory(offset.dx, offset.dy, picture, hints));
}
/// Adds a backend texture to the scene.
///
/// The texture is scaled to the given size and rasterized at the given
/// offset.
@override
void addTexture(int textureId,
{ui.Offset offset = ui.Offset.zero,
double width = 0.0,
double height = 0.0,
bool freeze = false}) {
assert(offset != null, 'Offset argument was null');
_addTexture(offset.dx, offset.dy, width, height, textureId);
}
void _addTexture(
double dx, double dy, double width, double height, int textureId) {
// In test mode, allow this to be a no-op.
if (!ui.debugEmulateFlutterTesterEnvironment) {
throw UnimplementedError('Textures are not supported in Flutter Web');
}
}
/// Adds a platform view (e.g an iOS UIView) to the scene.
///
/// 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.
@override
void addPlatformView(
int viewId, {
ui.Offset offset = ui.Offset.zero,
double width = 0.0,
double height = 0.0,
}) {
assert(offset != null, 'Offset argument was null');
_addPlatformView(offset.dx, offset.dy, width, height, viewId);
}
void _addPlatformView(
double dx,
double dy,
double width,
double height,
int viewId,
) {
_addSurface(PersistedPlatformView(viewId, dx, dy, width, height));
}
/// (Fuchsia-only) Adds a scene rendered by another application to the scene
/// for this application.
@override
void addChildScene(
{ui.Offset offset = ui.Offset.zero,
double width = 0.0,
double height = 0.0,
ui.SceneHost sceneHost,
bool hitTestable = true}) {
_addChildScene(offset.dx, offset.dy, width, height, sceneHost, hitTestable);
}
void _addChildScene(double dx, double dy, double width, double height,
ui.SceneHost sceneHost, bool hitTestable) {
throw UnimplementedError();
}
/// 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.
@override
void setRasterizerTracingThreshold(int frameInterval) {}
/// 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).
@override
void setCheckerboardRasterCacheImages(bool checkerboard) {}
/// Sets whether the compositor should checkerboard layers that are rendered
/// to offscreen bitmaps.
///
/// This is only useful for debugging purposes.
@override
void setCheckerboardOffscreenLayers(bool checkerboard) {}
/// The scene recorded in the last frame.
///
/// This is a surface tree that holds onto the DOM elements that can be reused
/// on the next frame.
static PersistedScene _lastFrameScene;
/// Returns the computed persisted scene graph recorded in the last frame.
///
/// This is only available in debug mode. It returns `null` in profile and
/// release modes.
static PersistedScene get debugLastFrameScene {
PersistedScene result;
assert(() {
result = _lastFrameScene;
return true;
}());
return result;
}
/// Discards information about previously rendered frames, including DOM
/// elements and cached canvases.
///
/// After calling this function new canvases will be created for the
/// subsequent scene. This is useful when tests need predictable canvas
/// sizes. If the cache is not cleared, then canvases allocated in one test
/// may be reused in another test.
static void debugForgetFrameScene() {
_lastFrameScene?.rootElement?.remove();
_lastFrameScene = null;
_clipIdCounter = 0;
_recycledCanvases.clear();
}
/// Finishes building the scene.
///
/// 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].
///
/// After calling this function, the scene builder object is invalid and
/// cannot be used further.
@override
SurfaceScene build() {
_persistedScene.preroll();
if (_lastFrameScene == null) {
_persistedScene.build();
} else {
_persistedScene.update(_lastFrameScene);
}
commitScene(_persistedScene);
_lastFrameScene = _persistedScene;
return SurfaceScene(_persistedScene.rootElement);
}
/// 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.
@override
void setProperties(double width, double height, double insetTop,
double insetRight, double insetBottom, double insetLeft, bool focusable) {
throw UnimplementedError();
}
}
......@@ -111,18 +111,6 @@ void commitScene(PersistedScene scene) {
}());
}
/// Discards information about previously rendered frames, including DOM
/// elements and cached canvases.
///
/// After calling this function new canvases will be created for the
/// subsequent scene. This is useful when tests need predictable canvas
/// sizes. If the cache is not cleared, then canvases allocated in one test
/// may be reused in another test.
void debugForgetFrameScene() {
_clipIdCounter = 0;
_recycledCanvases.clear();
}
/// Surfaces that were retained this frame.
///
/// Surfaces should be added to this list directly. Instead, if a surface needs
......@@ -639,6 +627,14 @@ abstract class PersistedSurface implements ui.EngineLayer {
@protected
@mustCallSuper
void build() {
if (rootElement != null) {
try {
throw null;
} catch(_, stack) {
print('Attempted to build a $runtimeType, but it already has an HTML element ${rootElement.tagName}.');
print(stack.toString().split('\n').take(20).join('\n'));
}
}
assert(rootElement == null);
assert(isCreated);
rootElement = createElement();
......
......@@ -248,12 +248,23 @@ class EngineWindow extends ui.Window {
_brightnessMediaQueryListener = null;
}
@override
void dispose() {
_removeBrightnessMediaQueryListener();
void render(ui.Scene scene) {
if (experimentalUseSkia) {
final LayerScene layerScene = scene;
_rasterizer.draw(layerScene.layerTree);
} else {
final SurfaceScene surfaceScene = scene;
domRenderer.renderScene(surfaceScene.webOnlyRootElement);
}
}
final Rasterizer _rasterizer = experimentalUseSkia
? Rasterizer(Surface((SkCanvas canvas) {
domRenderer.renderScene(canvas.htmlCanvas);
canvas.skSurface.callMethod('flush');
}))
: null;
}
/// The window singleton.
......
......@@ -10,33 +10,15 @@ part of ui;
///
/// Scene objects can be displayed on the screen using the
/// [Window.render] method.
class Scene {
/// This class is created by the engine, and should not be instantiated
/// or extended directly.
///
/// To create a Scene object, use a [SceneBuilder].
Scene._(this.webOnlyRootElement);
final html.Element webOnlyRootElement;
abstract class Scene {
/// Creates a raster image representation of the current state of the scene.
/// This is a slow operation that is performed on a background thread.
Future<Image> toImage(int width, int height) {
if (width <= 0 || height <= 0) {
throw Exception('Invalid image dimensions.');
}
throw UnsupportedError('toImage is not supported on the Web');
// TODO(flutter_web): Implement [_toImage].
// return futurize(
// (Callback<Image> callback) => _toImage(width, height, callback));
}
// String _toImage(int width, int height, Callback<Image> callback) => null;
Future<Image> toImage(int width, int height);
/// Releases the resources used by this scene.
///
/// After calling this function, the scene is cannot be used further.
void dispose() {}
void dispose();
}
/// An opaque handle to a transform engine layer.
......@@ -120,81 +102,23 @@ abstract class PhysicalShapeEngineLayer implements EngineLayer {}
/// 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].
class SceneBuilder {
abstract class SceneBuilder {
/// Creates an empty [SceneBuilder] object.
factory SceneBuilder() {
if (engine.experimentalUseSkia) {
return engine.LayerSceneBuilder();
} else {
return SceneBuilder._();
return engine.SurfaceSceneBuilder();
}
}
SceneBuilder._() {
_surfaceStack.add(engine.PersistedScene(_lastFrameScene));
}
factory SceneBuilder.layer() = engine.LayerSceneBuilder;
final List<engine.PersistedContainerSurface> _surfaceStack =
<engine.PersistedContainerSurface>[];
/// The scene built by this scene builder.
///
/// This getter should only be called after all surfaces are built.
engine.PersistedScene get _persistedScene {
assert(() {
if (_surfaceStack.length != 1) {
final String surfacePrintout = _surfaceStack
.map<Type>((engine.PersistedContainerSurface surface) =>
surface.runtimeType)
.toList()
.join(', ');
throw Exception('Incorrect sequence of push/pop operations while '
'building scene surfaces. After building the scene the persisted '
'surface stack must contain a single element which corresponds '
'to the scene itself (_PersistedScene). All other surfaces '
'should have been popped off the stack. Found the following '
'surfaces in the stack:\n$surfacePrintout');
}
return true;
}());
return _surfaceStack.first;
}
/// The surface currently being built.
engine.PersistedContainerSurface get _currentSurface => _surfaceStack.last;
EngineLayer _pushSurface(engine.PersistedContainerSurface surface) {
// Only attempt to update if the update is requested and the surface is in
// the live tree.
if (surface.oldLayer != null) {
assert(surface.oldLayer.runtimeType == surface.runtimeType);
assert(surface.oldLayer.isActive);
surface.oldLayer.state = engine.PersistedSurfaceState.pendingUpdate;
}
_adoptSurface(surface);
_surfaceStack.add(surface);
return surface;
}
void _addSurface(engine.PersistedSurface surface) {
_adoptSurface(surface);
}
void _adoptSurface(engine.PersistedSurface surface) {
_currentSurface.appendChild(surface);
}
/// Pushes an offset operation onto the operation stack.
///
/// This is equivalent to [pushTransform] with a matrix with only translation.
///
/// See [pop] for details about the operation stack.
OffsetEngineLayer pushOffset(double dx, double dy,
{OffsetEngineLayer oldLayer}) {
return _pushSurface(engine.PersistedOffset(oldLayer, dx, dy));
}
{OffsetEngineLayer oldLayer});
/// Pushes a transform operation onto the operation stack.
///
......@@ -202,15 +126,7 @@ class SceneBuilder {
///
/// See [pop] for details about the operation stack.
TransformEngineLayer pushTransform(Float64List matrix4,
{TransformEngineLayer oldLayer}) {
if (matrix4 == null) {
throw ArgumentError('"matrix4" argument cannot be null');
}
if (matrix4.length != 16) {
throw ArgumentError('"matrix4" must have 16 entries.');
}
return _pushSurface(engine.PersistedTransform(oldLayer, matrix4));
}
{TransformEngineLayer oldLayer});
/// Pushes a rectangular clip operation onto the operation stack.
///
......@@ -219,11 +135,7 @@ 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]).
ClipRectEngineLayer pushClipRect(Rect rect,
{Clip clipBehavior = Clip.antiAlias, ClipRectEngineLayer oldLayer}) {
assert(clipBehavior != null);
assert(clipBehavior != Clip.none);
return _pushSurface(engine.PersistedClipRect(oldLayer, rect));
}
{Clip clipBehavior = Clip.antiAlias, ClipRectEngineLayer oldLayer});
/// Pushes a rounded-rectangular clip operation onto the operation stack.
///
......@@ -231,10 +143,7 @@ class SceneBuilder {
///
/// See [pop] for details about the operation stack.
ClipRRectEngineLayer pushClipRRect(RRect rrect,
{Clip clipBehavior, ClipRRectEngineLayer oldLayer}) {
return _pushSurface(
engine.PersistedClipRRect(oldLayer, rrect, clipBehavior));
}
{Clip clipBehavior, ClipRRectEngineLayer oldLayer});
/// Pushes a path clip operation onto the operation stack.
///
......@@ -242,11 +151,7 @@ class SceneBuilder {
///
/// See [pop] for details about the operation stack.
ClipPathEngineLayer pushClipPath(Path path,
{Clip clipBehavior = Clip.antiAlias, ClipPathEngineLayer oldLayer}) {
assert(clipBehavior != null);
assert(clipBehavior != Clip.none);
return _pushSurface(engine.PersistedClipPath(oldLayer, path, clipBehavior));
}
{Clip clipBehavior = Clip.antiAlias, ClipPathEngineLayer oldLayer});
/// Pushes an opacity operation onto the operation stack.
///
......@@ -257,9 +162,7 @@ class SceneBuilder {
///
/// See [pop] for details about the operation stack.
OpacityEngineLayer pushOpacity(int alpha,
{Offset offset = Offset.zero, OpacityEngineLayer oldLayer}) {
return _pushSurface(engine.PersistedOpacity(oldLayer, alpha, offset));
}
{Offset offset = Offset.zero, OpacityEngineLayer oldLayer});
/// Pushes a color filter operation onto the operation stack.
///
......@@ -272,10 +175,7 @@ class SceneBuilder {
///
/// See [pop] for details about the operation stack.
ColorFilterEngineLayer pushColorFilter(ColorFilter filter,
{ColorFilterEngineLayer oldLayer}) {
assert(filter != null);
throw UnimplementedError();
}
{ColorFilterEngineLayer oldLayer});
/// Pushes a backdrop filter operation onto the operation stack.
///
......@@ -284,9 +184,7 @@ class SceneBuilder {
///
/// See [pop] for details about the operation stack.
BackdropFilterEngineLayer pushBackdropFilter(ImageFilter filter,
{BackdropFilterEngineLayer oldLayer}) {
return _pushSurface(engine.PersistedBackdropFilter(oldLayer, filter));
}
{BackdropFilterEngineLayer oldLayer});
/// Pushes a shader mask operation onto the operation stack.
///
......@@ -296,9 +194,7 @@ class SceneBuilder {
/// See [pop] for details about the operation stack.
ShaderMaskEngineLayer pushShaderMask(
Shader shader, Rect maskRect, BlendMode blendMode,
{ShaderMaskEngineLayer oldLayer}) {
throw UnimplementedError();
}
{ShaderMaskEngineLayer oldLayer});
/// Pushes a physical layer operation for an arbitrary shape onto the
/// operation stack.
......@@ -319,16 +215,7 @@ class SceneBuilder {
Color shadowColor,
Clip clipBehavior = Clip.none,
PhysicalShapeEngineLayer oldLayer,
}) {
return _pushSurface(engine.PersistedPhysicalShape(
oldLayer,
path,
elevation,
color.value,
shadowColor?.value ?? 0xFF000000,
clipBehavior,
));
}
});
/// Add a retained engine layer subtree from previous frames.
///
......@@ -338,12 +225,7 @@ class SceneBuilder {
/// Therefore, when implementing a subclass of the [Layer] concept defined in
/// the rendering layer of Flutter's framework, once this is called, there's
/// no need to call [addToScene] for its children layers.
void addRetained(EngineLayer retainedLayer) {
final engine.PersistedContainerSurface retainedSurface = retainedLayer;
assert(retainedSurface.isActive || retainedSurface.isReleased);
retainedSurface.tryRetain();
_adoptSurface(retainedSurface);
}
void addRetained(EngineLayer retainedLayer);
/// Ends the effect of the most recently pushed operation.
///
......@@ -351,10 +233,7 @@ class SceneBuilder {
/// 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.
void pop() {
assert(_surfaceStack.isNotEmpty);
_surfaceStack.removeLast();
}
void pop();
/// Adds an object to the scene that displays performance statistics.
///
......@@ -379,25 +258,7 @@ class SceneBuilder {
///
/// See also the [PerformanceOverlayOption] enum in the rendering library.
/// for more details.
void addPerformanceOverlay(int enabledOptions, Rect bounds) {
_addPerformanceOverlay(
enabledOptions, bounds.left, bounds.right, bounds.top, bounds.bottom);
}
/// Whether we've already warned the user about the lack of the performance
/// overlay or not.
///
/// We use this to avoid spamming the console with redundant warning messages.
static bool _webOnlyDidWarnAboutPerformanceOverlay = false;
void _addPerformanceOverlay(int enabledOptions, double left, double right,
double top, double bottom) {
if (!_webOnlyDidWarnAboutPerformanceOverlay) {
_webOnlyDidWarnAboutPerformanceOverlay = true;
html.window.console
.warn('The performance overlay isn\'t supported on the web');
}
}
void addPerformanceOverlay(int enabledOptions, Rect bounds);
/// Adds a [Picture] to the scene.
///
......@@ -407,17 +268,7 @@ class SceneBuilder {
Picture picture, {
bool isComplexHint = false,
bool willChangeHint = false,
}) {
int hints = 0;
if (isComplexHint) {
hints |= 1;
}
if (willChangeHint) {
hints |= 2;
}
_addSurface(
engine.persistedPictureFactory(offset.dx, offset.dy, picture, hints));
}
});
/// Adds a backend texture to the scene.
///
......@@ -427,18 +278,7 @@ class SceneBuilder {
{Offset offset = Offset.zero,
double width = 0.0,
double height = 0.0,
bool freeze = false}) {
assert(offset != null, 'Offset argument was null');
_addTexture(offset.dx, offset.dy, width, height, textureId);
}
void _addTexture(
double dx, double dy, double width, double height, int textureId) {
// In test mode, allow this to be a no-op.
if (!debugEmulateFlutterTesterEnvironment) {
throw UnimplementedError('Textures are not supported in Flutter Web');
}
}
bool freeze = false});
/// Adds a platform view (e.g an iOS UIView) to the scene.
///
......@@ -461,20 +301,7 @@ class SceneBuilder {
Offset offset = Offset.zero,
double width = 0.0,
double height = 0.0,
}) {
assert(offset != null, 'Offset argument was null');
_addPlatformView(offset.dx, offset.dy, width, height, viewId);
}
void _addPlatformView(
double dx,
double dy,
double width,
double height,
int viewId,
) {
_addSurface(engine.PersistedPlatformView(viewId, dx, dy, width, height));
}
});
/// (Fuchsia-only) Adds a scene rendered by another application to the scene
/// for this application.
......@@ -483,14 +310,7 @@ class SceneBuilder {
double width = 0.0,
double height = 0.0,
SceneHost sceneHost,
bool hitTestable = true}) {
_addChildScene(offset.dx, offset.dy, width, height, sceneHost, hitTestable);
}
void _addChildScene(double dx, double dy, double width, double height,
SceneHost sceneHost, bool hitTestable) {
throw UnimplementedError();
}
bool hitTestable = true});
/// Sets a threshold after which additional debugging information should be
/// recorded.
......@@ -499,7 +319,7 @@ class SceneBuilder {
/// 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.
void setRasterizerTracingThreshold(int frameInterval) {}
void setRasterizerTracingThreshold(int frameInterval);
/// Sets whether the raster cache should checkerboard cached entries. This is
/// only useful for debugging purposes.
......@@ -517,45 +337,13 @@ class SceneBuilder {
///
/// 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).
void setCheckerboardRasterCacheImages(bool checkerboard) {}
void setCheckerboardRasterCacheImages(bool checkerboard);
/// Sets whether the compositor should checkerboard layers that are rendered
/// to offscreen bitmaps.
///
/// This is only useful for debugging purposes.
void setCheckerboardOffscreenLayers(bool checkerboard) {}
/// The scene recorded in the last frame.
///
/// This is a surface tree that holds onto the DOM elements that can be reused
/// on the next frame.
static engine.PersistedScene _lastFrameScene;
/// Returns the computed persisted scene graph recorded in the last frame.
///
/// This is only available in debug mode. It returns `null` in profile and
/// release modes.
static engine.PersistedScene get debugLastFrameScene {
engine.PersistedScene result;
assert(() {
result = _lastFrameScene;
return true;
}());
return result;
}
/// Discards information about previously rendered frames, including DOM
/// elements and cached canvases.
///
/// After calling this function new canvases will be created for the
/// subsequent scene. This is useful when tests need predictable canvas
/// sizes. If the cache is not cleared, then canvases allocated in one test
/// may be reused in another test.
static void debugForgetFrameScene() {
_lastFrameScene?.rootElement?.remove();
_lastFrameScene = null;
engine.debugForgetFrameScene();
}
void setCheckerboardOffscreenLayers(bool checkerboard);
/// Finishes building the scene.
///
......@@ -565,24 +353,12 @@ class SceneBuilder {
///
/// After calling this function, the scene builder object is invalid and
/// cannot be used further.
Scene build() {
_persistedScene.preroll();
if (_lastFrameScene == null) {
_persistedScene.build();
} else {
_persistedScene.update(_lastFrameScene);
}
engine.commitScene(_persistedScene);
_lastFrameScene = _persistedScene;
return Scene._(_persistedScene.rootElement);
}
Scene build();
/// 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(double width, double height, double insetTop,
double insetRight, double insetBottom, double insetLeft, bool focusable) {
throw UnimplementedError();
}
double insetRight, double insetBottom, double insetLeft, bool focusable);
}
/// A handle for the framework to hold and retain an engine layer across frames.
......
......@@ -974,21 +974,7 @@ abstract class Window {
/// scheduling of frames.
/// * [RendererBinding], the Flutter framework class which manages layout and
/// painting.
void render(Scene scene) {
if (engine.experimentalUseSkia) {
final engine.LayerScene layerScene = scene;
_rasterizer.draw(layerScene.layerTree);
} else {
engine.domRenderer.renderScene(scene.webOnlyRootElement);
}
}
final engine.Rasterizer _rasterizer = engine.experimentalUseSkia
? engine.Rasterizer(engine.Surface((engine.SkCanvas canvas) {
engine.domRenderer.renderScene(canvas.htmlCanvas);
canvas.skSurface.callMethod('flush');
}))
: null;
void render(Scene scene);
String get initialLifecycleState => _initialLifecycleState;
......
......@@ -185,7 +185,7 @@ void testLayerLifeCycle(
TestLayerBuilder layerBuilder, ExpectedHtmlGetter expectedHtmlGetter) {
// Force scene builder to start from scratch. This guarantees that the first
// scene starts from the "build" phase.
SceneBuilder.debugForgetFrameScene();
SurfaceSceneBuilder.debugForgetFrameScene();
// Build: builds a brand new layer.
SceneBuilder sceneBuilder = SceneBuilder();
......
......@@ -12,7 +12,7 @@ import 'package:test/test.dart';
void main() {
group('Surface', () {
setUp(() {
SceneBuilder.debugForgetFrameScene();
SurfaceSceneBuilder.debugForgetFrameScene();
});
test('is created', () {
......
......@@ -18,14 +18,14 @@ void main() async {
debugShowClipLayers = true;
setUp(() {
SceneBuilder.debugForgetFrameScene();
SurfaceSceneBuilder.debugForgetFrameScene();
for (html.Node scene in html.document.querySelectorAll('flt-scene')) {
scene.remove();
}
});
test('pushClipRect', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRect(
const Rect.fromLTRB(10, 10, 60, 60),
);
......@@ -38,7 +38,7 @@ void main() async {
}, timeout: const Timeout(Duration(seconds: 10)));
test('pushClipRect with offset and transform', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(0, 60);
builder.pushTransform(
......@@ -58,7 +58,7 @@ void main() async {
}, timeout: const Timeout(Duration(seconds: 10)));
test('pushClipRRect', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRRect(
RRect.fromLTRBR(10, 10, 60, 60, const Radius.circular(5)),
);
......@@ -71,7 +71,7 @@ void main() async {
}, timeout: const Timeout(Duration(seconds: 10)));
test('pushPhysicalShape', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushPhysicalShape(
path: Path()..addRect(const Rect.fromLTRB(10, 10, 60, 60)),
clipBehavior: Clip.hardEdge,
......@@ -204,7 +204,7 @@ void _testCullRectComputation() {
// Draw a picture inside a layer clip but fill all available space inside it.
// Verify that the cull rect is equal to the layer clip.
test('fills layer clip rect', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRect(
const Rect.fromLTWH(10, 10, 60, 60),
);
......@@ -232,7 +232,7 @@ void _testCullRectComputation() {
// paint bounds overflow the layer clip. Verify that the cull rect is the
// intersection between the layer clip and paint bounds.
test('intersects layer clip rect and paint bounds', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRect(
const Rect.fromLTWH(10, 10, 60, 60),
);
......@@ -260,7 +260,7 @@ void _testCullRectComputation() {
// an offset layer. Verify that the cull rect is the intersection between the
// layer clip and the offset paint bounds.
test('offsets picture inside layer clip rect', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushClipRect(
const Rect.fromLTWH(10, 10, 60, 60),
);
......@@ -320,7 +320,7 @@ void _testCullRectComputation() {
// Draw a picture inside a rotated clip. Verify that the cull rect is big
// enough to fit the rotated clip.
test('rotates clip and the picture', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
builder.pushOffset(80, 50);
builder.pushTransform(
......@@ -364,7 +364,7 @@ void _testCullRectComputation() {
}, timeout: const Timeout(Duration(seconds: 10)));
test('pushClipPath', () async {
final SceneBuilder builder = SceneBuilder();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
final Path path = Path();
path..addRect(const Rect.fromLTRB(10, 10, 60, 60));
builder.pushClipPath(
......@@ -381,9 +381,10 @@ void _testCullRectComputation() {
// Draw a picture inside a rotated clip. Verify that the cull rect is big
// enough to fit the rotated clip.
test('clips correctly when using 3d transforms', () async {
final SceneBuilder builder = SceneBuilder();
final double screenWidth = html.window.innerWidth.toDouble();
final double screenHeight = html.window.innerHeight.toDouble();
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
// TODO(yjbanov): see the TODO below.
// final double screenWidth = html.window.innerWidth.toDouble();
// final double screenHeight = html.window.innerHeight.toDouble();
final Matrix4 scaleTransform = Matrix4.identity().scaled(0.5, 0.2);
builder.pushTransform(
......
......@@ -23,7 +23,7 @@ import 'package:ui/src/engine.dart';
///
/// Surfaces are returned in a depth-first order.
Iterable<PersistedSurface> enumerateSurfaces([PersistedSurface root]) {
root ??= SceneBuilder.debugLastFrameScene;
root ??= SurfaceSceneBuilder.debugLastFrameScene;
final List<PersistedSurface> surfaces = <PersistedSurface>[root];
root.visitChildren((PersistedSurface surface) {
......@@ -37,7 +37,7 @@ Iterable<PersistedSurface> enumerateSurfaces([PersistedSurface root]) {
///
/// If [root] is `null` returns all pictures from the last rendered scene.
Iterable<PersistedPicture> enumeratePictures([PersistedSurface root]) {
root ??= SceneBuilder.debugLastFrameScene;
root ??= SurfaceSceneBuilder.debugLastFrameScene;
return enumerateSurfaces(root).whereType<PersistedPicture>();
}
......@@ -45,7 +45,7 @@ Iterable<PersistedPicture> enumeratePictures([PersistedSurface root]) {
///
/// If [root] is `null` returns all pictures from the last rendered scene.
Iterable<PersistedOffset> enumerateOffsets([PersistedSurface root]) {
root ??= SceneBuilder.debugLastFrameScene;
root ??= SurfaceSceneBuilder.debugLastFrameScene;
return enumerateSurfaces(root).whereType<PersistedOffset>();
}
......@@ -459,7 +459,7 @@ String get currentHtml {
class SceneTester {
SceneTester(this.scene);
final Scene scene;
final SurfaceScene scene;
void expectSceneHtml(String expectedHtml) {
expectHtml(scene.webOnlyRootElement, expectedHtml,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册