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

Commit

Permalink
[framework] make ImageFiltered a repaint boundary (#116385)
Browse files Browse the repository at this point in the history
* ++

* ++

* ++
  • Loading branch information
jonahwilliams committed Dec 2, 2022
1 parent 5c97543 commit e065c7f
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 22 deletions.
32 changes: 12 additions & 20 deletions packages/flutter/lib/src/widgets/image_filter.dart
Expand Up @@ -79,7 +79,11 @@ class _ImageFilterRenderObject extends RenderProxyBox {
if (enabled == value) {
return;
}
final bool wasRepaintBoundary = isRepaintBoundary;
_enabled = value;
if (isRepaintBoundary != wasRepaintBoundary) {
markNeedsCompositingBitsUpdate();
}
markNeedsPaint();
}

Expand All @@ -89,32 +93,20 @@ class _ImageFilterRenderObject extends RenderProxyBox {
assert(value != null);
if (value != _imageFilter) {
_imageFilter = value;
markNeedsPaint();
markNeedsCompositedLayerUpdate();
}
}

@override
bool get alwaysNeedsCompositing => child != null && enabled;

@override
void paint(PaintingContext context, Offset offset) {
assert(imageFilter != null);
if (!enabled) {
layer = null;
return super.paint(context, offset);
}
@override
bool get isRepaintBoundary => alwaysNeedsCompositing;

if (layer == null) {
layer = ImageFilterLayer(imageFilter: imageFilter, offset: offset);
} else {
final ImageFilterLayer filterLayer = layer! as ImageFilterLayer;
filterLayer.imageFilter = imageFilter;
filterLayer.offset = offset;
}
context.pushLayer(layer!, super.paint, Offset.zero);
assert(() {
layer!.debugCreator = debugCreator;
return true;
}());
@override
OffsetLayer updateCompositedLayer({required covariant ImageFilterLayer? oldLayer}) {
final ImageFilterLayer layer = oldLayer ?? ImageFilterLayer();
layer.imageFilter = imageFilter;
return layer;
}
}
@@ -0,0 +1,57 @@
// Copyright 2014 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.

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
testWidgets('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async {
RenderTestObject.paintCount = 0;
await tester.pumpWidget(
Container(
color: Colors.red,
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: const TestWidget(),
),
)
);

expect(RenderTestObject.paintCount, 1);

await tester.pumpWidget(
Container(
color: Colors.red,
child: ImageFiltered(
imageFilter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
child: const TestWidget(),
),
)
);

expect(RenderTestObject.paintCount, 1);
});
}

class TestWidget extends SingleChildRenderObjectWidget {
const TestWidget({super.key, super.child});

@override
RenderObject createRenderObject(BuildContext context) {
return RenderTestObject();
}
}

class RenderTestObject extends RenderProxyBox {
static int paintCount = 0;

@override
void paint(PaintingContext context, Offset offset) {
paintCount += 1;
super.paint(context, offset);
}
}
8 changes: 6 additions & 2 deletions packages/flutter/test/widgets/image_filter_test.dart
Expand Up @@ -31,8 +31,10 @@ void main() {
});

testWidgets('Image filter - blur with offset', (WidgetTester tester) async {
final Key key = GlobalKey();
await tester.pumpWidget(
RepaintBoundary(
key: key,
child: Transform.translate(
offset: const Offset(50, 50),
child: ImageFiltered(
Expand All @@ -43,7 +45,7 @@ void main() {
),
);
await expectLater(
find.byType(ImageFiltered),
find.byKey(key),
matchesGoldenFile('image_filter_blur_offset.png'),
);
});
Expand Down Expand Up @@ -119,8 +121,10 @@ void main() {
testWidgets('Image filter - matrix with offset', (WidgetTester tester) async {
final Matrix4 matrix = Matrix4.rotationZ(pi / 18);
final ImageFilter matrixFilter = ImageFilter.matrix(matrix.storage);
final Key key = GlobalKey();
await tester.pumpWidget(
RepaintBoundary(
key: key,
child: Transform.translate(
offset: const Offset(50, 50),
child: ImageFiltered(
Expand All @@ -147,7 +151,7 @@ void main() {
),
);
await expectLater(
find.byType(ImageFiltered),
find.byKey(key),
matchesGoldenFile('image_filter_matrix_offset.png'),
);
});
Expand Down

0 comments on commit e065c7f

Please sign in to comment.