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