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