Unverified Commit c91a2982 authored by Dan Field's avatar Dan Field Committed by GitHub

Take DPR into account for image inversion (#88309)

parent a562b3cb
...@@ -72,7 +72,7 @@ void main() { ...@@ -72,7 +72,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame'); expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect( expect(
jsonEncode(event.extensionData!.data), jsonEncode(event.extensionData!.data),
'{"test.png":{"source":"test.png","displaySize":{"width":200.0,"height":100.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":106666,"decodedSizeInBytes":480000}}', '{"test.png":{"source":"test.png","displaySize":{"width":600.0,"height":300.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":960000,"decodedSizeInBytes":480000}}',
); );
}, skip: isBrowser); // [intended] uses dart:isolate and io. }, skip: isBrowser); // [intended] uses dart:isolate and io.
...@@ -104,7 +104,7 @@ void main() { ...@@ -104,7 +104,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame'); expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect( expect(
jsonEncode(event.extensionData!.data), jsonEncode(event.extensionData!.data),
'{"test.png":{"source":"test.png","displaySize":{"width":300.0,"height":300.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":480000,"decodedSizeInBytes":480000}}', '{"test.png":{"source":"test.png","displaySize":{"width":900.0,"height":900.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":4320000,"decodedSizeInBytes":480000}}',
); );
}, skip: isBrowser); // [intended] uses dart:isolate and io. }, skip: isBrowser); // [intended] uses dart:isolate and io.
} }
......
...@@ -54,20 +54,20 @@ class ImageSizeInfo { ...@@ -54,20 +54,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, required this.imageSize}); const ImageSizeInfo({this.source, required 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);
...@@ -82,10 +82,9 @@ class ImageSizeInfo { ...@@ -82,10 +82,9 @@ class ImageSizeInfo {
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
return <String, Object?>{ return <String, Object?>{
'source': source, 'source': source,
if (displaySize != null)
'displaySize': <String, Object?>{ 'displaySize': <String, Object?>{
'width': displaySize!.width, 'width': displaySize.width,
'height': displaySize!.height, 'height': displaySize.height,
}, },
'imageSize': <String, Object?>{ 'imageSize': <String, Object?>{
'width': imageSize.width, 'width': imageSize.width,
......
...@@ -11,6 +11,7 @@ import 'package:flutter/scheduler.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter/scheduler.dart';
import 'alignment.dart'; import 'alignment.dart';
import 'basic_types.dart'; import 'basic_types.dart';
import 'binding.dart';
import 'borders.dart'; import 'borders.dart';
import 'box_fit.dart'; import 'box_fit.dart';
import 'debug.dart'; import 'debug.dart';
...@@ -494,14 +495,16 @@ void paintImage({ ...@@ -494,14 +495,16 @@ void paintImage({
// Some ImageProvider implementations may not have given this. // Some ImageProvider implementations may not have given this.
source: debugImageLabel ?? '<Unknown Image(${image.width}×${image.height})>', source: debugImageLabel ?? '<Unknown Image(${image.width}×${image.height})>',
imageSize: Size(image.width.toDouble(), image.height.toDouble()), imageSize: Size(image.width.toDouble(), image.height.toDouble()),
displaySize: outputSize, // It's ok to use this instead of a MediaQuery because if this changes,
// whatever is aware of the MediaQuery will be repainting the image anyway.
displaySize: outputSize * PaintingBinding.instance!.window.devicePixelRatio,
); );
assert(() { assert(() {
if (debugInvertOversizedImages && if (debugInvertOversizedImages &&
sizeInfo.decodedSizeInBytes > sizeInfo.displaySizeInBytes + debugImageOverheadAllowance) { sizeInfo.decodedSizeInBytes > sizeInfo.displaySizeInBytes + debugImageOverheadAllowance) {
final int overheadInKilobytes = (sizeInfo.decodedSizeInBytes - sizeInfo.displaySizeInBytes) ~/ 1024; final int overheadInKilobytes = (sizeInfo.decodedSizeInBytes - sizeInfo.displaySizeInBytes) ~/ 1024;
final int outputWidth = outputSize.width.toInt(); final int outputWidth = sizeInfo.displaySize.width.toInt();
final int outputHeight = outputSize.height.toInt(); final int outputHeight = sizeInfo.displaySize.height.toInt();
FlutterError.reportError(FlutterErrorDetails( FlutterError.reportError(FlutterErrorDetails(
exception: 'Image $debugImageLabel has a display size of ' exception: 'Image $debugImageLabel has a display size of '
'$outputWidth×$outputHeight but a decode size of ' '$outputWidth×$outputHeight but a decode size of '
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
...@@ -52,6 +53,7 @@ void main() { ...@@ -52,6 +53,7 @@ void main() {
test('debugInvertOversizedImages', () async { test('debugInvertOversizedImages', () async {
debugInvertOversizedImages = true; debugInvertOversizedImages = true;
expect(PaintingBinding.instance!.window.devicePixelRatio != 1.0, true);
final FlutterExceptionHandler? oldFlutterError = FlutterError.onError; final FlutterExceptionHandler? oldFlutterError = FlutterError.onError;
final List<String> messages = <String>[]; final List<String> messages = <String>[];
...@@ -60,7 +62,7 @@ void main() { ...@@ -60,7 +62,7 @@ void main() {
}; };
final TestCanvas canvas = TestCanvas(); final TestCanvas canvas = TestCanvas();
const Rect rect = Rect.fromLTWH(50.0, 50.0, 200.0, 100.0); const Rect rect = Rect.fromLTWH(50.0, 50.0, 100.0, 50.0);
paintImage( paintImage(
canvas: canvas, canvas: canvas,
...@@ -88,7 +90,7 @@ void main() { ...@@ -88,7 +90,7 @@ void main() {
); );
expect(commands[1].memberName, #translate); expect(commands[1].memberName, #translate);
expect(commands[1].positionalArguments[0], 0.0); expect(commands[1].positionalArguments[0], 0.0);
expect(commands[1].positionalArguments[1], 100.0); expect(commands[1].positionalArguments[1], 75.0);
expect(commands[2].memberName, #scale); expect(commands[2].memberName, #scale);
expect(commands[2].positionalArguments[0], 1.0); expect(commands[2].positionalArguments[0], 1.0);
...@@ -97,12 +99,12 @@ void main() { ...@@ -97,12 +99,12 @@ void main() {
expect(commands[3].memberName, #translate); expect(commands[3].memberName, #translate);
expect(commands[3].positionalArguments[0], 0.0); expect(commands[3].positionalArguments[0], 0.0);
expect(commands[3].positionalArguments[1], -100.0); expect(commands[3].positionalArguments[1], -75.0);
expect( expect(
messages.single, messages.single,
'Image TestImage has a display size of 200×100 but a decode size of 300×300, which uses an additional 364KB.\n\n' 'Image TestImage has a display size of 300×150 but a decode size of 300×300, which uses an additional 234KB.\n\n'
'Consider resizing the asset ahead of time, supplying a cacheWidth parameter of 200, a cacheHeight parameter of 100, or using a ResizeImage.', 'Consider resizing the asset ahead of time, supplying a cacheWidth parameter of 300, a cacheHeight parameter of 150, or using a ResizeImage.',
); );
debugInvertOversizedImages = false; debugInvertOversizedImages = false;
...@@ -179,7 +181,7 @@ void main() { ...@@ -179,7 +181,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300)); expect(imageSizeInfo.imageSize, const Size(300, 300));
expect(imageSizeInfo.displaySize, const Size(200, 100)); expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance!.window.devicePixelRatio);
// Make sure that we don't report an identical image size info if we // Make sure that we don't report an identical image size info if we
// redraw in the next frame. // redraw in the next frame.
...@@ -218,7 +220,7 @@ void main() { ...@@ -218,7 +220,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300)); expect(imageSizeInfo.imageSize, const Size(300, 300));
expect(imageSizeInfo.displaySize, const Size(200, 100)); expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance!.window.devicePixelRatio);
// Make sure that we don't report an identical image size info if we // Make sure that we don't report an identical image size info if we
// redraw in the next frame. // redraw in the next frame.
...@@ -236,7 +238,7 @@ void main() { ...@@ -236,7 +238,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png'); expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300)); expect(imageSizeInfo.imageSize, const Size(300, 300));
expect(imageSizeInfo.displaySize, const Size(200, 150)); expect(imageSizeInfo.displaySize, const Size(200, 150) * PaintingBinding.instance!.window.devicePixelRatio);
debugOnPaintImage = null; debugOnPaintImage = null;
}); });
...@@ -260,7 +262,7 @@ void main() { ...@@ -260,7 +262,7 @@ void main() {
expect(imageSizeInfo, isNotNull); expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, '<Unknown Image(300×200)>'); expect(imageSizeInfo.source, '<Unknown Image(300×200)>');
expect(imageSizeInfo.imageSize, const Size(300, 200)); expect(imageSizeInfo.imageSize, const Size(300, 200));
expect(imageSizeInfo.displaySize, const Size(200, 100)); expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance!.window.devicePixelRatio);
debugOnPaintImage = null; debugOnPaintImage = null;
}); });
......
...@@ -1819,7 +1819,7 @@ void main() { ...@@ -1819,7 +1819,7 @@ void main() {
const ImageSizeInfo( const ImageSizeInfo(
source: 'test.png', source: 'test.png',
imageSize: Size(100, 100), imageSize: Size(100, 100),
displaySize: Size(50, 50), displaySize: Size(150, 150),
), ),
); );
......
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