diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index f20ecff7349c6..d24b262275905 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -814,11 +814,14 @@ class SceneBuilder extends NativeFieldWrapperClass1 { /// synchronized with the UIView frames adding additional performance overhead. /// /// The `offset` argument is not used for iOS and Android. + /// The `zIndex` argument is only used by the CanvasKit renderer. Negative values render behind the + /// canvas and will not require additional WebGL contexts. void addPlatformView( int viewId, { Offset offset = Offset.zero, double width = 0.0, double height = 0.0, + int? zIndex, }) { _addPlatformView(offset.dx, offset.dy, width, height, viewId); } diff --git a/lib/web_ui/lib/compositing.dart b/lib/web_ui/lib/compositing.dart index d3f0acddd6797..9b0ac872b9f64 100644 --- a/lib/web_ui/lib/compositing.dart +++ b/lib/web_ui/lib/compositing.dart @@ -120,6 +120,7 @@ abstract class SceneBuilder { Offset offset = Offset.zero, double width = 0.0, double height = 0.0, + int zIndex, }); void setRasterizerTracingThreshold(int frameInterval); void setCheckerboardRasterCacheImages(bool checkerboard); diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index e2d5f196348f9..8a18b44f83cbe 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -15,12 +15,14 @@ import '../vector_math.dart'; import '../window.dart'; import 'canvas.dart'; import 'embedded_views_diff.dart'; +import 'layer_scene_builder.dart'; import 'path.dart'; import 'picture_recorder.dart'; import 'renderer.dart'; import 'surface.dart'; import 'surface_factory.dart'; + /// This composites HTML views into the [ui.Scene]. class HtmlViewEmbedder { HtmlViewEmbedder._(); @@ -123,24 +125,27 @@ class HtmlViewEmbedder { } void prerollCompositeEmbeddedView(int viewId, EmbeddedViewParams params) { - final bool hasAvailableOverlay = - _context.pictureRecordersCreatedDuringPreroll.length < - SurfaceFactory.instance.maximumOverlays; - if (!hasAvailableOverlay && !_warnedAboutTooManySurfaces) { - _warnedAboutTooManySurfaces = true; - printWarning('Flutter was unable to create enough overlay surfaces. ' - 'This is usually caused by too many platform views being ' - 'displayed at once. ' - 'You may experience incorrect rendering.'); - } - // We need an overlay for each visible platform view. Invisible platform - // views will be grouped with (at most) one visible platform view later. - final bool needNewOverlay = platformViewManager.isVisible(viewId); - if (needNewOverlay && hasAvailableOverlay) { - final CkPictureRecorder pictureRecorder = CkPictureRecorder(); - pictureRecorder.beginRecording(ui.Offset.zero & _frameSize); - pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000)); - _context.pictureRecordersCreatedDuringPreroll.add(pictureRecorder); + if (params.zIndex >= 0) { + + final bool hasAvailableOverlay = + _context.pictureRecordersCreatedDuringPreroll.length < + SurfaceFactory.instance.maximumOverlays; + if (!hasAvailableOverlay && !_warnedAboutTooManySurfaces) { + _warnedAboutTooManySurfaces = true; + printWarning('Flutter was unable to create enough overlay surfaces. ' + 'This is usually caused by too many platform views being ' + 'displayed at once. ' + 'You may experience incorrect rendering.'); + } + // We need an overlay for each visible platform view. Invisible platform + // views will be grouped with (at most) one visible platform view later. + final bool needNewOverlay = platformViewManager.isVisible(viewId); + if (needNewOverlay && hasAvailableOverlay) { + final CkPictureRecorder pictureRecorder = CkPictureRecorder(); + pictureRecorder.beginRecording(ui.Offset.zero & _frameSize); + pictureRecorder.recordingCanvas!.clear(const ui.Color(0x00000000)); + _context.pictureRecordersCreatedDuringPreroll.add(pictureRecorder); + } } // Do nothing if the params didn't change. @@ -167,14 +172,18 @@ class HtmlViewEmbedder { if (platformViewManager.isVisible(viewId)) { _context.visibleViewCount++; } - // We need a new overlay if this is a visible view. - final bool needNewOverlay = platformViewManager.isVisible(viewId); + CkPictureRecorder? recorderToUseForRendering; - if (needNewOverlay) { - if (overlayIndex < _context.pictureRecordersCreatedDuringPreroll.length) { - recorderToUseForRendering = - _context.pictureRecordersCreatedDuringPreroll[overlayIndex]; - _context.pictureRecorders.add(recorderToUseForRendering); + if((_currentCompositionParams[viewId]?.zIndex ?? defaultPlatformViewLayerZIndex) >= 0) { + // We need a new overlay if this is a visible view. + final bool needNewOverlay = platformViewManager.isVisible(viewId); + + if (needNewOverlay) { + if (overlayIndex < _context.pictureRecordersCreatedDuringPreroll.length) { + recorderToUseForRendering = + _context.pictureRecordersCreatedDuringPreroll[overlayIndex]; + _context.pictureRecorders.add(recorderToUseForRendering); + } } } @@ -215,6 +224,10 @@ class HtmlViewEmbedder { root: newPlatformViewRoot, clipCount: currentClippingCount, ); + + if(params.zIndex != 0) { + newPlatformViewRoot.style.zIndex = params.zIndex.toString(); + } } // Apply mutators to the slot @@ -646,6 +659,10 @@ class HtmlViewEmbedder { for (int i = 0; i < views.length; i++) { final int view = views[i]; + if((_currentCompositionParams[view]?.zIndex ?? defaultPlatformViewLayerZIndex) < 0) { + // If view will be rendered behind canvas we don't need an overlay + continue; + } if (platformViewManager.isInvisible(view)) { // We add as many invisible views as we find to the current group. currentGroup.add(view); @@ -785,12 +802,13 @@ class ViewClipChain { /// The parameters passed to the view embedder. class EmbeddedViewParams { - EmbeddedViewParams(this.offset, this.size, MutatorsStack mutators) + EmbeddedViewParams(this.offset, this.size, MutatorsStack mutators, this.zIndex) : mutators = MutatorsStack._copy(mutators); final ui.Offset offset; final ui.Size size; final MutatorsStack mutators; + final int zIndex; @override bool operator ==(Object other) { @@ -800,11 +818,12 @@ class EmbeddedViewParams { return other is EmbeddedViewParams && other.offset == offset && other.size == size && - other.mutators == mutators; + other.mutators == mutators && + other.zIndex == zIndex; } @override - int get hashCode => Object.hash(offset, size, mutators); + int get hashCode => Object.hash(offset, size, mutators, zIndex); } enum MutatorType { diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index 640b3712e36ab..56c303baacddb 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -498,7 +498,8 @@ class PhysicalShapeEngineLayer extends ContainerLayer final double _elevation; final ui.Color _color; - final ui.Color? _shadowColor; // ignore: use_late_for_private_fields_and_variables + final ui.Color? + _shadowColor; // ignore: use_late_for_private_fields_and_variables final CkPath _path; final ui.Clip _clipBehavior; @@ -583,12 +584,13 @@ class ColorFilterEngineLayer extends ContainerLayer /// A layer which renders a platform view (an HTML element in this case). class PlatformViewLayer extends Layer { - PlatformViewLayer(this.viewId, this.offset, this.width, this.height); + PlatformViewLayer(this.viewId, this.offset, this.width, this.height, this.zIndex); final int viewId; final ui.Offset offset; final double width; final double height; + final int zIndex; @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { @@ -602,6 +604,7 @@ class PlatformViewLayer extends Layer { offset, ui.Size(width, height), prerollContext.mutatorsStack, + zIndex, ), ); } @@ -613,5 +616,9 @@ class PlatformViewLayer extends Layer { if (canvas != null) { paintContext.leafNodesCanvas = canvas; } + + if (zIndex < 0) { + paintContext.leafNodesCanvas?.clear(const ui.Color.fromARGB(0, 0, 0, 0)); + } } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart index e1f71752e63c1..13548e4343e31 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart @@ -12,6 +12,8 @@ import 'layer_tree.dart'; import 'path.dart'; import 'picture.dart'; +const int defaultPlatformViewLayerZIndex = -1; + class LayerScene implements ui.Scene { LayerScene(RootLayer rootLayer) : layerTree = LayerTree(rootLayer); @@ -82,8 +84,9 @@ class LayerSceneBuilder implements ui.SceneBuilder { double width = 0.0, double height = 0.0, Object? webOnlyPaintedBy, + int? zIndex, }) { - currentLayer.add(PlatformViewLayer(viewId, offset, width, height)); + currentLayer.add(PlatformViewLayer(viewId, offset, width, height, zIndex ?? defaultPlatformViewLayerZIndex)); } @override diff --git a/lib/web_ui/lib/src/engine/html/scene_builder.dart b/lib/web_ui/lib/src/engine/html/scene_builder.dart index 40270dfaf6ed3..9fae484eb8ebd 100644 --- a/lib/web_ui/lib/src/engine/html/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/html/scene_builder.dart @@ -441,6 +441,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.Offset offset = ui.Offset.zero, double width = 0.0, double height = 0.0, + int? zIndex }) { _addPlatformView(offset.dx, offset.dy, width, height, viewId); } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart index e2cc62508bf03..2f1fc5e3f4a21 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/scene_builder.dart @@ -59,7 +59,8 @@ class SkwasmSceneBuilder implements ui.SceneBuilder { int viewId, { ui.Offset offset = ui.Offset.zero, double width = 0.0, - double height = 0.0 + double height = 0.0, + int? zIndex }) { throw UnimplementedError('Platform view not yet implemented with skwasm renderer.'); }