@@ -18,9 +18,9 @@ import 'embedded_views_diff.dart';
1818import 'path.dart' ;
1919import 'picture.dart' ;
2020import 'picture_recorder.dart' ;
21+ import 'render_canvas.dart' ;
22+ import 'render_canvas_factory.dart' ;
2123import 'renderer.dart' ;
22- import 'surface.dart' ;
23- import 'surface_factory.dart' ;
2424
2525/// This composites HTML views into the [ui.Scene] .
2626class HtmlViewEmbedder {
@@ -31,42 +31,6 @@ class HtmlViewEmbedder {
3131
3232 DomElement get skiaSceneHost => CanvasKitRenderer .instance.sceneHost! ;
3333
34- /// Force the view embedder to disable overlays.
35- ///
36- /// This should never be used outside of tests.
37- static set debugDisableOverlays (bool disable) {
38- // Short circuit if the value is the same as what we already have.
39- if (disable == _debugOverlaysDisabled) {
40- return ;
41- }
42- _debugOverlaysDisabled = disable;
43- final SurfaceFactory ? instance = SurfaceFactory .debugUninitializedInstance;
44- if (instance != null ) {
45- instance.releaseSurfaces ();
46- instance.removeSurfacesFromDom ();
47- instance.debugClear ();
48- }
49- if (disable) {
50- // If we are disabling overlays then get the current [SurfaceFactory]
51- // instance, clear it, and overwrite it with a new instance with only
52- // one surface for the base surface.
53- SurfaceFactory .debugSetInstance (SurfaceFactory (1 ));
54- } else {
55- // If we are re-enabling overlays then replace the current
56- // [SurfaceFactory]instance with one with
57- // [configuration.canvasKitMaximumSurfaces] overlays.
58- SurfaceFactory .debugSetInstance (
59- SurfaceFactory (configuration.canvasKitMaximumSurfaces));
60- }
61- }
62-
63- static bool _debugOverlaysDisabled = false ;
64-
65- /// Whether or not we have issues a warning to the user about having too many
66- /// surfaces on screen at once. This is so we only warn once, instead of every
67- /// frame.
68- bool _warnedAboutTooManySurfaces = false ;
69-
7034 /// The context for the current frame.
7135 EmbedderFrameContext _context = EmbedderFrameContext ();
7236
@@ -86,10 +50,12 @@ class HtmlViewEmbedder {
8650 /// * The number of clipping elements used last time the view was composited.
8751 final Map <int , ViewClipChain > _viewClipChains = < int , ViewClipChain > {};
8852
89- /// Surfaces used to draw on top of platform views, keyed by platform view ID.
90- ///
91- /// These surfaces are cached in the [OverlayCache] and reused.
92- final Map <int , Surface > _overlays = < int , Surface > {};
53+ /// The maximum number of overlays to create. Too many overlays can cause a
54+ /// performance burden.
55+ static const int maximumOverlays = 7 ;
56+
57+ /// Canvases used to draw on top of platform views, keyed by platform view ID.
58+ final Map <int , RenderCanvas > _overlays = < int , RenderCanvas > {};
9359
9460 /// The views that need to be recomposited into the scene on the next frame.
9561 final Set <int > _viewsToRecomposite = < int > {};
@@ -100,6 +66,9 @@ class HtmlViewEmbedder {
10066 /// The most recent composition order.
10167 final List <int > _activeCompositionOrder = < int > [];
10268
69+ /// The most recent overlay groups.
70+ List <OverlayGroup > _activeOverlayGroups = < OverlayGroup > [];
71+
10372 /// The size of the frame, in physical pixels.
10473 ui.Size _frameSize = ui.window.physicalSize;
10574
@@ -124,20 +93,10 @@ class HtmlViewEmbedder {
12493 }
12594
12695 void prerollCompositeEmbeddedView (int viewId, EmbeddedViewParams params) {
127- final bool hasAvailableOverlay =
128- _context.pictureRecordersCreatedDuringPreroll.length <
129- SurfaceFactory .instance.maximumOverlays;
130- if (! hasAvailableOverlay && ! _warnedAboutTooManySurfaces) {
131- _warnedAboutTooManySurfaces = true ;
132- printWarning ('Flutter was unable to create enough overlay surfaces. '
133- 'This is usually caused by too many platform views being '
134- 'displayed at once. '
135- 'You may experience incorrect rendering.' );
136- }
13796 // We need an overlay for each visible platform view. Invisible platform
13897 // views will be grouped with (at most) one visible platform view later.
13998 final bool needNewOverlay = PlatformViewManager .instance.isVisible (viewId);
140- if (needNewOverlay && hasAvailableOverlay ) {
99+ if (needNewOverlay) {
141100 final CkPictureRecorder pictureRecorder = CkPictureRecorder ();
142101 pictureRecorder.beginRecording (ui.Offset .zero & _frameSize);
143102 _context.pictureRecordersCreatedDuringPreroll.add (pictureRecorder);
@@ -409,26 +368,27 @@ class HtmlViewEmbedder {
409368 (_activeCompositionOrder.isEmpty || _compositionOrder.isEmpty)
410369 ? null
411370 : diffViewList (_activeCompositionOrder, _compositionOrder);
412- _updateOverlays (diffResult);
371+ final List <OverlayGroup >? overlayGroups = _updateOverlays (diffResult);
372+ if (overlayGroups != null ) {
373+ _activeOverlayGroups = overlayGroups;
374+ }
413375 assert (
414- _context.pictureRecorders.length = = _overlays.length,
415- 'There should be the same number of picture recorders '
376+ _context.pictureRecorders.length > = _overlays.length,
377+ 'There should be at least as many picture recorders '
416378 '(${_context .pictureRecorders .length }) as overlays (${_overlays .length }).' ,
417379 );
418- int pictureRecorderIndex = 0 ;
419380
420- for (int i = 0 ; i < _compositionOrder.length; i++ ) {
421- final int viewId = _compositionOrder[i];
422- if (_overlays[viewId] != null ) {
423- final SurfaceFrame frame = _overlays[viewId]! .acquireFrame (_frameSize);
424- final CkCanvas canvas = frame.skiaCanvas;
425- final CkPicture ckPicture =
426- _context.pictureRecorders[pictureRecorderIndex].endRecording ();
427- canvas.clear (const ui.Color (0x00000000 ));
428- canvas.drawPicture (ckPicture);
381+ int pictureRecorderIndex = 0 ;
382+ for (final OverlayGroup overlayGroup in _activeOverlayGroups) {
383+ final RenderCanvas overlay = _overlays[overlayGroup.last]! ;
384+ final List <CkPicture > pictures = < CkPicture > [];
385+ for (int i = 0 ; i < overlayGroup.visibleCount; i++ ) {
386+ pictures.add (
387+ _context.pictureRecorders[pictureRecorderIndex].endRecording ());
429388 pictureRecorderIndex++ ;
430- frame.submit ();
431389 }
390+ CanvasKitRenderer .instance.rasterizer
391+ .rasterizeToCanvas (overlay, pictures);
432392 }
433393 for (final CkPictureRecorder recorder
434394 in _context.pictureRecordersCreatedDuringPreroll) {
@@ -481,15 +441,15 @@ class HtmlViewEmbedder {
481441 if (diffResult.addToBeginning) {
482442 final DomElement platformViewRoot = _viewClipChains[viewId]! .root;
483443 skiaSceneHost.insertBefore (platformViewRoot, elementToInsertBefore);
484- final Surface ? overlay = _overlays[viewId];
444+ final RenderCanvas ? overlay = _overlays[viewId];
485445 if (overlay != null ) {
486446 skiaSceneHost.insertBefore (
487447 overlay.htmlElement, elementToInsertBefore);
488448 }
489449 } else {
490450 final DomElement platformViewRoot = _viewClipChains[viewId]! .root;
491451 skiaSceneHost.append (platformViewRoot);
492- final Surface ? overlay = _overlays[viewId];
452+ final RenderCanvas ? overlay = _overlays[viewId];
493453 if (overlay != null ) {
494454 skiaSceneHost.append (overlay.htmlElement);
495455 }
@@ -514,7 +474,7 @@ class HtmlViewEmbedder {
514474 }
515475 }
516476 } else {
517- SurfaceFactory .instance.removeSurfacesFromDom ();
477+ RenderCanvasFactory .instance.removeSurfacesFromDom ();
518478 for (int i = 0 ; i < _compositionOrder.length; i++ ) {
519479 final int viewId = _compositionOrder[i];
520480
@@ -532,7 +492,7 @@ class HtmlViewEmbedder {
532492 }
533493
534494 final DomElement platformViewRoot = _viewClipChains[viewId]! .root;
535- final Surface ? overlay = _overlays[viewId];
495+ final RenderCanvas ? overlay = _overlays[viewId];
536496 skiaSceneHost.append (platformViewRoot);
537497 if (overlay != null ) {
538498 skiaSceneHost.append (overlay.htmlElement);
@@ -568,8 +528,8 @@ class HtmlViewEmbedder {
568528
569529 void _releaseOverlay (int viewId) {
570530 if (_overlays[viewId] != null ) {
571- final Surface overlay = _overlays[viewId]! ;
572- SurfaceFactory .instance.releaseSurface (overlay);
531+ final RenderCanvas overlay = _overlays[viewId]! ;
532+ RenderCanvasFactory .instance.releaseCanvas (overlay);
573533 _overlays.remove (viewId);
574534 }
575535 }
@@ -591,13 +551,13 @@ class HtmlViewEmbedder {
591551 // composition order of the current and previous frame, respectively.
592552 //
593553 // TODO(hterkelsen): Test this more thoroughly.
594- void _updateOverlays (ViewListDiffResult ? diffResult) {
554+ List < OverlayGroup > ? _updateOverlays (ViewListDiffResult ? diffResult) {
595555 if (diffResult != null &&
596556 diffResult.viewsToAdd.isEmpty &&
597557 diffResult.viewsToRemove.isEmpty) {
598558 // The composition order has not changed, continue using the assigned
599559 // overlays.
600- return ;
560+ return null ;
601561 }
602562 // Group platform views from their composition order.
603563 // Each group contains one visible view, and any number of invisible views
@@ -606,17 +566,10 @@ class HtmlViewEmbedder {
606566 getOverlayGroups (_compositionOrder);
607567 final List <int > viewsNeedingOverlays =
608568 overlayGroups.map ((OverlayGroup group) => group.last).toList ();
609- // If there were more visible views than overlays, then the last group
610- // doesn't have an overlay.
611- if (viewsNeedingOverlays.length > SurfaceFactory .instance.maximumOverlays) {
612- assert (viewsNeedingOverlays.length ==
613- SurfaceFactory .instance.maximumOverlays + 1 );
614- viewsNeedingOverlays.removeLast ();
615- }
616569 if (diffResult == null ) {
617570 // Everything is going to be explicitly recomposited anyway. Release all
618571 // the surfaces and assign an overlay to all the surfaces needing one.
619- SurfaceFactory .instance.releaseSurfaces ();
572+ RenderCanvasFactory .instance.releaseCanvases ();
620573 _overlays.clear ();
621574 viewsNeedingOverlays.forEach (_initializeOverlay);
622575 } else {
@@ -635,6 +588,7 @@ class HtmlViewEmbedder {
635588 .forEach (_initializeOverlay);
636589 }
637590 assert (_overlays.length == viewsNeedingOverlays.length);
591+ return overlayGroups;
638592 }
639593
640594 // Group the platform views into "overlay groups". These are sublists
@@ -646,12 +600,8 @@ class HtmlViewEmbedder {
646600 // be assigned an overlay are grouped together and will be rendered on top of
647601 // the rest of the scene.
648602 List <OverlayGroup > getOverlayGroups (List <int > views) {
649- final int maxOverlays = SurfaceFactory .instance.maximumOverlays;
650- if (maxOverlays == 0 ) {
651- return const < OverlayGroup > [];
652- }
653603 final List <OverlayGroup > result = < OverlayGroup > [];
654- OverlayGroup currentGroup = OverlayGroup (< int > [] );
604+ OverlayGroup currentGroup = OverlayGroup ();
655605
656606 for (int i = 0 ; i < views.length; i++ ) {
657607 final int view = views[i];
@@ -660,8 +610,10 @@ class HtmlViewEmbedder {
660610 currentGroup.add (view);
661611 } else {
662612 // `view` is visible.
663- if (! currentGroup.hasVisibleView) {
664- // If `view` is the first visible one of the group, add it.
613+ if (! currentGroup.hasVisibleView ||
614+ result.length + 1 >= HtmlViewEmbedder .maximumOverlays) {
615+ // If `view` is the first visible one of the group or we've reached
616+ // the maximum number of overlays, add it.
665617 currentGroup.add (view, visible: true );
666618 } else {
667619 // There's already a visible `view` in `currentGroup`, so a new
@@ -671,17 +623,8 @@ class HtmlViewEmbedder {
671623 // We only care about groups that have one visible view.
672624 result.add (currentGroup);
673625 }
674- // If there are overlays still available.
675- if (result.length < maxOverlays) {
676- // Create a new group, starting with `view`.
677- currentGroup = OverlayGroup (< int > [view], visible: true );
678- } else {
679- // Add the rest of the views to a final group that will be rendered
680- // on top of the scene.
681- currentGroup = OverlayGroup (views.sublist (i), visible: true );
682- // And break out of the loop!
683- break ;
684- }
626+ currentGroup = OverlayGroup ();
627+ currentGroup.add (view, visible: true );
685628 }
686629 }
687630 }
@@ -696,8 +639,7 @@ class HtmlViewEmbedder {
696639 assert (! _overlays.containsKey (viewId));
697640
698641 // Try reusing a cached overlay created for another platform view.
699- final Surface overlay = SurfaceFactory .instance.getSurface ()! ;
700- overlay.createOrUpdateSurface (_frameSize);
642+ final RenderCanvas overlay = RenderCanvasFactory .instance.getCanvas ();
701643 _overlays[viewId] = overlay;
702644 }
703645
@@ -742,29 +684,30 @@ class HtmlViewEmbedder {
742684/// Every overlay group is a list containing a visible view preceded or followed
743685/// by zero or more invisible views.
744686class OverlayGroup {
745- /// Constructor
746- OverlayGroup (
747- List <int > viewGroup, {
748- bool visible = false ,
749- }) : _group = viewGroup,
750- _containsVisibleView = visible;
687+ OverlayGroup () : _group = < int > [];
751688
752689 // The internal list of ints.
753690 final List <int > _group;
754- // A boolean flag to mark if any visible view has been added to the list.
755- bool _containsVisibleView;
691+
692+ /// The number of visible views in this group.
693+ int _visibleCount = 0 ;
756694
757695 /// Add a [view] (maybe [visible] ) to this group.
758696 void add (int view, {bool visible = false }) {
759697 _group.add (view);
760- _containsVisibleView | = visible;
698+ if (visible) {
699+ _visibleCount++ ;
700+ }
761701 }
762702
763703 /// Get the "last" view added to this group.
764704 int get last => _group.last;
765705
766706 /// Returns true if this group contains any visible view.
767- bool get hasVisibleView => _group.isNotEmpty && _containsVisibleView;
707+ bool get hasVisibleView => _visibleCount > 0 ;
708+
709+ /// Returns the number of visible views in this overlay group.
710+ int get visibleCount => _visibleCount;
768711}
769712
770713/// Represents a Clip Chain (for a view).
0 commit comments