Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2d0eac0

Browse files
[canvaskit] Fix incorrect clipping with Opacity scene layer (#55751)
Fixes opacity layer incorrectly clipping its children when there are complex transforms applied to them. Since the opacity saveLayer only applies to children which actually draw, it doesn't need to have tight bounds anyways. Pre-requisite for re-enabling tests here: flutter/flutter#110785 BEFORE: ![Screenshot 2024-10-08 at 11 00 14�AM](https://github.com/user-attachments/assets/cf4c6296-7730-4db6-96f6-e22f32e28d94) AFTER: ![Screenshot 2024-10-08 at 11 06 22�AM](https://github.com/user-attachments/assets/6a680e2c-23d0-41e2-9de5-1c9667a785ab) BEFORE: ![failing_opacity](https://github.com/user-attachments/assets/d8acf075-c92d-4f8a-aa1a-476f46f1c931) AFTER: ![working_opacity](https://github.com/user-attachments/assets/3e589deb-d8b6-4466-9e19-95daff870bfb) [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent be2bc34 commit 2d0eac0

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

lib/web_ui/lib/src/engine/canvaskit/layer_visitor.dart

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,7 @@ class MeasureVisitor extends LayerVisitor {
329329
measuringCanvas.save();
330330
measuringCanvas.translate(opacity.offset.dx, opacity.offset.dy);
331331

332-
final ui.Rect saveLayerBounds = opacity.paintBounds.shift(-opacity.offset);
333-
334-
measuringCanvas.saveLayer(saveLayerBounds, paint);
332+
measuringCanvas.saveLayer(ui.Rect.largest, paint);
335333
measureChildren(opacity);
336334
// Restore twice: once for the translate and once for the saveLayer.
337335
measuringCanvas.restore();
@@ -567,9 +565,7 @@ class PaintVisitor extends LayerVisitor {
567565
nWayCanvas.save();
568566
nWayCanvas.translate(opacity.offset.dx, opacity.offset.dy);
569567

570-
final ui.Rect saveLayerBounds = opacity.paintBounds.shift(-opacity.offset);
571-
572-
nWayCanvas.saveLayer(saveLayerBounds, paint);
568+
nWayCanvas.saveLayer(ui.Rect.largest, paint);
573569
paintChildren(opacity);
574570
// Restore twice: once for the translate and once for the saveLayer.
575571
nWayCanvas.restore();

lib/web_ui/test/ui/scene_builder_test.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:math' as math;
6+
import 'dart:typed_data';
67

78
import 'package:test/bootstrap/browser.dart';
89
import 'package:test/test.dart';
@@ -403,6 +404,69 @@ Future<void> testMain() async {
403404
},
404405
skip: isFirefox &&
405406
isHtml); // https://github.com/flutter/flutter/issues/86623
407+
408+
test('opacity layer with transformed children', () async {
409+
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder();
410+
sceneBuilder.pushOffset(0, 0);
411+
sceneBuilder.pushOpacity(128);
412+
// Push some complex transforms
413+
final Float64List transform1 = Float64List.fromList([
414+
1.00,
415+
0.00,
416+
0.00,
417+
0.00,
418+
0.06,
419+
1.00,
420+
-0.88,
421+
0.00,
422+
-0.03,
423+
0.60,
424+
0.47,
425+
-0.00,
426+
-4.58,
427+
257.03,
428+
63.11,
429+
0.81,
430+
]);
431+
final Float64List transform2 = Float64List.fromList([
432+
1.00,
433+
0.00,
434+
0.00,
435+
0.00,
436+
0.07,
437+
0.90,
438+
-0.94,
439+
0.00,
440+
-0.02,
441+
0.75,
442+
0.33,
443+
-0.00,
444+
-3.28,
445+
309.29,
446+
45.20,
447+
0.86,
448+
]);
449+
sceneBuilder
450+
.pushTransform(Matrix4.identity().scaled(0.3, 0.3).toFloat64());
451+
sceneBuilder.pushTransform(transform1);
452+
sceneBuilder.pushTransform(transform2);
453+
454+
sceneBuilder.addPicture(const ui.Offset(20, 20),
455+
drawPicture((ui.Canvas canvas) {
456+
canvas.drawCircle(const ui.Offset(25, 75), 25,
457+
ui.Paint()..color = const ui.Color(0xFFFF0000));
458+
}));
459+
sceneBuilder.pop();
460+
sceneBuilder.pop();
461+
sceneBuilder.pop();
462+
sceneBuilder.pop();
463+
sceneBuilder.pop();
464+
await renderScene(sceneBuilder.build());
465+
466+
await matchGoldenFile(
467+
'scene_builder_opacity_layer_with_transformed_children.png',
468+
region: region);
469+
});
406470
});
407471
}
408472

0 commit comments

Comments
 (0)