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