skip painting clipped out pictures (#18204)
diff --git a/lib/web_ui/lib/src/engine/surface/picture.dart b/lib/web_ui/lib/src/engine/surface/picture.dart
index 50d77b0..9ecb9cf 100644
--- a/lib/web_ui/lib/src/engine/surface/picture.dart
+++ b/lib/web_ui/lib/src/engine/surface/picture.dart
@@ -180,7 +180,11 @@
return 1.0;
} else {
final BitmapCanvas oldCanvas = existingSurface._canvas;
- if (!oldCanvas.doesFitBounds(_exactLocalCullRect)) {
+ if (oldCanvas == null) {
+ // We did not allocate a canvas last time. This can happen when the
+ // picture is completely clipped out of the view.
+ return 1.0;
+ } else if (!oldCanvas.doesFitBounds(_exactLocalCullRect)) {
// The canvas needs to be resized before painting.
return 1.0;
} else {
@@ -547,7 +551,10 @@
void _applyPaint(PersistedPicture oldSurface) {
final EngineCanvas oldCanvas = oldSurface?._canvas;
- if (!picture.recordingCanvas.didDraw) {
+ if (!picture.recordingCanvas.didDraw || _optimalLocalCullRect.isEmpty) {
+ // The picture is empty, or it has been completely clipped out. Skip
+ // painting. This removes all the setup work and scaffolding objects
+ // that won't be useful for anything anyway.
_recycleCanvas(oldCanvas);
domRenderer.clearDom(rootElement);
return;
@@ -642,7 +649,7 @@
super.debugValidate(validationErrors);
if (picture.recordingCanvas.didDraw) {
- if (debugCanvas == null) {
+ if (!_optimalLocalCullRect.isEmpty && debugCanvas == null) {
validationErrors
.add('$runtimeType has non-trivial picture but it has null canvas');
}
diff --git a/lib/web_ui/test/compositing_test.dart b/lib/web_ui/test/engine/surface/scene_builder_test.dart
similarity index 92%
rename from lib/web_ui/test/compositing_test.dart
rename to lib/web_ui/test/engine/surface/scene_builder_test.dart
index 93925bd..6006b2f 100644
--- a/lib/web_ui/test/compositing_test.dart
+++ b/lib/web_ui/test/engine/surface/scene_builder_test.dart
@@ -10,7 +10,7 @@
import 'package:test/test.dart';
-import 'matchers.dart';
+import '../../matchers.dart';
void main() {
group('SceneBuilder', () {
@@ -239,6 +239,31 @@
});
});
+ test('skips painting picture when picture fully clipped out', () async {
+ final Picture picture = _drawPicture();
+
+ // Picture not clipped out, so we should see a `<flt-canvas>`
+ {
+ final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
+ builder.pushOffset(0, 0);
+ builder.addPicture(Offset.zero, picture);
+ builder.pop();
+ html.HtmlElement content = builder.build().webOnlyRootElement;
+ expect(content.querySelectorAll('flt-picture').single.children, isNotEmpty);
+ }
+
+ // Picture fully clipped out, so we should not see a `<flt-canvas>`
+ {
+ final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
+ builder.pushOffset(0, 0);
+ builder.pushClipRect(const Rect.fromLTRB(1000, 1000, 2000, 2000));
+ builder.addPicture(Offset.zero, picture);
+ builder.pop();
+ builder.pop();
+ html.HtmlElement content = builder.build().webOnlyRootElement;
+ expect(content.querySelectorAll('flt-picture').single.children, isEmpty);
+ }
+ });
}
typedef TestLayerBuilder = EngineLayer Function(