-
Notifications
You must be signed in to change notification settings - Fork 27.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separate web and io implementations of network image (#34112)
* add web and io implemenations of network and asset image * fix foundation import * update to remove extra asset image indirection * skip chunk test * address comments * disable non-functional test * disable all golden tests * address comments
- Loading branch information
1 parent
fd1291f
commit dfa39f3
Showing
7 changed files
with
216 additions
and
102 deletions.
There are no files selected for viewing
124 changes: 124 additions & 0 deletions
124
packages/flutter/lib/src/painting/_network_image_io.dart
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// Copyright 2019 The Chromium 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:io'; | ||
import 'dart:typed_data'; | ||
import 'dart:ui' as ui; | ||
|
||
import 'package:flutter/foundation.dart'; | ||
|
||
import 'binding.dart'; | ||
import 'debug.dart'; | ||
import 'image_provider.dart' as image_provider; | ||
import 'image_stream.dart'; | ||
|
||
/// The dart:io implemenation of [image_provider.NetworkImage]. | ||
class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage { | ||
/// Creates an object that fetches the image at the given URL. | ||
/// | ||
/// The arguments [url] and [scale] must not be null. | ||
const NetworkImage(this.url, { this.scale = 1.0, this.headers }) | ||
: assert(url != null), | ||
assert(scale != null); | ||
|
||
@override | ||
final String url; | ||
|
||
@override | ||
final double scale; | ||
|
||
@override | ||
final Map<String, String> headers; | ||
|
||
@override | ||
Future<NetworkImage> obtainKey(image_provider.ImageConfiguration configuration) { | ||
return SynchronousFuture<NetworkImage>(this); | ||
} | ||
|
||
@override | ||
ImageStreamCompleter load(image_provider.NetworkImage key) { | ||
// Ownership of this controller is handed off to [_loadAsync]; it is that | ||
// method's responsibility to close the controller's stream when the image | ||
// has been loaded or an error is thrown. | ||
final StreamController<ImageChunkEvent> chunkEvents = StreamController<ImageChunkEvent>(); | ||
|
||
return MultiFrameImageStreamCompleter( | ||
codec: _loadAsync(key, chunkEvents), | ||
chunkEvents: chunkEvents.stream, | ||
scale: key.scale, | ||
informationCollector: () { | ||
return <DiagnosticsNode>[ | ||
DiagnosticsProperty<image_provider.ImageProvider>('Image provider', this), | ||
DiagnosticsProperty<image_provider.NetworkImage>('Image key', key), | ||
]; | ||
}, | ||
); | ||
} | ||
|
||
// Do not access this field directly; use [_httpClient] instead. | ||
// We set `autoUncompress` to false to ensure that we can trust the value of | ||
// the `Content-Length` HTTP header. We automatically uncompress the content | ||
// in our call to [consolidateHttpClientResponseBytes]. | ||
static final HttpClient _sharedHttpClient = HttpClient()..autoUncompress = false; | ||
|
||
static HttpClient get _httpClient { | ||
HttpClient client = _sharedHttpClient; | ||
assert(() { | ||
if (debugNetworkImageHttpClientProvider != null) | ||
client = debugNetworkImageHttpClientProvider(); | ||
return true; | ||
}()); | ||
return client; | ||
} | ||
|
||
Future<ui.Codec> _loadAsync( | ||
NetworkImage key, | ||
StreamController<ImageChunkEvent> chunkEvents, | ||
) async { | ||
try { | ||
assert(key == this); | ||
|
||
final Uri resolved = Uri.base.resolve(key.url); | ||
final HttpClientRequest request = await _httpClient.getUrl(resolved); | ||
headers?.forEach((String name, String value) { | ||
request.headers.add(name, value); | ||
}); | ||
final HttpClientResponse response = await request.close(); | ||
if (response.statusCode != HttpStatus.ok) | ||
throw Exception('HTTP request failed, statusCode: ${response?.statusCode}, $resolved'); | ||
|
||
final Uint8List bytes = await consolidateHttpClientResponseBytes( | ||
response, | ||
onBytesReceived: (int cumulative, int total) { | ||
chunkEvents.add(ImageChunkEvent( | ||
cumulativeBytesLoaded: cumulative, | ||
expectedTotalBytes: total, | ||
)); | ||
}, | ||
); | ||
if (bytes.lengthInBytes == 0) | ||
throw Exception('NetworkImage is an empty file: $resolved'); | ||
|
||
return PaintingBinding.instance.instantiateImageCodec(bytes); | ||
} finally { | ||
chunkEvents.close(); | ||
} | ||
} | ||
|
||
@override | ||
bool operator ==(dynamic other) { | ||
if (other.runtimeType != runtimeType) | ||
return false; | ||
final NetworkImage typedOther = other; | ||
return url == typedOther.url | ||
&& scale == typedOther.scale; | ||
} | ||
|
||
@override | ||
int get hashCode => ui.hashValues(url, scale); | ||
|
||
@override | ||
String toString() => '$runtimeType("$url", scale: $scale)'; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright 2019 The Chromium 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/foundation.dart'; | ||
|
||
import 'image_provider.dart' as image_provider; | ||
import 'image_stream.dart'; | ||
|
||
/// The dart:html implemenation of [image_provider.NetworkImage]. | ||
class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage { | ||
/// Creates an object that fetches the image at the given URL. | ||
/// | ||
/// The arguments [url] and [scale] must not be null. | ||
const NetworkImage(this.url, {this.scale = 1.0, this.headers}) | ||
: assert(url != null), | ||
assert(scale != null); | ||
|
||
@override | ||
final String url; | ||
|
||
@override | ||
final double scale; | ||
|
||
@override | ||
final Map<String, String> headers; | ||
|
||
@override | ||
Future<NetworkImage> obtainKey(image_provider.ImageConfiguration configuration) { | ||
return SynchronousFuture<NetworkImage>(this); | ||
} | ||
|
||
@override | ||
ImageStreamCompleter load(image_provider.NetworkImage key) { | ||
return MultiFrameImageStreamCompleter( | ||
codec: _loadAsync(key), | ||
scale: key.scale, | ||
informationCollector: () { | ||
return <DiagnosticsNode>[ | ||
DiagnosticsProperty<image_provider.ImageProvider>('Image provider', this), | ||
DiagnosticsProperty<NetworkImage>('Image key', key), | ||
]; | ||
}, | ||
); | ||
} | ||
|
||
Future<ui.Codec> _loadAsync(NetworkImage key) async { | ||
assert(key == this); | ||
|
||
final Uri resolved = Uri.base.resolve(key.url); | ||
// This API only exists in the web engine implementation and is not | ||
// contained in the analyzer summary for Flutter. | ||
return ui.webOnlyInstantiateImageCodecFromUrl(resolved); // ignore: undefined_function | ||
} | ||
|
||
@override | ||
bool operator ==(dynamic other) { | ||
if (other.runtimeType != runtimeType) { | ||
return false; | ||
} | ||
final NetworkImage typedOther = other; | ||
return url == typedOther.url && scale == typedOther.scale; | ||
} | ||
|
||
@override | ||
int get hashCode => ui.hashValues(url, scale); | ||
|
||
@override | ||
String toString() => '$runtimeType("$url", scale: $scale)'; | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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