Bug 1856663 - Add more chunks for Android mochitest-plain. r=jmaher,taskgraph-reviewe...
[gecko.git] / gfx / thebes / gfxUtils.h
bloba7b9f067ebbfcf820443ca39ab5f9ab754ad34c8
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/. */
6 #ifndef GFX_UTILS_H
7 #define GFX_UTILS_H
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/Maybe.h"
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/UniquePtr.h"
18 #include "nsColor.h"
19 #include "nsContentUtils.h"
20 #include "nsPrintfCString.h"
21 #include "nsRegionFwd.h"
22 #include "mozilla/gfx/Rect.h"
23 #include "mozilla/CheckedInt.h"
24 #include "mozilla/webrender/WebRenderTypes.h"
25 #include "qcms.h"
27 class gfxASurface;
28 class gfxDrawable;
29 class gfxTextRun;
30 struct gfxQuad;
31 class nsICookieJarSettings;
32 class nsIInputStream;
33 class nsIGfxInfo;
35 namespace mozilla {
36 namespace dom {
37 class Element;
38 } // namespace dom
39 namespace layers {
40 class WebRenderBridgeChild;
41 class GlyphArray;
42 struct PlanarYCbCrData;
43 class WebRenderCommand;
44 } // namespace layers
45 namespace image {
46 class ImageRegion;
47 } // namespace image
48 namespace wr {
49 class DisplayListBuilder;
50 } // namespace wr
51 } // namespace mozilla
53 enum class ImageType {
54 BMP,
55 ICO,
56 JPEG,
57 PNG,
60 class gfxUtils {
61 public:
62 typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
63 typedef mozilla::gfx::DrawTarget DrawTarget;
64 typedef mozilla::gfx::IntPoint IntPoint;
65 typedef mozilla::gfx::Matrix Matrix;
66 typedef mozilla::gfx::Matrix4x4 Matrix4x4;
67 typedef mozilla::gfx::SourceSurface SourceSurface;
68 typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
69 typedef mozilla::image::ImageRegion ImageRegion;
72 * Premultiply or Unpremultiply aSourceSurface, writing the result
73 * to aDestSurface or back into aSourceSurface if aDestSurface is null.
75 * If aDestSurface is given, it must have identical format, dimensions, and
76 * stride as the source.
78 * If the source is not SurfaceFormat::A8R8G8B8_UINT32, no operation is
79 * performed. If aDestSurface is given, the data is copied over.
81 static bool PremultiplyDataSurface(DataSourceSurface* srcSurf,
82 DataSourceSurface* destSurf);
83 static bool UnpremultiplyDataSurface(DataSourceSurface* srcSurf,
84 DataSourceSurface* destSurf);
86 static already_AddRefed<DataSourceSurface> CreatePremultipliedDataSurface(
87 DataSourceSurface* srcSurf);
88 static already_AddRefed<DataSourceSurface> CreateUnpremultipliedDataSurface(
89 DataSourceSurface* srcSurf);
91 static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);
93 /**
94 * Draw something drawable while working around limitations like bad support
95 * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with
96 * extreme user-space-to-image-space transforms.
98 * The input parameters here usually come from the output of our image
99 * snapping algorithm in nsLayoutUtils.cpp.
100 * This method is split from nsLayoutUtils::DrawPixelSnapped to allow for
101 * adjusting the parameters. For example, certain images with transparent
102 * margins only have a drawable subimage. For those images, imgFrame::Draw
103 * will tweak the rects and transforms that it gets from the pixel snapping
104 * algorithm before passing them on to this method.
106 static void DrawPixelSnapped(gfxContext* aContext, gfxDrawable* aDrawable,
107 const gfxSize& aImageSize,
108 const ImageRegion& aRegion,
109 const mozilla::gfx::SurfaceFormat aFormat,
110 mozilla::gfx::SamplingFilter aSamplingFilter,
111 uint32_t aImageFlags = imgIContainer::FLAG_NONE,
112 gfxFloat aOpacity = 1.0,
113 bool aUseOptimalFillOp = true);
116 * Clip aContext to the region aRegion.
118 static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion);
121 * Clip aTarget to the region aRegion.
123 static void ClipToRegion(mozilla::gfx::DrawTarget* aTarget,
124 const nsIntRegion& aRegion);
127 * Convert image format to depth value
129 static int ImageFormatToDepth(gfxImageFormat aFormat);
132 * Return the transform matrix that maps aFrom to the rectangle defined by
133 * aToTopLeft/aToTopRight/aToBottomRight. aFrom must be
134 * nonempty and the destination rectangle must be axis-aligned.
136 static gfxMatrix TransformRectToRect(const gfxRect& aFrom,
137 const gfxPoint& aToTopLeft,
138 const gfxPoint& aToTopRight,
139 const gfxPoint& aToBottomRight);
141 static Matrix TransformRectToRect(const gfxRect& aFrom,
142 const IntPoint& aToTopLeft,
143 const IntPoint& aToTopRight,
144 const IntPoint& aToBottomRight);
147 * If aIn can be represented exactly using an gfx::IntRect (i.e.
148 * integer-aligned edges and coordinates in the int32_t range) then we
149 * set aOut to that rectangle, otherwise return failure.
151 static bool GfxRectToIntRect(const gfxRect& aIn, mozilla::gfx::IntRect* aOut);
153 /* Conditions this border to Cairo's max coordinate space.
154 * The caller can check IsEmpty() after Condition() -- if it's TRUE,
155 * the caller can possibly avoid doing any extra rendering.
157 static void ConditionRect(gfxRect& aRect);
160 * Transform this rectangle with aMatrix, resulting in a gfxQuad.
162 static gfxQuad TransformToQuad(const gfxRect& aRect,
163 const mozilla::gfx::Matrix4x4& aMatrix);
166 * Return the smallest power of kScaleResolution (2) greater than or equal to
167 * aVal. If aRoundDown is specified, the power of 2 will rather be less than
168 * or equal to aVal.
170 static float ClampToScaleFactor(float aVal, bool aRoundDown = false);
173 * We can snap layer transforms for two reasons:
174 * 1) To avoid unnecessary resampling when a transform is a translation
175 * by a non-integer number of pixels.
176 * Snapping the translation to an integer number of pixels avoids
177 * blurring the layer and can be faster to composite.
178 * 2) When a layer is used to render a rectangular object, we need to
179 * emulate the rendering of rectangular inactive content and snap the
180 * edges of the rectangle to pixel boundaries. This is both to ensure
181 * layer rendering is consistent with inactive content rendering, and to
182 * avoid seams.
183 * This function implements type 1 snapping. If aTransform is a 2D
184 * translation, and this layer's layer manager has enabled snapping
185 * (which is the default), return aTransform with the translation snapped
186 * to nearest pixels. Otherwise just return aTransform. Call this when the
187 * layer does not correspond to a single rectangular content object.
188 * This function does not try to snap if aTransform has a scale, because in
189 * that case resampling is inevitable and there's no point in trying to
190 * avoid it. In fact snapping can cause problems because pixel edges in the
191 * layer's content can be rendered unpredictably (jiggling) as the scale
192 * interacts with the snapping of the translation, especially with animated
193 * transforms.
194 * @param aResidualTransform a transform to apply before the result transform
195 * in order to get the results to completely match aTransform.
197 static Matrix4x4 SnapTransformTranslation(const Matrix4x4& aTransform,
198 Matrix* aResidualTransform);
199 static Matrix SnapTransformTranslation(const Matrix& aTransform,
200 Matrix* aResidualTransform);
201 static Matrix4x4 SnapTransformTranslation3D(const Matrix4x4& aTransform,
202 Matrix* aResidualTransform);
204 * See comment for SnapTransformTranslation.
205 * This function implements type 2 snapping. If aTransform is a translation
206 * and/or scale, transform aSnapRect by aTransform, snap to pixel boundaries,
207 * and return the transform that maps aSnapRect to that rect. Otherwise
208 * just return aTransform.
209 * @param aSnapRect a rectangle whose edges should be snapped to pixel
210 * boundaries in the destination surface.
211 * @param aResidualTransform a transform to apply before the result transform
212 * in order to get the results to completely match aTransform.
214 static Matrix4x4 SnapTransform(const Matrix4x4& aTransform,
215 const gfxRect& aSnapRect,
216 Matrix* aResidualTransform);
217 static Matrix SnapTransform(const Matrix& aTransform,
218 const gfxRect& aSnapRect,
219 Matrix* aResidualTransform);
222 * Clears surface to aColor (which defaults to transparent black).
224 static void ClearThebesSurface(gfxASurface* aSurface);
226 static const float* YuvToRgbMatrix4x3RowMajor(
227 mozilla::gfx::YUVColorSpace aYUVColorSpace);
228 static const float* YuvToRgbMatrix3x3ColumnMajor(
229 mozilla::gfx::YUVColorSpace aYUVColorSpace);
230 static const float* YuvToRgbMatrix4x4ColumnMajor(
231 mozilla::gfx::YUVColorSpace aYUVColorSpace);
233 static mozilla::Maybe<mozilla::gfx::YUVColorSpace> CicpToColorSpace(
234 const mozilla::gfx::CICP::MatrixCoefficients,
235 const mozilla::gfx::CICP::ColourPrimaries,
236 mozilla::LazyLogModule& aLogger);
238 static mozilla::Maybe<mozilla::gfx::ColorSpace2> CicpToColorPrimaries(
239 const mozilla::gfx::CICP::ColourPrimaries,
240 mozilla::LazyLogModule& aLogger);
242 static mozilla::Maybe<mozilla::gfx::TransferFunction> CicpToTransferFunction(
243 const mozilla::gfx::CICP::TransferCharacteristics);
246 * Creates a copy of aSurface, but having the SurfaceFormat aFormat.
248 * This function always creates a new surface. Do not call it if aSurface's
249 * format is the same as aFormat. Such a non-conversion would just be an
250 * unnecessary and wasteful copy (this function asserts to prevent that).
252 * This function is intended to be called by code that needs to access the
253 * pixel data of the surface, but doesn't want to have lots of branches
254 * to handle different pixel data formats (code which would become out of
255 * date if and when new formats are added). Callers can use this function
256 * to copy the surface to a specified format so that they only have to
257 * handle pixel data in that one format.
259 * WARNING: There are format conversions that will not be supported by this
260 * function. It very much depends on what the Moz2D backends support. If
261 * the temporary B8G8R8A8 DrawTarget that this function creates has a
262 * backend that supports DrawSurface() calls passing a surface with
263 * aSurface's format it will work. Otherwise it will not.
265 * *** IMPORTANT PERF NOTE ***
267 * This function exists partly because format conversion is fraught with
268 * non-obvious performance hazards, so we don't want Moz2D consumers to be
269 * doing their own format conversion. Do not try to do so, or at least read
270 * the comments in this functions implemtation. That said, the copy that
271 * this function carries out has a cost and, although this function tries
272 * to avoid perf hazards such as expensive uploads to/readbacks from the
273 * GPU, it can't guarantee that it always successfully does so. Perf
274 * critical code that can directly handle the common formats that it
275 * encounters in a way that is cheaper than a copy-with-format-conversion
276 * should consider doing so, and only use this function as a fallback to
277 * handle other formats.
279 * XXXjwatt it would be nice if SourceSurface::GetDataSurface took a
280 * SurfaceFormat argument (with a default argument meaning "use the
281 * existing surface's format") and returned a DataSourceSurface in that
282 * format. (There would then be an issue of callers maybe failing to
283 * realize format conversion may involve expensive copying/uploading/
284 * readback.)
286 static already_AddRefed<DataSourceSurface>
287 CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
288 SurfaceFormat aFormat);
291 * Return a color that can be used to identify a frame with a given frame
292 * number. The colors will cycle after sNumFrameColors. You can query colors
293 * 0 .. sNumFrameColors-1 to get all the colors back.
295 static const mozilla::gfx::DeviceColor& GetColorForFrameNumber(
296 uint64_t aFrameNumber);
297 static const uint32_t sNumFrameColors;
299 enum BinaryOrData { eBinaryEncode, eDataURIEncode };
302 * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder.
303 * If both aFile and aString are null, the encoded data is copied to the
304 * clipboard.
306 * @param aImageType The image type that the surface is to be encoded to.
307 * Used to create an appropriate imgIEncoder instance to do the encoding.
309 * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
310 * the value of the |outputOptions| parameter. Callers are responsible
311 * for making sure that this is a reasonable value for the passed MIME-type
312 * (i.e. for the type of encoder that will be created).
314 * @aBinaryOrData Flag used to determine if the surface is simply encoded
315 * to the requested binary image format, or if the binary image is
316 * further converted to base-64 and written out as a 'data:' URI.
318 * @aFile If specified, the encoded data is written out to aFile.
320 * @aString If specified, the encoded data is written out to aString.
322 * TODO: Copying to the clipboard as a binary file is not currently
323 * supported.
325 static nsresult EncodeSourceSurface(SourceSurface* aSurface,
326 const ImageType aImageType,
327 const nsAString& aOutputOptions,
328 BinaryOrData aBinaryOrData, FILE* aFile,
329 nsACString* aString = nullptr);
332 * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder
333 * and returns the result as an nsIInputStream.
335 * @param aSurface The source surface to encode
337 * @param aImageType The image type that the surface is to be encoded to.
338 * Used to create an appropriate imgIEncoder instance to do the encoding.
340 * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
341 * the value of the |outputOptions| parameter. Callers are responsible
342 * for making sure that this is a reasonable value for the passed MIME-type
343 * (i.e. for the type of encoder that will be created).
345 * @param aOutStream pointer to the output stream
348 static nsresult EncodeSourceSurfaceAsStream(SourceSurface* aSurface,
349 const ImageType aImageType,
350 const nsAString& aOutputOptions,
351 nsIInputStream** aOutStream);
354 * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder
355 * and returns the result as a vector of bytes
357 * @param aImageType The image type that the surface is to be encoded to.
358 * Used to create an appropriate imgIEncoder instance to do the encoding.
360 * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
361 * the value of the |outputOptions| parameter. Callers are responsible
362 * for making sure that this is a reasonable value for the passed MIME-type
363 * (i.e. for the type of encoder that will be created).
366 static mozilla::Maybe<nsTArray<uint8_t>> EncodeSourceSurfaceAsBytes(
367 SourceSurface* aSurface, const ImageType aImageType,
368 const nsAString& aOutputOptions);
371 * Write as a PNG file to the path aFile.
373 static void WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile);
374 static void WriteAsPNG(SourceSurface* aSurface, const char* aFile);
375 static void WriteAsPNG(DrawTarget* aDT, const nsAString& aFile);
376 static void WriteAsPNG(DrawTarget* aDT, const char* aFile);
379 * Dump as a PNG encoded Data URL to a FILE stream (using stdout by
380 * default).
382 * Rather than giving aFile a default argument we have separate functions
383 * to make them easier to use from a debugger.
385 static void DumpAsDataURI(SourceSurface* aSourceSurface, FILE* aFile);
386 static inline void DumpAsDataURI(SourceSurface* aSourceSurface) {
387 DumpAsDataURI(aSourceSurface, stdout);
389 static void DumpAsDataURI(DrawTarget* aDT, FILE* aFile);
390 static inline void DumpAsDataURI(DrawTarget* aDT) {
391 DumpAsDataURI(aDT, stdout);
393 static nsCString GetAsDataURI(SourceSurface* aSourceSurface);
394 static nsCString GetAsDataURI(DrawTarget* aDT);
395 static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface);
397 static mozilla::UniquePtr<uint8_t[]> GetImageBuffer(
398 DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
399 int32_t* outFormat);
401 static mozilla::UniquePtr<uint8_t[]> GetImageBufferWithRandomNoise(
402 DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
403 nsICookieJarSettings* aCookieJarSettings, int32_t* outFormat);
405 static nsresult GetInputStream(DataSourceSurface* aSurface,
406 bool aIsAlphaPremultiplied,
407 const char* aMimeType,
408 const nsAString& aEncoderOptions,
409 nsIInputStream** outStream);
411 static nsresult GetInputStreamWithRandomNoise(
412 DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
413 const char* aMimeType, const nsAString& aEncoderOptions,
414 nsICookieJarSettings* aCookieJarSettings, nsIInputStream** outStream);
416 static void RemoveShaderCacheFromDiskIfNecessary();
419 * Copy to the clipboard as a PNG encoded Data URL.
421 static void CopyAsDataURI(SourceSurface* aSourceSurface);
422 static void CopyAsDataURI(DrawTarget* aDT);
424 static bool DumpDisplayList();
426 static FILE* sDumpPaintFile;
429 namespace mozilla {
431 // Container for either a single element of type T, or an nsTArray<T>.
432 // Provides a minimal subset of nsTArray's API, just enough to support use
433 // by ContextState for the clipsAndTransforms list, and by gfxTextRun for
434 // its mGlyphRuns.
435 // Using this instead of a simple nsTArray avoids an extra allocation in the
436 // common case where no more than one element is ever added to the list.
437 // Unlike an AutoTArray<..., 1>, this class is memmovable and therefore can
438 // be used in ContextState without breaking its movability.
439 template <typename T>
440 class ElementOrArray {
441 union {
442 T mElement;
443 nsTArray<T> mArray;
445 enum class Tag : uint8_t {
446 Element,
447 Array,
448 } mTag;
450 // gfxTextRun::SortGlyphRuns and SanitizeGlyphRuns directly access the array.
451 friend class ::gfxTextRun;
452 nsTArray<T>& Array() {
453 MOZ_DIAGNOSTIC_ASSERT(mTag == Tag::Array);
454 return mArray;
457 public:
458 // Construct as an empty array.
459 ElementOrArray() : mTag(Tag::Array) { new (&mArray) nsTArray<T>(); }
461 // For now, don't support copy/move.
462 ElementOrArray(const ElementOrArray&) = delete;
463 ElementOrArray(ElementOrArray&&) = delete;
465 ElementOrArray& operator=(const ElementOrArray&) = delete;
466 ElementOrArray& operator=(ElementOrArray&&) = delete;
468 // Destroy the appropriate variant.
469 ~ElementOrArray() {
470 switch (mTag) {
471 case Tag::Element:
472 mElement.~T();
473 break;
474 case Tag::Array:
475 mArray.~nsTArray();
476 break;
480 size_t Length() const { return mTag == Tag::Element ? 1 : mArray.Length(); }
482 T* AppendElement(const T& aElement) {
483 switch (mTag) {
484 case Tag::Element: {
485 // Move the existing element into an array, then append the new one.
486 T temp = std::move(mElement);
487 mElement.~T();
488 mTag = Tag::Array;
489 new (&mArray) nsTArray<T>();
490 mArray.AppendElement(std::move(temp));
491 return mArray.AppendElement(aElement);
493 case Tag::Array: {
494 // If currently empty, just store the element directly.
495 if (mArray.IsEmpty()) {
496 mArray.~nsTArray();
497 mTag = Tag::Element;
498 new (&mElement) T(aElement);
499 return &mElement;
501 // Otherwise, append it to the array.
502 return mArray.AppendElement(aElement);
504 default:
505 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("invalid tag");
509 const T& LastElement() const {
510 return mTag == Tag::Element ? mElement : mArray.LastElement();
513 T& LastElement() {
514 return mTag == Tag::Element ? mElement : mArray.LastElement();
517 bool IsEmpty() const {
518 return mTag == Tag::Element ? false : mArray.IsEmpty();
521 void TruncateLength(uint32_t aLength = 0) {
522 MOZ_DIAGNOSTIC_ASSERT(aLength <= Length());
523 switch (mTag) {
524 case Tag::Element:
525 if (aLength == 0) {
526 // Destroy the single element, and convert to an empty array.
527 mElement.~T();
528 mTag = Tag::Array;
529 new (&mArray) nsTArray<T>();
531 break;
532 case Tag::Array:
533 mArray.TruncateLength(aLength);
534 break;
538 void Clear() {
539 switch (mTag) {
540 case Tag::Element:
541 mElement.~T();
542 mTag = Tag::Array;
543 new (&mArray) nsTArray<T>();
544 break;
545 case Tag::Array:
546 mArray.Clear();
547 break;
551 // Convert from Array to Element storage. Only to be used when the current
552 // state is a single-element array!
553 void ConvertToElement() {
554 MOZ_DIAGNOSTIC_ASSERT(mTag == Tag::Array && mArray.Length() == 1);
555 T temp = std::move(mArray[0]);
556 mArray.~nsTArray();
557 mTag = Tag::Element;
558 new (&mElement) T(std::move(temp));
561 const T& operator[](uint32_t aIndex) const {
562 MOZ_DIAGNOSTIC_ASSERT(aIndex < Length());
563 return mTag == Tag::Element ? mElement : mArray[aIndex];
565 T& operator[](uint32_t aIndex) {
566 MOZ_DIAGNOSTIC_ASSERT(aIndex < Length());
567 return mTag == Tag::Element ? mElement : mArray[aIndex];
570 // Simple iterators to support range-for loops.
571 const T* begin() const {
572 return mTag == Tag::Array ? mArray.IsEmpty() ? nullptr : &*mArray.begin()
573 : &mElement;
575 T* begin() {
576 return mTag == Tag::Array ? mArray.IsEmpty() ? nullptr : &*mArray.begin()
577 : &mElement;
580 const T* end() const {
581 return mTag == Tag::Array ? begin() + mArray.Length() : &mElement + 1;
583 T* end() {
584 return mTag == Tag::Array ? begin() + mArray.Length() : &mElement + 1;
587 size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
588 return mTag == Tag::Array ? mArray.ShallowSizeOfExcludingThis(aMallocSizeOf)
589 : 0;
593 struct StyleAbsoluteColor;
595 namespace gfx {
598 * If the CMS mode is CMSMode::All, these functions transform the passed
599 * color to a device color using the transform returned by
600 * gfxPlatform::GetCMSRGBTransform(). If the CMS mode is some other value, the
601 * color is returned unchanged (other than a type change to Moz2D Color, if
602 * applicable).
604 DeviceColor ToDeviceColor(const sRGBColor&);
605 DeviceColor ToDeviceColor(const StyleAbsoluteColor&);
606 DeviceColor ToDeviceColor(nscolor);
608 sRGBColor ToSRGBColor(const StyleAbsoluteColor&);
611 * Performs a checked multiply of the given width, height, and bytes-per-pixel
612 * values.
614 static inline CheckedInt<uint32_t> SafeBytesForBitmap(uint32_t aWidth,
615 uint32_t aHeight,
616 unsigned aBytesPerPixel) {
617 MOZ_ASSERT(aBytesPerPixel > 0);
618 CheckedInt<uint32_t> width = uint32_t(aWidth);
619 CheckedInt<uint32_t> height = uint32_t(aHeight);
620 return width * height * aBytesPerPixel;
623 } // namespace gfx
624 } // namespace mozilla
626 #endif