@@ -213,6 +213,10 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
213213 }
214214 }
215215
216+ /// A set of views which have rendered in the current `onBeginFrame` or
217+ /// `onDrawFrame` scope.
218+ Set <ui.FlutterView >? _viewsRenderedInCurrentFrame;
219+
216220 /// A callback invoked when any window begins a frame.
217221 ///
218222 /// A callback that is invoked to notify the application that it is an
@@ -235,7 +239,9 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
235239 /// Engine code should use this method instead of the callback directly.
236240 /// Otherwise zones won't work properly.
237241 void invokeOnBeginFrame (Duration duration) {
242+ _viewsRenderedInCurrentFrame = < ui.FlutterView > {};
238243 invoke1 <Duration >(_onBeginFrame, _onBeginFrameZone, duration);
244+ _viewsRenderedInCurrentFrame = null ;
239245 }
240246
241247 /// A callback that is invoked for each frame after [onBeginFrame] has
@@ -256,7 +262,9 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
256262 /// Engine code should use this method instead of the callback directly.
257263 /// Otherwise zones won't work properly.
258264 void invokeOnDrawFrame () {
265+ _viewsRenderedInCurrentFrame = < ui.FlutterView > {};
259266 invoke (_onDrawFrame, _onDrawFrameZone);
267+ _viewsRenderedInCurrentFrame = null ;
260268 }
261269
262270 /// A callback that is invoked when pointer data is available.
@@ -753,14 +761,27 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
753761 /// * [RendererBinding] , the Flutter framework class which manages layout and
754762 /// painting.
755763 @override
756- void render (ui.Scene scene, [ui.FlutterView ? view]) {
764+ Future < void > render (ui.Scene scene, [ui.FlutterView ? view]) async {
757765 assert (view != null || implicitView != null ,
758766 'Calling render without a FlutterView' );
759767 if (view == null && implicitView == null ) {
760768 // If there is no view to render into, then this is a no-op.
761769 return ;
762770 }
763- renderer.renderScene (scene, view ?? implicitView! );
771+ final ui.FlutterView viewToRender = view ?? implicitView! ;
772+
773+ // Only render in an `onDrawFrame` or `onBeginFrame` scope. This is checked
774+ // by checking if the `_viewsRenderedInCurrentFrame` is non-null and this
775+ // view hasn't been rendered already in this scope.
776+ final bool shouldRender =
777+ _viewsRenderedInCurrentFrame? .add (viewToRender) ?? false ;
778+ // TODO(harryterkelsen): HTML renderer needs to violate the render rule in
779+ // order to perform golden tests in Flutter framework because on the HTML
780+ // renderer, golden tests render to DOM and then take a browser screenshot,
781+ // https://github.com/flutter/flutter/issues/137073.
782+ if (shouldRender || renderer.rendererTag == 'html' ) {
783+ await renderer.renderScene (scene, viewToRender);
784+ }
764785 }
765786
766787 /// Additional accessibility features that may be enabled by the platform.
@@ -1275,7 +1296,8 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
12751296 String get defaultRouteName {
12761297 // TODO(mdebbar): What should we do in multi-view mode?
12771298 // https://github.com/flutter/flutter/issues/139174
1278- return _defaultRouteName ?? = implicitView? .browserHistory.currentPath ?? '/' ;
1299+ return _defaultRouteName ?? =
1300+ implicitView? .browserHistory.currentPath ?? '/' ;
12791301 }
12801302
12811303 /// Lazily initialized when the `defaultRouteName` getter is invoked.
0 commit comments