cacheWidth cacheHeight support for canvaskit on web (#117423)
* cacheWidth cacheHeight support for web canvaskit * comments * clarifying comment for loadTestImageProvider class Co-authored-by: alanwutang11 <alpwu@google.com>
This commit is contained in:
parent
2a502363e1
commit
1970bc919b
@ -1182,6 +1182,11 @@ Future<void> _runWebLongRunningTests() async {
|
||||
() => _runWebE2eTest('capabilities_integration_canvaskit', buildMode: 'profile', renderer: 'canvaskit'),
|
||||
() => _runWebE2eTest('capabilities_integration_html', buildMode: 'release', renderer: 'html'),
|
||||
|
||||
// This test doesn't do anything interesting w.r.t. rendering, so we don't run the full build mode x renderer matrix.
|
||||
// CacheWidth and CacheHeight are only currently supported in CanvasKit mode, so we don't run the test in HTML mode.
|
||||
() => _runWebE2eTest('cache_width_cache_height_integration', buildMode: 'debug', renderer: 'auto'),
|
||||
() => _runWebE2eTest('cache_width_cache_height_integration', buildMode: 'profile', renderer: 'canvaskit'),
|
||||
|
||||
() => _runWebTreeshakeTest(),
|
||||
|
||||
() => _runFlutterDriverWebTest(
|
||||
|
@ -0,0 +1,80 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
// This class allows loadBuffer, a protected method, to be called with a custom
|
||||
// DecoderBufferCallback function.
|
||||
class LoadTestImageProvider extends ImageProvider<Object> {
|
||||
LoadTestImageProvider(this.provider);
|
||||
|
||||
final ImageProvider provider;
|
||||
|
||||
ImageStreamCompleter testLoad(Object key, DecoderBufferCallback decode) {
|
||||
return provider.loadBuffer(key, decode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Object> obtainKey(ImageConfiguration configuration) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
ImageStreamCompleter loadBuffer(Object key, DecoderBufferCallback decode) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
testWidgets('Image.network uses cacheWidth and cacheHeight', (WidgetTester tester) async {
|
||||
const int expectedCacheHeight = 9;
|
||||
const int expectedCacheWidth = 11;
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Image image = Image.network(
|
||||
'assets/packages/flutter_gallery_assets/assets/icons/material/material.png',
|
||||
cacheHeight: 9,
|
||||
cacheWidth: 11,
|
||||
);
|
||||
|
||||
bool called = false;
|
||||
|
||||
Future<ui.Codec> decode(ui.ImmutableBuffer buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling = false}) {
|
||||
expect(cacheHeight, expectedCacheHeight);
|
||||
expect(cacheWidth, expectedCacheWidth);
|
||||
expect(allowUpscaling, false);
|
||||
called = true;
|
||||
return PaintingBinding.instance.instantiateImageCodecFromBuffer(buffer, cacheWidth: cacheWidth, cacheHeight: cacheHeight, allowUpscaling: allowUpscaling);
|
||||
}
|
||||
|
||||
final ImageProvider resizeImage = image.image;
|
||||
expect(image.image, isA<ResizeImage>());
|
||||
|
||||
final LoadTestImageProvider testProvider = LoadTestImageProvider(image.image);
|
||||
final ImageStreamCompleter streamCompleter = testProvider.testLoad(await resizeImage.obtainKey(ImageConfiguration.empty), decode);
|
||||
|
||||
final Completer<void> completer = Completer<void>();
|
||||
int? imageInfoCachedWidth;
|
||||
int? imageInfoCachedHeight;
|
||||
streamCompleter.addListener(ImageStreamListener((ImageInfo imageInfo, bool syncCall) {
|
||||
imageInfoCachedWidth = imageInfo.image.width;
|
||||
imageInfoCachedHeight = imageInfo.image.height;
|
||||
completer.complete();
|
||||
}));
|
||||
await completer.future;
|
||||
|
||||
expect(imageInfoCachedHeight, isNotNull);
|
||||
expect(imageInfoCachedHeight, expectedCacheHeight);
|
||||
expect(imageInfoCachedWidth, isNotNull);
|
||||
expect(imageInfoCachedWidth, expectedCacheWidth);
|
||||
expect(called, true);
|
||||
});
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:integration_test/integration_test_driver.dart' as test;
|
||||
|
||||
Future<void> main() async => test.integrationDriver();
|
@ -103,10 +103,7 @@ class NetworkImage
|
||||
return collector;
|
||||
}
|
||||
|
||||
// TODO(garyq): We should eventually support custom decoding of network images on Web as
|
||||
// well, see https://github.com/flutter/flutter/issues/42789.
|
||||
//
|
||||
// Web does not support decoding network images to a specified size. The decode parameter
|
||||
// Html renderer does not support decoding network images to a specified size. The decode parameter
|
||||
// here is ignored and the web-only `ui.webOnlyInstantiateImageCodecFromUrl` will be used
|
||||
// directly in place of the typical `instantiateImageCodec` method.
|
||||
Future<ui.Codec> _loadAsync(
|
||||
@ -119,18 +116,22 @@ class NetworkImage
|
||||
|
||||
final Uri resolved = Uri.base.resolve(key.url);
|
||||
|
||||
final bool containsNetworkImageHeaders = key.headers?.isNotEmpty ?? false;
|
||||
|
||||
// We use a different method when headers are set because the
|
||||
// `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers.
|
||||
if (key.headers?.isNotEmpty ?? false) {
|
||||
if (isCanvasKit || containsNetworkImageHeaders) {
|
||||
final Completer<DomXMLHttpRequest> completer =
|
||||
Completer<DomXMLHttpRequest>();
|
||||
final DomXMLHttpRequest request = httpRequestFactory();
|
||||
|
||||
request.open('GET', key.url, true);
|
||||
request.responseType = 'arraybuffer';
|
||||
key.headers!.forEach((String header, String value) {
|
||||
request.setRequestHeader(header, value);
|
||||
});
|
||||
if (containsNetworkImageHeaders) {
|
||||
key.headers!.forEach((String header, String value) {
|
||||
request.setRequestHeader(header, value);
|
||||
});
|
||||
}
|
||||
|
||||
request.addEventListener('load', allowInterop((DomEvent e) {
|
||||
final int? status = request.status;
|
||||
|
@ -901,9 +901,10 @@ class ResizeImage extends ImageProvider<ResizeImageKey> {
|
||||
/// The image will be cached regardless of cache headers from the server.
|
||||
///
|
||||
/// When a network image is used on the Web platform, the `cacheWidth` and
|
||||
/// `cacheHeight` parameters of the [DecoderCallback] are ignored as the Web
|
||||
/// engine delegates image decoding of network images to the Web, which does
|
||||
/// not support custom decode sizes.
|
||||
/// `cacheHeight` parameters of the [DecoderCallback] are only supported when the
|
||||
/// application is running with the CanvasKit renderer. When the application is using
|
||||
/// the HTML renderer, the web engine delegates image decoding of network images to the Web,
|
||||
/// which does not support custom decode sizes.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
|
@ -288,8 +288,9 @@ typedef ImageErrorWidgetBuilder = Widget Function(
|
||||
/// memory usage of [ImageCache].
|
||||
///
|
||||
/// In the case where a network image is used on the Web platform, the
|
||||
/// `cacheWidth` and `cacheHeight` parameters are ignored as the Web engine
|
||||
/// delegates image decoding of network images to the Web, which does not support
|
||||
/// `cacheWidth` and `cacheHeight` parameters are only supported when the application is
|
||||
/// running with the CanvasKit renderer. When the application is using the HTML renderer,
|
||||
/// the web engine delegates image decoding of network images to the Web, which does not support
|
||||
/// custom decode sizes.
|
||||
///
|
||||
/// See also:
|
||||
|
Loading…
x
Reference in New Issue
Block a user