Skip to content

Commit 68bf137

Browse files
authored
skip painting clipped out pictures (flutter#18204)
1 parent a1218dd commit 68bf137

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

lib/web_ui/lib/src/engine/surface/picture.dart

+10-3
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,11 @@ class PersistedStandardPicture extends PersistedPicture {
180180
return 1.0;
181181
} else {
182182
final BitmapCanvas oldCanvas = existingSurface._canvas;
183-
if (!oldCanvas.doesFitBounds(_exactLocalCullRect)) {
183+
if (oldCanvas == null) {
184+
// We did not allocate a canvas last time. This can happen when the
185+
// picture is completely clipped out of the view.
186+
return 1.0;
187+
} else if (!oldCanvas.doesFitBounds(_exactLocalCullRect)) {
184188
// The canvas needs to be resized before painting.
185189
return 1.0;
186190
} else {
@@ -547,7 +551,10 @@ abstract class PersistedPicture extends PersistedLeafSurface {
547551

548552
void _applyPaint(PersistedPicture oldSurface) {
549553
final EngineCanvas oldCanvas = oldSurface?._canvas;
550-
if (!picture.recordingCanvas.didDraw) {
554+
if (!picture.recordingCanvas.didDraw || _optimalLocalCullRect.isEmpty) {
555+
// The picture is empty, or it has been completely clipped out. Skip
556+
// painting. This removes all the setup work and scaffolding objects
557+
// that won't be useful for anything anyway.
551558
_recycleCanvas(oldCanvas);
552559
domRenderer.clearDom(rootElement);
553560
return;
@@ -642,7 +649,7 @@ abstract class PersistedPicture extends PersistedLeafSurface {
642649
super.debugValidate(validationErrors);
643650

644651
if (picture.recordingCanvas.didDraw) {
645-
if (debugCanvas == null) {
652+
if (!_optimalLocalCullRect.isEmpty && debugCanvas == null) {
646653
validationErrors
647654
.add('$runtimeType has non-trivial picture but it has null canvas');
648655
}

lib/web_ui/test/compositing_test.dart renamed to lib/web_ui/test/engine/surface/scene_builder_test.dart

+26-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'package:ui/ui.dart';
1010

1111
import 'package:test/test.dart';
1212

13-
import 'matchers.dart';
13+
import '../../matchers.dart';
1414

1515
void main() {
1616
group('SceneBuilder', () {
@@ -239,6 +239,31 @@ void main() {
239239
});
240240
});
241241

242+
test('skips painting picture when picture fully clipped out', () async {
243+
final Picture picture = _drawPicture();
244+
245+
// Picture not clipped out, so we should see a `<flt-canvas>`
246+
{
247+
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
248+
builder.pushOffset(0, 0);
249+
builder.addPicture(Offset.zero, picture);
250+
builder.pop();
251+
html.HtmlElement content = builder.build().webOnlyRootElement;
252+
expect(content.querySelectorAll('flt-picture').single.children, isNotEmpty);
253+
}
254+
255+
// Picture fully clipped out, so we should not see a `<flt-canvas>`
256+
{
257+
final SurfaceSceneBuilder builder = SurfaceSceneBuilder();
258+
builder.pushOffset(0, 0);
259+
builder.pushClipRect(const Rect.fromLTRB(1000, 1000, 2000, 2000));
260+
builder.addPicture(Offset.zero, picture);
261+
builder.pop();
262+
builder.pop();
263+
html.HtmlElement content = builder.build().webOnlyRootElement;
264+
expect(content.querySelectorAll('flt-picture').single.children, isEmpty);
265+
}
266+
});
242267
}
243268

244269
typedef TestLayerBuilder = EngineLayer Function(

0 commit comments

Comments
 (0)