[ui] Fix ImageFilter.shader equality to consider uniform values. (#163348)

Fixes https://github.com/flutter/flutter/issues/163302

Framework widgets check for ImageFIlter.== to determine whether to mark
themselves dirty. The filter obejct needs to delegate its equality to
the underlying native filter so that uniform values are considered.
This commit is contained in:
Jonah Williams 2025-02-24 11:01:55 -08:00 committed by GitHub
parent 35eaaaa3d0
commit 1e2583eff2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 40 additions and 1 deletions

View File

@ -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) \

View File

@ -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<Bool Function(Handle, Handle)>(symbol: 'ImageFilter::equal')
external static bool _equals(_ImageFilter a, _ImageFilter b);
@override
int get hashCode => shader.hashCode;
}

View File

@ -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

View File

@ -36,6 +36,7 @@ class ImageFilter : public RefCountedDartWrappable<ImageFilter> {
void initColorFilter(ColorFilter* colorFilter);
void initComposeFilter(ImageFilter* outer, ImageFilter* inner);
void initShader(ReusableFragmentShader* shader);
bool equals(ImageFilter* a, ImageFilter* b);
const std::shared_ptr<DlImageFilter> filter(DlTileMode mode) const;

View File

@ -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;