Repository navigation
feat(web): implement image decoding throttling for HTML images - #186032
Merged
auto-submit[bot] merged 7 commits intoMay 7, 2026
Merged
auto-submit[bot] merged 7 commits into
auto-submit[bot] merged 7 commits into
Conversation
Introduces a centralized ImageDecodingManager to coordinate the concurrency and memory footprint of HTMLImageElement.decode() calls. This prevents resource exhaustion and silent crashes on browsers like iOS Safari when handling high volumes of large image assets. - Added ImageDecodingManager to enforce safety limits (20 decodes / 128MB). - Refactored HtmlImageElementCodec to use a multi-phase throttled decode. - Implemented aggressive resource reclamation by clearing img.src on disposal. - Added unit tests for the manager and updated codec integration tests.
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces an ImageDecodingManager to throttle HTMLImageElement.decode() calls, addressing resource exhaustion and crashes on browsers like iOS Safari. The HtmlImageElementCodec is refactored into a multi-phase asynchronous process that manages concurrency and memory limits through a centralized FIFO queue. Feedback focuses on improving resource reclamation by clearing image sources during failures and enhancing error reporting by wrapping decoding operations in descriptive exceptions.
mdebbar
previously approved these changes
May 5, 2026
mdebbar
approved these changes
May 7, 2026
This was referenced May 8, 2026
This was referenced May 8, 2026
This was referenced May 9, 2026
jhbruhn
added a commit
to jhbruhn/zugvogel
that referenced
this pull request
Aug 21, 2026
…n Chrome 0ec9641 hat dieses Repo auf 3.47.1 gehoben, "in lockstep with both apps". Das war die falsche Richtung: 3.47 hört auf Firefox und Safari (iPhone eingeschlossen) still auf, Bilder zu zeichnen — ein Thumbnail rendert einmal und bleibt bei jedem späteren Repaint leer, bis die Seite neu geladen wird. CachedFileImage ist die Stelle, an der es auftaucht, also erben es beide Apps, und nichts in diesem Repo kann es reparieren. Also fordern die Pubspecs hier wieder `^3.44.0`. Das ist der Punkt und nicht bloß Kosmetik: solange sie ^3.47.0 fordern, bricht der NÄCHSTE Pin-Bump den Build jeder App, die auf 3.44 zurück ist — federfall entkam nur, weil sein Pin älter ist als 0ec9641, und eiermann entkam gar nicht. Vier Stellen, alle zusammen: die zwei Pubspecs, CI, und die Versionszeilen in README und CLAUDE.md. Dazu zurück, was 0ec9641 am Code geändert hatte: auf 3.44 sind die Animationsfutures nicht `@awaitNotRequired`, also greift wieder `discarded_futures` und die vier `unawaited(...)` müssen stehen (mit `dart:async` in offline_notice.dart). Gemessen: ohne sie meldet `flutter analyze` genau diese vier Stellen. Die AUSFÜHRLICHE Analyse des Fehlers in CLAUDE.md — skwasm gegen CanvasKit, flutter.js' wasmAllowList, flutter/flutter#186032 und der Fix in #188573 — stammt aus einer parallelen Sitzung. Ihr Commit ging bei einem Reset in diesem Arbeitsbaum verloren; der Text ist aus dem noch vorhandenen Objekt wiederhergestellt und steht hier unverändert, bis auf den Schlussabsatz: die Falle, die er beschreibt ("die nächste Pin-Bump bricht federfalls Build"), ist genau die, die dieser Commit zumacht. Verifiziert auf 3.44.3: analyze sauber, 127 + 68 + 50 + 48 Tests grün, `dart format --set-exit-if-changed` sauber. Ziel bleibt 3.48 (flutter/flutter#188573). Auf 3.47 wird nicht gewartet. Co-Authored-By: Claude Opus 5 <[email protected]>
jhbruhn
added a commit
to jhbruhn/federfall
that referenced
this pull request
Aug 21, 2026
This reverts commit 7da167f. 3.47 silently loses images on Firefox and Safari — iPhone included. A thumbnail paints once and then draws nothing on any later repaint, until a full page reload. Chrome is unaffected, which is what made it easy to miss. Two gates decide it, and Firefox/Safari fail both. `--wasm` ships skwasm plus a CanvasKit fallback, and flutter.js's default wasmAllowList is {blink:true, gecko:false, webkit:false} — so only Chrome runs skwasm, which copies decoded bytes eagerly into an ImageBitmap and owns them. Everything else falls back to CanvasKit, where an image decoded from bytes is a LAZY SkImage over the <img> element the codec made, re-uploading its texture on every paint. flutter/flutter#186032 then taught the engine to reclaim that element aggressively — `ImageElementImageSource._doClose()` went from a deliberate no-op ("let the browser garbage collect it") to `imageElement.src = ''`. Its stated purpose was to stop iOS Safari crashing on many large images, so the regression lands squarely in the case the change was written for. Confirmed by A/B, not by reading: the same commit built `--wasm --release` against the same backend, served with the same COOP/COEP headers, breaks on 3.47.1 and works on 3.44.3. Three app-side workarounds were tried and all failed — clamping the decode below the 200x200 thumb, raising the ImageCache ceilings, and waiting out the new 30s decode timeout — so this is not something federfall can hold at arm's length. The exact defect is still unpinned; a lazy texture whose source is freed on refcount-zero is the suspect, but ImageBitmapImageSource frees its source the same way and is fine on both versions, so that story is incomplete. 3.48 fixes it. flutter/flutter#188573 moves image decoding and lifetime onto the shared frontend skwasm already used, and 3.48.0-0.2.pre renders correctly in Firefox on the same harness. It is a refactor, not a targeted fix, so a 3.47.2 backport is not worth waiting for — and 3.47 offered nothing this app wanted anyway, only higher Java and iOS floors. So: back to 3.44.3, and go straight to 3.48 when it is stable (the cadence puts that around November). Co-Authored-By: Claude Opus 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces a centralized ImageDecodingManager to coordinate the concurrency and memory footprint of
HTMLImageElement.decode()calls. This prevents resource exhaustion and silent crashes on browsers like iOS Safari when handling high volumes of large image assets.Largely alleviates #152709
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.