Fix ImageInfo.isCloneOf to correctly compare scale values (fixes #184626)#184643
Conversation
There was a problem hiding this comment.
Code Review
This pull request fixes a bug in ImageInfo.isCloneOf where the scale property was incorrectly compared against itself instead of the other object's scale. Unit tests were added to verify the fix. The review feedback suggests using addTearDown for resource disposal in the new tests to ensure cleanup even if assertions fail, preventing potential memory leaks.
|
@Hari-07, I apologize for the unrelated commit that was accidentally pushed to this branch. I have reverted it in the latest commit. This PR now only contains the intended changes for the Since the accidental commit may have dismissed your previous approval, I'd appreciate it if you could review the PR again at your convenience. Thank you! |
There was a problem hiding this comment.
Code Review
This pull request corrects a logic error in the ImageInfo.isCloneOf method by ensuring the scale property is compared against the other object's scale instead of itself. It also introduces unit tests to verify the method's behavior when scales differ and when all properties match. I have no feedback to provide.
justinmc
left a comment
There was a problem hiding this comment.
LGTM 👍 . Thanks for fixing this! Very clear bug now that it's pointed out. I hope this didn't cause any problems for anyone in the 2+ years it's been in the framework...
| final imageInfo1 = ImageInfo(image: image.clone()); | ||
| addTearDown(imageInfo1.dispose); | ||
| final imageInfo2 = ImageInfo(image: image.clone()); |
There was a problem hiding this comment.
Nit: Would it be more clear if you added a matching scale: 2.0 or something to these?
There was a problem hiding this comment.
Right! Adding the matching scale: 2.0 to both ImageInfo objects makes the test much clearer. I've updated both lines 1117 and 1119. Thanks for the suggestion!
|
autosubmit label was removed for flutter/flutter/184643, because The base commit of the PR is older than 7 days and can not be merged. Please merge the latest changes from the main into this branch and resubmit the PR. |
|
autosubmit label was removed for flutter/flutter/184643, because - The status or check suite ci.yaml validation has failed. Please fix the issues identified (or deflake) before re-applying this label. |
|
@Hari-07, Can you please add auto submit label if everything is okay? I think this PR is ready to be merged. |
|
This appears to have closed the tree in a sneaky, delayed time-bomb sort of way. The fix itself looks good but the tests are (surprisingly and not at all obviously) non-hermetic. Specifically, the
See the code and the note in the docs here: flutter/packages/flutter_test/lib/src/image.dart Lines 29 to 48 in 7e31a5b The random seed for the tests is just the date, and it changed from Fails with today's seed: bin/flutter test --test-randomize-ordering-seed=20260417 --track-widget-creation ./packages/flutter/test/painting/image_stream_test.dartPasses with yesterday's seed: bin/flutter test --test-randomize-ordering-seed=20260416 --track-widget-creation ./packages/flutter/test/painting/image_stream_test.dartThis is a super subtle bug; it was missed by 4 long-time Flutter experts and I 100% guarantee I would have missed this too in review. Edit: I've added a patch that should fix this for you below. Patch that in and you should be able to reland the fix. There are probably other ways you could fix it too, but I verified locally that it "works for me" :) |
|
Reason for revert: tests added are order dependent and break depending on random seed. |
|
I poked around at this a little. Instead of calling Something like this: diff --git a/packages/flutter/test/painting/image_stream_test.dart b/packages/flutter/test/painting/image_stream_test.dart
index cebe89ace0..46e9138b80 100644
--- a/packages/flutter/test/painting/image_stream_test.dart
+++ b/packages/flutter/test/painting/image_stream_test.dart
@@ -1096,7 +1096,7 @@
});
testWidgets('ImageInfo.isCloneOf returns false when scales differ', (WidgetTester tester) async {
- final Image image = await createTestImage(width: 10, height: 10);
+ final Image image = image20x10.clone();
addTearDown(image.dispose);
final imageInfo1 = ImageInfo(image: image.clone());
@@ -1111,7 +1111,7 @@
testWidgets('ImageInfo.isCloneOf returns true when all properties match', (
WidgetTester tester,
) async {
- final Image image = await createTestImage(width: 10, height: 10);
+ final Image image = image20x10.clone();
addTearDown(image.dispose);
final imageInfo1 = ImageInfo(image: image.clone(), scale: 2.0); |
|
Sorry about the revert, everyone. :( /cc @Istiak-Ahmed78 to trigger a notification just in case. |
…ixes #184626) (#184643)" (#185203) <!-- start_original_pr_link --> Reverts: #184643 <!-- end_original_pr_link --> <!-- start_initiating_author --> Initiated by: cbracken <!-- end_initiating_author --> <!-- start_revert_reason --> Reason for reverting: tests added are order dependent and break depending on random seed. <!-- end_revert_reason --> <!-- start_original_pr_author --> Original PR Author: Istiak-Ahmed78 <!-- end_original_pr_author --> <!-- start_reviewers --> Reviewed By: {justinmc, QuncCccccc, chunhtai, Piinks} <!-- end_reviewers --> <!-- start_revert_body --> This change reverts the following previous change: Fixes a bug in `ImageInfo.isCloneOf` where the `scale` property was being compared to itself (`scale == scale`) instead of comparing against the other object's scale (`other.scale == scale`). This caused the method to always return `true` for scale comparisons, incorrectly identifying `ImageInfo` objects with different scales as clones. ## Root Cause In `packages/flutter/lib/src/painting/image_stream.dart`, line 104: ```dart // Before (bug) return other.image.isCloneOf(image) && scale == scale && other.debugLabel == debugLabel; // After (fix) return other.image.isCloneOf(image) && other.scale == scale && other.debugLabel == debugLabel; ``` The `scale == scale` comparison is a typo that always evaluates to `true`, making the scale check ineffective. ## Impact This bug could cause: - Images not repainting when their scale changes - Incorrect caching behavior in `ImageCache` - Visual bugs where images render at wrong sizes - `RawImage` and `DecorationImage` widgets skipping necessary repaints ## Tests Added two regression tests to `packages/flutter/test/painting/image_stream_test.dart`: 1. `ImageInfo.isCloneOf returns false when scales differ` - verifies the fix 2. `ImageInfo.isCloneOf returns true when all properties match` - verifies correct behavior ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added/updated tests for this change. - [x] I used self-descriptive commit messages. Fixes #184626 <!-- end_revert_body --> Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com>
|
Damn thats a sneaky one |
|
This is subtle enough it'll probably happen again. We should probably have some automated means of catching these. |
"Wow! What a catch. I didn't think of this. Whatever, |
If you resend your original PR but make the changes from my diff above, the patch should be good to land. I tested that locally to confirm. |
flutter/flutter@31f1802...8e8a194 2026-04-17 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Fix ImageInfo.isCloneOf to correctly compare scale values (fixes #184626) (#184643)" (flutter/flutter#185203) 2026-04-17 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Roll Fuchsia Test Scripts from R2EllDf4DgBXVNuiN... to dQ4PjIJB5kZFU8Y32... (#185192)" (flutter/flutter#185199) 2026-04-17 chris@bracken.jp [iOS] Migrate FlutterLaunchEngine to Swift (flutter/flutter#185151) 2026-04-17 116356835+AbdeMohlbi@users.noreply.github.com Remove unused `FlutterRunArguments.java` file (flutter/flutter#184160) 2026-04-17 engine-flutter-autoroll@skia.org Roll Fuchsia Test Scripts from R2EllDf4DgBXVNuiN... to dQ4PjIJB5kZFU8Y32... (flutter/flutter#185192) 2026-04-17 pewpewstol@gmail.com [Impeller] Fix morphology filter asymmetric dilation/erosion (flutter/flutter#184913) 2026-04-17 nate.w5687@gmail.com `AnimationStyle` methods (flutter/flutter#182333) 2026-04-17 karan@solvejet.net Fix _scheduleSystemFontsUpdate assertion during non-idle scheduler phase (flutter/flutter#184332) 2026-04-17 154381524+flutteractionsbot@users.noreply.github.com Revert "Unpin sdk package dependencies" (flutter/flutter#185186) 2026-04-16 116356835+AbdeMohlbi@users.noreply.github.com Clarify why the `child` is nullable in `AnimatedTransitionBuilder` (flutter/flutter#182995) 2026-04-16 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from IdBT8fSMYrYSip65j... to di3JdYrdE9OFu8Iyl... (flutter/flutter#185173) 2026-04-16 1063596+reidbaker@users.noreply.github.com Add dart_skills_lint to dev/tool with test and update readme instructions for new skills authors (flutter/flutter#185033) 2026-04-16 flar@google.com [Impeller] Provide std::optional getter for stroke property (flutter/flutter#185112) 2026-04-16 katelovett@google.com Validate itemExtent with geometry in RenderSliverFixedExtentBoxAdaptor (flutter/flutter#185159) 2026-04-16 152433210+mozammal-hossain@users.noreply.github.com [iOS] Clarify provisioning profile error instructions (flutter/flutter#184051) 2026-04-16 bkonyi@google.com [Widget Preview] Fix flaky integration test timeout during flutter clean (flutter/flutter#184991) 2026-04-16 engine-flutter-autoroll@skia.org Roll Dart SDK from fbddcbe0cd96 to 7c2564c18770 (2 revisions) (flutter/flutter#185143) 2026-04-16 sigurdm@google.com Unpin sdk package dependencies (flutter/flutter#184821) 2026-04-16 68919043+Istiak-Ahmed78@users.noreply.github.com Fix ImageInfo.isCloneOf to correctly compare scale values (fixes #184626) (flutter/flutter#184643) 2026-04-16 engine-flutter-autoroll@skia.org Roll Skia from 391cdbe3ffe9 to d8415c5d7b91 (2 revisions) (flutter/flutter#185141) 2026-04-16 154381524+flutteractionsbot@users.noreply.github.com Sync CHANGELOG.md from stable (flutter/flutter#185166) 2026-04-16 154381524+flutteractionsbot@users.noreply.github.com Revert "Move widget_preview_scaffold into pub workspace" (flutter/flutter#185164) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC boetger@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
|
@Istiak-Ahmed78 Since this PR was previously merged you'll need to send a new one. Maybe easiest is to sync your master local branch to tip-of-tree flutter master branch, then something like: # Check out new branch.
% git checkout -b fix-iscloneof
# Revert my revert.
% git revert 8e8a194923dc579beb7fe83b363903e30d79243c
# Patch in the fix described above in comment
# https://github.com/flutter/flutter/pull/184643#issuecomment-4267815665
% [your edits here]
# Squash the fix into the previous commit and clean up the
# commit description so it's not revert: revert: ...
% git add packages/flutter/test/painting/image_stream_test.dart
% git commit --amend
% git push -u origin fix-iscloneofthen send the new PR from the GitHub web UI. Add @justinmc and the original reviewers back for the reland and it should go pretty quick :) |
Thank you for the suggestion. However, I will be unavailable at my desk for a day. If it’s not urgent, I’ll be able to provide feedback after a day. Sorry for the inconvenience. |
…alues (fixes flutter#184626) (flutter#184643)" (flutter#185203)" This reverts commit 8e8a194.
…185254) This PR fixes the non-hermetic tests in `ImageInfo.isCloneOf` by separating real async operations from the FakeAsync zone. ### Problem The original tests were calling `await createTestImage()` directly inside `testWidgets()`, which runs in a FakeAsync zone. This caused: - Non-deterministic failures dependent on random seed - Timing-dependent issues - Non-hermetic tests ### Solution Move the real async work (`createTestImage()`) to `setUp()` (outside FakeAsync) and use pre-created images in the test cases. ### Changes - Added `setUp()` to create test images before tests run - Replaced `await createTestImage()` with `image20x10.clone()` in test cases - Ensures tests are hermetic and deterministic ### Related Issues Reland of flutter#184643 (which was reverted due to the FakeAsync issue) Fixes the issue identified in the revert commit: 8e8a194 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] page, which explains my responsibilities. - [x] I read and followed the [relevant style guides] and ran [the auto-formatter]. - [x] I signed the [CLA]. - [x] The title of the PR starts with the name of the package surrounded by square brackets, e.g. `[shared_preferences]` - [x] I [linked to at least one issue that this PR fixes] in the description above. - [x] I followed [the version and CHANGELOG instructions], using [semantic versioning] and the [repository CHANGELOG style], or I have commented below to indicate which documented exception this PR falls under[^1]. - [x] I updated/added any relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or I have commented below to indicate which [test exemption] this PR falls under[^1]. - [x] All existing and new tests are passing.
…r#11523) flutter/flutter@31f1802...8e8a194 2026-04-17 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Fix ImageInfo.isCloneOf to correctly compare scale values (fixes #184626) (#184643)" (flutter/flutter#185203) 2026-04-17 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Roll Fuchsia Test Scripts from R2EllDf4DgBXVNuiN... to dQ4PjIJB5kZFU8Y32... (#185192)" (flutter/flutter#185199) 2026-04-17 chris@bracken.jp [iOS] Migrate FlutterLaunchEngine to Swift (flutter/flutter#185151) 2026-04-17 116356835+AbdeMohlbi@users.noreply.github.com Remove unused `FlutterRunArguments.java` file (flutter/flutter#184160) 2026-04-17 engine-flutter-autoroll@skia.org Roll Fuchsia Test Scripts from R2EllDf4DgBXVNuiN... to dQ4PjIJB5kZFU8Y32... (flutter/flutter#185192) 2026-04-17 pewpewstol@gmail.com [Impeller] Fix morphology filter asymmetric dilation/erosion (flutter/flutter#184913) 2026-04-17 nate.w5687@gmail.com `AnimationStyle` methods (flutter/flutter#182333) 2026-04-17 karan@solvejet.net Fix _scheduleSystemFontsUpdate assertion during non-idle scheduler phase (flutter/flutter#184332) 2026-04-17 154381524+flutteractionsbot@users.noreply.github.com Revert "Unpin sdk package dependencies" (flutter/flutter#185186) 2026-04-16 116356835+AbdeMohlbi@users.noreply.github.com Clarify why the `child` is nullable in `AnimatedTransitionBuilder` (flutter/flutter#182995) 2026-04-16 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from IdBT8fSMYrYSip65j... to di3JdYrdE9OFu8Iyl... (flutter/flutter#185173) 2026-04-16 1063596+reidbaker@users.noreply.github.com Add dart_skills_lint to dev/tool with test and update readme instructions for new skills authors (flutter/flutter#185033) 2026-04-16 flar@google.com [Impeller] Provide std::optional getter for stroke property (flutter/flutter#185112) 2026-04-16 katelovett@google.com Validate itemExtent with geometry in RenderSliverFixedExtentBoxAdaptor (flutter/flutter#185159) 2026-04-16 152433210+mozammal-hossain@users.noreply.github.com [iOS] Clarify provisioning profile error instructions (flutter/flutter#184051) 2026-04-16 bkonyi@google.com [Widget Preview] Fix flaky integration test timeout during flutter clean (flutter/flutter#184991) 2026-04-16 engine-flutter-autoroll@skia.org Roll Dart SDK from fbddcbe0cd96 to 7c2564c18770 (2 revisions) (flutter/flutter#185143) 2026-04-16 sigurdm@google.com Unpin sdk package dependencies (flutter/flutter#184821) 2026-04-16 68919043+Istiak-Ahmed78@users.noreply.github.com Fix ImageInfo.isCloneOf to correctly compare scale values (fixes #184626) (flutter/flutter#184643) 2026-04-16 engine-flutter-autoroll@skia.org Roll Skia from 391cdbe3ffe9 to d8415c5d7b91 (2 revisions) (flutter/flutter#185141) 2026-04-16 154381524+flutteractionsbot@users.noreply.github.com Sync CHANGELOG.md from stable (flutter/flutter#185166) 2026-04-16 154381524+flutteractionsbot@users.noreply.github.com Revert "Move widget_preview_scaffold into pub workspace" (flutter/flutter#185164) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC boetger@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Fixes a bug in
ImageInfo.isCloneOfwhere thescaleproperty was being compared to itself (scale == scale) instead of comparing against the other object's scale (other.scale == scale). This caused the method to always returntruefor scale comparisons, incorrectly identifyingImageInfoobjects with different scales as clones.Root Cause
In
packages/flutter/lib/src/painting/image_stream.dart, line 104:The
scale == scalecomparison is a typo that always evaluates totrue, making the scale check ineffective.Impact
This bug could cause:
ImageCacheRawImageandDecorationImagewidgets skipping necessary repaintsTests
Added two regression tests to
packages/flutter/test/painting/image_stream_test.dart:ImageInfo.isCloneOf returns false when scales differ- verifies the fixImageInfo.isCloneOf returns true when all properties match- verifies correct behaviorPre-launch Checklist
Fixes #184626