[canvaskit] Fix incorrect clipping with Opacity scene layer (flutter/engine#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: https://github.com/flutter/flutter/issues/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
This commit is contained in:
Harry Terkelsen 2024-10-08 16:49:09 -07:00 committed by GitHub
parent 173af3d95f
commit 0ed39374df
2 changed files with 66 additions and 6 deletions

View File

@ -329,9 +329,7 @@ class MeasureVisitor extends LayerVisitor {
measuringCanvas.save();
measuringCanvas.translate(opacity.offset.dx, opacity.offset.dy);
final ui.Rect saveLayerBounds = opacity.paintBounds.shift(-opacity.offset);
measuringCanvas.saveLayer(saveLayerBounds, paint);
measuringCanvas.saveLayer(ui.Rect.largest, paint);
measureChildren(opacity);
// Restore twice: once for the translate and once for the saveLayer.
measuringCanvas.restore();
@ -567,9 +565,7 @@ class PaintVisitor extends LayerVisitor {
nWayCanvas.save();
nWayCanvas.translate(opacity.offset.dx, opacity.offset.dy);
final ui.Rect saveLayerBounds = opacity.paintBounds.shift(-opacity.offset);
nWayCanvas.saveLayer(saveLayerBounds, paint);
nWayCanvas.saveLayer(ui.Rect.largest, paint);
paintChildren(opacity);
// Restore twice: once for the translate and once for the saveLayer.
nWayCanvas.restore();

View File

@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:test/bootstrap/browser.dart';
import 'package:test/test.dart';
@ -403,6 +404,69 @@ Future<void> testMain() async {
},
skip: isFirefox &&
isHtml); // https://github.com/flutter/flutter/issues/86623
test('opacity layer with transformed children', () async {
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder();
sceneBuilder.pushOffset(0, 0);
sceneBuilder.pushOpacity(128);
// Push some complex transforms
final Float64List transform1 = Float64List.fromList([
1.00,
0.00,
0.00,
0.00,
0.06,
1.00,
-0.88,
0.00,
-0.03,
0.60,
0.47,
-0.00,
-4.58,
257.03,
63.11,
0.81,
]);
final Float64List transform2 = Float64List.fromList([
1.00,
0.00,
0.00,
0.00,
0.07,
0.90,
-0.94,
0.00,
-0.02,
0.75,
0.33,
-0.00,
-3.28,
309.29,
45.20,
0.86,
]);
sceneBuilder
.pushTransform(Matrix4.identity().scaled(0.3, 0.3).toFloat64());
sceneBuilder.pushTransform(transform1);
sceneBuilder.pushTransform(transform2);
sceneBuilder.addPicture(const ui.Offset(20, 20),
drawPicture((ui.Canvas canvas) {
canvas.drawCircle(const ui.Offset(25, 75), 25,
ui.Paint()..color = const ui.Color(0xFFFF0000));
}));
sceneBuilder.pop();
sceneBuilder.pop();
sceneBuilder.pop();
sceneBuilder.pop();
sceneBuilder.pop();
await renderScene(sceneBuilder.build());
await matchGoldenFile(
'scene_builder_opacity_layer_with_transformed_children.png',
region: region);
});
});
}