1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'dart:developer';
6/// @docImport 'dart:ui';
7///
8/// @docImport 'package:flutter_test/flutter_test.dart';
9///
10/// @docImport 'borders.dart';
11/// @docImport 'box_decoration.dart';
12/// @docImport 'box_shadow.dart';
13/// @docImport 'image_provider.dart';
14/// @docImport 'shader_warm_up.dart';
15/// @docImport 'shape_decoration.dart';
16library;
17
18import 'dart:io';
19import 'dart:ui' show Image, Picture, Size;
20
21import 'package:flutter/foundation.dart';
22
23/// Whether to replace all shadows with solid color blocks.
24///
25/// This is useful when writing golden file tests (see [matchesGoldenFile]) since
26/// the rendering of shadows is not guaranteed to be pixel-for-pixel identical from
27/// version to version (or even from run to run).
28///
29/// This is set to true in [AutomatedTestWidgetsFlutterBinding]. Tests will fail
30/// if they change this value and do not reset it before the end of the test.
31///
32/// When this is set, [BoxShadow.toPaint] acts as if the [BoxShadow.blurStyle]
33/// was [BlurStyle.normal] regardless of the actual specified blur style. This
34/// is compensated for in [BoxDecoration] and [ShapeDecoration] but may need to
35/// be explicitly considered in other situations.
36///
37/// This property should not be changed during a frame (e.g. during a call to
38/// [ShapeBorder.paintInterior] or [ShapeBorder.getOuterPath]); doing so may
39/// cause undefined effects.
40bool debugDisableShadows = false;
41
42/// Signature for a method that returns an [HttpClient].
43///
44/// Used by [debugNetworkImageHttpClientProvider].
45typedef HttpClientProvider = HttpClient Function();
46
47/// Provider from which [NetworkImage] will get its [HttpClient] in debug builds.
48///
49/// If this value is unset, [NetworkImage] will use its own internally-managed
50/// [HttpClient].
51///
52/// This setting can be overridden for testing to ensure that each test receives
53/// a mock client that hasn't been affected by other tests.
54///
55/// This value is ignored in non-debug builds.
56HttpClientProvider? debugNetworkImageHttpClientProvider;
57
58/// Called when the framework is about to paint an [Image] to a [Canvas] with an
59/// [ImageSizeInfo] that contains the decoded size of the image as well as its
60/// output size.
61///
62/// See: [debugOnPaintImage].
63typedef PaintImageCallback = void Function(ImageSizeInfo info);
64
65/// Tracks the bytes used by a [dart:ui.Image] compared to the bytes needed to
66/// paint that image without scaling it.
67@immutable
68class ImageSizeInfo {
69 /// Creates an object to track the backing size of a [dart:ui.Image] compared
70 /// to its display size on a [Canvas].
71 ///
72 /// This class is used by the framework when it paints an image to a canvas
73 /// to report to `dart:developer`'s [postEvent], as well as to the
74 /// [debugOnPaintImage] callback if it is set.
75 const ImageSizeInfo({this.source, required this.displaySize, required this.imageSize});
76
77 /// A unique identifier for this image, for example its asset path or network
78 /// URL.
79 final String? source;
80
81 /// The size of the area the image will be rendered in.
82 final Size displaySize;
83
84 /// The size the image has been decoded to.
85 final Size imageSize;
86
87 /// The number of bytes needed to render the image without scaling it.
88 int get displaySizeInBytes => _sizeToBytes(displaySize);
89
90 /// The number of bytes used by the image in memory.
91 int get decodedSizeInBytes => _sizeToBytes(imageSize);
92
93 int _sizeToBytes(Size size) {
94 // Assume 4 bytes per pixel and that mipmapping will be used, which adds
95 // 4/3.
96 return (size.width * size.height * 4 * (4/3)).toInt();
97 }
98
99 /// Returns a JSON encodable representation of this object.
100 Map<String, Object?> toJson() {
101 return <String, Object?>{
102 'source': source,
103 'displaySize': <String, Object?>{
104 'width': displaySize.width,
105 'height': displaySize.height,
106 },
107 'imageSize': <String, Object?>{
108 'width': imageSize.width,
109 'height': imageSize.height,
110 },
111 'displaySizeInBytes': displaySizeInBytes,
112 'decodedSizeInBytes': decodedSizeInBytes,
113 };
114 }
115
116 @override
117 bool operator ==(Object other) {
118 if (other.runtimeType != runtimeType) {
119 return false;
120 }
121 return other is ImageSizeInfo
122 && other.source == source
123 && other.imageSize == imageSize
124 && other.displaySize == displaySize;
125 }
126
127 @override
128 int get hashCode => Object.hash(source, displaySize, imageSize);
129
130 @override
131 String toString() => 'ImageSizeInfo($source, imageSize: $imageSize, displaySize: $displaySize)';
132}
133
134/// If not null, called when the framework is about to paint an [Image] to a
135/// [Canvas] with an [ImageSizeInfo] that contains the decoded size of the
136/// image as well as its output size.
137///
138/// A test can use this callback to detect if images under test are being
139/// rendered with the appropriate cache dimensions.
140///
141/// For example, if a 100x100 image is decoded it takes roughly 53kb in memory
142/// (including mipmapping overhead). If it is only ever displayed at 50x50, it
143/// would take only 13kb if the cacheHeight/cacheWidth parameters had been
144/// specified at that size. This problem becomes more serious for larger
145/// images, such as a high resolution image from a 12MP camera, which would be
146/// 64mb when decoded.
147///
148/// When using this callback, developers should consider whether the image will
149/// be panned or scaled up in the application, how many images are being
150/// displayed, and whether the application will run on multiple devices with
151/// different resolutions and memory capacities. For example, it should be fine
152/// to have an image that animates from thumbnail size to full screen be at
153/// a higher resolution while animating, but it would be problematic to have
154/// a grid or list of such thumbnails all be at the full resolution at the same
155/// time.
156PaintImageCallback? debugOnPaintImage;
157
158/// If true, the framework will color invert and horizontally flip images that
159/// have been decoded to a size taking at least [debugImageOverheadAllowance]
160/// bytes more than necessary.
161///
162/// It will also call [FlutterError.reportError] with information about the
163/// image's decoded size and its display size, which can be used resize the
164/// asset before shipping it, apply `cacheHeight` or `cacheWidth` parameters, or
165/// directly use a [ResizeImage]. Whenever possible, resizing the image asset
166/// itself should be preferred, to avoid unnecessary network traffic, disk space
167/// usage, and other memory overhead incurred during decoding.
168///
169/// Developers using this flag should test their application on appropriate
170/// devices and display sizes for their expected deployment targets when using
171/// these parameters. For example, an application that responsively resizes
172/// images for a desktop and mobile layout should avoid decoding all images at
173/// sizes appropriate for mobile when on desktop. Applications should also avoid
174/// animating these parameters, as each change will result in a newly decoded
175/// image. For example, an image that always grows into view should decode only
176/// at its largest size, whereas an image that normally is a thumbnail and then
177/// pops into view should be decoded at its smallest size for the thumbnail and
178/// the largest size when needed.
179///
180/// This has no effect unless asserts are enabled.
181bool debugInvertOversizedImages = false;
182
183const int _imageOverheadAllowanceDefault = 128 * 1024;
184
185/// The number of bytes an image must use before it triggers inversion when
186/// [debugInvertOversizedImages] is true.
187///
188/// Default is 128kb.
189int debugImageOverheadAllowance = _imageOverheadAllowanceDefault;
190
191/// Returns true if none of the painting library debug variables have been changed.
192///
193/// This function is used by the test framework to ensure that debug variables
194/// haven't been inadvertently changed.
195///
196/// See [the painting library](painting/painting-library.html) for a complete
197/// list.
198///
199/// The `debugDisableShadowsOverride` argument can be provided to override
200/// the expected value for [debugDisableShadows]. (This exists because the
201/// test framework itself overrides this value in some cases.)
202bool debugAssertAllPaintingVarsUnset(String reason, { bool debugDisableShadowsOverride = false }) {
203 assert(() {
204 if (debugDisableShadows != debugDisableShadowsOverride ||
205 debugNetworkImageHttpClientProvider != null ||
206 debugOnPaintImage != null ||
207 debugInvertOversizedImages ||
208 debugImageOverheadAllowance != _imageOverheadAllowanceDefault) {
209 throw FlutterError(reason);
210 }
211 return true;
212 }());
213 return true;
214}
215
216/// The signature of [debugCaptureShaderWarmUpPicture].
217///
218/// Used by tests to run assertions on the [Picture] created by
219/// [ShaderWarmUp.execute]. The return value indicates whether the assertions
220/// pass or not.
221typedef ShaderWarmUpPictureCallback = bool Function(Picture picture);
222
223/// The signature of [debugCaptureShaderWarmUpImage].
224///
225/// Used by tests to run assertions on the [Image] created by
226/// [ShaderWarmUp.execute]. The return value indicates whether the assertions
227/// pass or not.
228typedef ShaderWarmUpImageCallback = bool Function(Image image);
229
230/// Called by [ShaderWarmUp.execute] immediately after it creates a [Picture].
231///
232/// Tests may use this to capture the picture and run assertions on it.
233ShaderWarmUpPictureCallback debugCaptureShaderWarmUpPicture = _defaultPictureCapture;
234bool _defaultPictureCapture(Picture picture) => true;
235
236/// Called by [ShaderWarmUp.execute] immediately after it creates an [Image].
237///
238/// Tests may use this to capture the picture and run assertions on it.
239ShaderWarmUpImageCallback debugCaptureShaderWarmUpImage = _defaultImageCapture;
240bool _defaultImageCapture(Image image) => true;
241

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com