Unverified Commit 3b887bec authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Reland "migrate part of painting to nullsafety (#62696)" (#62872)

parent 428be907
<<skip until matching line>> <<skip until matching line>>
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building Listener The following assertion was thrown building Listener
'package:flutter\/src\/painting\/basic_types\.dart': Failed assertion: line 225 pos 10: 'textDirection 'package:flutter\/src\/painting\/basic_types\.dart': Failed assertion: line 222 pos 10: 'textDirection
!= null': is not true\. != null': is not true\.
Either the assertion indicates an error in the framework itself, or we should provide substantially Either the assertion indicates an error in the framework itself, or we should provide substantially
......
<<skip until matching line>> <<skip until matching line>>
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building Listener The following assertion was thrown building Listener
'package:flutter\/src\/painting\/basic_types\.dart': Failed assertion: line 225 pos 10: 'textDirection 'package:flutter\/src\/painting\/basic_types\.dart': Failed assertion: line 222 pos 10: 'textDirection
!= null': is not true\. != null': is not true\.
Either the assertion indicates an error in the framework itself, or we should provide substantially Either the assertion indicates an error in the framework itself, or we should provide substantially
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:ui' as ui show lerpDouble; import 'dart:ui' as ui show lerpDouble;
...@@ -88,12 +87,12 @@ abstract class AlignmentGeometry { ...@@ -88,12 +87,12 @@ abstract class AlignmentGeometry {
/// into a concrete [Alignment] using [resolve]. /// into a concrete [Alignment] using [resolve].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static AlignmentGeometry lerp(AlignmentGeometry a, AlignmentGeometry b, double t) { static AlignmentGeometry? lerp(AlignmentGeometry? a, AlignmentGeometry? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b * t; return b! * t;
if (b == null) if (b == null)
return a * (1.0 - t); return a * (1.0 - t);
if (a is Alignment && b is Alignment) if (a is Alignment && b is Alignment)
...@@ -101,9 +100,9 @@ abstract class AlignmentGeometry { ...@@ -101,9 +100,9 @@ abstract class AlignmentGeometry {
if (a is AlignmentDirectional && b is AlignmentDirectional) if (a is AlignmentDirectional && b is AlignmentDirectional)
return AlignmentDirectional.lerp(a, b, t); return AlignmentDirectional.lerp(a, b, t);
return _MixedAlignment( return _MixedAlignment(
ui.lerpDouble(a._x, b._x, t), ui.lerpDouble(a._x, b._x, t)!,
ui.lerpDouble(a._start, b._start, t), ui.lerpDouble(a._start, b._start, t)!,
ui.lerpDouble(a._y, b._y, t), ui.lerpDouble(a._y, b._y, t)!,
); );
} }
...@@ -116,7 +115,7 @@ abstract class AlignmentGeometry { ...@@ -116,7 +115,7 @@ abstract class AlignmentGeometry {
/// * [Alignment], for which this is a no-op (returns itself). /// * [Alignment], for which this is a no-op (returns itself).
/// * [AlignmentDirectional], which flips the horizontal direction /// * [AlignmentDirectional], which flips the horizontal direction
/// based on the `direction` argument. /// based on the `direction` argument.
Alignment resolve(TextDirection direction); Alignment resolve(TextDirection? direction);
@override @override
String toString() { String toString() {
...@@ -333,19 +332,19 @@ class Alignment extends AlignmentGeometry { ...@@ -333,19 +332,19 @@ class Alignment extends AlignmentGeometry {
/// If either is null, this function interpolates from [Alignment.center]. /// If either is null, this function interpolates from [Alignment.center].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static Alignment lerp(Alignment a, Alignment b, double t) { static Alignment? lerp(Alignment? a, Alignment? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return Alignment(ui.lerpDouble(0.0, b.x, t), ui.lerpDouble(0.0, b.y, t)); return Alignment(ui.lerpDouble(0.0, b!.x, t)!, ui.lerpDouble(0.0, b.y, t)!);
if (b == null) if (b == null)
return Alignment(ui.lerpDouble(a.x, 0.0, t), ui.lerpDouble(a.y, 0.0, t)); return Alignment(ui.lerpDouble(a.x, 0.0, t)!, ui.lerpDouble(a.y, 0.0, t)!);
return Alignment(ui.lerpDouble(a.x, b.x, t), ui.lerpDouble(a.y, b.y, t)); return Alignment(ui.lerpDouble(a.x, b.x, t)!, ui.lerpDouble(a.y, b.y, t)!);
} }
@override @override
Alignment resolve(TextDirection direction) => this; Alignment resolve(TextDirection? direction) => this;
static String _stringify(double x, double y) { static String _stringify(double x, double y) {
if (x == -1.0 && y == -1.0) if (x == -1.0 && y == -1.0)
...@@ -514,27 +513,26 @@ class AlignmentDirectional extends AlignmentGeometry { ...@@ -514,27 +513,26 @@ class AlignmentDirectional extends AlignmentGeometry {
/// If either is null, this function interpolates from [AlignmentDirectional.center]. /// If either is null, this function interpolates from [AlignmentDirectional.center].
/// ///
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
static AlignmentDirectional lerp(AlignmentDirectional a, AlignmentDirectional b, double t) { static AlignmentDirectional? lerp(AlignmentDirectional? a, AlignmentDirectional? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return AlignmentDirectional(ui.lerpDouble(0.0, b.start, t), ui.lerpDouble(0.0, b.y, t)); return AlignmentDirectional(ui.lerpDouble(0.0, b!.start, t)!, ui.lerpDouble(0.0, b.y, t)!);
if (b == null) if (b == null)
return AlignmentDirectional(ui.lerpDouble(a.start, 0.0, t), ui.lerpDouble(a.y, 0.0, t)); return AlignmentDirectional(ui.lerpDouble(a.start, 0.0, t)!, ui.lerpDouble(a.y, 0.0, t)!);
return AlignmentDirectional(ui.lerpDouble(a.start, b.start, t), ui.lerpDouble(a.y, b.y, t)); return AlignmentDirectional(ui.lerpDouble(a.start, b.start, t)!, ui.lerpDouble(a.y, b.y, t)!);
} }
@override @override
Alignment resolve(TextDirection direction) { Alignment resolve(TextDirection? direction) {
assert(direction != null, 'Cannot resolve $runtimeType without a TextDirection.'); assert(direction != null, 'Cannot resolve $runtimeType without a TextDirection.');
switch (direction) { switch (direction!) {
case TextDirection.rtl: case TextDirection.rtl:
return Alignment(-start, y); return Alignment(-start, y);
case TextDirection.ltr: case TextDirection.ltr:
return Alignment(start, y); return Alignment(start, y);
} }
return null;
} }
static String _stringify(double start, double y) { static String _stringify(double start, double y) {
...@@ -622,15 +620,14 @@ class _MixedAlignment extends AlignmentGeometry { ...@@ -622,15 +620,14 @@ class _MixedAlignment extends AlignmentGeometry {
} }
@override @override
Alignment resolve(TextDirection direction) { Alignment resolve(TextDirection? direction) {
assert(direction != null, 'Cannot resolve $runtimeType without a TextDirection.'); assert(direction != null, 'Cannot resolve $runtimeType without a TextDirection.');
switch (direction) { switch (direction!) {
case TextDirection.rtl: case TextDirection.rtl:
return Alignment(_x - _start, _y); return Alignment(_x - _start, _y);
case TextDirection.ltr: case TextDirection.ltr:
return Alignment(_x + _start, _y); return Alignment(_x + _start, _y);
} }
return null;
} }
} }
...@@ -652,7 +649,7 @@ class _MixedAlignment extends AlignmentGeometry { ...@@ -652,7 +649,7 @@ class _MixedAlignment extends AlignmentGeometry {
class TextAlignVertical { class TextAlignVertical {
/// Creates a TextAlignVertical from any y value between -1.0 and 1.0. /// Creates a TextAlignVertical from any y value between -1.0 and 1.0.
const TextAlignVertical({ const TextAlignVertical({
@required this.y, required this.y,
}) : assert(y != null), }) : assert(y != null),
assert(y >= -1.0 && y <= 1.0); assert(y >= -1.0 && y <= 1.0);
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:ui' show TextDirection; import 'dart:ui' show TextDirection;
...@@ -143,7 +142,6 @@ Axis flipAxis(Axis direction) { ...@@ -143,7 +142,6 @@ Axis flipAxis(Axis direction) {
case Axis.vertical: case Axis.vertical:
return Axis.horizontal; return Axis.horizontal;
} }
return null;
} }
/// A direction in which boxes flow vertically. /// A direction in which boxes flow vertically.
...@@ -214,7 +212,6 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) { ...@@ -214,7 +212,6 @@ Axis axisDirectionToAxis(AxisDirection axisDirection) {
case AxisDirection.right: case AxisDirection.right:
return Axis.horizontal; return Axis.horizontal;
} }
return null;
} }
/// Returns the [AxisDirection] in which reading occurs in the given [TextDirection]. /// Returns the [AxisDirection] in which reading occurs in the given [TextDirection].
...@@ -229,7 +226,6 @@ AxisDirection textDirectionToAxisDirection(TextDirection textDirection) { ...@@ -229,7 +226,6 @@ AxisDirection textDirectionToAxisDirection(TextDirection textDirection) {
case TextDirection.ltr: case TextDirection.ltr:
return AxisDirection.right; return AxisDirection.right;
} }
return null;
} }
/// Returns the opposite of the given [AxisDirection]. /// Returns the opposite of the given [AxisDirection].
...@@ -253,7 +249,6 @@ AxisDirection flipAxisDirection(AxisDirection axisDirection) { ...@@ -253,7 +249,6 @@ AxisDirection flipAxisDirection(AxisDirection axisDirection) {
case AxisDirection.left: case AxisDirection.left:
return AxisDirection.right; return AxisDirection.right;
} }
return null;
} }
/// Returns whether traveling along the given axis direction visits coordinates /// Returns whether traveling along the given axis direction visits coordinates
...@@ -271,5 +266,4 @@ bool axisDirectionIsReversed(AxisDirection axisDirection) { ...@@ -271,5 +266,4 @@ bool axisDirectionIsReversed(AxisDirection axisDirection) {
case AxisDirection.right: case AxisDirection.right:
return false; return false;
} }
return null;
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'dart:ui' as ui show instantiateImageCodec, Codec; import 'dart:ui' as ui show instantiateImageCodec, Codec;
...@@ -23,14 +22,12 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -23,14 +22,12 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
super.initInstances(); super.initInstances();
_instance = this; _instance = this;
_imageCache = createImageCache(); _imageCache = createImageCache();
if (shaderWarmUp != null) { shaderWarmUp?.execute();
shaderWarmUp.execute();
}
} }
/// The current [PaintingBinding], if one has been created. /// The current [PaintingBinding], if one has been created.
static PaintingBinding get instance => _instance; static PaintingBinding? get instance => _instance;
static PaintingBinding _instance; static PaintingBinding? _instance;
/// [ShaderWarmUp] to be executed during [initInstances]. /// [ShaderWarmUp] to be executed during [initInstances].
/// ///
...@@ -53,7 +50,7 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -53,7 +50,7 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
/// See also: /// See also:
/// ///
/// * [ShaderWarmUp], the interface of how this warm up works. /// * [ShaderWarmUp], the interface of how this warm up works.
static ShaderWarmUp shaderWarmUp = const DefaultShaderWarmUp(); static ShaderWarmUp? shaderWarmUp = const DefaultShaderWarmUp();
/// The singleton that implements the Flutter framework's image cache. /// The singleton that implements the Flutter framework's image cache.
/// ///
...@@ -62,8 +59,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -62,8 +59,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
/// ///
/// The image cache is created during startup by the [createImageCache] /// The image cache is created during startup by the [createImageCache]
/// method. /// method.
ImageCache get imageCache => _imageCache; ImageCache? get imageCache => _imageCache;
ImageCache _imageCache; ImageCache? _imageCache;
/// Creates the [ImageCache] singleton (accessible via [imageCache]). /// Creates the [ImageCache] singleton (accessible via [imageCache]).
/// ///
...@@ -90,8 +87,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -90,8 +87,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
/// above its native resolution should prefer scaling the canvas the image is /// above its native resolution should prefer scaling the canvas the image is
/// drawn into. /// drawn into.
Future<ui.Codec> instantiateImageCodec(Uint8List bytes, { Future<ui.Codec> instantiateImageCodec(Uint8List bytes, {
int cacheWidth, int? cacheWidth,
int cacheHeight, int? cacheHeight,
bool allowUpscaling = false, bool allowUpscaling = false,
}) { }) {
assert(cacheWidth == null || cacheWidth > 0); assert(cacheWidth == null || cacheWidth > 0);
...@@ -108,8 +105,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding { ...@@ -108,8 +105,8 @@ mixin PaintingBinding on BindingBase, ServicesBinding {
@override @override
void evict(String asset) { void evict(String asset) {
super.evict(asset); super.evict(asset);
imageCache.clear(); imageCache!.clear();
imageCache.clearLiveImages(); imageCache!.clearLiveImages();
} }
@override @override
...@@ -170,4 +167,4 @@ class _SystemFontsNotifier extends Listenable { ...@@ -170,4 +167,4 @@ class _SystemFontsNotifier extends Listenable {
/// ///
/// The image cache is created during startup by the [PaintingBinding]'s /// The image cache is created during startup by the [PaintingBinding]'s
/// [PaintingBinding.createImageCache] method. /// [PaintingBinding.createImageCache] method.
ImageCache get imageCache => PaintingBinding.instance.imageCache; ImageCache? get imageCache => PaintingBinding.instance!.imageCache;
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' show Color, lerpDouble, hashValues; import 'dart:ui' show Color, lerpDouble, hashValues;
...@@ -10,7 +9,7 @@ import 'dart:ui' show Color, lerpDouble, hashValues; ...@@ -10,7 +9,7 @@ import 'dart:ui' show Color, lerpDouble, hashValues;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
double _getHue(double red, double green, double blue, double max, double delta) { double _getHue(double red, double green, double blue, double max, double delta) {
double hue; late double hue;
if (max == 0.0) { if (max == 0.0) {
hue = 0.0; hue = 0.0;
} else if (max == red) { } else if (max == red) {
...@@ -199,19 +198,19 @@ class HSVColor { ...@@ -199,19 +198,19 @@ class HSVColor {
/// {@macro dart.ui.shadow.lerp} /// {@macro dart.ui.shadow.lerp}
/// ///
/// Values outside of the valid range for each channel will be clamped. /// Values outside of the valid range for each channel will be clamped.
static HSVColor lerp(HSVColor a, HSVColor b, double t) { static HSVColor? lerp(HSVColor? a, HSVColor? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b._scaleAlpha(t); return b!._scaleAlpha(t);
if (b == null) if (b == null)
return a._scaleAlpha(1.0 - t); return a._scaleAlpha(1.0 - t);
return HSVColor.fromAHSV( return HSVColor.fromAHSV(
lerpDouble(a.alpha, b.alpha, t).clamp(0.0, 1.0) as double, lerpDouble(a.alpha, b.alpha, t)!.clamp(0.0, 1.0) as double,
lerpDouble(a.hue, b.hue, t) % 360.0, lerpDouble(a.hue, b.hue, t)! % 360.0,
lerpDouble(a.saturation, b.saturation, t).clamp(0.0, 1.0) as double, lerpDouble(a.saturation, b.saturation, t)!.clamp(0.0, 1.0) as double,
lerpDouble(a.value, b.value, t).clamp(0.0, 1.0) as double, lerpDouble(a.value, b.value, t)!.clamp(0.0, 1.0) as double,
); );
} }
...@@ -383,19 +382,19 @@ class HSLColor { ...@@ -383,19 +382,19 @@ class HSLColor {
/// ///
/// Values for `t` are usually obtained from an [Animation<double>], such as /// Values for `t` are usually obtained from an [Animation<double>], such as
/// an [AnimationController]. /// an [AnimationController].
static HSLColor lerp(HSLColor a, HSLColor b, double t) { static HSLColor? lerp(HSLColor? a, HSLColor? b, double t) {
assert(t != null); assert(t != null);
if (a == null && b == null) if (a == null && b == null)
return null; return null;
if (a == null) if (a == null)
return b._scaleAlpha(t); return b!._scaleAlpha(t);
if (b == null) if (b == null)
return a._scaleAlpha(1.0 - t); return a._scaleAlpha(1.0 - t);
return HSLColor.fromAHSL( return HSLColor.fromAHSL(
lerpDouble(a.alpha, b.alpha, t).clamp(0.0, 1.0) as double, lerpDouble(a.alpha, b.alpha, t)!.clamp(0.0, 1.0) as double,
lerpDouble(a.hue, b.hue, t) % 360.0, lerpDouble(a.hue, b.hue, t)! % 360.0,
lerpDouble(a.saturation, b.saturation, t).clamp(0.0, 1.0) as double, lerpDouble(a.saturation, b.saturation, t)!.clamp(0.0, 1.0) as double,
lerpDouble(a.lightness, b.lightness, t).clamp(0.0, 1.0) as double, lerpDouble(a.lightness, b.lightness, t)!.clamp(0.0, 1.0) as double,
); );
} }
...@@ -441,7 +440,7 @@ class ColorSwatch<T> extends Color { ...@@ -441,7 +440,7 @@ class ColorSwatch<T> extends Color {
final Map<T, Color> _swatch; final Map<T, Color> _swatch;
/// Returns an element of the swatch table. /// Returns an element of the swatch table.
Color operator [](T index) => _swatch[index]; Color? operator [](T index) => _swatch[index];
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
...@@ -468,9 +467,9 @@ class ColorProperty extends DiagnosticsProperty<Color> { ...@@ -468,9 +467,9 @@ class ColorProperty extends DiagnosticsProperty<Color> {
/// The [showName], [style], and [level] arguments must not be null. /// The [showName], [style], and [level] arguments must not be null.
ColorProperty( ColorProperty(
String name, String name,
Color value, { Color? value, {
bool showName = true, bool showName = true,
Object defaultValue = kNoDefaultValue, Object? defaultValue = kNoDefaultValue,
DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine, DiagnosticsTreeStyle style = DiagnosticsTreeStyle.singleLine,
DiagnosticLevel level = DiagnosticLevel.info, DiagnosticLevel level = DiagnosticLevel.info,
}) : assert(showName != null), }) : assert(showName != null),
...@@ -484,14 +483,14 @@ class ColorProperty extends DiagnosticsProperty<Color> { ...@@ -484,14 +483,14 @@ class ColorProperty extends DiagnosticsProperty<Color> {
); );
@override @override
Map<String, Object> toJsonMap(DiagnosticsSerializationDelegate delegate) { Map<String, Object?> toJsonMap(DiagnosticsSerializationDelegate delegate) {
final Map<String, Object> json = super.toJsonMap(delegate); final Map<String, Object?> json = super.toJsonMap(delegate);
if (value != null) { if (value != null) {
json['valueProperties'] = <String, Object>{ json['valueProperties'] = <String, Object>{
'red': value.red, 'red': value!.red,
'green': value.green, 'green': value!.green,
'blue': value.blue, 'blue': value!.blue,
'alpha': value.alpha, 'alpha': value!.alpha,
}; };
} }
return json; return json;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:io'; import 'dart:io';
import 'dart:ui' show Size, hashValues; import 'dart:ui' show Size, hashValues;
...@@ -30,7 +29,7 @@ typedef HttpClientProvider = HttpClient Function(); ...@@ -30,7 +29,7 @@ typedef HttpClientProvider = HttpClient Function();
/// a mock client that hasn't been affected by other tests. /// a mock client that hasn't been affected by other tests.
/// ///
/// This value is ignored in non-debug builds. /// This value is ignored in non-debug builds.
HttpClientProvider debugNetworkImageHttpClientProvider; HttpClientProvider? debugNetworkImageHttpClientProvider;
typedef PaintImageCallback = void Function(ImageSizeInfo); typedef PaintImageCallback = void Function(ImageSizeInfo);
...@@ -44,20 +43,20 @@ class ImageSizeInfo { ...@@ -44,20 +43,20 @@ class ImageSizeInfo {
/// This class is used by the framework when it paints an image to a canvas /// This class is used by the framework when it paints an image to a canvas
/// to report to `dart:developer`'s [postEvent], as well as to the /// to report to `dart:developer`'s [postEvent], as well as to the
/// [debugOnPaintImage] callback if it is set. /// [debugOnPaintImage] callback if it is set.
const ImageSizeInfo({this.source, this.displaySize, this.imageSize}); const ImageSizeInfo({this.source, this.displaySize, required this.imageSize});
/// A unique identifier for this image, for example its asset path or network /// A unique identifier for this image, for example its asset path or network
/// URL. /// URL.
final String source; final String? source;
/// The size of the area the image will be rendered in. /// The size of the area the image will be rendered in.
final Size displaySize; final Size? displaySize;
/// The size the image has been decoded to. /// The size the image has been decoded to.
final Size imageSize; final Size imageSize;
/// The number of bytes needed to render the image without scaling it. /// The number of bytes needed to render the image without scaling it.
int get displaySizeInBytes => _sizeToBytes(displaySize); int get displaySizeInBytes => _sizeToBytes(displaySize!);
/// The number of bytes used by the image in memory. /// The number of bytes used by the image in memory.
int get decodedSizeInBytes => _sizeToBytes(imageSize); int get decodedSizeInBytes => _sizeToBytes(imageSize);
...@@ -69,14 +68,15 @@ class ImageSizeInfo { ...@@ -69,14 +68,15 @@ class ImageSizeInfo {
} }
/// Returns a JSON encodable representation of this object. /// Returns a JSON encodable representation of this object.
Map<String, Object> toJson() { Map<String, Object?> toJson() {
return <String, Object>{ return <String, Object?>{
'source': source, 'source': source,
'displaySize': <String, double>{ if (displaySize != null)
'width': displaySize.width, 'displaySize': <String, Object?>{
'height': displaySize.height, 'width': displaySize!.width,
}, 'height': displaySize!.height,
'imageSize': <String, double>{ },
'imageSize': <String, Object?>{
'width': imageSize.width, 'width': imageSize.width,
'height': imageSize.height, 'height': imageSize.height,
}, },
...@@ -125,7 +125,7 @@ class ImageSizeInfo { ...@@ -125,7 +125,7 @@ class ImageSizeInfo {
/// a higher resolution while animating, but it would be problematic to have /// a higher resolution while animating, but it would be problematic to have
/// a grid or list of such thumbnails all be at the full resolution at the same /// a grid or list of such thumbnails all be at the full resolution at the same
/// time. /// time.
PaintImageCallback debugOnPaintImage; PaintImageCallback? debugOnPaintImage;
/// If true, the framework will color invert and horizontally flip images that /// If true, the framework will color invert and horizontally flip images that
/// have been decoded to a size taking at least [debugImageOverheadAllowance] /// have been decoded to a size taking at least [debugImageOverheadAllowance]
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:developer'; import 'dart:developer';
import 'dart:ui' show hashValues; import 'dart:ui' show hashValues;
...@@ -103,7 +102,7 @@ class ImageCache { ...@@ -103,7 +102,7 @@ class ImageCache {
assert(value >= 0); assert(value >= 0);
if (value == maximumSize) if (value == maximumSize)
return; return;
TimelineTask timelineTask; TimelineTask? timelineTask;
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask = TimelineTask()..start( timelineTask = TimelineTask()..start(
'ImageCache.setMaximumSize', 'ImageCache.setMaximumSize',
...@@ -117,7 +116,7 @@ class ImageCache { ...@@ -117,7 +116,7 @@ class ImageCache {
_checkCacheSize(timelineTask); _checkCacheSize(timelineTask);
} }
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask.finish(); timelineTask!.finish();
} }
} }
...@@ -142,7 +141,7 @@ class ImageCache { ...@@ -142,7 +141,7 @@ class ImageCache {
assert(value >= 0); assert(value >= 0);
if (value == _maximumSizeBytes) if (value == _maximumSizeBytes)
return; return;
TimelineTask timelineTask; TimelineTask? timelineTask;
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask = TimelineTask()..start( timelineTask = TimelineTask()..start(
'ImageCache.setMaximumSizeBytes', 'ImageCache.setMaximumSizeBytes',
...@@ -156,7 +155,7 @@ class ImageCache { ...@@ -156,7 +155,7 @@ class ImageCache {
_checkCacheSize(timelineTask); _checkCacheSize(timelineTask);
} }
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask.finish(); timelineTask!.finish();
} }
} }
...@@ -239,10 +238,10 @@ class ImageCache { ...@@ -239,10 +238,10 @@ class ImageCache {
// will never complete, e.g. it was loaded in a FakeAsync zone. // will never complete, e.g. it was loaded in a FakeAsync zone.
// In such a case, we need to make sure subsequent calls to // In such a case, we need to make sure subsequent calls to
// putIfAbsent don't return this image that may never complete. // putIfAbsent don't return this image that may never complete.
final _LiveImage image = _liveImages.remove(key); final _LiveImage? image = _liveImages.remove(key);
image?.removeListener(); image?.removeListener();
} }
final _PendingImage pendingImage = _pendingImages.remove(key); final _PendingImage? pendingImage = _pendingImages.remove(key);
if (pendingImage != null) { if (pendingImage != null) {
if (!kReleaseMode) { if (!kReleaseMode) {
Timeline.instantSync('ImageCache.evict', arguments: <String, dynamic>{ Timeline.instantSync('ImageCache.evict', arguments: <String, dynamic>{
...@@ -252,7 +251,7 @@ class ImageCache { ...@@ -252,7 +251,7 @@ class ImageCache {
pendingImage.removeListener(); pendingImage.removeListener();
return true; return true;
} }
final _CachedImage image = _cache.remove(key); final _CachedImage? image = _cache.remove(key);
if (image != null) { if (image != null) {
if (!kReleaseMode) { if (!kReleaseMode) {
Timeline.instantSync('ImageCache.evict', arguments: <String, dynamic>{ Timeline.instantSync('ImageCache.evict', arguments: <String, dynamic>{
...@@ -260,7 +259,7 @@ class ImageCache { ...@@ -260,7 +259,7 @@ class ImageCache {
'sizeInBytes': image.sizeBytes, 'sizeInBytes': image.sizeBytes,
}); });
} }
_currentSizeBytes -= image.sizeBytes; _currentSizeBytes -= image.sizeBytes!;
return true; return true;
} }
if (!kReleaseMode) { if (!kReleaseMode) {
...@@ -276,13 +275,13 @@ class ImageCache { ...@@ -276,13 +275,13 @@ class ImageCache {
/// ///
/// Resizes the cache as appropriate to maintain the constraints of /// Resizes the cache as appropriate to maintain the constraints of
/// [maximumSize] and [maximumSizeBytes]. /// [maximumSize] and [maximumSizeBytes].
void _touch(Object key, _CachedImage image, TimelineTask timelineTask) { void _touch(Object key, _CachedImage image, TimelineTask? timelineTask) {
// TODO(dnfield): Some customers test in release mode with asserts enabled. // TODO(dnfield): Some customers test in release mode with asserts enabled.
// This is bound to cause problems, b/150295238 is tracking that. For now, // This is bound to cause problems, b/150295238 is tracking that. For now,
// avoid this being a point of failure. // avoid this being a point of failure.
assert(kReleaseMode || timelineTask != null); assert(kReleaseMode || timelineTask != null);
if (image.sizeBytes != null && image.sizeBytes <= maximumSizeBytes) { if (image.sizeBytes != null && image.sizeBytes! <= maximumSizeBytes) {
_currentSizeBytes += image.sizeBytes; _currentSizeBytes += image.sizeBytes!;
_cache[key] = image; _cache[key] = image;
_checkCacheSize(timelineTask); _checkCacheSize(timelineTask);
} }
...@@ -310,11 +309,11 @@ class ImageCache { ...@@ -310,11 +309,11 @@ class ImageCache {
/// `onError` is also provided. When an exception is caught resolving an image, /// `onError` is also provided. When an exception is caught resolving an image,
/// no completers are cached and `null` is returned instead of a new /// no completers are cached and `null` is returned instead of a new
/// completer. /// completer.
ImageStreamCompleter putIfAbsent(Object key, ImageStreamCompleter loader(), { ImageErrorListener onError }) { ImageStreamCompleter? putIfAbsent(Object key, ImageStreamCompleter loader(), { ImageErrorListener? onError }) {
assert(key != null); assert(key != null);
assert(loader != null); assert(loader != null);
TimelineTask timelineTask; TimelineTask? timelineTask;
TimelineTask listenerTask; TimelineTask? listenerTask;
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask = TimelineTask()..start( timelineTask = TimelineTask()..start(
'ImageCache.putIfAbsent', 'ImageCache.putIfAbsent',
...@@ -323,11 +322,11 @@ class ImageCache { ...@@ -323,11 +322,11 @@ class ImageCache {
}, },
); );
} }
ImageStreamCompleter result = _pendingImages[key]?.completer; ImageStreamCompleter? result = _pendingImages[key]?.completer;
// Nothing needs to be done because the image hasn't loaded yet. // Nothing needs to be done because the image hasn't loaded yet.
if (result != null) { if (result != null) {
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask.finish(arguments: <String, dynamic>{'result': 'pending'}); timelineTask!.finish(arguments: <String, dynamic>{'result': 'pending'});
} }
return result; return result;
} }
...@@ -335,10 +334,10 @@ class ImageCache { ...@@ -335,10 +334,10 @@ class ImageCache {
// recently used position below. // recently used position below.
// Don't use _touch here, which would trigger a check on cache size that is // Don't use _touch here, which would trigger a check on cache size that is
// not needed since this is just moving an existing cache entry to the head. // not needed since this is just moving an existing cache entry to the head.
final _CachedImage image = _cache.remove(key); final _CachedImage? image = _cache.remove(key);
if (image != null) { if (image != null) {
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask.finish(arguments: <String, dynamic>{'result': 'keepAlive'}); timelineTask!.finish(arguments: <String, dynamic>{'result': 'keepAlive'});
} }
// The image might have been keptAlive but had no listeners (so not live). // The image might have been keptAlive but had no listeners (so not live).
// Make sure the cache starts tracking it as live again. // Make sure the cache starts tracking it as live again.
...@@ -347,11 +346,11 @@ class ImageCache { ...@@ -347,11 +346,11 @@ class ImageCache {
return image.completer; return image.completer;
} }
final _CachedImage liveImage = _liveImages[key]; final _CachedImage? liveImage = _liveImages[key];
if (liveImage != null) { if (liveImage != null) {
_touch(key, liveImage, timelineTask); _touch(key, liveImage, timelineTask);
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask.finish(arguments: <String, dynamic>{'result': 'keepAlive'}); timelineTask!.finish(arguments: <String, dynamic>{'result': 'keepAlive'});
} }
return liveImage.completer; return liveImage.completer;
} }
...@@ -361,7 +360,7 @@ class ImageCache { ...@@ -361,7 +360,7 @@ class ImageCache {
_trackLiveImage(key, _LiveImage(result, null, () => _liveImages.remove(key))); _trackLiveImage(key, _LiveImage(result, null, () => _liveImages.remove(key)));
} catch (error, stackTrace) { } catch (error, stackTrace) {
if (!kReleaseMode) { if (!kReleaseMode) {
timelineTask.finish(arguments: <String, dynamic>{ timelineTask!.finish(arguments: <String, dynamic>{
'result': 'error', 'result': 'error',
'error': error.toString(), 'error': error.toString(),
'stackTrace': stackTrace.toString(), 'stackTrace': stackTrace.toString(),
...@@ -387,12 +386,12 @@ class ImageCache { ...@@ -387,12 +386,12 @@ class ImageCache {
// will have to listen to the image at least once so we don't leak it in // will have to listen to the image at least once so we don't leak it in
// the live image tracking. // the live image tracking.
// If the cache is disabled, this variable will be set. // If the cache is disabled, this variable will be set.
_PendingImage untrackedPendingImage; _PendingImage? untrackedPendingImage;
void listener(ImageInfo info, bool syncCall) { void listener(ImageInfo? info, bool syncCall) {
// Images that fail to load don't contribute to cache size. // Images that fail to load don't contribute to cache size.
final int imageSize = info?.image == null ? 0 : info.image.height * info.image.width * 4; final int imageSize = info == null || info.image == null ? 0 : info.image.height * info.image.width * 4;
final _CachedImage image = _CachedImage(result, imageSize); final _CachedImage image = _CachedImage(result!, imageSize);
_trackLiveImage( _trackLiveImage(
key, key,
...@@ -403,7 +402,7 @@ class ImageCache { ...@@ -403,7 +402,7 @@ class ImageCache {
), ),
); );
final _PendingImage pendingImage = untrackedPendingImage ?? _pendingImages.remove(key); final _PendingImage? pendingImage = untrackedPendingImage ?? _pendingImages.remove(key);
if (pendingImage != null) { if (pendingImage != null) {
pendingImage.removeListener(); pendingImage.removeListener();
} }
...@@ -413,11 +412,11 @@ class ImageCache { ...@@ -413,11 +412,11 @@ class ImageCache {
} }
if (!kReleaseMode && !listenedOnce) { if (!kReleaseMode && !listenedOnce) {
listenerTask.finish(arguments: <String, dynamic>{ listenerTask!.finish(arguments: <String, dynamic>{
'syncCall': syncCall, 'syncCall': syncCall,
'sizeInBytes': imageSize, 'sizeInBytes': imageSize,
}); });
timelineTask.finish(arguments: <String, dynamic>{ timelineTask!.finish(arguments: <String, dynamic>{
'currentSizeBytes': currentSizeBytes, 'currentSizeBytes': currentSizeBytes,
'currentSize': currentSize, 'currentSize': currentSize,
}); });
...@@ -481,9 +480,9 @@ class ImageCache { ...@@ -481,9 +480,9 @@ class ImageCache {
// Remove images from the cache until both the length and bytes are below // Remove images from the cache until both the length and bytes are below
// maximum, or the cache is empty. // maximum, or the cache is empty.
void _checkCacheSize(TimelineTask timelineTask) { void _checkCacheSize(TimelineTask? timelineTask) {
final Map<String, dynamic> finishArgs = <String, dynamic>{}; final Map<String, dynamic> finishArgs = <String, dynamic>{};
TimelineTask checkCacheTask; TimelineTask? checkCacheTask;
if (!kReleaseMode) { if (!kReleaseMode) {
checkCacheTask = TimelineTask(parent: timelineTask)..start('checkCacheSize'); checkCacheTask = TimelineTask(parent: timelineTask)..start('checkCacheSize');
finishArgs['evictedKeys'] = <String>[]; finishArgs['evictedKeys'] = <String>[];
...@@ -492,8 +491,8 @@ class ImageCache { ...@@ -492,8 +491,8 @@ class ImageCache {
} }
while (_currentSizeBytes > _maximumSizeBytes || _cache.length > _maximumSize) { while (_currentSizeBytes > _maximumSizeBytes || _cache.length > _maximumSize) {
final Object key = _cache.keys.first; final Object key = _cache.keys.first;
final _CachedImage image = _cache[key]; final _CachedImage image = _cache[key]!;
_currentSizeBytes -= image.sizeBytes; _currentSizeBytes -= image.sizeBytes!;
_cache.remove(key); _cache.remove(key);
if (!kReleaseMode) { if (!kReleaseMode) {
finishArgs['evictedKeys'].add(key.toString()); finishArgs['evictedKeys'].add(key.toString());
...@@ -502,7 +501,7 @@ class ImageCache { ...@@ -502,7 +501,7 @@ class ImageCache {
if (!kReleaseMode) { if (!kReleaseMode) {
finishArgs['endSize'] = currentSize; finishArgs['endSize'] = currentSize;
finishArgs['endSizeBytes'] = currentSizeBytes; finishArgs['endSizeBytes'] = currentSizeBytes;
checkCacheTask.finish(arguments: finishArgs); checkCacheTask!.finish(arguments: finishArgs);
} }
assert(_currentSizeBytes >= 0); assert(_currentSizeBytes >= 0);
assert(_cache.length <= maximumSize); assert(_cache.length <= maximumSize);
...@@ -585,11 +584,11 @@ class _CachedImage { ...@@ -585,11 +584,11 @@ class _CachedImage {
_CachedImage(this.completer, this.sizeBytes); _CachedImage(this.completer, this.sizeBytes);
final ImageStreamCompleter completer; final ImageStreamCompleter completer;
int sizeBytes; int? sizeBytes;
} }
class _LiveImage extends _CachedImage { class _LiveImage extends _CachedImage {
_LiveImage(ImageStreamCompleter completer, int sizeBytes, this.handleRemove) _LiveImage(ImageStreamCompleter completer, int? sizeBytes, this.handleRemove)
: super(completer, sizeBytes); : super(completer, sizeBytes);
final VoidCallback handleRemove; final VoidCallback handleRemove;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment