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

Commit e331dcd

Browse files
[framework] make transform with filterQuality a rpb (#116792)
* [framework] make transform with filterQuality a rpb * fix tests * ++
1 parent 15939b4 commit e331dcd

File tree

3 files changed

+81
-54
lines changed

3 files changed

+81
-54
lines changed

packages/flutter/lib/src/rendering/proxy_box.dart

+51-53
Original file line numberDiff line numberDiff line change
@@ -2430,7 +2430,7 @@ class RenderTransform extends RenderProxyBox {
24302430
return;
24312431
}
24322432
_origin = value;
2433-
markNeedsPaint();
2433+
markNeedsCompositedLayerUpdate();
24342434
markNeedsSemanticsUpdate();
24352435
}
24362436

@@ -2452,7 +2452,7 @@ class RenderTransform extends RenderProxyBox {
24522452
return;
24532453
}
24542454
_alignment = value;
2455-
markNeedsPaint();
2455+
markNeedsCompositedLayerUpdate();
24562456
markNeedsSemanticsUpdate();
24572457
}
24582458

@@ -2467,10 +2467,13 @@ class RenderTransform extends RenderProxyBox {
24672467
return;
24682468
}
24692469
_textDirection = value;
2470-
markNeedsPaint();
2470+
markNeedsCompositedLayerUpdate();
24712471
markNeedsSemanticsUpdate();
24722472
}
24732473

2474+
@override
2475+
bool get isRepaintBoundary => alwaysNeedsCompositing;
2476+
24742477
@override
24752478
bool get alwaysNeedsCompositing => child != null && _filterQuality != null;
24762479

@@ -2495,7 +2498,7 @@ class RenderTransform extends RenderProxyBox {
24952498
return;
24962499
}
24972500
_transform = Matrix4.copy(value);
2498-
markNeedsPaint();
2501+
markNeedsCompositedLayerUpdate();
24992502
markNeedsSemanticsUpdate();
25002503
}
25012504

@@ -2513,48 +2516,48 @@ class RenderTransform extends RenderProxyBox {
25132516
if (didNeedCompositing != alwaysNeedsCompositing) {
25142517
markNeedsCompositingBitsUpdate();
25152518
}
2516-
markNeedsPaint();
2519+
markNeedsCompositedLayerUpdate();
25172520
}
25182521

25192522
/// Sets the transform to the identity matrix.
25202523
void setIdentity() {
25212524
_transform!.setIdentity();
2522-
markNeedsPaint();
2525+
markNeedsCompositedLayerUpdate();
25232526
markNeedsSemanticsUpdate();
25242527
}
25252528

25262529
/// Concatenates a rotation about the x axis into the transform.
25272530
void rotateX(double radians) {
25282531
_transform!.rotateX(radians);
2529-
markNeedsPaint();
2532+
markNeedsCompositedLayerUpdate();
25302533
markNeedsSemanticsUpdate();
25312534
}
25322535

25332536
/// Concatenates a rotation about the y axis into the transform.
25342537
void rotateY(double radians) {
25352538
_transform!.rotateY(radians);
2536-
markNeedsPaint();
2539+
markNeedsCompositedLayerUpdate();
25372540
markNeedsSemanticsUpdate();
25382541
}
25392542

25402543
/// Concatenates a rotation about the z axis into the transform.
25412544
void rotateZ(double radians) {
25422545
_transform!.rotateZ(radians);
2543-
markNeedsPaint();
2546+
markNeedsCompositedLayerUpdate();
25442547
markNeedsSemanticsUpdate();
25452548
}
25462549

25472550
/// Concatenates a translation by (x, y, z) into the transform.
25482551
void translate(double x, [ double y = 0.0, double z = 0.0 ]) {
25492552
_transform!.translate(x, y, z);
2550-
markNeedsPaint();
2553+
markNeedsCompositedLayerUpdate();
25512554
markNeedsSemanticsUpdate();
25522555
}
25532556

25542557
/// Concatenates a scale into the transform.
25552558
void scale(double x, [ double? y, double? z ]) {
25562559
_transform!.scale(x, y, z);
2557-
markNeedsPaint();
2560+
markNeedsCompositedLayerUpdate();
25582561
markNeedsSemanticsUpdate();
25592562
}
25602563

@@ -2603,51 +2606,46 @@ class RenderTransform extends RenderProxyBox {
26032606
);
26042607
}
26052608

2609+
@override
2610+
OffsetLayer updateCompositedLayer({required covariant ImageFilterLayer? oldLayer}) {
2611+
final ImageFilterLayer layer = oldLayer ?? ImageFilterLayer();
2612+
layer.imageFilter = ui.ImageFilter.matrix(
2613+
_effectiveTransform!.storage,
2614+
filterQuality: filterQuality!
2615+
);
2616+
return layer;
2617+
}
2618+
26062619
@override
26072620
void paint(PaintingContext context, Offset offset) {
2608-
if (child != null) {
2609-
final Matrix4 transform = _effectiveTransform!;
2610-
if (filterQuality == null) {
2611-
final Offset? childOffset = MatrixUtils.getAsTranslation(transform);
2612-
if (childOffset == null) {
2613-
// if the matrix is singular the children would be compressed to a line or
2614-
// single point, instead short-circuit and paint nothing.
2615-
final double det = transform.determinant();
2616-
if (det == 0 || !det.isFinite) {
2617-
layer = null;
2618-
return;
2619-
}
2620-
layer = context.pushTransform(
2621-
needsCompositing,
2622-
offset,
2623-
transform,
2624-
super.paint,
2625-
oldLayer: layer is TransformLayer ? layer as TransformLayer? : null,
2626-
);
2627-
} else {
2628-
super.paint(context, offset + childOffset);
2629-
layer = null;
2630-
}
2631-
} else {
2632-
final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0)
2633-
..multiply(transform)..translate(-offset.dx, -offset.dy);
2634-
final ui.ImageFilter filter = ui.ImageFilter.matrix(
2635-
effectiveTransform.storage,
2636-
filterQuality: filterQuality!,
2637-
);
2638-
if (layer is ImageFilterLayer) {
2639-
final ImageFilterLayer filterLayer = layer! as ImageFilterLayer;
2640-
filterLayer.imageFilter = filter;
2641-
} else {
2642-
layer = ImageFilterLayer(imageFilter: filter);
2643-
}
2644-
context.pushLayer(layer!, super.paint, offset);
2645-
assert(() {
2646-
layer!.debugCreator = debugCreator;
2647-
return true;
2648-
}());
2649-
}
2621+
if (child == null) {
2622+
return;
26502623
}
2624+
if (isRepaintBoundary) {
2625+
return super.paint(context, offset);
2626+
}
2627+
2628+
final Matrix4 transform = _effectiveTransform!;
2629+
final Offset? childOffset = MatrixUtils.getAsTranslation(transform);
2630+
if (childOffset != null) {
2631+
super.paint(context, offset + childOffset);
2632+
layer = null;
2633+
return;
2634+
}
2635+
// if the matrix is singular the children would be compressed to a line or
2636+
// single point, instead short-circuit and paint nothing.
2637+
final double det = transform.determinant();
2638+
if (det == 0 || !det.isFinite) {
2639+
layer = null;
2640+
return;
2641+
}
2642+
layer = context.pushTransform(
2643+
needsCompositing,
2644+
offset,
2645+
transform,
2646+
super.paint,
2647+
oldLayer: layer is TransformLayer ? layer as TransformLayer? : null,
2648+
);
26512649
}
26522650

26532651
@override

packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart

+29
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,35 @@ void main() {
3535

3636
expect(RenderTestObject.paintCount, 1);
3737
});
38+
39+
testWidgets('Transform with FilterQuality avoids repainting child as it animates', (WidgetTester tester) async {
40+
RenderTestObject.paintCount = 0;
41+
await tester.pumpWidget(
42+
Container(
43+
color: Colors.red,
44+
child: Transform.translate(
45+
offset: const Offset(5.0, 10.0),
46+
filterQuality: FilterQuality.low,
47+
child: const TestWidget(),
48+
),
49+
)
50+
);
51+
52+
expect(RenderTestObject.paintCount, 1);
53+
54+
await tester.pumpWidget(
55+
Container(
56+
color: Colors.red,
57+
child: Transform.translate(
58+
offset: const Offset(25.0, 0.0),
59+
filterQuality: FilterQuality.low,
60+
child: const TestWidget(),
61+
),
62+
)
63+
);
64+
65+
expect(RenderTestObject.paintCount, 1);
66+
});
3867
}
3968

4069
class TestWidget extends SingleChildRenderObjectWidget {

packages/flutter/test/widgets/transform_test.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ void main() {
616616
moreOrLessEquals(0.7071067811865476), moreOrLessEquals(0.7071067811865475), 0.0, 0.0,
617617
moreOrLessEquals(-0.7071067811865475), moreOrLessEquals(0.7071067811865476), 0.0, 0.0,
618618
0.0, 0.0, 1.0, 0.0,
619-
moreOrLessEquals(329.28932188134524), moreOrLessEquals(-194.97474683058329), 0.0, 1.0,
619+
moreOrLessEquals(50), moreOrLessEquals(-20.710678118654755), 0.0, 1.0,
620620
]);
621621
});
622622

0 commit comments

Comments
 (0)