Skip to content

Commit 203ec67

Browse files
authored
Fix violation of the render rule in Windows Startup Test (#134245)
This PR fixes yet another case in the windows startup test that violates the render rule, which caused flutter/engine#45300 to be reverted. Although the `FlutterView.render` call is within `onBeginFrame`, there is an `await` before the call, causing the call to fall out of the synchronous scope. I've added this problem to the documentation of `FlutterView.render` in flutter/engine#45555.
1 parent de44daf commit 203ec67

File tree

1 file changed

+48
-17
lines changed
  • dev/integration_tests/windows_startup_test/lib

1 file changed

+48
-17
lines changed

dev/integration_tests/windows_startup_test/lib/main.dart

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ void drawHelloWorld(ui.FlutterView view) {
3131
view.render(sceneBuilder.build());
3232
}
3333

34+
Future<void> _waitUntilWindowVisible() async {
35+
while (!await isWindowVisible()) {
36+
await Future<void>.delayed(const Duration(milliseconds: 100));
37+
}
38+
}
39+
40+
void _expectVisible(bool current, bool expect, Completer<String> completer, int frameCount) {
41+
if (current != expect) {
42+
try {
43+
throw 'Window should be ${expect ? 'visible' : 'hidden'} on frame $frameCount';
44+
} catch (e) {
45+
if (!completer.isCompleted) {
46+
completer.completeError(e);
47+
}
48+
rethrow;
49+
}
50+
}
51+
}
52+
3453
void main() async {
3554
// TODO(goderbauer): Create a window if embedder doesn't provide an implicit view to draw into.
3655
assert(ui.PlatformDispatcher.instance.implicitView != null);
@@ -70,27 +89,39 @@ void main() async {
7089
throw 'Window should be hidden at startup';
7190
}
7291

73-
bool firstFrame = true;
74-
ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) async {
75-
if (await isWindowVisible()) {
76-
if (firstFrame) {
77-
throw 'Window should be hidden on first frame';
78-
}
79-
80-
if (!visibilityCompleter.isCompleted) {
81-
visibilityCompleter.complete('success');
82-
}
92+
int frameCount = 0;
93+
ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
94+
// Our goal is to verify that it's `drawHelloWorld` that makes the window
95+
// appear, not anything else. This requires checking the visibility right
96+
// before drawing, but since `isWindowVisible` has to be async, and
97+
// `FlutterView.render` (in `drawHelloWorld`) forbids async before it,
98+
// this can not be done during a single onBeginFrame. However, we can
99+
// verify in separate frames to indirectly prove it, by ensuring that
100+
// no other mechanism can affect isWindowVisible in the first frame at all.
101+
frameCount += 1;
102+
switch (frameCount) {
103+
// The 1st frame: render nothing, just verify that the window is hidden.
104+
case 1:
105+
isWindowVisible().then((bool visible) {
106+
_expectVisible(visible, false, visibilityCompleter, frameCount);
107+
ui.PlatformDispatcher.instance.scheduleFrame();
108+
});
109+
// The 2nd frame: render, which makes the window appear.
110+
case 2:
111+
drawHelloWorld(view);
112+
_waitUntilWindowVisible().then((_) {
113+
if (!visibilityCompleter.isCompleted) {
114+
visibilityCompleter.complete('success');
115+
}
116+
});
117+
// Others, in case requested to render.
118+
default:
119+
drawHelloWorld(view);
83120
}
84-
85-
// Draw something to trigger the first frame callback that displays the
86-
// window.
87-
drawHelloWorld(view);
88-
firstFrame = false;
89121
};
90-
91-
ui.PlatformDispatcher.instance.scheduleFrame();
92122
} catch (e) {
93123
visibilityCompleter.completeError(e);
94124
rethrow;
95125
}
126+
ui.PlatformDispatcher.instance.scheduleFrame();
96127
}

0 commit comments

Comments
 (0)