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

Take DPR into account for image inversion (#88309)

parent a562b3cb
......@@ -4,4 +4,4 @@ The tests in this folder must be run with `flutter test --enable-vmservice`,
since they test that trace data is written to the timeline by connecting to
the observatory.
These tests will fail if run without this flag.
\ No newline at end of file
These tests will fail if run without this flag.
......@@ -72,7 +72,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect(
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.
......@@ -104,7 +104,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect(
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.
}
......
......@@ -54,20 +54,20 @@ class ImageSizeInfo {
/// 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
/// [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
/// URL.
final String? source;
/// 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.
final Size imageSize;
/// 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.
int get decodedSizeInBytes => _sizeToBytes(imageSize);
......@@ -82,11 +82,10 @@ class ImageSizeInfo {
Map<String, Object?> toJson() {
return <String, Object?>{
'source': source,
if (displaySize != null)
'displaySize': <String, Object?>{
'width': displaySize!.width,
'height': displaySize!.height,
},
'displaySize': <String, Object?>{
'width': displaySize.width,
'height': displaySize.height,
},
'imageSize': <String, Object?>{
'width': imageSize.width,
'height': imageSize.height,
......
......@@ -11,6 +11,7 @@ import 'package:flutter/scheduler.dart';
import 'alignment.dart';
import 'basic_types.dart';
import 'binding.dart';
import 'borders.dart';
import 'box_fit.dart';
import 'debug.dart';
......@@ -494,14 +495,16 @@ void paintImage({
// Some ImageProvider implementations may not have given this.
source: debugImageLabel ?? '<Unknown Image(${image.width}×${image.height})>',
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(() {
if (debugInvertOversizedImages &&
sizeInfo.decodedSizeInBytes > sizeInfo.displaySizeInBytes + debugImageOverheadAllowance) {
final int overheadInKilobytes = (sizeInfo.decodedSizeInBytes - sizeInfo.displaySizeInBytes) ~/ 1024;
final int outputWidth = outputSize.width.toInt();
final int outputHeight = outputSize.height.toInt();
final int outputWidth = sizeInfo.displaySize.width.toInt();
final int outputHeight = sizeInfo.displaySize.height.toInt();
FlutterError.reportError(FlutterErrorDetails(
exception: 'Image $debugImageLabel has a display size of '
'$outputWidth×$outputHeight but a decode size of '
......
......@@ -5,6 +5,7 @@
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -52,6 +53,7 @@ void main() {
test('debugInvertOversizedImages', () async {
debugInvertOversizedImages = true;
expect(PaintingBinding.instance!.window.devicePixelRatio != 1.0, true);
final FlutterExceptionHandler? oldFlutterError = FlutterError.onError;
final List<String> messages = <String>[];
......@@ -60,7 +62,7 @@ void main() {
};
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(
canvas: canvas,
......@@ -88,7 +90,7 @@ void main() {
);
expect(commands[1].memberName, #translate);
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].positionalArguments[0], 1.0);
......@@ -97,12 +99,12 @@ void main() {
expect(commands[3].memberName, #translate);
expect(commands[3].positionalArguments[0], 0.0);
expect(commands[3].positionalArguments[1], -100.0);
expect(commands[3].positionalArguments[1], -75.0);
expect(
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'
'Consider resizing the asset ahead of time, supplying a cacheWidth parameter of 200, a cacheHeight parameter of 100, or using a ResizeImage.',
'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 300, a cacheHeight parameter of 150, or using a ResizeImage.',
);
debugInvertOversizedImages = false;
......@@ -179,7 +181,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png');
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
// redraw in the next frame.
......@@ -218,7 +220,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png');
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
// redraw in the next frame.
......@@ -236,7 +238,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png');
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;
});
......@@ -260,7 +262,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, '<Unknown Image(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;
});
......
......@@ -1819,7 +1819,7 @@ void main() {
const ImageSizeInfo(
source: 'test.png',
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