mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[canvaskit] fix TransformLayer.preroll (flutter/engine#22890)
This commit is contained in:
parent
ba12ac7908
commit
2f6c8a9865
@ -71,6 +71,11 @@ class PaintContext {
|
||||
abstract class ContainerLayer extends Layer {
|
||||
final List<Layer> _layers = <Layer>[];
|
||||
|
||||
/// The list of child layers.
|
||||
///
|
||||
/// Useful in tests.
|
||||
List<Layer> get debugLayers => _layers;
|
||||
|
||||
/// Register [child] as a child of this layer.
|
||||
void add(Layer child) {
|
||||
child.parent = this;
|
||||
@ -294,46 +299,10 @@ class TransformLayer extends ContainerLayer
|
||||
final Matrix4 childMatrix = matrix * _transform;
|
||||
context.mutatorsStack.pushTransform(_transform);
|
||||
final ui.Rect childPaintBounds = prerollChildren(context, childMatrix);
|
||||
paintBounds = _transformRect(_transform, childPaintBounds);
|
||||
paintBounds = transformRect(_transform, childPaintBounds);
|
||||
context.mutatorsStack.pop();
|
||||
}
|
||||
|
||||
/// Applies the given matrix as a perspective transform to the given point.
|
||||
///
|
||||
/// This function assumes the given point has a z-coordinate of 0.0. The
|
||||
/// z-coordinate of the result is ignored.
|
||||
static ui.Offset _transformPoint(Matrix4 transform, ui.Offset point) {
|
||||
final Vector3 position3 = Vector3(point.dx, point.dy, 0.0);
|
||||
final Vector3 transformed3 = transform.perspectiveTransform(position3);
|
||||
return ui.Offset(transformed3.x, transformed3.y);
|
||||
}
|
||||
|
||||
/// Returns a rect that bounds the result of applying the given matrix as a
|
||||
/// perspective transform to the given rect.
|
||||
///
|
||||
/// This function assumes the given rect is in the plane with z equals 0.0.
|
||||
/// The transformed rect is then projected back into the plane with z equals
|
||||
/// 0.0 before computing its bounding rect.
|
||||
static ui.Rect _transformRect(Matrix4 transform, ui.Rect rect) {
|
||||
final ui.Offset point1 = _transformPoint(transform, rect.topLeft);
|
||||
final ui.Offset point2 = _transformPoint(transform, rect.topRight);
|
||||
final ui.Offset point3 = _transformPoint(transform, rect.bottomLeft);
|
||||
final ui.Offset point4 = _transformPoint(transform, rect.bottomRight);
|
||||
return ui.Rect.fromLTRB(
|
||||
_min4(point1.dx, point2.dx, point3.dx, point4.dx),
|
||||
_min4(point1.dy, point2.dy, point3.dy, point4.dy),
|
||||
_max4(point1.dx, point2.dx, point3.dx, point4.dx),
|
||||
_max4(point1.dy, point2.dy, point3.dy, point4.dy));
|
||||
}
|
||||
|
||||
static double _min4(double a, double b, double c, double d) {
|
||||
return math.min(a, math.min(b, math.min(c, d)));
|
||||
}
|
||||
|
||||
static double _max4(double a, double b, double c, double d) {
|
||||
return math.max(a, math.max(b, math.max(c, d)));
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(PaintContext paintContext) {
|
||||
assert(needsPainting);
|
||||
|
||||
@ -45,6 +45,16 @@ void setUpCanvasKitTest() {
|
||||
});
|
||||
}
|
||||
|
||||
/// Utility function for CanvasKit tests to draw pictures without
|
||||
/// the [CkPictureRecorder] boilerplate.
|
||||
CkPicture paintPicture(
|
||||
ui.Rect cullRect, void Function(CkCanvas canvas) painter) {
|
||||
final CkPictureRecorder recorder = CkPictureRecorder();
|
||||
final CkCanvas canvas = recorder.beginRecording(cullRect);
|
||||
painter(canvas);
|
||||
return recorder.endRecording();
|
||||
}
|
||||
|
||||
class _TestFinalizerRegistration {
|
||||
_TestFinalizerRegistration(this.wrapper, this.deletable, this.stackTrace);
|
||||
|
||||
|
||||
55
engine/src/flutter/lib/web_ui/test/canvaskit/layer_test.dart
Normal file
55
engine/src/flutter/lib/web_ui/test/canvaskit/layer_test.dart
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.12
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:test/bootstrap/browser.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:ui/src/engine.dart';
|
||||
import 'package:ui/ui.dart' as ui;
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
internalBootstrapBrowserTest(() => testMain);
|
||||
}
|
||||
|
||||
void testMain() {
|
||||
group('CanvasKit', () {
|
||||
setUpCanvasKitTest();
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/63715
|
||||
test('TransformLayer prerolls correctly', () async {
|
||||
final EnginePlatformDispatcher dispatcher =
|
||||
ui.window.platformDispatcher as EnginePlatformDispatcher;
|
||||
|
||||
final CkPicture picture =
|
||||
paintPicture(ui.Rect.fromLTRB(0, 0, 30, 30), (CkCanvas canvas) {
|
||||
canvas.drawRect(ui.Rect.fromLTRB(0, 0, 30, 30),
|
||||
CkPaint()..style = ui.PaintingStyle.fill);
|
||||
});
|
||||
|
||||
final LayerSceneBuilder sb = LayerSceneBuilder();
|
||||
sb.pushClipRect(ui.Rect.fromLTRB(15, 15, 30, 30));
|
||||
|
||||
// Intentionally use a perspective transform, which triggered the
|
||||
// https://github.com/flutter/flutter/issues/63715 bug.
|
||||
sb.pushTransform(
|
||||
Float64List.fromList(Matrix4.identity().storage
|
||||
..[15] = 2,
|
||||
));
|
||||
|
||||
sb.addPicture(ui.Offset.zero, picture);
|
||||
final LayerTree layerTree = sb.build().layerTree;
|
||||
dispatcher.rasterizer!.draw(layerTree);
|
||||
final ClipRectLayer clipRect = layerTree.rootLayer as ClipRectLayer;
|
||||
expect(clipRect.paintBounds, ui.Rect.fromLTRB(15, 15, 30, 30));
|
||||
|
||||
final TransformLayer transform = clipRect.debugLayers.single as TransformLayer;
|
||||
expect(transform.paintBounds, ui.Rect.fromLTRB(0, 0, 30, 30));
|
||||
});
|
||||
// TODO: https://github.com/flutter/flutter/issues/60040
|
||||
}, skip: isIosSafari);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user