Skip to content

Commit

Permalink
Fix violation of the render rule in Windows Startup Test (#134245)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dkwingsmt authored Sep 21, 2023
1 parent de44daf commit 203ec67
Showing 1 changed file with 48 additions and 17 deletions.
65 changes: 48 additions & 17 deletions dev/integration_tests/windows_startup_test/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ void drawHelloWorld(ui.FlutterView view) {
view.render(sceneBuilder.build());
}

Future<void> _waitUntilWindowVisible() async {
while (!await isWindowVisible()) {
await Future<void>.delayed(const Duration(milliseconds: 100));
}
}

void _expectVisible(bool current, bool expect, Completer<String> completer, int frameCount) {
if (current != expect) {
try {
throw 'Window should be ${expect ? 'visible' : 'hidden'} on frame $frameCount';
} catch (e) {
if (!completer.isCompleted) {
completer.completeError(e);
}
rethrow;
}
}
}

void main() async {
// TODO(goderbauer): Create a window if embedder doesn't provide an implicit view to draw into.
assert(ui.PlatformDispatcher.instance.implicitView != null);
Expand Down Expand Up @@ -70,27 +89,39 @@ void main() async {
throw 'Window should be hidden at startup';
}

bool firstFrame = true;
ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) async {
if (await isWindowVisible()) {
if (firstFrame) {
throw 'Window should be hidden on first frame';
}

if (!visibilityCompleter.isCompleted) {
visibilityCompleter.complete('success');
}
int frameCount = 0;
ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
// Our goal is to verify that it's `drawHelloWorld` that makes the window
// appear, not anything else. This requires checking the visibility right
// before drawing, but since `isWindowVisible` has to be async, and
// `FlutterView.render` (in `drawHelloWorld`) forbids async before it,
// this can not be done during a single onBeginFrame. However, we can
// verify in separate frames to indirectly prove it, by ensuring that
// no other mechanism can affect isWindowVisible in the first frame at all.
frameCount += 1;
switch (frameCount) {
// The 1st frame: render nothing, just verify that the window is hidden.
case 1:
isWindowVisible().then((bool visible) {
_expectVisible(visible, false, visibilityCompleter, frameCount);
ui.PlatformDispatcher.instance.scheduleFrame();
});
// The 2nd frame: render, which makes the window appear.
case 2:
drawHelloWorld(view);
_waitUntilWindowVisible().then((_) {
if (!visibilityCompleter.isCompleted) {
visibilityCompleter.complete('success');
}
});
// Others, in case requested to render.
default:
drawHelloWorld(view);
}

// Draw something to trigger the first frame callback that displays the
// window.
drawHelloWorld(view);
firstFrame = false;
};

ui.PlatformDispatcher.instance.scheduleFrame();
} catch (e) {
visibilityCompleter.completeError(e);
rethrow;
}
ui.PlatformDispatcher.instance.scheduleFrame();
}

0 comments on commit 203ec67

Please sign in to comment.