diff --git a/engine/src/flutter/lib/ui/dart_ui.cc b/engine/src/flutter/lib/ui/dart_ui.cc index a47bf094c4..7bb1aef0ed 100644 --- a/engine/src/flutter/lib/ui/dart_ui.cc +++ b/engine/src/flutter/lib/ui/dart_ui.cc @@ -207,6 +207,7 @@ typedef CanvasPath Path; V(ImageFilter, initComposeFilter) \ V(ImageFilter, initShader) \ V(ImageFilter, initMatrix) \ + V(ImageFilter, equals) \ V(ImageShader, dispose) \ V(ImageShader, initWithImage) \ V(ImmutableBuffer, dispose) \ diff --git a/engine/src/flutter/lib/ui/painting.dart b/engine/src/flutter/lib/ui/painting.dart index dea0c7885f..ddda85d275 100644 --- a/engine/src/flutter/lib/ui/painting.dart +++ b/engine/src/flutter/lib/ui/painting.dart @@ -4474,9 +4474,14 @@ class _FragmentShaderImageFilter implements ImageFilter { if (other.runtimeType != runtimeType) { return false; } - return other is _FragmentShaderImageFilter && other.shader == shader; + return other is _FragmentShaderImageFilter && + other.shader == shader && + _equals(nativeFilter, other.nativeFilter); } + @Native(symbol: 'ImageFilter::equal') + external static bool _equals(_ImageFilter a, _ImageFilter b); + @override int get hashCode => shader.hashCode; } diff --git a/engine/src/flutter/lib/ui/painting/image_filter.cc b/engine/src/flutter/lib/ui/painting/image_filter.cc index 2319008bc4..8d21d63884 100644 --- a/engine/src/flutter/lib/ui/painting/image_filter.cc +++ b/engine/src/flutter/lib/ui/painting/image_filter.cc @@ -125,4 +125,8 @@ void ImageFilter::initShader(ReusableFragmentShader* shader) { filter_ = shader->as_image_filter(); } +bool ImageFilter::equals(ImageFilter* a, ImageFilter* b) { + return a->filter_ == b->filter_; +} + } // namespace flutter diff --git a/engine/src/flutter/lib/ui/painting/image_filter.h b/engine/src/flutter/lib/ui/painting/image_filter.h index c7bb6369bd..c251d9653f 100644 --- a/engine/src/flutter/lib/ui/painting/image_filter.h +++ b/engine/src/flutter/lib/ui/painting/image_filter.h @@ -36,6 +36,7 @@ class ImageFilter : public RefCountedDartWrappable { void initColorFilter(ColorFilter* colorFilter); void initComposeFilter(ImageFilter* outer, ImageFilter* inner); void initShader(ReusableFragmentShader* shader); + bool equals(ImageFilter* a, ImageFilter* b); const std::shared_ptr filter(DlTileMode mode) const; diff --git a/engine/src/flutter/testing/dart/fragment_shader_test.dart b/engine/src/flutter/testing/dart/fragment_shader_test.dart index 0bfffbf515..54366f7af2 100644 --- a/engine/src/flutter/testing/dart/fragment_shader_test.dart +++ b/engine/src/flutter/testing/dart/fragment_shader_test.dart @@ -415,6 +415,34 @@ void main() async { expect(color, const Color(0xFF00FF00)); }); + // For an explaination of the problem see https://github.com/flutter/flutter/issues/163302 . + test('ImageFilter.shader equality checks consider uniform values', () async { + if (!impellerEnabled) { + print('Skipped for Skia'); + return; + } + final FragmentProgram program = await FragmentProgram.fromAsset('filter_shader.frag.iplr'); + final FragmentShader shader = program.fragmentShader(); + final ImageFilter filter = ImageFilter.shader(shader); + + // The same shader is equal to itself. + expect(filter, filter); + expect(identical(filter, filter), true); + + final ImageFilter filter_2 = ImageFilter.shader(shader); + + // The different shader is equal as long as uniforms are identical. + expect(filter, filter_2); + expect(identical(filter, filter_2), false); + + // Not equal if uniforms change. + shader.setFloat(0, 1); + final ImageFilter filter_3 = ImageFilter.shader(shader); + + expect(filter, isNot(filter_3)); + expect(identical(filter, filter_3), false); + }); + if (impellerEnabled) { print('Skipped for Impeller - https://github.com/flutter/flutter/issues/122823'); return;