Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit e6528cd

Browse files
committed
[web] Dispose a temporary image that may be created by instantiateImageCodecWithSize
Fixes flutter/flutter#147066
1 parent 30e215f commit e6528cd

File tree

2 files changed

+34
-8
lines changed

2 files changed

+34
-8
lines changed

lib/web_ui/lib/src/engine/image_decoder.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,15 +229,16 @@ class ResizingCodec implements ui.Codec {
229229
@override
230230
Future<ui.FrameInfo> getNextFrame() async {
231231
final ui.FrameInfo frameInfo = await delegate.getNextFrame();
232-
return AnimatedImageFrameInfo(
233-
frameInfo.duration,
234-
scaleImage(
232+
final ui.Image scaledImage = scaleImage(
235233
frameInfo.image,
236234
targetWidth: targetWidth,
237235
targetHeight: targetHeight,
238236
allowUpscaling: allowUpscaling,
239-
),
240237
);
238+
if (!identical(frameInfo.image, scaledImage)) {
239+
frameInfo.image.dispose();
240+
}
241+
return AnimatedImageFrameInfo(frameInfo.duration, scaledImage);
241242
}
242243

243244
ui.Image scaleImage(

lib/web_ui/test/canvaskit/image_test.dart

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ void main() {
2121
void testMain() {
2222
setUpCanvasKitTest();
2323

24+
tearDown(() {
25+
ui.Image.onCreate = null;
26+
ui.Image.onDispose = null;
27+
});
28+
2429
test('toImage succeeds', () async {
2530
final ui.Image image = await _createImage();
2631
expect(image.runtimeType.toString(), equals('CkImage'));
@@ -44,8 +49,6 @@ void testMain() {
4449

4550
expect(onCreateInvokedCount, 2);
4651
expect(createdImage, image2);
47-
48-
ui.Image.onCreate = null;
4952
});
5053

5154
test('dispose() invokes onDispose once', () async {
@@ -65,8 +68,6 @@ void testMain() {
6568

6669
expect(onDisposeInvokedCount, 2);
6770
expect(disposedImage, image2);
68-
69-
ui.Image.onDispose = null;
7071
});
7172

7273
test('fetchImage fetches image in chunks', () async {
@@ -105,6 +106,30 @@ void testMain() {
105106
final BitmapSize? size = scaledImageSize(200, 100, 600, null);
106107
expect(size?.width, 600);
107108
expect(size?.height, 300);
109+
}
110+
111+
test('instantiateImageCodecWithSize disposes temporary image', () async {
112+
final Set<ui.Image> activeImages = <ui.Image>{};
113+
ui.Image.onCreate = activeImages.add;
114+
ui.Image.onDispose = activeImages.remove;
115+
116+
final ui.Image image = await _createImage();
117+
final ByteData? imageData = await image.toByteData(format: ui.ImageByteFormat.png);
118+
final ui.ImmutableBuffer imageBuffer = await ui.ImmutableBuffer.fromUint8List(imageData!.buffer.asUint8List());
119+
image.dispose();
120+
121+
final ui.Codec codec = await ui.instantiateImageCodecWithSize(
122+
imageBuffer,
123+
getTargetSize: (w, h) => ui.TargetImageSize(width: w ~/ 2, height: h ~/ 2)
124+
);
125+
final ui.FrameInfo frameInfo = await codec.getNextFrame();
126+
127+
expect(activeImages.length, 1);
128+
129+
frameInfo.image.dispose();
130+
codec.dispose();
131+
132+
expect(activeImages.length, 0);
108133
});
109134
}
110135

0 commit comments

Comments
 (0)