diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index e2036f50e68..c46b237b0cd 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -1816,13 +1816,14 @@ class ColorFilterLayer extends ContainerLayer { } /// A composite layer that applies an [ImageFilter] to its children. -class ImageFilterLayer extends ContainerLayer { +class ImageFilterLayer extends OffsetLayer { /// Creates a layer that applies an [ImageFilter] to its children. /// /// The [imageFilter] property must be non-null before the compositing phase /// of the pipeline. ImageFilterLayer({ ui.ImageFilter? imageFilter, + super.offset, }) : _imageFilter = imageFilter; /// The image filter to apply to children. @@ -1844,6 +1845,7 @@ class ImageFilterLayer extends ContainerLayer { assert(imageFilter != null); engineLayer = builder.pushImageFilter( imageFilter!, + offset: offset, oldLayer: _engineLayer as ui.ImageFilterEngineLayer?, ); addChildrenToScene(builder); diff --git a/packages/flutter/lib/src/widgets/image_filter.dart b/packages/flutter/lib/src/widgets/image_filter.dart index 09648211e33..60e3c19df1b 100644 --- a/packages/flutter/lib/src/widgets/image_filter.dart +++ b/packages/flutter/lib/src/widgets/image_filter.dart @@ -105,12 +105,13 @@ class _ImageFilterRenderObject extends RenderProxyBox { } if (layer == null) { - layer = ImageFilterLayer(imageFilter: imageFilter); + 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); + context.pushLayer(layer!, super.paint, Offset.zero); assert(() { layer!.debugCreator = debugCreator; return true; diff --git a/packages/flutter/test/widgets/image_filter_test.dart b/packages/flutter/test/widgets/image_filter_test.dart index 69baae8dfbb..fa982da337c 100644 --- a/packages/flutter/test/widgets/image_filter_test.dart +++ b/packages/flutter/test/widgets/image_filter_test.dart @@ -6,6 +6,7 @@ // machines. @Tags(['reduced-test-set']) +import 'dart:math'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -29,6 +30,24 @@ void main() { ); }); + testWidgets('Image filter - blur with offset', (WidgetTester tester) async { + await tester.pumpWidget( + RepaintBoundary( + child: Transform.translate( + offset: const Offset(50, 50), + child: ImageFiltered( + imageFilter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0), + child: const Placeholder(), + ), + ), + ), + ); + await expectLater( + find.byType(ImageFiltered), + matchesGoldenFile('image_filter_blur_offset.png'), + ); + }); + testWidgets('Image filter - dilate', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary( @@ -97,6 +116,42 @@ 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); + await tester.pumpWidget( + RepaintBoundary( + child: Transform.translate( + offset: const Offset(50, 50), + child: ImageFiltered( + imageFilter: matrixFilter, + child: MaterialApp( + title: 'Flutter Demo', + theme: ThemeData(primarySwatch: Colors.blue), + home: Scaffold( + appBar: AppBar( + title: const Text('Matrix ImageFilter Test'), + ), + body: const Center( + child:Text('Hooray!'), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { }, + tooltip: 'Increment', + child: const Icon(Icons.add), + ), + ), + ), + ), + ), + ), + ); + await expectLater( + find.byType(ImageFiltered), + matchesGoldenFile('image_filter_matrix_offset.png'), + ); + }); + testWidgets('Image filter - reuses its layer', (WidgetTester tester) async { Future pumpWithSigma(double sigma) async { await tester.pumpWidget(