summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxUtils.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /gfx/thebes/gfxUtils.h
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/thebes/gfxUtils.h')
-rw-r--r--gfx/thebes/gfxUtils.h626
1 files changed, 626 insertions, 0 deletions
diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h
new file mode 100644
index 0000000000..a7b9f067eb
--- /dev/null
+++ b/gfx/thebes/gfxUtils.h
@@ -0,0 +1,626 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_UTILS_H
+#define GFX_UTILS_H
+
+#include "gfxMatrix.h"
+#include "gfxRect.h"
+#include "gfxTypes.h"
+#include "ImageTypes.h"
+#include "imgIContainer.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "nsColor.h"
+#include "nsContentUtils.h"
+#include "nsPrintfCString.h"
+#include "nsRegionFwd.h"
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "qcms.h"
+
+class gfxASurface;
+class gfxDrawable;
+class gfxTextRun;
+struct gfxQuad;
+class nsICookieJarSettings;
+class nsIInputStream;
+class nsIGfxInfo;
+
+namespace mozilla {
+namespace dom {
+class Element;
+} // namespace dom
+namespace layers {
+class WebRenderBridgeChild;
+class GlyphArray;
+struct PlanarYCbCrData;
+class WebRenderCommand;
+} // namespace layers
+namespace image {
+class ImageRegion;
+} // namespace image
+namespace wr {
+class DisplayListBuilder;
+} // namespace wr
+} // namespace mozilla
+
+enum class ImageType {
+ BMP,
+ ICO,
+ JPEG,
+ PNG,
+};
+
+class gfxUtils {
+ public:
+ typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
+ typedef mozilla::gfx::DrawTarget DrawTarget;
+ typedef mozilla::gfx::IntPoint IntPoint;
+ typedef mozilla::gfx::Matrix Matrix;
+ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+ typedef mozilla::gfx::SourceSurface SourceSurface;
+ typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
+ typedef mozilla::image::ImageRegion ImageRegion;
+
+ /*
+ * Premultiply or Unpremultiply aSourceSurface, writing the result
+ * to aDestSurface or back into aSourceSurface if aDestSurface is null.
+ *
+ * If aDestSurface is given, it must have identical format, dimensions, and
+ * stride as the source.
+ *
+ * If the source is not SurfaceFormat::A8R8G8B8_UINT32, no operation is
+ * performed. If aDestSurface is given, the data is copied over.
+ */
+ static bool PremultiplyDataSurface(DataSourceSurface* srcSurf,
+ DataSourceSurface* destSurf);
+ static bool UnpremultiplyDataSurface(DataSourceSurface* srcSurf,
+ DataSourceSurface* destSurf);
+
+ static already_AddRefed<DataSourceSurface> CreatePremultipliedDataSurface(
+ DataSourceSurface* srcSurf);
+ static already_AddRefed<DataSourceSurface> CreateUnpremultipliedDataSurface(
+ DataSourceSurface* srcSurf);
+
+ static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);
+
+ /**
+ * Draw something drawable while working around limitations like bad support
+ * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with
+ * extreme user-space-to-image-space transforms.
+ *
+ * The input parameters here usually come from the output of our image
+ * snapping algorithm in nsLayoutUtils.cpp.
+ * This method is split from nsLayoutUtils::DrawPixelSnapped to allow for
+ * adjusting the parameters. For example, certain images with transparent
+ * margins only have a drawable subimage. For those images, imgFrame::Draw
+ * will tweak the rects and transforms that it gets from the pixel snapping
+ * algorithm before passing them on to this method.
+ */
+ static void DrawPixelSnapped(gfxContext* aContext, gfxDrawable* aDrawable,
+ const gfxSize& aImageSize,
+ const ImageRegion& aRegion,
+ const mozilla::gfx::SurfaceFormat aFormat,
+ mozilla::gfx::SamplingFilter aSamplingFilter,
+ uint32_t aImageFlags = imgIContainer::FLAG_NONE,
+ gfxFloat aOpacity = 1.0,
+ bool aUseOptimalFillOp = true);
+
+ /**
+ * Clip aContext to the region aRegion.
+ */
+ static void ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion);
+
+ /**
+ * Clip aTarget to the region aRegion.
+ */
+ static void ClipToRegion(mozilla::gfx::DrawTarget* aTarget,
+ const nsIntRegion& aRegion);
+
+ /*
+ * Convert image format to depth value
+ */
+ static int ImageFormatToDepth(gfxImageFormat aFormat);
+
+ /**
+ * Return the transform matrix that maps aFrom to the rectangle defined by
+ * aToTopLeft/aToTopRight/aToBottomRight. aFrom must be
+ * nonempty and the destination rectangle must be axis-aligned.
+ */
+ static gfxMatrix TransformRectToRect(const gfxRect& aFrom,
+ const gfxPoint& aToTopLeft,
+ const gfxPoint& aToTopRight,
+ const gfxPoint& aToBottomRight);
+
+ static Matrix TransformRectToRect(const gfxRect& aFrom,
+ const IntPoint& aToTopLeft,
+ const IntPoint& aToTopRight,
+ const IntPoint& aToBottomRight);
+
+ /**
+ * If aIn can be represented exactly using an gfx::IntRect (i.e.
+ * integer-aligned edges and coordinates in the int32_t range) then we
+ * set aOut to that rectangle, otherwise return failure.
+ */
+ static bool GfxRectToIntRect(const gfxRect& aIn, mozilla::gfx::IntRect* aOut);
+
+ /* Conditions this border to Cairo's max coordinate space.
+ * The caller can check IsEmpty() after Condition() -- if it's TRUE,
+ * the caller can possibly avoid doing any extra rendering.
+ */
+ static void ConditionRect(gfxRect& aRect);
+
+ /*
+ * Transform this rectangle with aMatrix, resulting in a gfxQuad.
+ */
+ static gfxQuad TransformToQuad(const gfxRect& aRect,
+ const mozilla::gfx::Matrix4x4& aMatrix);
+
+ /**
+ * Return the smallest power of kScaleResolution (2) greater than or equal to
+ * aVal. If aRoundDown is specified, the power of 2 will rather be less than
+ * or equal to aVal.
+ */
+ static float ClampToScaleFactor(float aVal, bool aRoundDown = false);
+
+ /**
+ * We can snap layer transforms for two reasons:
+ * 1) To avoid unnecessary resampling when a transform is a translation
+ * by a non-integer number of pixels.
+ * Snapping the translation to an integer number of pixels avoids
+ * blurring the layer and can be faster to composite.
+ * 2) When a layer is used to render a rectangular object, we need to
+ * emulate the rendering of rectangular inactive content and snap the
+ * edges of the rectangle to pixel boundaries. This is both to ensure
+ * layer rendering is consistent with inactive content rendering, and to
+ * avoid seams.
+ * This function implements type 1 snapping. If aTransform is a 2D
+ * translation, and this layer's layer manager has enabled snapping
+ * (which is the default), return aTransform with the translation snapped
+ * to nearest pixels. Otherwise just return aTransform. Call this when the
+ * layer does not correspond to a single rectangular content object.
+ * This function does not try to snap if aTransform has a scale, because in
+ * that case resampling is inevitable and there's no point in trying to
+ * avoid it. In fact snapping can cause problems because pixel edges in the
+ * layer's content can be rendered unpredictably (jiggling) as the scale
+ * interacts with the snapping of the translation, especially with animated
+ * transforms.
+ * @param aResidualTransform a transform to apply before the result transform
+ * in order to get the results to completely match aTransform.
+ */
+ static Matrix4x4 SnapTransformTranslation(const Matrix4x4& aTransform,
+ Matrix* aResidualTransform);
+ static Matrix SnapTransformTranslation(const Matrix& aTransform,
+ Matrix* aResidualTransform);
+ static Matrix4x4 SnapTransformTranslation3D(const Matrix4x4& aTransform,
+ Matrix* aResidualTransform);
+ /**
+ * See comment for SnapTransformTranslation.
+ * This function implements type 2 snapping. If aTransform is a translation
+ * and/or scale, transform aSnapRect by aTransform, snap to pixel boundaries,
+ * and return the transform that maps aSnapRect to that rect. Otherwise
+ * just return aTransform.
+ * @param aSnapRect a rectangle whose edges should be snapped to pixel
+ * boundaries in the destination surface.
+ * @param aResidualTransform a transform to apply before the result transform
+ * in order to get the results to completely match aTransform.
+ */
+ static Matrix4x4 SnapTransform(const Matrix4x4& aTransform,
+ const gfxRect& aSnapRect,
+ Matrix* aResidualTransform);
+ static Matrix SnapTransform(const Matrix& aTransform,
+ const gfxRect& aSnapRect,
+ Matrix* aResidualTransform);
+
+ /**
+ * Clears surface to aColor (which defaults to transparent black).
+ */
+ static void ClearThebesSurface(gfxASurface* aSurface);
+
+ static const float* YuvToRgbMatrix4x3RowMajor(
+ mozilla::gfx::YUVColorSpace aYUVColorSpace);
+ static const float* YuvToRgbMatrix3x3ColumnMajor(
+ mozilla::gfx::YUVColorSpace aYUVColorSpace);
+ static const float* YuvToRgbMatrix4x4ColumnMajor(
+ mozilla::gfx::YUVColorSpace aYUVColorSpace);
+
+ static mozilla::Maybe<mozilla::gfx::YUVColorSpace> CicpToColorSpace(
+ const mozilla::gfx::CICP::MatrixCoefficients,
+ const mozilla::gfx::CICP::ColourPrimaries,
+ mozilla::LazyLogModule& aLogger);
+
+ static mozilla::Maybe<mozilla::gfx::ColorSpace2> CicpToColorPrimaries(
+ const mozilla::gfx::CICP::ColourPrimaries,
+ mozilla::LazyLogModule& aLogger);
+
+ static mozilla::Maybe<mozilla::gfx::TransferFunction> CicpToTransferFunction(
+ const mozilla::gfx::CICP::TransferCharacteristics);
+
+ /**
+ * Creates a copy of aSurface, but having the SurfaceFormat aFormat.
+ *
+ * This function always creates a new surface. Do not call it if aSurface's
+ * format is the same as aFormat. Such a non-conversion would just be an
+ * unnecessary and wasteful copy (this function asserts to prevent that).
+ *
+ * This function is intended to be called by code that needs to access the
+ * pixel data of the surface, but doesn't want to have lots of branches
+ * to handle different pixel data formats (code which would become out of
+ * date if and when new formats are added). Callers can use this function
+ * to copy the surface to a specified format so that they only have to
+ * handle pixel data in that one format.
+ *
+ * WARNING: There are format conversions that will not be supported by this
+ * function. It very much depends on what the Moz2D backends support. If
+ * the temporary B8G8R8A8 DrawTarget that this function creates has a
+ * backend that supports DrawSurface() calls passing a surface with
+ * aSurface's format it will work. Otherwise it will not.
+ *
+ * *** IMPORTANT PERF NOTE ***
+ *
+ * This function exists partly because format conversion is fraught with
+ * non-obvious performance hazards, so we don't want Moz2D consumers to be
+ * doing their own format conversion. Do not try to do so, or at least read
+ * the comments in this functions implemtation. That said, the copy that
+ * this function carries out has a cost and, although this function tries
+ * to avoid perf hazards such as expensive uploads to/readbacks from the
+ * GPU, it can't guarantee that it always successfully does so. Perf
+ * critical code that can directly handle the common formats that it
+ * encounters in a way that is cheaper than a copy-with-format-conversion
+ * should consider doing so, and only use this function as a fallback to
+ * handle other formats.
+ *
+ * XXXjwatt it would be nice if SourceSurface::GetDataSurface took a
+ * SurfaceFormat argument (with a default argument meaning "use the
+ * existing surface's format") and returned a DataSourceSurface in that
+ * format. (There would then be an issue of callers maybe failing to
+ * realize format conversion may involve expensive copying/uploading/
+ * readback.)
+ */
+ static already_AddRefed<DataSourceSurface>
+ CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface,
+ SurfaceFormat aFormat);
+
+ /**
+ * Return a color that can be used to identify a frame with a given frame
+ * number. The colors will cycle after sNumFrameColors. You can query colors
+ * 0 .. sNumFrameColors-1 to get all the colors back.
+ */
+ static const mozilla::gfx::DeviceColor& GetColorForFrameNumber(
+ uint64_t aFrameNumber);
+ static const uint32_t sNumFrameColors;
+
+ enum BinaryOrData { eBinaryEncode, eDataURIEncode };
+
+ /**
+ * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder.
+ * If both aFile and aString are null, the encoded data is copied to the
+ * clipboard.
+ *
+ * @param aImageType The image type that the surface is to be encoded to.
+ * Used to create an appropriate imgIEncoder instance to do the encoding.
+ *
+ * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
+ * the value of the |outputOptions| parameter. Callers are responsible
+ * for making sure that this is a reasonable value for the passed MIME-type
+ * (i.e. for the type of encoder that will be created).
+ *
+ * @aBinaryOrData Flag used to determine if the surface is simply encoded
+ * to the requested binary image format, or if the binary image is
+ * further converted to base-64 and written out as a 'data:' URI.
+ *
+ * @aFile If specified, the encoded data is written out to aFile.
+ *
+ * @aString If specified, the encoded data is written out to aString.
+ *
+ * TODO: Copying to the clipboard as a binary file is not currently
+ * supported.
+ */
+ static nsresult EncodeSourceSurface(SourceSurface* aSurface,
+ const ImageType aImageType,
+ const nsAString& aOutputOptions,
+ BinaryOrData aBinaryOrData, FILE* aFile,
+ nsACString* aString = nullptr);
+
+ /**
+ * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder
+ * and returns the result as an nsIInputStream.
+ *
+ * @param aSurface The source surface to encode
+ *
+ * @param aImageType The image type that the surface is to be encoded to.
+ * Used to create an appropriate imgIEncoder instance to do the encoding.
+ *
+ * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
+ * the value of the |outputOptions| parameter. Callers are responsible
+ * for making sure that this is a reasonable value for the passed MIME-type
+ * (i.e. for the type of encoder that will be created).
+ *
+ * @param aOutStream pointer to the output stream
+ *
+ */
+ static nsresult EncodeSourceSurfaceAsStream(SourceSurface* aSurface,
+ const ImageType aImageType,
+ const nsAString& aOutputOptions,
+ nsIInputStream** aOutStream);
+
+ /**
+ * Encodes the given surface to PNG/JPEG/BMP/etc. using imgIEncoder
+ * and returns the result as a vector of bytes
+ *
+ * @param aImageType The image type that the surface is to be encoded to.
+ * Used to create an appropriate imgIEncoder instance to do the encoding.
+ *
+ * @param aOutputOptions Passed directly to imgIEncoder::InitFromData as
+ * the value of the |outputOptions| parameter. Callers are responsible
+ * for making sure that this is a reasonable value for the passed MIME-type
+ * (i.e. for the type of encoder that will be created).
+ *
+ */
+ static mozilla::Maybe<nsTArray<uint8_t>> EncodeSourceSurfaceAsBytes(
+ SourceSurface* aSurface, const ImageType aImageType,
+ const nsAString& aOutputOptions);
+
+ /**
+ * Write as a PNG file to the path aFile.
+ */
+ static void WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile);
+ static void WriteAsPNG(SourceSurface* aSurface, const char* aFile);
+ static void WriteAsPNG(DrawTarget* aDT, const nsAString& aFile);
+ static void WriteAsPNG(DrawTarget* aDT, const char* aFile);
+
+ /**
+ * Dump as a PNG encoded Data URL to a FILE stream (using stdout by
+ * default).
+ *
+ * Rather than giving aFile a default argument we have separate functions
+ * to make them easier to use from a debugger.
+ */
+ static void DumpAsDataURI(SourceSurface* aSourceSurface, FILE* aFile);
+ static inline void DumpAsDataURI(SourceSurface* aSourceSurface) {
+ DumpAsDataURI(aSourceSurface, stdout);
+ }
+ static void DumpAsDataURI(DrawTarget* aDT, FILE* aFile);
+ static inline void DumpAsDataURI(DrawTarget* aDT) {
+ DumpAsDataURI(aDT, stdout);
+ }
+ static nsCString GetAsDataURI(SourceSurface* aSourceSurface);
+ static nsCString GetAsDataURI(DrawTarget* aDT);
+ static nsCString GetAsLZ4Base64Str(DataSourceSurface* aSourceSurface);
+
+ static mozilla::UniquePtr<uint8_t[]> GetImageBuffer(
+ DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
+ int32_t* outFormat);
+
+ static mozilla::UniquePtr<uint8_t[]> GetImageBufferWithRandomNoise(
+ DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
+ nsICookieJarSettings* aCookieJarSettings, int32_t* outFormat);
+
+ static nsresult GetInputStream(DataSourceSurface* aSurface,
+ bool aIsAlphaPremultiplied,
+ const char* aMimeType,
+ const nsAString& aEncoderOptions,
+ nsIInputStream** outStream);
+
+ static nsresult GetInputStreamWithRandomNoise(
+ DataSourceSurface* aSurface, bool aIsAlphaPremultiplied,
+ const char* aMimeType, const nsAString& aEncoderOptions,
+ nsICookieJarSettings* aCookieJarSettings, nsIInputStream** outStream);
+
+ static void RemoveShaderCacheFromDiskIfNecessary();
+
+ /**
+ * Copy to the clipboard as a PNG encoded Data URL.
+ */
+ static void CopyAsDataURI(SourceSurface* aSourceSurface);
+ static void CopyAsDataURI(DrawTarget* aDT);
+
+ static bool DumpDisplayList();
+
+ static FILE* sDumpPaintFile;
+};
+
+namespace mozilla {
+
+// Container for either a single element of type T, or an nsTArray<T>.
+// Provides a minimal subset of nsTArray's API, just enough to support use
+// by ContextState for the clipsAndTransforms list, and by gfxTextRun for
+// its mGlyphRuns.
+// Using this instead of a simple nsTArray avoids an extra allocation in the
+// common case where no more than one element is ever added to the list.
+// Unlike an AutoTArray<..., 1>, this class is memmovable and therefore can
+// be used in ContextState without breaking its movability.
+template <typename T>
+class ElementOrArray {
+ union {
+ T mElement;
+ nsTArray<T> mArray;
+ };
+ enum class Tag : uint8_t {
+ Element,
+ Array,
+ } mTag;
+
+ // gfxTextRun::SortGlyphRuns and SanitizeGlyphRuns directly access the array.
+ friend class ::gfxTextRun;
+ nsTArray<T>& Array() {
+ MOZ_DIAGNOSTIC_ASSERT(mTag == Tag::Array);
+ return mArray;
+ }
+
+ public:
+ // Construct as an empty array.
+ ElementOrArray() : mTag(Tag::Array) { new (&mArray) nsTArray<T>(); }
+
+ // For now, don't support copy/move.
+ ElementOrArray(const ElementOrArray&) = delete;
+ ElementOrArray(ElementOrArray&&) = delete;
+
+ ElementOrArray& operator=(const ElementOrArray&) = delete;
+ ElementOrArray& operator=(ElementOrArray&&) = delete;
+
+ // Destroy the appropriate variant.
+ ~ElementOrArray() {
+ switch (mTag) {
+ case Tag::Element:
+ mElement.~T();
+ break;
+ case Tag::Array:
+ mArray.~nsTArray();
+ break;
+ }
+ }
+
+ size_t Length() const { return mTag == Tag::Element ? 1 : mArray.Length(); }
+
+ T* AppendElement(const T& aElement) {
+ switch (mTag) {
+ case Tag::Element: {
+ // Move the existing element into an array, then append the new one.
+ T temp = std::move(mElement);
+ mElement.~T();
+ mTag = Tag::Array;
+ new (&mArray) nsTArray<T>();
+ mArray.AppendElement(std::move(temp));
+ return mArray.AppendElement(aElement);
+ }
+ case Tag::Array: {
+ // If currently empty, just store the element directly.
+ if (mArray.IsEmpty()) {
+ mArray.~nsTArray();
+ mTag = Tag::Element;
+ new (&mElement) T(aElement);
+ return &mElement;
+ }
+ // Otherwise, append it to the array.
+ return mArray.AppendElement(aElement);
+ }
+ default:
+ MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("invalid tag");
+ }
+ }
+
+ const T& LastElement() const {
+ return mTag == Tag::Element ? mElement : mArray.LastElement();
+ }
+
+ T& LastElement() {
+ return mTag == Tag::Element ? mElement : mArray.LastElement();
+ }
+
+ bool IsEmpty() const {
+ return mTag == Tag::Element ? false : mArray.IsEmpty();
+ }
+
+ void TruncateLength(uint32_t aLength = 0) {
+ MOZ_DIAGNOSTIC_ASSERT(aLength <= Length());
+ switch (mTag) {
+ case Tag::Element:
+ if (aLength == 0) {
+ // Destroy the single element, and convert to an empty array.
+ mElement.~T();
+ mTag = Tag::Array;
+ new (&mArray) nsTArray<T>();
+ }
+ break;
+ case Tag::Array:
+ mArray.TruncateLength(aLength);
+ break;
+ }
+ }
+
+ void Clear() {
+ switch (mTag) {
+ case Tag::Element:
+ mElement.~T();
+ mTag = Tag::Array;
+ new (&mArray) nsTArray<T>();
+ break;
+ case Tag::Array:
+ mArray.Clear();
+ break;
+ }
+ }
+
+ // Convert from Array to Element storage. Only to be used when the current
+ // state is a single-element array!
+ void ConvertToElement() {
+ MOZ_DIAGNOSTIC_ASSERT(mTag == Tag::Array && mArray.Length() == 1);
+ T temp = std::move(mArray[0]);
+ mArray.~nsTArray();
+ mTag = Tag::Element;
+ new (&mElement) T(std::move(temp));
+ }
+
+ const T& operator[](uint32_t aIndex) const {
+ MOZ_DIAGNOSTIC_ASSERT(aIndex < Length());
+ return mTag == Tag::Element ? mElement : mArray[aIndex];
+ }
+ T& operator[](uint32_t aIndex) {
+ MOZ_DIAGNOSTIC_ASSERT(aIndex < Length());
+ return mTag == Tag::Element ? mElement : mArray[aIndex];
+ }
+
+ // Simple iterators to support range-for loops.
+ const T* begin() const {
+ return mTag == Tag::Array ? mArray.IsEmpty() ? nullptr : &*mArray.begin()
+ : &mElement;
+ }
+ T* begin() {
+ return mTag == Tag::Array ? mArray.IsEmpty() ? nullptr : &*mArray.begin()
+ : &mElement;
+ }
+
+ const T* end() const {
+ return mTag == Tag::Array ? begin() + mArray.Length() : &mElement + 1;
+ }
+ T* end() {
+ return mTag == Tag::Array ? begin() + mArray.Length() : &mElement + 1;
+ }
+
+ size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
+ return mTag == Tag::Array ? mArray.ShallowSizeOfExcludingThis(aMallocSizeOf)
+ : 0;
+ }
+};
+
+struct StyleAbsoluteColor;
+
+namespace gfx {
+
+/**
+ * If the CMS mode is CMSMode::All, these functions transform the passed
+ * color to a device color using the transform returned by
+ * gfxPlatform::GetCMSRGBTransform(). If the CMS mode is some other value, the
+ * color is returned unchanged (other than a type change to Moz2D Color, if
+ * applicable).
+ */
+DeviceColor ToDeviceColor(const sRGBColor&);
+DeviceColor ToDeviceColor(const StyleAbsoluteColor&);
+DeviceColor ToDeviceColor(nscolor);
+
+sRGBColor ToSRGBColor(const StyleAbsoluteColor&);
+
+/**
+ * Performs a checked multiply of the given width, height, and bytes-per-pixel
+ * values.
+ */
+static inline CheckedInt<uint32_t> SafeBytesForBitmap(uint32_t aWidth,
+ uint32_t aHeight,
+ unsigned aBytesPerPixel) {
+ MOZ_ASSERT(aBytesPerPixel > 0);
+ CheckedInt<uint32_t> width = uint32_t(aWidth);
+ CheckedInt<uint32_t> height = uint32_t(aHeight);
+ return width * height * aBytesPerPixel;
+}
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif