Closed
Description
Steps to reproduce
flutter/engine#55402 introduces a test for the case when addRetained
is used on a layer with pictures which are clipped in one frame and visible in a later frame.
test('picture clipped but scrolls back in', () async {
// Frame 1: Clip out the right circle
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder();
sceneBuilder.pushClipRect(const ui.Rect.fromLTRB(0, 0, 125, 300));
// Save this offsetLayer to add back in so we are using the same
// picture layers on the next scene.
final ui.OffsetEngineLayer offsetLayer = sceneBuilder.pushOffset(0, 0);
sceneBuilder.addPicture(ui.Offset.zero, drawPicture((ui.Canvas canvas) {
canvas.drawCircle(const ui.Offset(50, 150), 50,
ui.Paint()..color = const ui.Color(0xFFFF0000));
}));
sceneBuilder.addPicture(ui.Offset.zero, drawPicture((ui.Canvas canvas) {
canvas.drawCircle(const ui.Offset(200, 150), 50,
ui.Paint()..color = const ui.Color(0xFFFF0000));
}));
sceneBuilder.pop();
sceneBuilder.pop();
await renderScene(sceneBuilder.build());
// Frame 2: Clip out the left circle
final ui.SceneBuilder sceneBuilder2 = ui.SceneBuilder();
sceneBuilder2.pushClipRect(const ui.Rect.fromLTRB(150, 0, 300, 300));
sceneBuilder2.addRetained(offsetLayer);
sceneBuilder2.pop();
sceneBuilder2.pop();
await renderScene(sceneBuilder2.build());
// Frame 3: Clip out the right circle again
final ui.SceneBuilder sceneBuilder3 = ui.SceneBuilder();
sceneBuilder3.pushClipRect(const ui.Rect.fromLTRB(0, 0, 125, 300));
sceneBuilder3.addRetained(offsetLayer);
sceneBuilder3.pop();
sceneBuilder3.pop();
await renderScene(sceneBuilder3.build());
await matchGoldenFile(
'scene_builder_picture_clipped_out_then_clipped_in.png',
region: region);
});
Expected results
The test should pass and the screenshot should show the red circle on the left (the red circle on the right is clipped out).
Actual results
The HTML renderer crashes on this test with this stack trace:
00:40 +117 ~23 -1: scene_builder_test.dart: SceneBuilder picture clipped but scrolls back in [E]
Bad state: No element
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart 1209:19 Object.wrapException
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_array.dart 448:5 JavaScriptObject.first
../../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart 42:26 SurfaceSceneBuilder._persistedScene
../../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart 485:7 SurfaceSceneBuilder.build.<fn>
../../../../flutter/lib/web_ui/lib/src/engine/profiler.dart 44:12 Object.timeAction
../../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart 480:5 SurfaceSceneBuilder.build
../../../../flutter/lib/web_ui/test/ui/scene_builder_test.dart 363:25 <fn>
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 311:19 _wrapJsFunctionForAsync.closure.$protected
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 336:23 _wrapJsFunctionForAsync.<fn>
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 287:19 _awaitOnObject.<fn>
Code sample
test('picture clipped but scrolls back in', () async {
// Frame 1: Clip out the right circle
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder();
sceneBuilder.pushClipRect(const ui.Rect.fromLTRB(0, 0, 125, 300));
// Save this offsetLayer to add back in so we are using the same
// picture layers on the next scene.
final ui.OffsetEngineLayer offsetLayer = sceneBuilder.pushOffset(0, 0);
sceneBuilder.addPicture(ui.Offset.zero, drawPicture((ui.Canvas canvas) {
canvas.drawCircle(const ui.Offset(50, 150), 50,
ui.Paint()..color = const ui.Color(0xFFFF0000));
}));
sceneBuilder.addPicture(ui.Offset.zero, drawPicture((ui.Canvas canvas) {
canvas.drawCircle(const ui.Offset(200, 150), 50,
ui.Paint()..color = const ui.Color(0xFFFF0000));
}));
sceneBuilder.pop();
sceneBuilder.pop();
await renderScene(sceneBuilder.build());
// Frame 2: Clip out the left circle
final ui.SceneBuilder sceneBuilder2 = ui.SceneBuilder();
sceneBuilder2.pushClipRect(const ui.Rect.fromLTRB(150, 0, 300, 300));
sceneBuilder2.addRetained(offsetLayer);
sceneBuilder2.pop();
sceneBuilder2.pop();
await renderScene(sceneBuilder2.build());
// Frame 3: Clip out the right circle again
final ui.SceneBuilder sceneBuilder3 = ui.SceneBuilder();
sceneBuilder3.pushClipRect(const ui.Rect.fromLTRB(0, 0, 125, 300));
sceneBuilder3.addRetained(offsetLayer);
sceneBuilder3.pop();
sceneBuilder3.pop();
await renderScene(sceneBuilder3.build());
await matchGoldenFile(
'scene_builder_picture_clipped_out_then_clipped_in.png',
region: region);
});
Screenshots or Video
No response
Logs
00:40 +117 ~23 -1: scene_builder_test.dart: SceneBuilder picture clipped but scrolls back in [E]
Bad state: No element
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_helper.dart 1209:19 Object.wrapException
org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_array.dart 448:5 JavaScriptObject.first
../../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart 42:26 SurfaceSceneBuilder._persistedScene
../../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart 485:7 SurfaceSceneBuilder.build.<fn>
../../../../flutter/lib/web_ui/lib/src/engine/profiler.dart 44:12 Object.timeAction
../../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart 480:5 SurfaceSceneBuilder.build
../../../../flutter/lib/web_ui/test/ui/scene_builder_test.dart 363:25 <fn>
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 311:19 _wrapJsFunctionForAsync.closure.$protected
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 336:23 _wrapJsFunctionForAsync.<fn>
org-dartlang-sdk:///lib/_internal/js_runtime/lib/async_patch.dart 287:19 _awaitOnObject.<fn>
Flutter Doctor output
❯ flutter doctor -v
[✓] Flutter (Channel main, 3.26.0-1.0.pre.193, on Debian GNU/Linux rodete 6.9.10-1rodete5-amd64, locale en_US.UTF-8)
• Flutter version 3.26.0-1.0.pre.193 on channel main at /usr/local/google/home/het/Projects/flutter
• Upstream repository [email protected]:flutter/flutter.git
• Framework revision f83b08495a (28 hours ago), 2024-09-24 14:23:26 -0400
• Engine revision dc44f95b70
• Dart version 3.6.0 (build 3.6.0-273.0.dev)
• DevTools version 2.40.0-dev.1
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at /usr/local/google/home/het/Android/Sdk
✗ cmdline-tools component is missing
Run `path/to/sdkmanager --install "cmdline-tools;latest"`
See https://developer.android.com/studio/command-line for more details.
✗ Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/to/linux-android-setup for more details.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✗] Linux toolchain - develop for Linux desktop
• Debian clang version 16.0.6 (26)
• cmake version 3.29.6
• ninja version 1.11.1
• pkg-config version 1.8.1
✗ GTK 3.0 development libraries are required for Linux development.
They are likely available from your distribution (e.g.: apt install libgtk-3-dev)
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/to/linux-android-setup for detailed instructions).
[✓] Connected device (2 available)
• Linux (desktop) • linux • linux-x64 • Debian GNU/Linux rodete 6.9.10-1rodete5-amd64
• Chrome (web) • chrome • web-javascript • Google Chrome 129.0.6668.70
[✓] Network resources
• All expected network resources are available.
! Doctor found issues in 3 categories.