Skip to content

Commit 1970bc9

Browse files
authored
cacheWidth cacheHeight support for canvaskit on web (#117423)
* cacheWidth cacheHeight support for web canvaskit * comments * clarifying comment for loadTestImageProvider class Co-authored-by: alanwutang11 <[email protected]>
1 parent 2a50236 commit 1970bc9

File tree

6 files changed

+108
-13
lines changed

6 files changed

+108
-13
lines changed

dev/bots/test.dart

+5
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,11 @@ Future<void> _runWebLongRunningTests() async {
11821182
() => _runWebE2eTest('capabilities_integration_canvaskit', buildMode: 'profile', renderer: 'canvaskit'),
11831183
() => _runWebE2eTest('capabilities_integration_html', buildMode: 'release', renderer: 'html'),
11841184

1185+
// This test doesn't do anything interesting w.r.t. rendering, so we don't run the full build mode x renderer matrix.
1186+
// CacheWidth and CacheHeight are only currently supported in CanvasKit mode, so we don't run the test in HTML mode.
1187+
() => _runWebE2eTest('cache_width_cache_height_integration', buildMode: 'debug', renderer: 'auto'),
1188+
() => _runWebE2eTest('cache_width_cache_height_integration', buildMode: 'profile', renderer: 'canvaskit'),
1189+
11851190
() => _runWebTreeshakeTest(),
11861191

11871192
() => _runFlutterDriverWebTest(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:ui' as ui;
7+
8+
import 'package:flutter/material.dart';
9+
import 'package:flutter_test/flutter_test.dart';
10+
import 'package:integration_test/integration_test.dart';
11+
12+
// This class allows loadBuffer, a protected method, to be called with a custom
13+
// DecoderBufferCallback function.
14+
class LoadTestImageProvider extends ImageProvider<Object> {
15+
LoadTestImageProvider(this.provider);
16+
17+
final ImageProvider provider;
18+
19+
ImageStreamCompleter testLoad(Object key, DecoderBufferCallback decode) {
20+
return provider.loadBuffer(key, decode);
21+
}
22+
23+
@override
24+
Future<Object> obtainKey(ImageConfiguration configuration) {
25+
throw UnimplementedError();
26+
}
27+
28+
@override
29+
ImageStreamCompleter loadBuffer(Object key, DecoderBufferCallback decode) {
30+
throw UnimplementedError();
31+
}
32+
}
33+
34+
void main() {
35+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
36+
37+
testWidgets('Image.network uses cacheWidth and cacheHeight', (WidgetTester tester) async {
38+
const int expectedCacheHeight = 9;
39+
const int expectedCacheWidth = 11;
40+
await tester.pumpAndSettle();
41+
42+
final Image image = Image.network(
43+
'assets/packages/flutter_gallery_assets/assets/icons/material/material.png',
44+
cacheHeight: 9,
45+
cacheWidth: 11,
46+
);
47+
48+
bool called = false;
49+
50+
Future<ui.Codec> decode(ui.ImmutableBuffer buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling = false}) {
51+
expect(cacheHeight, expectedCacheHeight);
52+
expect(cacheWidth, expectedCacheWidth);
53+
expect(allowUpscaling, false);
54+
called = true;
55+
return PaintingBinding.instance.instantiateImageCodecFromBuffer(buffer, cacheWidth: cacheWidth, cacheHeight: cacheHeight, allowUpscaling: allowUpscaling);
56+
}
57+
58+
final ImageProvider resizeImage = image.image;
59+
expect(image.image, isA<ResizeImage>());
60+
61+
final LoadTestImageProvider testProvider = LoadTestImageProvider(image.image);
62+
final ImageStreamCompleter streamCompleter = testProvider.testLoad(await resizeImage.obtainKey(ImageConfiguration.empty), decode);
63+
64+
final Completer<void> completer = Completer<void>();
65+
int? imageInfoCachedWidth;
66+
int? imageInfoCachedHeight;
67+
streamCompleter.addListener(ImageStreamListener((ImageInfo imageInfo, bool syncCall) {
68+
imageInfoCachedWidth = imageInfo.image.width;
69+
imageInfoCachedHeight = imageInfo.image.height;
70+
completer.complete();
71+
}));
72+
await completer.future;
73+
74+
expect(imageInfoCachedHeight, isNotNull);
75+
expect(imageInfoCachedHeight, expectedCacheHeight);
76+
expect(imageInfoCachedWidth, isNotNull);
77+
expect(imageInfoCachedWidth, expectedCacheWidth);
78+
expect(called, true);
79+
});
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:integration_test/integration_test_driver.dart' as test;
6+
7+
Future<void> main() async => test.integrationDriver();

packages/flutter/lib/src/painting/_network_image_web.dart

+9-8
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,7 @@ class NetworkImage
103103
return collector;
104104
}
105105

106-
// TODO(garyq): We should eventually support custom decoding of network images on Web as
107-
// well, see https://github.com/flutter/flutter/issues/42789.
108-
//
109-
// Web does not support decoding network images to a specified size. The decode parameter
106+
// Html renderer does not support decoding network images to a specified size. The decode parameter
110107
// here is ignored and the web-only `ui.webOnlyInstantiateImageCodecFromUrl` will be used
111108
// directly in place of the typical `instantiateImageCodec` method.
112109
Future<ui.Codec> _loadAsync(
@@ -119,18 +116,22 @@ class NetworkImage
119116

120117
final Uri resolved = Uri.base.resolve(key.url);
121118

119+
final bool containsNetworkImageHeaders = key.headers?.isNotEmpty ?? false;
120+
122121
// We use a different method when headers are set because the
123122
// `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers.
124-
if (key.headers?.isNotEmpty ?? false) {
123+
if (isCanvasKit || containsNetworkImageHeaders) {
125124
final Completer<DomXMLHttpRequest> completer =
126125
Completer<DomXMLHttpRequest>();
127126
final DomXMLHttpRequest request = httpRequestFactory();
128127

129128
request.open('GET', key.url, true);
130129
request.responseType = 'arraybuffer';
131-
key.headers!.forEach((String header, String value) {
132-
request.setRequestHeader(header, value);
133-
});
130+
if (containsNetworkImageHeaders) {
131+
key.headers!.forEach((String header, String value) {
132+
request.setRequestHeader(header, value);
133+
});
134+
}
134135

135136
request.addEventListener('load', allowInterop((DomEvent e) {
136137
final int? status = request.status;

packages/flutter/lib/src/painting/image_provider.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -901,9 +901,10 @@ class ResizeImage extends ImageProvider<ResizeImageKey> {
901901
/// The image will be cached regardless of cache headers from the server.
902902
///
903903
/// When a network image is used on the Web platform, the `cacheWidth` and
904-
/// `cacheHeight` parameters of the [DecoderCallback] are ignored as the Web
905-
/// engine delegates image decoding of network images to the Web, which does
906-
/// not support custom decode sizes.
904+
/// `cacheHeight` parameters of the [DecoderCallback] are only supported when the
905+
/// application is running with the CanvasKit renderer. When the application is using
906+
/// the HTML renderer, the web engine delegates image decoding of network images to the Web,
907+
/// which does not support custom decode sizes.
907908
///
908909
/// See also:
909910
///

packages/flutter/lib/src/widgets/image.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,9 @@ typedef ImageErrorWidgetBuilder = Widget Function(
288288
/// memory usage of [ImageCache].
289289
///
290290
/// In the case where a network image is used on the Web platform, the
291-
/// `cacheWidth` and `cacheHeight` parameters are ignored as the Web engine
292-
/// delegates image decoding of network images to the Web, which does not support
291+
/// `cacheWidth` and `cacheHeight` parameters are only supported when the application is
292+
/// running with the CanvasKit renderer. When the application is using the HTML renderer,
293+
/// the web engine delegates image decoding of network images to the Web, which does not support
293294
/// custom decode sizes.
294295
///
295296
/// See also:

0 commit comments

Comments
 (0)