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'; |
16 | library; |
17 | |
18 | import 'dart:io'; |
19 | import 'dart:ui' show Image, Picture, Size; |
20 | |
21 | import '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. |
40 | bool debugDisableShadows = false; |
41 | |
42 | /// Signature for a method that returns an [HttpClient]. |
43 | /// |
44 | /// Used by [debugNetworkImageHttpClientProvider]. |
45 | typedef 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. |
56 | HttpClientProvider? 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]. |
63 | typedef 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 |
68 | class 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. |
156 | PaintImageCallback? 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. |
181 | bool debugInvertOversizedImages = false; |
182 | |
183 | const 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. |
189 | int 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.) |
202 | bool 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. |
221 | typedef 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. |
228 | typedef 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. |
233 | ShaderWarmUpPictureCallback debugCaptureShaderWarmUpPicture = _defaultPictureCapture; |
234 | bool _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. |
239 | ShaderWarmUpImageCallback debugCaptureShaderWarmUpImage = _defaultImageCapture; |
240 | bool _defaultImageCapture(Image image) => true; |
241 |
Definitions
- debugDisableShadows
- debugNetworkImageHttpClientProvider
- ImageSizeInfo
- ImageSizeInfo
- displaySizeInBytes
- decodedSizeInBytes
- _sizeToBytes
- toJson
- ==
- hashCode
- toString
- debugOnPaintImage
- debugInvertOversizedImages
- _imageOverheadAllowanceDefault
- debugImageOverheadAllowance
- debugAssertAllPaintingVarsUnset
- debugCaptureShaderWarmUpPicture
- _defaultPictureCapture
- debugCaptureShaderWarmUpImage
Learn more about Flutter for embedded and desktop on industrialflutter.com