1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef GFX_UTILS_H
7 #define GFX_UTILS_H
8
9 #include "gfxMatrix.h"
10 #include "gfxRect.h"
11 #include "gfxTypes.h"
12 #include "ImageTypes.h"
13 #include "imgIContainer.h"
14 #include "mozilla/gfx/2D.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/UniquePtr.h"
17 #include "nsColor.h"
18 #include "nsContentUtils.h"
19 #include "nsPrintfCString.h"
20 #include "nsRegionFwd.h"
21 #include "mozilla/gfx/Rect.h"
22 #include "mozilla/CheckedInt.h"
23 #include "mozilla/webrender/WebRenderTypes.h"
24 #include "qcms.h"
25
26 class gfxASurface;
27 class gfxDrawable;
28 struct gfxQuad;
29 class nsIInputStream;
30 class nsIGfxInfo;
31
32 namespace mozilla {
33 namespace dom {
34 class Element;
35 }
36 namespace layers {
37 class WebRenderBridgeChild;
38 class GlyphArray;
39 struct PlanarYCbCrData;
40 class WebRenderCommand;
41 } // namespace layers
42 namespace image {
43 class ImageRegion;
44 } // namespace image
45 namespace wr {
46 class DisplayListBuilder;
47 } // namespace wr
48 } // namespace mozilla
49
50 enum class ImageType {
51 BMP,
52 ICO,
53 JPEG,
54 PNG,
55 };
56
57 class gfxUtils {
58 public:
59 typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
60 typedef mozilla::gfx::DrawTarget DrawTarget;
61 typedef mozilla::gfx::IntPoint IntPoint;
62 typedef mozilla::gfx::Matrix Matrix;
63 typedef mozilla::gfx::Matrix4x4 Matrix4x4;
64 typedef mozilla::gfx::SourceSurface SourceSurface;
65 typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
66 typedef mozilla::image::ImageRegion ImageRegion;
67
68 /*
69 * Premultiply or Unpremultiply aSourceSurface, writing the result
70 * to aDestSurface or back into aSourceSurface if aDestSurface is null.
71 *
72 * If aDestSurface is given, it must have identical format, dimensions, and
73 * stride as the source.
74 *
75 * If the source is not SurfaceFormat::A8R8G8B8_UINT32, no operation is
76 * performed. If aDestSurface is given, the data is copied over.
77 */
78 static bool PremultiplyDataSurface(DataSourceSurface* srcSurf,
79 DataSourceSurface* destSurf);
80 static bool UnpremultiplyDataSurface(DataSourceSurface* srcSurf,
81 DataSourceSurface* destSurf);
82
83 static already_AddRefed<DataSourceSurface> CreatePremultipliedDataSurface(
84 DataSourceSurface* srcSurf);
85 static already_AddRefed<DataSourceSurface> CreateUnpremultipliedDataSurface(
86 DataSourceSurface* srcSurf);
87
88 static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);
89
90 /**
91 * Draw something drawable while working around limitations like bad support
92 * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with
93 * extreme user-space-to-image-space transforms.
94 *
95 * The input parameters here usually come from the output of our image
96 * snapping algorithm in nsLayoutUtils.cpp.
97 * This method is split from nsLayoutUtils::DrawPixelSnapped to allow for
98 * adjusting the parameters. For example, certain images with transparent
99 * margins only have a drawable subimage. For those images, imgFrame::Draw
100 * will tweak the rects and transforms that it gets from the pixel snapping
101 * algorithm before passing them on to this method.
102 */
103 static void DrawPixelSnapped(gfxContext* aContext, gfxDrawable* aDrawable,
104 const gfxSize& aImageSize,
105 const ImageRegion& aRegion,
106 const mozilla::gfx::SurfaceFormat aFormat,
107 mozilla::gfx::SamplingFilter aSamplingFilter,
108 uint32_t aImageFlags = imgIContainer::FLAG_NONE,
109 gfxFloat aOpacity = 1.0,
110 bool aUseOptimalFillOp = true);
111
112 /**
113 * Clip aContext to the region aRegion.
114 */
115 static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion);
116
117 /**
118 * Clip aTarget to the region aRegion.
119 */
120 static void ClipToRegion(mozilla::gfx::DrawTarget* aTarget,
121 const nsIntRegion& aRegion);
122
123 /*
124 * Convert image format to depth value
125 */
126 static int ImageFormatToDepth(gfxImageFormat aFormat);
127
128 /**
129 * Return the transform matrix that maps aFrom to the rectangle defined by
130 * aToTopLeft/aToTopRight/aToBottomRight. aFrom must be
131 * nonempty and the destination rectangle must be axis-aligned.
132 */
133 static gfxMatrix TransformRectToRect(const gfxRect& aFrom,
134 const gfxPoint& aToTopLeft,
135 const gfxPoint& aToTopRight,
136 const gfxPoint& aToBottomRight);
137
138 static Matrix TransformRectToRect(const gfxRect& aFrom,
139 const IntPoint& aToTopLeft,
140 const IntPoint& aToTopRight,
141 const IntPoint& aToBottomRight);
142
143 /**
144 * If aIn can be represented exactly using an gfx::IntRect (i.e.
145 * integer-aligned edges and coordinates in the int32_t range) then we
146 * set aOut to that rectangle, otherwise return failure.
147 */
148 static bool GfxRectToIntRect(const gfxRect& aIn, mozilla::gfx::IntRect* aOut);
149
150 /* Conditions this border to Cairo's max coordinate space.
151 * The caller can check IsEmpty() after Condition() -- if it's TRUE,
152 * the caller can possibly avoid doing any extra rendering.
153 */
154 static void ConditionRect(gfxRect& aRect);
155
156 /*
157 * Transform this rectangle with aMatrix, resulting in a gfxQuad.
158 */
159 static gfxQuad TransformToQuad(const gfxRect& aRect,
160 const mozilla::gfx::Matrix4x4& aMatrix);
161
162 /**
163 * Return the smallest power of kScaleResolution (2) greater than or equal to
164 * aVal. If aRoundDown is specified, the power of 2 will rather be less than
165 * or equal to aVal.
166 */
167 static float ClampToScaleFactor(float aVal, bool aRoundDown = false);
168
169 /**
170 * We can snap layer transforms for two reasons:
171 * 1) To avoid unnecessary resampling when a transform is a translation
172 * by a non-integer number of pixels.
173 * Snapping the translation to an integer number of pixels avoids
174 * blurring the layer and can be faster to composite.
175 * 2) When a layer is used to render a rectangular object, we need to
176 * emulate the rendering of rectangular inactive content and snap the
177 * edges of the rectangle to pixel boundaries. This is both to ensure
178 * layer rendering is consistent with inactive content rendering, and to
179 * avoid seams.
180 * This function implements type 1 snapping. If aTransform is a 2D
181 * translation, and this layer's layer manager has enabled snapping
182 * (which is the default), return aTransform with the translation snapped
183 * to nearest pixels. Otherwise just return aTransform. Call this when the
184 * layer does not correspond to a single rectangular content object.
185 * This function does not try to snap if aTransform has a scale, because in
186 * that case resampling is inevitable and there's no point in trying to
187 * avoid it. In fact snapping can cause problems because pixel edges in the
188 * layer's content can be rendered unpredictably (jiggling) as the scale
189 * interacts with the snapping of the translation, especially with animated
190 * transforms.
191 * @param aResidualTransform a transform to apply before the result transform
192 * in order to get the results to completely match aTransform.
193 */
194 static Matrix4x4 SnapTransformTranslation(const Matrix4x4& aTransform,
195 Matrix* aResidualTransform);
196 static Matrix SnapTransformTranslation(const Matrix& aTransform,
197 Matrix* aResidualTransform);
198 static Matrix4x4 SnapTransformTranslation3D(const Matrix4x4& aTransform,
199 Matrix* aResidualTransform);
200 /**
201 * See comment for SnapTransformTranslation.
202 * This function implements type 2 snapping. If aTransform is a translation
203 * and/or scale, transform aSnapRect by aTransform, snap to pixel boundaries,
204 * and return the transform that maps aSnapRect to that rect. Otherwise
205 * just return aTransform.
206 * @param aSnapRect a rectangle whose edges should be snapped to pixel
207 * boundaries in the destination surface.
208 * @param aResidualTransform a transform to apply before the result transform
209 * in order to get the results to completely match aTransform.
210 */
211 static Matrix4x4 SnapTransform(const Matrix4x4& aTransform,
212 const gfxRect& aSnapRect,
213 Matrix* aResidualTransform);
214 static Matrix SnapTransform(const Matrix& aTransform,
215 const gfxRect& aSnapRect,
216 Matrix* aResidualTransform);
217
218 /**
219 * Clears surface to aColor (which defaults to transparent black).
220 */
221 static void ClearThebesSurface(gfxASurface* aSurface);
222
223 static const float* YuvToRgbMatrix4x3RowMajor(
224 mozilla::gfx::YUVColorSpace aYUVColorSpace);
225 static const float* YuvToRgbMatrix3x3ColumnMajor(
226 mozilla::gfx::YUVColorSpace aYUVColorSpace);
227 static const float* YuvToRgbMatrix4x4ColumnMajor(
228 mozilla::gfx::YUVColorSpace aYUVColorSpace);
229
230 static mozilla::Maybe<mozilla::gfx::YUVColorSpace> CicpToColorSpace(
231 const mozilla::gfx::CICP::MatrixCoefficients,
232 const mozilla::gfx::CICP::ColourPrimaries,
233 mozilla::LazyLogModule& aLogger);
234
235 /**
236 * Creates a copy of aSurface, but having the SurfaceFormat aFormat.
237 *
238 * This function always creates a new surface. Do not call it if aSurface's
239 * format is the same as aFormat. Such a non-conversion would just be an
240 * unnecessary and wasteful copy (this function asserts to prevent that).
241 *
242 * This function is intended to be called by code that needs to access the
243 * pixel data of the surface, but doesn't want to have lots of branches
244 * to handle different pixel data formats (code which would become out of
245 * date if and when new formats are added). Callers can use this function
246 * to copy the surface to a specified format so that they only have to
247 * handle pixel data in that one format.
248 *
249 * WARNING: There are format conversions that will not be supported by this
250 * function. It very much depends on what the Moz2D backends support. If
251 * the temporary B8G8R8A8 DrawTarget that this function creates has a
252 * backend that supports DrawSurface() calls passing a surface with
253 * aSurface's format it will work. Otherwise it will not.
254 *
255 * *** IMPORTANT PERF NOTE ***
256 *
257 * This function exists partly because format conversion is fraught with
258 * non-obvious performance hazards, so we don't want Moz2D consumers to be
259 * doing their own format conversion. Do not try to do so, or at least read
260 * the comments in this functions implemtation. That said, the copy that
261 * this function carries out has a cost and, although this function tries
262 * to avoid perf hazards such as expensive uploads to/readbacks from the
263 * GPU, it can't guarantee that it always successfully does so. Perf
264 * critical code that can directly handle the common formats that it
265 * encounters in a way that is cheaper than a copy-with-format-conversion
266 * should consider doing so, and only use this function as a fallback to
267 * handle other formats.
268 *
269 * XXXjwatt it would be nice if SourceSurface::GetDataSurface took a
270 * SurfaceFormat argument (with a default argument meaning "use the
271 * existing surface's format") and returned a DataSourceSurface in that
272 * format. (There would then be an issue of callers maybe failing to
273 * realize format conversion may involve expensive copying/uploading/
274 * readback.)
275 */
276 static already_AddRefed<DataSourceSurface>
277 CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
278 SurfaceFormat aFormat);
279
280 /**
281 * Return a color that can be used to identify a frame with a given frame
282 * number. The colors will cycle after sNumFrameColors. You can query colors
283 * 0 .. sNumFrameColors-1 to get all the colors back.
284 */
285 static const mozilla::gfx::DeviceColor& GetColorForFrameNumber(
286 uint64_t aFrameNumber);
287 static const uint32_t sNumFrameColors;
288
289 enum BinaryOrData { eBinaryEncode, eDataURIEncode };
290
291 /**
292 * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder.
293 * If both aFile and aString are null, the encoded data is copied to the
294 * clipboard.
295 *
296 * @param aImageType The image type that the surface is to be encoded to.
297 * Used to create an appropriate imgIEncoder instance to do the encoding.
298 *
299 * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
300 * the value of the |outputOptions| parameter. Callers are responsible
301 * for making sure that this is a sane value for the passed MIME-type
302 * (i.e. for the type of encoder that will be created).
303 *
304 * @aBinaryOrData Flag used to determine if the surface is simply encoded
305 * to the requested binary image format, or if the binary image is
306 * further converted to base-64 and written out as a 'data:' URI.
307 *
308 * @aFile If specified, the encoded data is written out to aFile.
309 *
310 * @aString If specified, the encoded data is written out to aString.
311 *
312 * TODO: Copying to the clipboard as a binary file is not currently
313 * supported.
314 */
315 static nsresult EncodeSourceSurface(SourceSurface* aSurface,
316 const ImageType aImageType,
317 const nsAString& aOutputOptions,
318 BinaryOrData aBinaryOrData, FILE* aFile,
319 nsACString* aString = nullptr);
320
321 /**
322 * Write as a PNG file to the path aFile.
323 */
324 static void WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile);
325 static void WriteAsPNG(SourceSurface* aSurface, const char* aFile);
326 static void WriteAsPNG(DrawTarget* aDT, const nsAString& aFile);
327 static void WriteAsPNG(DrawTarget* aDT, const char* aFile);
328
329 /**
330 * Dump as a PNG encoded Data URL to a FILE stream (using stdout by
331 * default).
332 *
333 * Rather than giving aFile a default argument we have separate functions
334 * to make them easier to use from a debugger.
335 */
336 static void DumpAsDataURI(SourceSurface* aSourceSurface, FILE* aFile);
DumpAsDataURI(SourceSurface * aSourceSurface)337 static inline void DumpAsDataURI(SourceSurface* aSourceSurface) {
338 DumpAsDataURI(aSourceSurface, stdout);
339 }
340 static void DumpAsDataURI(DrawTarget* aDT, FILE* aFile);
DumpAsDataURI(DrawTarget * aDT)341 static inline void DumpAsDataURI(DrawTarget* aDT) {
342 DumpAsDataURI(aDT, stdout);
343 }
344 static nsCString GetAsDataURI(SourceSurface* aSourceSurface);
345 static nsCString GetAsDataURI(DrawTarget* aDT);
346 static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface);
347
348 static mozilla::UniquePtr<uint8_t[]> GetImageBuffer(
349 DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
350 int32_t* outFormat);
351
352 static nsresult GetInputStream(DataSourceSurface* aSurface,
353 bool aIsAlphaPremultiplied,
354 const char* aMimeType,
355 const nsAString& aEncoderOptions,
356 nsIInputStream** outStream);
357
358 static void RemoveShaderCacheFromDiskIfNecessary();
359
360 /**
361 * Copy to the clipboard as a PNG encoded Data URL.
362 */
363 static void CopyAsDataURI(SourceSurface* aSourceSurface);
364 static void CopyAsDataURI(DrawTarget* aDT);
365
366 static bool DumpDisplayList();
367
368 static FILE* sDumpPaintFile;
369 };
370
371 namespace mozilla {
372
373 struct StyleRGBA;
374
375 namespace gfx {
376
377 /**
378 * If the CMS mode is CMSMode::All, these functions transform the passed
379 * color to a device color using the transform returned by
380 * gfxPlatform::GetCMSRGBTransform(). If the CMS mode is some other value, the
381 * color is returned unchanged (other than a type change to Moz2D Color, if
382 * applicable).
383 */
384 DeviceColor ToDeviceColor(const sRGBColor& aColor);
385 DeviceColor ToDeviceColor(const StyleRGBA& aColor);
386 DeviceColor ToDeviceColor(nscolor aColor);
387
388 /**
389 * Performs a checked multiply of the given width, height, and bytes-per-pixel
390 * values.
391 */
SafeBytesForBitmap(uint32_t aWidth,uint32_t aHeight,unsigned aBytesPerPixel)392 static inline CheckedInt<uint32_t> SafeBytesForBitmap(uint32_t aWidth,
393 uint32_t aHeight,
394 unsigned aBytesPerPixel) {
395 MOZ_ASSERT(aBytesPerPixel > 0);
396 CheckedInt<uint32_t> width = uint32_t(aWidth);
397 CheckedInt<uint32_t> height = uint32_t(aHeight);
398 return width * height * aBytesPerPixel;
399 }
400
401 } // namespace gfx
402 } // namespace mozilla
403
404 #endif
405