summaryrefslogtreecommitdiffstats
path: root/gfx/2d/2D.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/2D.h')
-rw-r--r--gfx/2d/2D.h2283
1 files changed, 2283 insertions, 0 deletions
diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h
new file mode 100644
index 0000000000..3f16e39445
--- /dev/null
+++ b/gfx/2d/2D.h
@@ -0,0 +1,2283 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 _MOZILLA_GFX_2D_H
+#define _MOZILLA_GFX_2D_H
+
+#include "Types.h"
+#include "Point.h"
+#include "Rect.h"
+#include "Matrix.h"
+#include "Quaternion.h"
+#include "UserData.h"
+#include "FontVariation.h"
+#include <vector>
+
+// GenericRefCountedBase allows us to hold on to refcounted objects of any type
+// (contrary to RefCounted<T> which requires knowing the type T) and, in
+// particular, without having a dependency on that type. This is used for
+// DrawTargetSkia to be able to hold on to a GLContext.
+#include "mozilla/GenericRefCounted.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Path.h"
+
+// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T**
+// outparams using the &-operator. But it will have to do as there's no easy
+// solution.
+#include "mozilla/RefPtr.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/ThreadSafeWeakPtr.h"
+#include "mozilla/Atomics.h"
+
+#include "mozilla/DebugOnly.h"
+
+#include "nsRegionFwd.h"
+
+#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
+# ifndef MOZ_ENABLE_FREETYPE
+# define MOZ_ENABLE_FREETYPE
+# endif
+#endif
+
+struct _cairo_surface;
+typedef _cairo_surface cairo_surface_t;
+
+struct _cairo_scaled_font;
+typedef _cairo_scaled_font cairo_scaled_font_t;
+
+struct FT_LibraryRec_;
+typedef FT_LibraryRec_* FT_Library;
+
+struct FT_FaceRec_;
+typedef FT_FaceRec_* FT_Face;
+
+typedef int FT_Error;
+
+struct _FcPattern;
+typedef _FcPattern FcPattern;
+
+struct ID3D11Texture2D;
+struct ID3D11Device;
+struct ID2D1Device;
+struct ID2D1DeviceContext;
+struct ID2D1Multithread;
+struct IDWriteFactory;
+struct IDWriteRenderingParams;
+struct IDWriteFontFace;
+struct IDWriteFontCollection;
+
+class SkCanvas;
+struct gfxFontStyle;
+
+struct CGContext;
+typedef struct CGContext* CGContextRef;
+
+struct CGFont;
+typedef CGFont* CGFontRef;
+
+namespace mozilla {
+
+class Mutex;
+
+namespace layers {
+class TextureData;
+}
+
+namespace wr {
+struct FontInstanceOptions;
+struct FontInstancePlatformOptions;
+} // namespace wr
+
+namespace gfx {
+class UnscaledFont;
+class ScaledFont;
+} // namespace gfx
+
+namespace gfx {
+
+class AlphaBoxBlur;
+class ScaledFont;
+class SourceSurface;
+class DataSourceSurface;
+class DrawTarget;
+class DrawEventRecorder;
+class FilterNode;
+class LogForwarder;
+
+struct NativeSurface {
+ NativeSurfaceType mType;
+ SurfaceFormat mFormat;
+ gfx::IntSize mSize;
+ void* mSurface;
+};
+
+/**
+ * This structure is used to send draw options that are universal to all drawing
+ * operations.
+ */
+struct DrawOptions {
+ /// For constructor parameter description, see member data documentation.
+ explicit DrawOptions(Float aAlpha = 1.0f,
+ CompositionOp aCompositionOp = CompositionOp::OP_OVER,
+ AntialiasMode aAntialiasMode = AntialiasMode::DEFAULT)
+ : mAlpha(aAlpha),
+ mCompositionOp(aCompositionOp),
+ mAntialiasMode(aAntialiasMode) {}
+
+ Float mAlpha; /**< Alpha value by which the mask generated by this
+ operation is multiplied. */
+ CompositionOp mCompositionOp; /**< The operator that indicates how the source
+ and destination patterns are blended. */
+ AntialiasMode mAntialiasMode; /**< The AntiAlias mode used for this drawing
+ operation. */
+};
+
+struct StoredStrokeOptions;
+
+/**
+ * This structure is used to send stroke options that are used in stroking
+ * operations.
+ */
+struct StrokeOptions {
+ /// For constructor parameter description, see member data documentation.
+ explicit StrokeOptions(Float aLineWidth = 1.0f,
+ JoinStyle aLineJoin = JoinStyle::MITER_OR_BEVEL,
+ CapStyle aLineCap = CapStyle::BUTT,
+ Float aMiterLimit = 10.0f, size_t aDashLength = 0,
+ const Float* aDashPattern = 0, Float aDashOffset = 0.f)
+ : mLineWidth(aLineWidth),
+ mMiterLimit(aMiterLimit),
+ mDashPattern(aDashLength > 0 ? aDashPattern : 0),
+ mDashLength(aDashLength),
+ mDashOffset(aDashOffset),
+ mLineJoin(aLineJoin),
+ mLineCap(aLineCap) {
+ MOZ_ASSERT(aDashLength == 0 || aDashPattern);
+ }
+
+ Float mLineWidth; //!< Width of the stroke in userspace.
+ Float mMiterLimit; //!< Miter limit in units of linewidth
+ const Float* mDashPattern; /**< Series of on/off userspace lengths defining
+ dash. Owned by the caller; must live at least as
+ long as this StrokeOptions.
+ mDashPattern != null <=> mDashLength > 0. */
+ size_t mDashLength; //!< Number of on/off lengths in mDashPattern.
+ Float mDashOffset; /**< Userspace offset within mDashPattern at which
+ stroking begins. */
+ JoinStyle mLineJoin; //!< Join style used for joining lines.
+ CapStyle mLineCap; //!< Cap style used for capping lines.
+
+ StoredStrokeOptions* Clone() const;
+
+ bool operator==(const StrokeOptions& aOther) const {
+ return mLineWidth == aOther.mLineWidth &&
+ mMiterLimit == aOther.mMiterLimit &&
+ mDashLength == aOther.mDashLength &&
+ (!mDashLength || (mDashPattern && aOther.mDashPattern &&
+ !memcmp(mDashPattern, aOther.mDashPattern,
+ mDashLength * sizeof(Float)))) &&
+ mDashOffset == aOther.mDashOffset && mLineJoin == aOther.mLineJoin &&
+ mLineCap == aOther.mLineCap;
+ }
+};
+
+/**
+ * Heap-allocated variation of StrokeOptions that ensures dash patterns are
+ * properly allocated and destroyed even if the source was stack-allocated.
+ */
+struct StoredStrokeOptions : public StrokeOptions {
+ explicit StoredStrokeOptions(const StrokeOptions& aOptions)
+ : StrokeOptions(aOptions) {
+ if (mDashLength) {
+ Float* pattern = new Float[mDashLength];
+ memcpy(pattern, mDashPattern, mDashLength * sizeof(Float));
+ mDashPattern = pattern;
+ }
+ }
+
+ ~StoredStrokeOptions() {
+ if (mDashPattern) {
+ delete[] mDashPattern;
+ }
+ }
+};
+
+inline StoredStrokeOptions* StrokeOptions::Clone() const {
+ return new StoredStrokeOptions(*this);
+}
+
+/**
+ * This structure supplies additional options for calls to DrawSurface.
+ */
+struct DrawSurfaceOptions {
+ /// For constructor parameter description, see member data documentation.
+ explicit DrawSurfaceOptions(
+ SamplingFilter aSamplingFilter = SamplingFilter::LINEAR,
+ SamplingBounds aSamplingBounds = SamplingBounds::UNBOUNDED)
+ : mSamplingFilter(aSamplingFilter), mSamplingBounds(aSamplingBounds) {}
+
+ SamplingFilter
+ mSamplingFilter; /**< SamplingFilter used when resampling source surface
+ region to the destination region. */
+ SamplingBounds mSamplingBounds; /**< This indicates whether the implementation
+ is allowed to sample pixels outside the
+ source rectangle as specified in
+ DrawSurface on the surface. */
+};
+
+/**
+ * ShadowOptions supplies options necessary for describing the appearance of a
+ * a shadow in draw calls that use shadowing.
+ */
+struct ShadowOptions {
+ explicit ShadowOptions(const DeviceColor& aColor = DeviceColor(0.0f, 0.0f,
+ 0.0f),
+ const Point& aOffset = Point(), Float aSigma = 0.0f)
+ : mColor(aColor), mOffset(aOffset), mSigma(aSigma) {}
+
+ DeviceColor mColor; /**< Color of the drawn shadow. */
+ Point mOffset; /**< Offset of the shadow. */
+ Float mSigma; /**< Sigma used for the Gaussian filter kernel. */
+
+ int32_t BlurRadius() const;
+};
+
+/**
+ * This class is used to store gradient stops, it can only be used with a
+ * matching DrawTarget. Not adhering to this condition will make a draw call
+ * fail.
+ */
+class GradientStops : public SupportsThreadSafeWeakPtr<GradientStops> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
+ virtual ~GradientStops() = default;
+
+ virtual BackendType GetBackendType() const = 0;
+ virtual bool IsValid() const { return true; }
+
+ protected:
+ GradientStops() = default;
+};
+
+/**
+ * This is the base class for 'patterns'. Patterns describe the pixels used as
+ * the source for a masked composition operation that is done by the different
+ * drawing commands. These objects are not backend specific, however for
+ * example the gradient stops on a gradient pattern can be backend specific.
+ */
+class Pattern {
+ public:
+ virtual ~Pattern() = default;
+
+ virtual PatternType GetType() const = 0;
+
+ /** Instantiate a new clone with the same pattern type and values. Any
+ * internal strong references will be converted to weak references. */
+ virtual Pattern* CloneWeak() const { return nullptr; }
+
+ /** Whether the pattern holds an internal weak reference. */
+ virtual bool IsWeak() const { return false; }
+
+ /** Whether any internal weak references still point to a target. */
+ virtual bool IsValid() const { return true; }
+
+ /** Determine if the pattern type and values exactly match. */
+ virtual bool operator==(const Pattern& aOther) const = 0;
+
+ bool operator!=(const Pattern& aOther) const { return !(*this == aOther); }
+
+ protected:
+ Pattern() = default;
+
+ // Utility functions to check if a weak reference is still valid.
+ template <typename T>
+ static inline bool IsRefValid(const RefPtr<T>& aPtr) {
+ // RefPtrs are always valid.
+ return true;
+ }
+
+ template <typename T>
+ static inline bool IsRefValid(const ThreadSafeWeakPtr<T>& aPtr) {
+ // Weak refs are only valid if they aren't dead.
+ return !aPtr.IsDead();
+ }
+};
+
+class ColorPattern : public Pattern {
+ public:
+ // Explicit because consumers should generally use ToDeviceColor when
+ // creating a ColorPattern.
+ explicit ColorPattern(const DeviceColor& aColor) : mColor(aColor) {}
+
+ PatternType GetType() const override { return PatternType::COLOR; }
+
+ Pattern* CloneWeak() const override { return new ColorPattern(mColor); }
+
+ bool operator==(const Pattern& aOther) const override {
+ if (aOther.GetType() != PatternType::COLOR) {
+ return false;
+ }
+ const ColorPattern& other = static_cast<const ColorPattern&>(aOther);
+ return mColor == other.mColor;
+ }
+
+ DeviceColor mColor;
+};
+
+/**
+ * This class is used for Linear Gradient Patterns, the gradient stops are
+ * stored in a separate object and are backend dependent. This class itself
+ * may be used on the stack.
+ */
+template <template <typename> typename REF = RefPtr>
+class LinearGradientPatternT : public Pattern {
+ typedef LinearGradientPatternT<ThreadSafeWeakPtr> Weak;
+
+ public:
+ /// For constructor parameter description, see member data documentation.
+ LinearGradientPatternT(const Point& aBegin, const Point& aEnd,
+ RefPtr<GradientStops> aStops,
+ const Matrix& aMatrix = Matrix())
+ : mBegin(aBegin),
+ mEnd(aEnd),
+ mStops(std::move(aStops)),
+ mMatrix(aMatrix) {}
+
+ PatternType GetType() const override { return PatternType::LINEAR_GRADIENT; }
+
+ Pattern* CloneWeak() const override {
+ return new Weak(mBegin, mEnd, do_AddRef(mStops), mMatrix);
+ }
+
+ bool IsWeak() const override {
+ return std::is_same<decltype(*this), Weak>::value;
+ }
+
+ bool IsValid() const override { return IsRefValid(mStops); }
+
+ template <template <typename> typename T>
+ bool operator==(const LinearGradientPatternT<T>& aOther) const {
+ return mBegin == aOther.mBegin && mEnd == aOther.mEnd &&
+ mStops == aOther.mStops && mMatrix.ExactlyEquals(aOther.mMatrix);
+ }
+
+ bool operator==(const Pattern& aOther) const override {
+ if (aOther.GetType() != PatternType::LINEAR_GRADIENT) {
+ return false;
+ }
+ return aOther.IsWeak()
+ ? *this == static_cast<const Weak&>(aOther)
+ : *this == static_cast<const LinearGradientPatternT<>&>(aOther);
+ }
+
+ Point mBegin; //!< Start of the linear gradient
+ Point mEnd; /**< End of the linear gradient - NOTE: In the case
+ of a zero length gradient it will act as the
+ color of the last stop. */
+ REF<GradientStops> mStops; /**< GradientStops object for this gradient, this
+ should match the backend type of the draw
+ target this pattern will be used with. */
+ Matrix mMatrix; /**< A matrix that transforms the pattern into
+ user space */
+};
+
+typedef LinearGradientPatternT<> LinearGradientPattern;
+
+/**
+ * This class is used for Radial Gradient Patterns, the gradient stops are
+ * stored in a separate object and are backend dependent. This class itself
+ * may be used on the stack.
+ */
+template <template <typename> typename REF = RefPtr>
+class RadialGradientPatternT : public Pattern {
+ typedef RadialGradientPatternT<ThreadSafeWeakPtr> Weak;
+
+ public:
+ /// For constructor parameter description, see member data documentation.
+ RadialGradientPatternT(const Point& aCenter1, const Point& aCenter2,
+ Float aRadius1, Float aRadius2,
+ RefPtr<GradientStops> aStops,
+ const Matrix& aMatrix = Matrix())
+ : mCenter1(aCenter1),
+ mCenter2(aCenter2),
+ mRadius1(aRadius1),
+ mRadius2(aRadius2),
+ mStops(std::move(aStops)),
+ mMatrix(aMatrix) {}
+
+ PatternType GetType() const override { return PatternType::RADIAL_GRADIENT; }
+
+ Pattern* CloneWeak() const override {
+ return new Weak(mCenter1, mCenter2, mRadius1, mRadius2, do_AddRef(mStops),
+ mMatrix);
+ }
+
+ bool IsWeak() const override {
+ return std::is_same<decltype(*this), Weak>::value;
+ }
+
+ bool IsValid() const override { return IsRefValid(mStops); }
+
+ template <template <typename> typename T>
+ bool operator==(const RadialGradientPatternT<T>& aOther) const {
+ return mCenter1 == aOther.mCenter1 && mCenter2 == aOther.mCenter2 &&
+ mRadius1 == aOther.mRadius1 && mRadius2 == aOther.mRadius2 &&
+ mStops == aOther.mStops && mMatrix.ExactlyEquals(aOther.mMatrix);
+ }
+
+ bool operator==(const Pattern& aOther) const override {
+ if (aOther.GetType() != PatternType::RADIAL_GRADIENT) {
+ return false;
+ }
+ return aOther.IsWeak()
+ ? *this == static_cast<const Weak&>(aOther)
+ : *this == static_cast<const RadialGradientPatternT<>&>(aOther);
+ }
+
+ Point mCenter1; //!< Center of the inner (focal) circle.
+ Point mCenter2; //!< Center of the outer circle.
+ Float mRadius1; //!< Radius of the inner (focal) circle.
+ Float mRadius2; //!< Radius of the outer circle.
+ REF<GradientStops> mStops; /**< GradientStops object for this gradient, this
+ should match the backend type of the draw
+ target this pattern will be used with. */
+ Matrix mMatrix; //!< A matrix that transforms the pattern into user space
+};
+
+typedef RadialGradientPatternT<> RadialGradientPattern;
+
+/**
+ * This class is used for Conic Gradient Patterns, the gradient stops are
+ * stored in a separate object and are backend dependent. This class itself
+ * may be used on the stack.
+ */
+template <template <typename> typename REF = RefPtr>
+class ConicGradientPatternT : public Pattern {
+ typedef ConicGradientPatternT<ThreadSafeWeakPtr> Weak;
+
+ public:
+ /// For constructor parameter description, see member data documentation.
+ ConicGradientPatternT(const Point& aCenter, Float aAngle, Float aStartOffset,
+ Float aEndOffset, RefPtr<GradientStops> aStops,
+ const Matrix& aMatrix = Matrix())
+ : mCenter(aCenter),
+ mAngle(aAngle),
+ mStartOffset(aStartOffset),
+ mEndOffset(aEndOffset),
+ mStops(std::move(aStops)),
+ mMatrix(aMatrix) {}
+
+ PatternType GetType() const override { return PatternType::CONIC_GRADIENT; }
+
+ Pattern* CloneWeak() const override {
+ return new Weak(mCenter, mAngle, mStartOffset, mEndOffset,
+ do_AddRef(mStops), mMatrix);
+ }
+
+ bool IsWeak() const override {
+ return std::is_same<decltype(*this), Weak>::value;
+ }
+
+ bool IsValid() const override { return IsRefValid(mStops); }
+
+ template <template <typename> typename T>
+ bool operator==(const ConicGradientPatternT<T>& aOther) const {
+ return mCenter == aOther.mCenter && mAngle == aOther.mAngle &&
+ mStartOffset == aOther.mStartOffset &&
+ mEndOffset == aOther.mEndOffset && mStops == aOther.mStops &&
+ mMatrix.ExactlyEquals(aOther.mMatrix);
+ }
+
+ bool operator==(const Pattern& aOther) const override {
+ if (aOther.GetType() != PatternType::CONIC_GRADIENT) {
+ return false;
+ }
+ return aOther.IsWeak()
+ ? *this == static_cast<const Weak&>(aOther)
+ : *this == static_cast<const ConicGradientPatternT<>&>(aOther);
+ }
+
+ Point mCenter; //!< Center of the gradient
+ Float mAngle; //!< Start angle of gradient
+ Float mStartOffset; // Offset of first stop
+ Float mEndOffset; // Offset of last stop
+ REF<GradientStops> mStops; /**< GradientStops object for this gradient, this
+ should match the backend type of the draw
+ target this pattern will be used with. */
+ Matrix mMatrix; //!< A matrix that transforms the pattern into user space
+};
+
+typedef ConicGradientPatternT<> ConicGradientPattern;
+
+/**
+ * This class is used for Surface Patterns, they wrap a surface and a
+ * repetition mode for the surface. This may be used on the stack.
+ */
+template <template <typename> typename REF = RefPtr>
+class SurfacePatternT : public Pattern {
+ typedef SurfacePatternT<ThreadSafeWeakPtr> Weak;
+
+ public:
+ /// For constructor parameter description, see member data documentation.
+ SurfacePatternT(RefPtr<SourceSurface> aSourceSurface, ExtendMode aExtendMode,
+ const Matrix& aMatrix = Matrix(),
+ SamplingFilter aSamplingFilter = SamplingFilter::GOOD,
+ const IntRect& aSamplingRect = IntRect())
+ : mSurface(std::move(aSourceSurface)),
+ mExtendMode(aExtendMode),
+ mSamplingFilter(aSamplingFilter),
+ mMatrix(aMatrix),
+ mSamplingRect(aSamplingRect) {}
+
+ PatternType GetType() const override { return PatternType::SURFACE; }
+
+ Pattern* CloneWeak() const override {
+ return new Weak(do_AddRef(mSurface), mExtendMode, mMatrix, mSamplingFilter,
+ mSamplingRect);
+ }
+
+ bool IsWeak() const override {
+ return std::is_same<decltype(*this), Weak>::value;
+ }
+
+ bool IsValid() const override { return IsRefValid(mSurface); }
+
+ template <template <typename> typename T>
+ bool operator==(const SurfacePatternT<T>& aOther) const {
+ return mSurface == aOther.mSurface && mExtendMode == aOther.mExtendMode &&
+ mSamplingFilter == aOther.mSamplingFilter &&
+ mMatrix.ExactlyEquals(aOther.mMatrix) &&
+ mSamplingRect.IsEqualEdges(aOther.mSamplingRect);
+ }
+
+ bool operator==(const Pattern& aOther) const override {
+ if (aOther.GetType() != PatternType::SURFACE) {
+ return false;
+ }
+ return aOther.IsWeak()
+ ? *this == static_cast<const Weak&>(aOther)
+ : *this == static_cast<const SurfacePatternT<>&>(aOther);
+ }
+
+ REF<SourceSurface> mSurface; //!< Surface to use for drawing
+ ExtendMode mExtendMode; /**< This determines how the image is extended
+ outside the bounds of the image */
+ SamplingFilter
+ mSamplingFilter; //!< Resampling filter for resampling the image.
+ Matrix mMatrix; //!< Transforms the pattern into user space
+
+ IntRect mSamplingRect; /**< Rect that must not be sampled outside of,
+ or an empty rect if none has been
+ specified. */
+};
+
+typedef SurfacePatternT<> SurfacePattern;
+
+class StoredPattern;
+
+static const int32_t kReasonableSurfaceSize = 8192;
+
+/**
+ * This is the base class for source surfaces. These objects are surfaces
+ * which may be used as a source in a SurfacePattern or a DrawSurface call.
+ * They cannot be drawn to directly.
+ *
+ * Although SourceSurface has thread-safe refcount, some SourceSurface cannot
+ * be used on random threads at the same time. Only DataSourceSurface can be
+ * used on random threads now. This will be fixed in the future. Eventually
+ * all SourceSurface should be thread-safe.
+ */
+class SourceSurface : public SupportsThreadSafeWeakPtr<SourceSurface> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
+ virtual ~SourceSurface() = default;
+
+ virtual SurfaceType GetType() const = 0;
+ virtual IntSize GetSize() const = 0;
+ /* GetRect is useful for when the underlying surface doesn't actually
+ * have a backing store starting at 0, 0. e.g. SourceSurfaceOffset */
+ virtual IntRect GetRect() const { return IntRect(IntPoint(0, 0), GetSize()); }
+ virtual SurfaceFormat GetFormat() const = 0;
+
+ /**
+ * Structure containing memory size information for the surface.
+ */
+ struct SizeOfInfo {
+ SizeOfInfo()
+ : mHeapBytes(0),
+ mNonHeapBytes(0),
+ mUnknownBytes(0),
+ mExternalHandles(0),
+ mExternalId(0),
+ mTypes(0) {}
+
+ void Accumulate(const SizeOfInfo& aOther) {
+ mHeapBytes += aOther.mHeapBytes;
+ mNonHeapBytes += aOther.mNonHeapBytes;
+ mUnknownBytes += aOther.mUnknownBytes;
+ mExternalHandles += aOther.mExternalHandles;
+ if (aOther.mExternalId) {
+ mExternalId = aOther.mExternalId;
+ }
+ mTypes |= aOther.mTypes;
+ }
+
+ void AddType(SurfaceType aType) { mTypes |= 1 << uint32_t(aType); }
+
+ size_t mHeapBytes; // Bytes allocated on the heap.
+ size_t mNonHeapBytes; // Bytes allocated off the heap.
+ size_t mUnknownBytes; // Bytes allocated to either, but unknown.
+ size_t mExternalHandles; // Open handles for the surface.
+ uint64_t mExternalId; // External ID for WebRender, if available.
+ uint32_t mTypes; // Bit shifted values representing SurfaceType.
+ };
+
+ /**
+ * Get the size information of the underlying data buffer.
+ */
+ virtual void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
+ SizeOfInfo& aInfo) const {
+ // Default is to estimate the footprint based on its size/format.
+ auto size = GetSize();
+ auto format = GetFormat();
+ aInfo.AddType(GetType());
+ aInfo.mUnknownBytes = size.width * size.height * BytesPerPixel(format);
+ }
+
+ /** This returns false if some event has made this source surface invalid for
+ * usage with current DrawTargets. For example in the case of Direct2D this
+ * could return false if we have switched devices since this surface was
+ * created.
+ */
+ virtual bool IsValid() const { return true; }
+
+ /**
+ * This returns true if it is the same underlying surface data, even if
+ * the objects are different (e.g. indirection due to
+ * DataSourceSurfaceWrapper).
+ */
+ virtual bool Equals(SourceSurface* aOther, bool aSymmetric = true) {
+ return this == aOther ||
+ (aSymmetric && aOther && aOther->Equals(this, false));
+ }
+
+ /**
+ * This function will return true if the surface type matches that of a
+ * DataSourceSurface and if GetDataSurface will return the same object.
+ */
+ bool IsDataSourceSurface() const {
+ switch (GetType()) {
+ case SurfaceType::DATA:
+ case SurfaceType::DATA_SHARED:
+ case SurfaceType::DATA_RECYCLING_SHARED:
+ case SurfaceType::DATA_ALIGNED:
+ case SurfaceType::DATA_SHARED_WRAPPER:
+ case SurfaceType::DATA_MAPPED:
+ case SurfaceType::SKIA:
+ case SurfaceType::WEBGL:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * This function will get a DataSourceSurface for this surface, a
+ * DataSourceSurface's data can be accessed directly.
+ */
+ virtual already_AddRefed<DataSourceSurface> GetDataSurface() = 0;
+
+ /** This function will return a SourceSurface without any offset. */
+ virtual already_AddRefed<SourceSurface> GetUnderlyingSurface() {
+ RefPtr<SourceSurface> surface = this;
+ return surface.forget();
+ }
+
+ /** Tries to get this SourceSurface's native surface. This will fail if aType
+ * is not the type of this SourceSurface's native surface.
+ */
+ virtual void* GetNativeSurface(NativeSurfaceType aType) { return nullptr; }
+
+ void AddUserData(UserDataKey* key, void* userData, void (*destroy)(void*)) {
+ mUserData.Add(key, userData, destroy);
+ }
+ void* GetUserData(UserDataKey* key) const { return mUserData.Get(key); }
+ void RemoveUserData(UserDataKey* key) { mUserData.RemoveAndDestroy(key); }
+
+ /** Tries to extract an optimal subrect for the surface. This may fail if the
+ * request can't be satisfied.
+ */
+ virtual already_AddRefed<SourceSurface> ExtractSubrect(const IntRect& aRect) {
+ return nullptr;
+ }
+
+ protected:
+ friend class StoredPattern;
+
+ ThreadSafeUserData mUserData;
+};
+
+class DataSourceSurface : public SourceSurface {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurface, override)
+ DataSourceSurface() : mMapCount(0) {}
+
+#ifdef DEBUG
+ virtual ~DataSourceSurface() { MOZ_ASSERT(mMapCount == 0); }
+#endif
+
+ struct MappedSurface {
+ uint8_t* mData = nullptr;
+ int32_t mStride = 0;
+ };
+
+ enum MapType { READ, WRITE, READ_WRITE };
+
+ /**
+ * This is a scoped version of Map(). Map() is called in the constructor and
+ * Unmap() in the destructor. Use this for automatic unmapping of your data
+ * surfaces.
+ *
+ * Use IsMapped() to verify whether Map() succeeded or not.
+ */
+ class ScopedMap final {
+ public:
+ ScopedMap(DataSourceSurface* aSurface, MapType aType)
+ : mSurface(aSurface), mIsMapped(aSurface->Map(aType, &mMap)) {}
+
+ ScopedMap(ScopedMap&& aOther)
+ : mSurface(std::move(aOther.mSurface)),
+ mMap(aOther.mMap),
+ mIsMapped(aOther.mIsMapped) {
+ aOther.mMap.mData = nullptr;
+ aOther.mIsMapped = false;
+ }
+
+ ScopedMap& operator=(ScopedMap&& aOther) {
+ if (mIsMapped) {
+ mSurface->Unmap();
+ }
+ mSurface = std::move(aOther.mSurface);
+ mMap = aOther.mMap;
+ mIsMapped = aOther.mIsMapped;
+ aOther.mMap.mData = nullptr;
+ aOther.mIsMapped = false;
+ return *this;
+ }
+
+ ~ScopedMap() {
+ if (mIsMapped) {
+ mSurface->Unmap();
+ }
+ }
+
+ uint8_t* GetData() const {
+ MOZ_ASSERT(mIsMapped);
+ return mMap.mData;
+ }
+
+ int32_t GetStride() const {
+ MOZ_ASSERT(mIsMapped);
+ return mMap.mStride;
+ }
+
+ const MappedSurface* GetMappedSurface() const {
+ MOZ_ASSERT(mIsMapped);
+ return &mMap;
+ }
+
+ const DataSourceSurface* GetSurface() const {
+ MOZ_ASSERT(mIsMapped);
+ return mSurface;
+ }
+
+ bool IsMapped() const { return mIsMapped; }
+
+ private:
+ ScopedMap(const ScopedMap& aOther) = delete;
+ ScopedMap& operator=(const ScopedMap& aOther) = delete;
+
+ RefPtr<DataSourceSurface> mSurface;
+ MappedSurface mMap;
+ bool mIsMapped;
+ };
+
+ SurfaceType GetType() const override { return SurfaceType::DATA; }
+ /** @deprecated
+ * Get the raw bitmap data of the surface.
+ * Can return null if there was OOM allocating surface data.
+ *
+ * Deprecated means you shouldn't be using this!! Use Map instead.
+ * Please deny any reviews which add calls to this!
+ */
+ virtual uint8_t* GetData() = 0;
+
+ /** @deprecated
+ * Stride of the surface, distance in bytes between the start of the image
+ * data belonging to row y and row y+1. This may be negative.
+ * Can return 0 if there was OOM allocating surface data.
+ */
+ virtual int32_t Stride() = 0;
+
+ /**
+ * The caller is responsible for ensuring aMappedSurface is not null.
+ // Althought Map (and Moz2D in general) isn't normally threadsafe,
+ // we want to allow it for SourceSurfaceRawData since it should
+ // always be fine (for reading at least).
+ //
+ // This is the same as the base class implementation except using
+ // mMapCount instead of mIsMapped since that breaks for multithread.
+ //
+ // Once mfbt supports Monitors we should implement proper read/write
+ // locking to prevent write races.
+ */
+ virtual bool Map(MapType, MappedSurface* aMappedSurface) {
+ aMappedSurface->mData = GetData();
+ aMappedSurface->mStride = Stride();
+ bool success = !!aMappedSurface->mData;
+ if (success) {
+ mMapCount++;
+ }
+ return success;
+ }
+
+ virtual void Unmap() {
+ mMapCount--;
+ MOZ_ASSERT(mMapCount >= 0);
+ }
+
+ /**
+ * Returns a DataSourceSurface with the same data as this one, but
+ * guaranteed to have surface->GetType() == SurfaceType::DATA.
+ *
+ * The returning surface might be null, because of OOM or gfx device reset.
+ * The caller needs to do null-check before using it.
+ */
+ already_AddRefed<DataSourceSurface> GetDataSurface() override;
+
+ /**
+ * Returns whether or not the data was allocated on the heap. This should
+ * be used to determine if the memory needs to be cleared to 0.
+ */
+ virtual bool OnHeap() const { return true; }
+
+ /**
+ * Yields a dirty rect of what has changed since it was last called.
+ */
+ virtual Maybe<IntRect> TakeDirtyRect() { return Nothing(); }
+
+ /**
+ * Indicate a region which has changed in the surface.
+ */
+ virtual void Invalidate(const IntRect& aDirtyRect) {}
+
+ protected:
+ Atomic<int32_t> mMapCount;
+};
+
+/** This is an abstract object that accepts path segments. */
+class PathSink : public RefCounted<PathSink> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSink)
+ virtual ~PathSink() = default;
+
+ /** Move the current point in the path, any figure currently being drawn will
+ * be considered closed during fill operations, however when stroking the
+ * closing line segment will not be drawn.
+ */
+ virtual void MoveTo(const Point& aPoint) = 0;
+ /** Add a linesegment to the current figure */
+ virtual void LineTo(const Point& aPoint) = 0;
+ /** Add a cubic bezier curve to the current figure */
+ virtual void BezierTo(const Point& aCP1, const Point& aCP2,
+ const Point& aCP3) = 0;
+ /** Add a quadratic bezier curve to the current figure */
+ virtual void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) = 0;
+ /** Close the current figure, this will essentially generate a line segment
+ * from the current point to the starting point for the current figure
+ */
+ virtual void Close() = 0;
+ /** Add an arc to the current figure */
+ virtual void Arc(const Point& aOrigin, float aRadius, float aStartAngle,
+ float aEndAngle, bool aAntiClockwise = false) = 0;
+
+ virtual Point CurrentPoint() const { return mCurrentPoint; }
+
+ virtual Point BeginPoint() const { return mBeginPoint; }
+
+ virtual void SetCurrentPoint(const Point& aPoint) { mCurrentPoint = aPoint; }
+
+ virtual void SetBeginPoint(const Point& aPoint) { mBeginPoint = aPoint; }
+
+ protected:
+ /** Point the current subpath is at - or where the next subpath will start
+ * if there is no active subpath.
+ */
+ Point mCurrentPoint;
+
+ /** Position of the previous MoveTo operation. */
+ Point mBeginPoint;
+};
+
+class PathBuilder;
+class FlattenedPath;
+
+/** The path class is used to create (sets of) figures of any shape that can be
+ * filled or stroked to a DrawTarget
+ */
+class Path : public external::AtomicRefCounted<Path> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
+ virtual ~Path();
+
+ virtual BackendType GetBackendType() const = 0;
+
+ /** This returns a PathBuilder object that contains a copy of the contents of
+ * this path and is still writable.
+ */
+ inline already_AddRefed<PathBuilder> CopyToBuilder() const {
+ return CopyToBuilder(GetFillRule());
+ }
+ inline already_AddRefed<PathBuilder> TransformedCopyToBuilder(
+ const Matrix& aTransform) const {
+ return TransformedCopyToBuilder(aTransform, GetFillRule());
+ }
+ /** This returns a PathBuilder object that contains a copy of the contents of
+ * this path, converted to use the specified FillRule, and still writable.
+ */
+ virtual already_AddRefed<PathBuilder> CopyToBuilder(
+ FillRule aFillRule) const = 0;
+ virtual already_AddRefed<PathBuilder> TransformedCopyToBuilder(
+ const Matrix& aTransform, FillRule aFillRule) const = 0;
+
+ /** This function checks if a point lies within a path. It allows passing a
+ * transform that will transform the path to the coordinate space in which
+ * aPoint is given.
+ */
+ virtual bool ContainsPoint(const Point& aPoint,
+ const Matrix& aTransform) const = 0;
+
+ /** This function checks if a point lies within the stroke of a path using the
+ * specified strokeoptions. It allows passing a transform that will transform
+ * the path to the coordinate space in which aPoint is given.
+ */
+ virtual bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions,
+ const Point& aPoint,
+ const Matrix& aTransform) const = 0;
+
+ /** This functions gets the bounds of this path. These bounds are not
+ * guaranteed to be tight. A transform may be specified that gives the bounds
+ * after application of the transform.
+ */
+ virtual Rect GetBounds(const Matrix& aTransform = Matrix()) const = 0;
+
+ /** This function gets the bounds of the stroke of this path using the
+ * specified strokeoptions. These bounds are not guaranteed to be tight.
+ * A transform may be specified that gives the bounds after application of
+ * the transform.
+ */
+ virtual Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions,
+ const Matrix& aTransform = Matrix()) const = 0;
+
+ /** Gets conservative bounds for the path, optionally stroked or transformed.
+ * This function will prioritize speed of computation over tightness of the
+ * computed bounds if the backend supports the distinction.
+ */
+ virtual Rect GetFastBounds(
+ const Matrix& aTransform = Matrix(),
+ const StrokeOptions* aStrokeOptions = nullptr) const;
+
+ /** Take the contents of this path and stream it to another sink, this works
+ * regardless of the backend that might be used for the destination sink.
+ */
+ virtual void StreamToSink(PathSink* aSink) const = 0;
+
+ /** This gets the fillrule this path's builder was created with. This is not
+ * mutable.
+ */
+ virtual FillRule GetFillRule() const = 0;
+
+ virtual Float ComputeLength();
+
+ virtual Maybe<Rect> AsRect() const { return Nothing(); }
+
+ virtual Point ComputePointAtLength(Float aLength, Point* aTangent = nullptr);
+
+ protected:
+ Path();
+ void EnsureFlattenedPath();
+
+ RefPtr<FlattenedPath> mFlattenedPath;
+};
+
+/** The PathBuilder class allows path creation. Once finish is called on the
+ * pathbuilder it may no longer be written to.
+ */
+class PathBuilder : public PathSink {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilder, override)
+ /** Finish writing to the path and return a Path object that can be used for
+ * drawing. Future use of the builder results in a crash!
+ */
+ virtual already_AddRefed<Path> Finish() = 0;
+
+ virtual BackendType GetBackendType() const = 0;
+};
+
+struct Glyph {
+ uint32_t mIndex;
+ Point mPosition;
+};
+
+static inline bool operator==(const Glyph& aOne, const Glyph& aOther) {
+ return aOne.mIndex == aOther.mIndex && aOne.mPosition == aOther.mPosition;
+}
+
+/** This class functions as a glyph buffer that can be drawn to a DrawTarget.
+ * @todo XXX - This should probably contain the guts of gfxTextRun in the future
+ * as roc suggested. But for now it's a simple container for a glyph vector.
+ */
+struct GlyphBuffer {
+ const Glyph*
+ mGlyphs; //!< A pointer to a buffer of glyphs. Managed by the caller.
+ uint32_t mNumGlyphs; //!< Number of glyphs mGlyphs points to.
+};
+
+#ifdef MOZ_ENABLE_FREETYPE
+class SharedFTFace;
+
+/** SharedFTFaceData abstracts data that may be used to back a SharedFTFace.
+ * Its main function is to manage the lifetime of the data and ensure that it
+ * lasts as long as the face.
+ */
+class SharedFTFaceData {
+ public:
+ /** Utility for creating a new face from this data. */
+ virtual already_AddRefed<SharedFTFace> CloneFace(int aFaceIndex = 0) {
+ return nullptr;
+ }
+ /** Binds the data's lifetime to the face. */
+ virtual void BindData() = 0;
+ /** Signals that the data is no longer needed by a face. */
+ virtual void ReleaseData() = 0;
+};
+
+/** Wrapper class for ref-counted SharedFTFaceData that handles calling the
+ * appropriate ref-counting methods
+ */
+template <class T>
+class SharedFTFaceRefCountedData : public SharedFTFaceData {
+ public:
+ void BindData() { static_cast<T*>(this)->AddRef(); }
+ void ReleaseData() { static_cast<T*>(this)->Release(); }
+};
+
+// Helper class used for clearing out user font data when FT font
+// face is destroyed. Since multiple faces may use the same data, be
+// careful to assure that the data is only cleared out when all uses
+// expire. The font entry object contains a refptr to FTUserFontData and
+// each FT face created from that font entry contains a refptr to that
+// same FTUserFontData object.
+// This is also attached to FT faces for installed fonts (recording the
+// filename, rather than storing the font data) if variations are present.
+class FTUserFontData final
+ : public mozilla::gfx::SharedFTFaceRefCountedData<FTUserFontData> {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)
+
+ FTUserFontData(const uint8_t* aData, uint32_t aLength)
+ : mFontData(aData), mLength(aLength) {}
+ explicit FTUserFontData(const char* aFilename) : mFilename(aFilename) {}
+
+ const uint8_t* FontData() const { return mFontData; }
+
+ already_AddRefed<mozilla::gfx::SharedFTFace> CloneFace(
+ int aFaceIndex = 0) override;
+
+ private:
+ ~FTUserFontData() {
+ if (mFontData) {
+ free((void*)mFontData);
+ }
+ }
+
+ std::string mFilename;
+ const uint8_t* mFontData = nullptr;
+ uint32_t mLength = 0;
+};
+
+/** SharedFTFace is a shared wrapper around an FT_Face. It is ref-counted,
+ * unlike FT_Face itself, so that it may be shared among many users with
+ * RefPtr. Users should take care to lock SharedFTFace before accessing any
+ * FT_Face fields that may change to ensure exclusive access to it. It also
+ * allows backing data's lifetime to be bound to it via SharedFTFaceData so
+ * that the data will not disappear before the face does.
+ */
+class SharedFTFace : public external::AtomicRefCounted<SharedFTFace> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SharedFTFace)
+
+ explicit SharedFTFace(FT_Face aFace, SharedFTFaceData* aData);
+ virtual ~SharedFTFace();
+
+ FT_Face GetFace() const { return mFace; }
+ SharedFTFaceData* GetData() const { return mData; }
+
+ /** Locks the face for exclusive access by a given owner. Returns false if
+ * the given owner is acquiring the lock for the first time, and true if
+ * the owner was the prior owner of the lock. Thus the return value can be
+ * used to do owner-specific initialization of the FT face such as setting
+ * a size or transform that may have been invalidated by a previous owner.
+ * If no owner is given, then the user should avoid modifying any state on
+ * the face so as not to invalidate the prior owner's modification.
+ */
+ bool Lock(const void* aOwner = nullptr) MOZ_CAPABILITY_ACQUIRE(mLock) {
+ mLock.Lock();
+ return !aOwner || mLastLockOwner.exchange(aOwner) == aOwner;
+ }
+ void Unlock() MOZ_CAPABILITY_RELEASE(mLock) { mLock.Unlock(); }
+
+ /** Should be called when a lock owner is destroyed so that we don't have
+ * a dangling pointer to a destroyed owner.
+ */
+ void ForgetLockOwner(const void* aOwner) {
+ if (aOwner) {
+ mLastLockOwner.compareExchange(aOwner, nullptr);
+ }
+ }
+
+ private:
+ FT_Face mFace;
+ SharedFTFaceData* mData;
+ Mutex mLock;
+ // Remember the last owner of the lock, even after unlocking, to allow users
+ // to avoid reinitializing state on the FT face if the last owner hasn't
+ // changed by the next time it is locked with the same owner.
+ Atomic<const void*> mLastLockOwner;
+};
+#endif
+
+class UnscaledFont : public SupportsThreadSafeWeakPtr<UnscaledFont> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFont)
+
+ virtual ~UnscaledFont();
+
+ virtual FontType GetType() const = 0;
+
+ static uint32_t DeletionCounter() { return sDeletionCounter; }
+
+ typedef void (*FontFileDataOutput)(const uint8_t* aData, uint32_t aLength,
+ uint32_t aIndex, void* aBaton);
+ typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength,
+ void* aBaton);
+ typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength,
+ uint32_t aIndex, void* aBaton);
+
+ virtual bool GetFontFileData(FontFileDataOutput, void*) { return false; }
+
+ virtual bool GetFontInstanceData(FontInstanceDataOutput, void*) {
+ return false;
+ }
+
+ virtual bool GetFontDescriptor(FontDescriptorOutput, void*) { return false; }
+
+ virtual already_AddRefed<ScaledFont> CreateScaledFont(
+ Float aGlyphSize, const uint8_t* aInstanceData,
+ uint32_t aInstanceDataLength, const FontVariation* aVariations,
+ uint32_t aNumVariations) {
+ return nullptr;
+ }
+
+ virtual already_AddRefed<ScaledFont> CreateScaledFontFromWRFont(
+ Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
+ const wr::FontInstancePlatformOptions* aPlatformOptions,
+ const FontVariation* aVariations, uint32_t aNumVariations) {
+ return CreateScaledFont(aGlyphSize, nullptr, 0, aVariations,
+ aNumVariations);
+ }
+
+ protected:
+ UnscaledFont() = default;
+
+ private:
+ static Atomic<uint32_t> sDeletionCounter;
+};
+
+/** This class is an abstraction of a backend/platform specific font object
+ * at a particular size. It is passed into text drawing calls to describe
+ * the font used for the drawing call.
+ */
+class ScaledFont : public SupportsThreadSafeWeakPtr<ScaledFont> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
+
+ virtual ~ScaledFont();
+
+ virtual FontType GetType() const = 0;
+ virtual Float GetSize() const = 0;
+ virtual AntialiasMode GetDefaultAAMode() { return AntialiasMode::DEFAULT; }
+
+ static uint32_t DeletionCounter() { return sDeletionCounter; }
+
+ /** This allows getting a path that describes the outline of a set of glyphs.
+ * A target is passed in so that the guarantee is made the returned path
+ * can be used with any DrawTarget that has the same backend as the one
+ * passed in.
+ */
+ virtual already_AddRefed<Path> GetPathForGlyphs(
+ const GlyphBuffer& aBuffer, const DrawTarget* aTarget) = 0;
+
+ /** This copies the path describing the glyphs into a PathBuilder. We use this
+ * API rather than a generic API to append paths because it allows easier
+ * implementation in some backends, and more efficient implementation in
+ * others.
+ */
+ virtual void CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
+ PathBuilder* aBuilder,
+ const Matrix* aTransformHint = nullptr) = 0;
+
+ typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength,
+ const FontVariation* aVariations,
+ uint32_t aNumVariations, void* aBaton);
+
+ virtual bool GetFontInstanceData(FontInstanceDataOutput, void*) {
+ return false;
+ }
+
+ virtual bool GetWRFontInstanceOptions(
+ Maybe<wr::FontInstanceOptions>* aOutOptions,
+ Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
+ std::vector<FontVariation>* aOutVariations) {
+ return false;
+ }
+
+ virtual bool CanSerialize() { return false; }
+
+ virtual bool HasVariationSettings() { return false; }
+
+ virtual bool MayUseBitmaps() { return false; }
+
+ virtual bool UseSubpixelPosition() const { return false; }
+
+ void AddUserData(UserDataKey* key, void* userData, void (*destroy)(void*)) {
+ mUserData.Add(key, userData, destroy);
+ }
+ void* GetUserData(UserDataKey* key) { return mUserData.Get(key); }
+
+ void RemoveUserData(UserDataKey* key) { mUserData.RemoveAndDestroy(key); }
+
+ const RefPtr<UnscaledFont>& GetUnscaledFont() const { return mUnscaledFont; }
+
+ virtual cairo_scaled_font_t* GetCairoScaledFont() { return nullptr; }
+
+ Float GetSyntheticObliqueAngle() const { return mSyntheticObliqueAngle; }
+ void SetSyntheticObliqueAngle(Float aAngle) {
+ mSyntheticObliqueAngle = aAngle;
+ }
+
+ protected:
+ explicit ScaledFont(const RefPtr<UnscaledFont>& aUnscaledFont)
+ : mUnscaledFont(aUnscaledFont), mSyntheticObliqueAngle(0.0f) {}
+
+ ThreadSafeUserData mUserData;
+ RefPtr<UnscaledFont> mUnscaledFont;
+ Float mSyntheticObliqueAngle;
+
+ private:
+ static Atomic<uint32_t> sDeletionCounter;
+};
+
+/**
+ * Derived classes hold a native font resource from which to create
+ * ScaledFonts.
+ */
+class NativeFontResource
+ : public external::AtomicRefCounted<NativeFontResource> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource)
+
+ /**
+ * Creates a UnscaledFont using the font corresponding to the index.
+ *
+ * @param aIndex index for the font within the resource.
+ * @param aInstanceData pointer to read-only buffer of any available instance
+ * data.
+ * @param aInstanceDataLength the size of the instance data.
+ * @return an already_addrefed UnscaledFont, containing nullptr if failed.
+ */
+ virtual already_AddRefed<UnscaledFont> CreateUnscaledFont(
+ uint32_t aIndex, const uint8_t* aInstanceData,
+ uint32_t aInstanceDataLength) = 0;
+
+ NativeFontResource(size_t aDataLength);
+ virtual ~NativeFontResource();
+
+ static void RegisterMemoryReporter();
+
+ private:
+ size_t mDataLength;
+};
+
+/** This is the main class used for all the drawing. It is created through the
+ * factory and accepts drawing commands. The results of drawing to a target
+ * may be used either through a Snapshot or by flushing the target and directly
+ * accessing the backing store a DrawTarget was created with.
+ */
+class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget)
+ DrawTarget()
+ : mTransformDirty(false),
+ mPermitSubpixelAA(false),
+ mFormat(SurfaceFormat::UNKNOWN) {}
+ virtual ~DrawTarget() = default;
+
+ virtual bool IsValid() const { return true; };
+ virtual DrawTargetType GetType() const = 0;
+
+ virtual BackendType GetBackendType() const = 0;
+
+ virtual bool IsRecording() const { return false; }
+
+ /**
+ * Method to generate hyperlink in PDF output (with appropriate backend).
+ */
+ virtual void Link(const char* aDestination, const Rect& aRect) {}
+ virtual void Destination(const char* aDestination, const Point& aPoint) {}
+
+ /**
+ * Returns a SourceSurface which is a snapshot of the current contents of the
+ * DrawTarget. Multiple calls to Snapshot() without any drawing operations in
+ * between will normally return the same SourceSurface object.
+ */
+ virtual already_AddRefed<SourceSurface> Snapshot() = 0;
+
+ /**
+ * Returns a SourceSurface which wraps the buffer backing the DrawTarget. The
+ * contents of the buffer may change if there are drawing operations after
+ * calling but only guarantees that it reflects the state at the time it was
+ * called.
+ */
+ virtual already_AddRefed<SourceSurface> GetBackingSurface() {
+ return Snapshot();
+ }
+
+ // Snapshots the contents and returns an alpha mask
+ // based on the RGB values.
+ virtual already_AddRefed<SourceSurface> IntoLuminanceSource(
+ LuminanceType aLuminanceType, float aOpacity);
+ virtual IntSize GetSize() const = 0;
+ virtual IntRect GetRect() const { return IntRect(IntPoint(0, 0), GetSize()); }
+
+ /**
+ * If possible returns the bits to this DrawTarget for direct manipulation.
+ * While the bits is locked any modifications to this DrawTarget is forbidden.
+ * Release takes the original data pointer for safety.
+ */
+ virtual bool LockBits(uint8_t** aData, IntSize* aSize, int32_t* aStride,
+ SurfaceFormat* aFormat, IntPoint* aOrigin = nullptr) {
+ return false;
+ }
+ virtual void ReleaseBits(uint8_t* aData) {}
+
+ /** Ensure that the DrawTarget backend has flushed all drawing operations to
+ * this draw target. This must be called before using the backing surface of
+ * this draw target outside of GFX 2D code.
+ */
+ virtual void Flush() = 0;
+
+ /**
+ * Draw a surface to the draw target. Possibly doing partial drawing or
+ * applying scaling. No sampling happens outside the source.
+ *
+ * @param aSurface Source surface to draw
+ * @param aDest Destination rectangle that this drawing operation should draw
+ * to
+ * @param aSource Source rectangle in aSurface coordinates, this area of
+ * aSurface
+ * will be stretched to the size of aDest.
+ * @param aOptions General draw options that are applied to the operation
+ * @param aSurfOptions DrawSurface options that are applied
+ */
+ virtual void DrawSurface(
+ SourceSurface* aSurface, const Rect& aDest, const Rect& aSource,
+ const DrawSurfaceOptions& aSurfOptions = DrawSurfaceOptions(),
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Draw a surface to the draw target, when the surface will be available
+ * at a later time. This is only valid for recording DrawTargets.
+ *
+ * This is considered fallible, and replaying this without making the surface
+ * available to the replay will just skip the draw.
+ */
+ virtual void DrawDependentSurface(uint64_t aId, const Rect& aDest) {
+ MOZ_CRASH("GFX: DrawDependentSurface");
+ }
+
+ /**
+ * Draw the output of a FilterNode to the DrawTarget.
+ *
+ * @param aNode FilterNode to draw
+ * @param aSourceRect Source rectangle in FilterNode space to draw
+ * @param aDestPoint Destination point on the DrawTarget to draw the
+ * SourceRectangle of the filter output to
+ */
+ virtual void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
+ const Point& aDestPoint,
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Blend a surface to the draw target with a shadow. The shadow is drawn as a
+ * gaussian blur using a specified sigma. The shadow is clipped to the size
+ * of the input surface, so the input surface should contain a transparent
+ * border the size of the approximate coverage of the blur (3 * aSigma).
+ * NOTE: This function works in device space!
+ *
+ * @param aSurface Source surface to draw.
+ * @param aDest Destination point that this drawing operation should draw to.
+ * @param aShadow Description of shadow to be drawn.
+ * @param aOperator Composition operator used
+ */
+ virtual void DrawSurfaceWithShadow(SourceSurface* aSurface,
+ const Point& aDest,
+ const ShadowOptions& aShadow,
+ CompositionOp aOperator) = 0;
+
+ /**
+ * Draws a shadow for the specified path, which may be optionally stroked.
+ *
+ * @param aPath The path to use for the shadow geometry.
+ * @param aPattern The pattern to use for filling the path.
+ * @param aShadow Description of shadow to be drawn.
+ * @param aOptions General drawing options to apply to drawing the path.
+ * @param aStrokeOptions Stroking parameters that control stroking of path
+ * geometry, if supplied.
+ */
+ virtual void DrawShadow(const Path* aPath, const Pattern& aPattern,
+ const ShadowOptions& aShadow,
+ const DrawOptions& aOptions = DrawOptions(),
+ const StrokeOptions* aStrokeOptions = nullptr);
+
+ /**
+ * Clear a rectangle on the draw target to transparent black. This will
+ * respect the clipping region and transform.
+ *
+ * @param aRect Rectangle to clear
+ */
+ virtual void ClearRect(const Rect& aRect) = 0;
+
+ /**
+ * This is essentially a 'memcpy' between two surfaces. It moves a pixel
+ * aligned area from the source surface unscaled directly onto the
+ * drawtarget. This ignores both transform and clip.
+ *
+ * @param aSurface Surface to copy from
+ * @param aSourceRect Source rectangle to be copied
+ * @param aDest Destination point to copy the surface to
+ */
+ virtual void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect,
+ const IntPoint& aDestination) = 0;
+
+ /** @see CopySurface
+ * Same as CopySurface, except uses itself as the source.
+ *
+ * Some backends may be able to optimize this better
+ * than just taking a snapshot and using CopySurface.
+ */
+ virtual void CopyRect(const IntRect& aSourceRect,
+ const IntPoint& aDestination) {
+ RefPtr<SourceSurface> source = Snapshot();
+ CopySurface(source, aSourceRect, aDestination);
+ }
+
+ /**
+ * Fill a rectangle on the DrawTarget with a certain source pattern.
+ *
+ * @param aRect Rectangle that forms the mask of this filling operation
+ * @param aPattern Pattern that forms the source of this filling operation
+ * @param aOptions Options that are applied to this operation
+ */
+ virtual void FillRect(const Rect& aRect, const Pattern& aPattern,
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Fill a rounded rectangle on the DrawTarget with a certain source pattern.
+ *
+ * @param aRect Rounded rectangle that forms the mask of this filling
+ * operation
+ * @param aPattern Pattern that forms the source of this filling operation
+ * @param aOptions Options that are applied to this operation
+ */
+ virtual void FillRoundedRect(const RoundedRect& aRect,
+ const Pattern& aPattern,
+ const DrawOptions& aOptions = DrawOptions());
+
+ /**
+ * Stroke a rectangle on the DrawTarget with a certain source pattern.
+ *
+ * @param aRect Rectangle that forms the mask of this stroking operation
+ * @param aPattern Pattern that forms the source of this stroking operation
+ * @param aOptions Options that are applied to this operation
+ */
+ virtual void StrokeRect(const Rect& aRect, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions = StrokeOptions(),
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Stroke a line on the DrawTarget with a certain source pattern.
+ *
+ * @param aStart Starting point of the line
+ * @param aEnd End point of the line
+ * @param aPattern Pattern that forms the source of this stroking operation
+ * @param aOptions Options that are applied to this operation
+ */
+ virtual void StrokeLine(const Point& aStart, const Point& aEnd,
+ const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions = StrokeOptions(),
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Stroke a path on the draw target with a certain source pattern.
+ *
+ * @param aPath Path that is to be stroked
+ * @param aPattern Pattern that should be used for the stroke
+ * @param aStrokeOptions Stroke options used for this operation
+ * @param aOptions Draw options used for this operation
+ */
+ virtual void Stroke(const Path* aPath, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions = StrokeOptions(),
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Fill a path on the draw target with a certain source pattern.
+ *
+ * @param aPath Path that is to be filled
+ * @param aPattern Pattern that should be used for the fill
+ * @param aOptions Draw options used for this operation
+ */
+ virtual void Fill(const Path* aPath, const Pattern& aPattern,
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Fill a series of glyphs on the draw target with a certain source pattern.
+ */
+ virtual void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
+ const Pattern& aPattern,
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Stroke a series of glyphs on the draw target with a certain source pattern.
+ */
+ virtual void StrokeGlyphs(
+ ScaledFont* aFont, const GlyphBuffer& aBuffer, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions = StrokeOptions(),
+ const DrawOptions& aOptions = DrawOptions());
+
+ /**
+ * This takes a source pattern and a mask, and composites the source pattern
+ * onto the destination surface using the alpha channel of the mask pattern
+ * as a mask for the operation.
+ *
+ * @param aSource Source pattern
+ * @param aMask Mask pattern
+ * @param aOptions Drawing options
+ */
+ virtual void Mask(const Pattern& aSource, const Pattern& aMask,
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * This takes a source pattern and a mask, and composites the source pattern
+ * onto the destination surface using the alpha channel of the mask source.
+ * The operation is bound by the extents of the mask.
+ *
+ * @param aSource Source pattern
+ * @param aMask Mask surface
+ * @param aOffset a transformed offset that the surface is masked at
+ * @param aOptions Drawing options
+ */
+ virtual void MaskSurface(const Pattern& aSource, SourceSurface* aMask,
+ Point aOffset,
+ const DrawOptions& aOptions = DrawOptions()) = 0;
+
+ /**
+ * Draw aSurface using the 3D transform aMatrix. The DrawTarget's transform
+ * and clip are applied after the 3D transform.
+ *
+ * If the transform fails (i.e. because aMatrix is singular), false is
+ * returned and nothing is drawn.
+ */
+ virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
+ const Matrix4x4& aMatrix);
+
+ /**
+ * Push a clip to the DrawTarget.
+ *
+ * @param aPath The path to clip to
+ */
+ virtual void PushClip(const Path* aPath) = 0;
+
+ /**
+ * Push an axis-aligned rectangular clip to the DrawTarget. This rectangle
+ * is specified in user space.
+ *
+ * @param aRect The rect to clip to
+ */
+ virtual void PushClipRect(const Rect& aRect) = 0;
+
+ /**
+ * Push a clip region specifed by the union of axis-aligned rectangular
+ * clips to the DrawTarget. These rectangles are specified in device space.
+ * This must be balanced by a corresponding call to PopClip within a layer.
+ *
+ * @param aRects The rects to clip to
+ * @param aCount The number of rectangles
+ */
+ virtual void PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount);
+
+ /** Pop a clip from the DrawTarget. A pop without a corresponding push will
+ * be ignored.
+ */
+ virtual void PopClip() = 0;
+
+ /**
+ * Push a 'layer' to the DrawTarget, a layer is a temporary surface that all
+ * drawing will be redirected to, this is used for example to support group
+ * opacity or the masking of groups. Clips must be balanced within a layer,
+ * i.e. between a matching PushLayer/PopLayer pair there must be as many
+ * PushClip(Rect) calls as there are PopClip calls.
+ *
+ * @param aOpaque Whether the layer will be opaque
+ * @param aOpacity Opacity of the layer
+ * @param aMask Mask applied to the layer
+ * @param aMaskTransform Transform applied to the layer mask
+ * @param aBounds Optional bounds in device space to which the layer is
+ * limited in size.
+ * @param aCopyBackground Whether to copy the background into the layer, this
+ * is only supported when aOpaque is true.
+ */
+ virtual void PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
+ const Matrix& aMaskTransform,
+ const IntRect& aBounds = IntRect(),
+ bool aCopyBackground = false) {
+ MOZ_CRASH("GFX: PushLayer");
+ }
+
+ /**
+ * Push a 'layer' to the DrawTarget, a layer is a temporary surface that all
+ * drawing will be redirected to, this is used for example to support group
+ * opacity or the masking of groups. Clips must be balanced within a layer,
+ * i.e. between a matching PushLayer/PopLayer pair there must be as many
+ * PushClip(Rect) calls as there are PopClip calls.
+ *
+ * @param aOpaque Whether the layer will be opaque
+ * @param aOpacity Opacity of the layer
+ * @param aMask Mask applied to the layer
+ * @param aMaskTransform Transform applied to the layer mask
+ * @param aBounds Optional bounds in device space to which the layer is
+ * limited in size.
+ * @param aCopyBackground Whether to copy the background into the layer, this
+ * is only supported when aOpaque is true.
+ */
+ virtual void PushLayerWithBlend(bool aOpaque, Float aOpacity,
+ SourceSurface* aMask,
+ const Matrix& aMaskTransform,
+ const IntRect& aBounds = IntRect(),
+ bool aCopyBackground = false,
+ CompositionOp = CompositionOp::OP_OVER) {
+ MOZ_CRASH("GFX: PushLayerWithBlend");
+ }
+
+ /**
+ * This balances a call to PushLayer and proceeds to blend the layer back
+ * onto the background. This blend will blend the temporary surface back
+ * onto the target in device space using POINT sampling and operator over.
+ */
+ virtual void PopLayer() { MOZ_CRASH("GFX: PopLayer"); }
+
+ /**
+ * Perform an in-place blur operation. This is only supported on data draw
+ * targets.
+ */
+ virtual void Blur(const AlphaBoxBlur& aBlur);
+
+ /**
+ * Performs an in-place edge padding operation.
+ * aRegion is specified in device space.
+ */
+ virtual void PadEdges(const IntRegion& aRegion);
+
+ /**
+ * Performs an in-place buffer unrotation operation.
+ */
+ virtual bool Unrotate(IntPoint aRotation);
+
+ /**
+ * Create a SourceSurface optimized for use with this DrawTarget from
+ * existing bitmap data in memory.
+ *
+ * The SourceSurface does not take ownership of aData, and may be freed at any
+ * time.
+ */
+ virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(
+ unsigned char* aData, const IntSize& aSize, int32_t aStride,
+ SurfaceFormat aFormat) const = 0;
+
+ /**
+ * Create a SourceSurface optimized for use with this DrawTarget from an
+ * arbitrary SourceSurface type supported by this backend. This may return
+ * aSourceSurface or some other existing surface.
+ */
+ virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(
+ SourceSurface* aSurface) const = 0;
+ virtual already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(
+ SourceSurface* aSurface) const {
+ return OptimizeSourceSurface(aSurface);
+ }
+
+ /**
+ * Create a SourceSurface for a type of NativeSurface. This may fail if the
+ * draw target does not know how to deal with the type of NativeSurface passed
+ * in. If this succeeds, the SourceSurface takes the ownersip of the
+ * NativeSurface.
+ */
+ virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface(
+ const NativeSurface& aSurface) const = 0;
+
+ /**
+ * Create a DrawTarget whose snapshot is optimized for use with this
+ * DrawTarget.
+ */
+ virtual already_AddRefed<DrawTarget> CreateSimilarDrawTarget(
+ const IntSize& aSize, SurfaceFormat aFormat) const = 0;
+
+ /**
+ * Create a DrawTarget whose backing surface is optimized for use with this
+ * DrawTarget.
+ */
+ virtual already_AddRefed<DrawTarget> CreateSimilarDrawTargetWithBacking(
+ const IntSize& aSize, SurfaceFormat aFormat) const {
+ return CreateSimilarDrawTarget(aSize, aFormat);
+ }
+
+ /**
+ * Create a DrawTarget whose snapshot is optimized for use with this
+ * DrawTarget and aFilter.
+ * @param aSource is the FilterNode that that will be attached to this
+ * surface.
+ * @param aSourceRect is the source rect that will be passed to DrawFilter
+ * @param aDestPoint is the dest point that will be passed to DrawFilter.
+ */
+ virtual already_AddRefed<DrawTarget> CreateSimilarDrawTargetForFilter(
+ const IntSize& aSize, SurfaceFormat aFormat, FilterNode* aFilter,
+ FilterNode* aSource, const Rect& aSourceRect, const Point& aDestPoint) {
+ return CreateSimilarDrawTarget(aSize, aFormat);
+ }
+
+ /**
+ * Returns false if CreateSimilarDrawTarget would return null with the same
+ * parameters. May return true even in cases where CreateSimilarDrawTarget
+ * return null (i.e. this function returning false has meaning, but returning
+ * true doesn't guarantee anything).
+ */
+ virtual bool CanCreateSimilarDrawTarget(const IntSize& aSize,
+ SurfaceFormat aFormat) const {
+ return true;
+ }
+
+ /**
+ * Create a draw target optimized for drawing a shadow.
+ *
+ * Note that aSigma is the blur radius that must be used when we draw the
+ * shadow. Also note that this doesn't affect the size of the allocated
+ * surface, the caller is still responsible for including the shadow area in
+ * its size.
+ */
+ virtual already_AddRefed<DrawTarget> CreateShadowDrawTarget(
+ const IntSize& aSize, SurfaceFormat aFormat, float aSigma) const {
+ return CreateSimilarDrawTarget(aSize, aFormat);
+ }
+
+ /**
+ * Create a similar DrawTarget in the same space as this DrawTarget whose
+ * device size may be clipped based on the active clips intersected with
+ * aBounds (if it is not empty).
+ * aRect is a rectangle in user space.
+ */
+ virtual RefPtr<DrawTarget> CreateClippedDrawTarget(const Rect& aBounds,
+ SurfaceFormat aFormat) = 0;
+
+ /**
+ * Create a similar draw target, but if the draw target is not backed by a
+ * raster backend (for example, it is capturing or recording), force it to
+ * create a raster target instead. This is intended for code that wants to
+ * cache pixels, and would have no effect if it were caching a recording.
+ */
+ virtual RefPtr<DrawTarget> CreateSimilarRasterTarget(
+ const IntSize& aSize, SurfaceFormat aFormat) const {
+ return CreateSimilarDrawTarget(aSize, aFormat);
+ }
+
+ /**
+ * Create a path builder with the specified fillmode.
+ *
+ * We need the fill mode up front because of Direct2D.
+ * ID2D1SimplifiedGeometrySink requires the fill mode
+ * to be set before calling BeginFigure().
+ */
+ virtual already_AddRefed<PathBuilder> CreatePathBuilder(
+ FillRule aFillRule = FillRule::FILL_WINDING) const = 0;
+
+ /**
+ * Create a GradientStops object that holds information about a set of
+ * gradient stops, this object is required for linear or radial gradient
+ * patterns to represent the color stops in the gradient.
+ *
+ * @param aStops An array of gradient stops
+ * @param aNumStops Number of stops in the array aStops
+ * @param aExtendNone This describes how to extend the stop color outside of
+ * the gradient area.
+ */
+ virtual already_AddRefed<GradientStops> CreateGradientStops(
+ GradientStop* aStops, uint32_t aNumStops,
+ ExtendMode aExtendMode = ExtendMode::CLAMP) const = 0;
+
+ /**
+ * Create a FilterNode object that can be used to apply a filter to various
+ * inputs.
+ *
+ * @param aType Type of filter node to be created.
+ */
+ virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) = 0;
+
+ Matrix GetTransform() const { return mTransform; }
+
+ /**
+ * Set a transform on the surface, this transform is applied at drawing time
+ * to both the mask and source of the operation.
+ *
+ * Performance note: For some backends it is expensive to change the current
+ * transform (because transforms affect a lot of the parts of the pipeline,
+ * so new transform change can result in a pipeline flush). To get around
+ * this, DrawTarget implementations buffer transform changes and try to only
+ * set the current transform on the backend when required. That tracking has
+ * its own performance impact though, and ideally callers would be smart
+ * enough not to require it. At a future date this method may stop this
+ * doing transform buffering so, if you're a consumer, please try to be smart
+ * about calling this method as little as possible. For example, instead of
+ * concatenating a translation onto the current transform then calling
+ * FillRect, try to integrate the translation into FillRect's aRect
+ * argument's x/y offset.
+ */
+ virtual void SetTransform(const Matrix& aTransform) {
+ mTransform = aTransform;
+ mTransformDirty = true;
+ }
+
+ inline void ConcatTransform(const Matrix& aTransform) {
+ SetTransform(aTransform * Matrix(GetTransform()));
+ }
+
+ SurfaceFormat GetFormat() const { return mFormat; }
+
+ /** Tries to get a native surface for a DrawTarget, this may fail if the
+ * draw target cannot convert to this surface type.
+ */
+ virtual void* GetNativeSurface(NativeSurfaceType aType) { return nullptr; }
+
+ virtual bool IsTiledDrawTarget() const { return false; }
+ virtual bool SupportsRegionClipping() const { return true; }
+
+ void AddUserData(UserDataKey* key, void* userData, void (*destroy)(void*)) {
+ mUserData.Add(key, userData, destroy);
+ }
+ void* GetUserData(UserDataKey* key) const { return mUserData.Get(key); }
+ void* RemoveUserData(UserDataKey* key) { return mUserData.Remove(key); }
+
+ /** Within this rectangle all pixels will be opaque by the time the result of
+ * this DrawTarget is first used for drawing. Either by the underlying surface
+ * being used as an input to external drawing, or Snapshot() being called.
+ * This rectangle is specified in device space.
+ */
+ void SetOpaqueRect(const IntRect& aRect) { mOpaqueRect = aRect; }
+
+ const IntRect& GetOpaqueRect() const { return mOpaqueRect; }
+
+ virtual bool IsCurrentGroupOpaque() {
+ return GetFormat() == SurfaceFormat::B8G8R8X8;
+ }
+
+ virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA) {
+ mPermitSubpixelAA = aPermitSubpixelAA;
+ }
+
+ bool GetPermitSubpixelAA() { return mPermitSubpixelAA; }
+
+ /**
+ * Mark the end of an Item in a DrawTargetRecording. These markers
+ * are used for merging recordings together.
+ *
+ * This should only be called on the 'root' DrawTargetRecording.
+ * Calling it on a child DrawTargetRecordings will cause confusion.
+ *
+ * Note: this is a bit of a hack. It might be better to just recreate
+ * the DrawTargetRecording.
+ */
+ virtual void FlushItem(const IntRect& aBounds) {}
+
+ /**
+ * Ensures that no snapshot is still pointing to this DrawTarget's surface
+ * data.
+ *
+ * This can be useful if the DrawTarget is wrapped around data that it does
+ * not own, and for some reason the owner of the data has to make it
+ * temporarily unavailable without the DrawTarget knowing about it. This can
+ * cause costly surface copies, so it should not be used without a a good
+ * reason.
+ */
+ virtual void DetachAllSnapshots() = 0;
+
+ /**
+ * Remove all clips in the DrawTarget.
+ */
+ virtual bool RemoveAllClips() { return false; }
+
+ protected:
+ UserData mUserData;
+ Matrix mTransform;
+ IntRect mOpaqueRect;
+ bool mTransformDirty : 1;
+ bool mPermitSubpixelAA : 1;
+
+ SurfaceFormat mFormat;
+};
+
+class DrawEventRecorder : public RefCounted<DrawEventRecorder> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
+ // returns true if there were any items in the recording
+ virtual bool Finish() = 0;
+ virtual ~DrawEventRecorder() = default;
+};
+
+struct Tile {
+ RefPtr<DrawTarget> mDrawTarget;
+ IntPoint mTileOrigin;
+};
+
+struct TileSet {
+ Tile* mTiles;
+ size_t mTileCount;
+};
+
+struct Config {
+ LogForwarder* mLogForwarder;
+ int32_t mMaxTextureSize;
+ int32_t mMaxAllocSize;
+
+ Config()
+ : mLogForwarder(nullptr),
+ mMaxTextureSize(kReasonableSurfaceSize),
+ mMaxAllocSize(52000000) {}
+};
+
+class GFX2D_API Factory {
+ using char_type = filesystem::Path::value_type;
+
+ public:
+ static void Init(const Config& aConfig);
+ static void ShutDown();
+
+ static bool HasSSE2();
+ static bool HasSSE4();
+
+ /**
+ * Returns false if any of the following are true:
+ *
+ * - the width/height of |sz| are less than or equal to zero
+ * - the width/height of |sz| are greater than |limit|
+ * - the number of bytes that need to be allocated for the surface is too
+ * big to fit in an int32_t, or bigger than |allocLimit|, if specifed
+ *
+ * To calculate the number of bytes that need to be allocated for the surface
+ * this function makes the conservative assumption that there need to be
+ * 4 bytes-per-pixel, and the stride alignment is 16 bytes.
+ *
+ * The reason for using int32_t rather than uint32_t is again to be
+ * conservative; some code has in the past and may in the future use signed
+ * integers to store buffer lengths etc.
+ */
+ static bool CheckSurfaceSize(const IntSize& sz, int32_t limit = 0,
+ int32_t allocLimit = 0);
+
+ /** Make sure the given dimension satisfies the CheckSurfaceSize and is
+ * within 8k limit. The 8k value is chosen a bit randomly.
+ */
+ static bool ReasonableSurfaceSize(const IntSize& aSize);
+
+ static bool AllowedSurfaceSize(const IntSize& aSize);
+
+ static already_AddRefed<DrawTarget> CreateDrawTargetForCairoSurface(
+ cairo_surface_t* aSurface, const IntSize& aSize,
+ SurfaceFormat* aFormat = nullptr);
+
+ static already_AddRefed<SourceSurface> CreateSourceSurfaceForCairoSurface(
+ cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat);
+
+ static already_AddRefed<DrawTarget> CreateDrawTarget(BackendType aBackend,
+ const IntSize& aSize,
+ SurfaceFormat aFormat);
+
+ static already_AddRefed<PathBuilder> CreatePathBuilder(
+ BackendType aBackend, FillRule aFillRule = FillRule::FILL_WINDING);
+
+ /**
+ * Create a simple PathBuilder, which uses SKIA backend.
+ */
+ static already_AddRefed<PathBuilder> CreateSimplePathBuilder();
+
+ static already_AddRefed<DrawTarget> CreateRecordingDrawTarget(
+ DrawEventRecorder* aRecorder, DrawTarget* aDT, IntRect aRect);
+
+ static already_AddRefed<DrawTarget> CreateDrawTargetForData(
+ BackendType aBackend, unsigned char* aData, const IntSize& aSize,
+ int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);
+
+#ifdef XP_DARWIN
+ static already_AddRefed<ScaledFont> CreateScaledFontForMacFont(
+ CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
+ const DeviceColor& aFontSmoothingBackgroundColor,
+ bool aUseFontSmoothing = true, bool aApplySyntheticBold = false,
+ bool aHasColorGlyphs = false);
+#endif
+
+#ifdef MOZ_WIDGET_GTK
+ static already_AddRefed<ScaledFont> CreateScaledFontForFontconfigFont(
+ const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
+ RefPtr<SharedFTFace> aFace, FcPattern* aPattern);
+#endif
+
+#ifdef MOZ_WIDGET_ANDROID
+ static already_AddRefed<ScaledFont> CreateScaledFontForFreeTypeFont(
+ const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
+ RefPtr<SharedFTFace> aFace, bool aApplySyntheticBold = false);
+#endif
+
+ /**
+ * This creates a NativeFontResource from TrueType data.
+ *
+ * @param aData Pointer to the data
+ * @param aSize Size of the TrueType data
+ * @param aFontType Type of NativeFontResource that should be created.
+ * @param aFontContext Optional native font context to be used to create the
+ * NativeFontResource.
+ * @return a NativeFontResource of nullptr if failed.
+ */
+ static already_AddRefed<NativeFontResource> CreateNativeFontResource(
+ uint8_t* aData, uint32_t aSize, FontType aFontType,
+ void* aFontContext = nullptr);
+
+ /**
+ * This creates an unscaled font of the given type based on font descriptor
+ * data retrieved from ScaledFont::GetFontDescriptor.
+ */
+ static already_AddRefed<UnscaledFont> CreateUnscaledFontFromFontDescriptor(
+ FontType aType, const uint8_t* aData, uint32_t aDataLength,
+ uint32_t aIndex);
+
+ /**
+ * This creates a simple data source surface for a certain size. It allocates
+ * new memory for the surface. This memory is freed when the surface is
+ * destroyed. The caller is responsible for handing the case where nullptr
+ * is returned. The surface is not zeroed unless requested.
+ */
+ static already_AddRefed<DataSourceSurface> CreateDataSourceSurface(
+ const IntSize& aSize, SurfaceFormat aFormat, bool aZero = false);
+
+ /**
+ * This creates a simple data source surface for a certain size with a
+ * specific stride, which must be large enough to fit all pixels.
+ * It allocates new memory for the surface. This memory is freed when
+ * the surface is destroyed. The caller is responsible for handling the case
+ * where nullptr is returned. The surface is not zeroed unless requested.
+ */
+ static already_AddRefed<DataSourceSurface> CreateDataSourceSurfaceWithStride(
+ const IntSize& aSize, SurfaceFormat aFormat, int32_t aStride,
+ bool aZero = false);
+
+ typedef void (*SourceSurfaceDeallocator)(void* aClosure);
+
+ /**
+ * This creates a simple data source surface for some existing data. It will
+ * wrap this data and the data for this source surface.
+ *
+ * We can provide a custom destroying function for |aData|. This will be
+ * called in the surface dtor using |aDeallocator| and the |aClosure|. If
+ * there are errors during construction(return a nullptr surface), the caller
+ * is responsible for the deallocation.
+ *
+ * If there is no destroying function, the caller is responsible for
+ * deallocating the aData memory only after destruction of this
+ * DataSourceSurface.
+ */
+ static already_AddRefed<DataSourceSurface> CreateWrappingDataSourceSurface(
+ uint8_t* aData, int32_t aStride, const IntSize& aSize,
+ SurfaceFormat aFormat, SourceSurfaceDeallocator aDeallocator = nullptr,
+ void* aClosure = nullptr);
+
+ static void CopyDataSourceSurface(DataSourceSurface* aSource,
+ DataSourceSurface* aDest);
+
+ static uint32_t GetMaxSurfaceSize(BackendType aType);
+
+ static LogForwarder* GetLogForwarder() {
+ return sConfig ? sConfig->mLogForwarder : nullptr;
+ }
+
+ private:
+ static Config* sConfig;
+
+ public:
+ static void PurgeAllCaches();
+
+ static already_AddRefed<DrawTarget> CreateOffsetDrawTarget(
+ DrawTarget* aDrawTarget, IntPoint aTileOrigin);
+
+ static bool DoesBackendSupportDataDrawtarget(BackendType aType);
+
+ static void SetBGRSubpixelOrder(bool aBGR);
+ static bool GetBGRSubpixelOrder();
+
+ private:
+ static bool mBGRSubpixelOrder;
+
+ public:
+ static already_AddRefed<DrawTarget> CreateDrawTargetWithSkCanvas(
+ SkCanvas* aCanvas);
+
+#ifdef MOZ_ENABLE_FREETYPE
+ static void SetFTLibrary(FT_Library aFTLibrary);
+ static FT_Library GetFTLibrary();
+
+ static FT_Library NewFTLibrary();
+ static void ReleaseFTLibrary(FT_Library aFTLibrary);
+ static void LockFTLibrary(FT_Library aFTLibrary);
+ static void UnlockFTLibrary(FT_Library aFTLibrary);
+
+ static FT_Face NewFTFace(FT_Library aFTLibrary, const char* aFileName,
+ int aFaceIndex);
+ static already_AddRefed<SharedFTFace> NewSharedFTFace(FT_Library aFTLibrary,
+ const char* aFilename,
+ int aFaceIndex);
+ static FT_Face NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData,
+ size_t aDataSize, int aFaceIndex);
+ static already_AddRefed<SharedFTFace> NewSharedFTFaceFromData(
+ FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize,
+ int aFaceIndex, SharedFTFaceData* aSharedData = nullptr);
+ static void ReleaseFTFace(FT_Face aFace);
+ static FT_Error LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex,
+ int32_t aFlags);
+
+ private:
+ static FT_Library mFTLibrary;
+ static StaticMutex mFTLock;
+
+ public:
+#endif
+
+#ifdef WIN32
+ static already_AddRefed<DrawTarget> CreateDrawTargetForD3D11Texture(
+ ID3D11Texture2D* aTexture, SurfaceFormat aFormat);
+
+ /*
+ * Attempts to create and install a D2D1 device from the supplied Direct3D11
+ * device. Returns true on success, or false on failure and leaves the
+ * D2D1/Direct3D11 devices unset.
+ */
+ static bool SetDirect3D11Device(ID3D11Device* aDevice);
+ static RefPtr<ID3D11Device> GetDirect3D11Device();
+ static RefPtr<ID2D1Device> GetD2D1Device(uint32_t* aOutSeqNo = nullptr);
+ static bool HasD2D1Device();
+ static RefPtr<IDWriteFactory> GetDWriteFactory();
+ static RefPtr<IDWriteFactory> EnsureDWriteFactory();
+ static bool SupportsD2D1();
+ static RefPtr<IDWriteFontCollection> GetDWriteSystemFonts(
+ bool aUpdate = false);
+ static RefPtr<ID2D1DeviceContext> GetD2DDeviceContext();
+
+ static uint64_t GetD2DVRAMUsageDrawTarget();
+ static uint64_t GetD2DVRAMUsageSourceSurface();
+ static void D2DCleanup();
+
+ static already_AddRefed<ScaledFont> CreateScaledFontForDWriteFont(
+ IDWriteFontFace* aFontFace, const gfxFontStyle* aStyle,
+ const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
+ bool aUseEmbeddedBitmap, bool aUseMultistrikeBold, bool aGDIForced);
+
+ static already_AddRefed<ScaledFont> CreateScaledFontForGDIFont(
+ const void* aLogFont, const RefPtr<UnscaledFont>& aUnscaledFont,
+ Float aSize);
+
+ static void SetSystemTextQuality(uint8_t aQuality);
+
+ static already_AddRefed<DataSourceSurface>
+ CreateBGRA8DataSourceSurfaceForD3D11Texture(ID3D11Texture2D* aSrcTexture,
+ uint32_t aArrayIndex = 0);
+
+ static bool ReadbackTexture(layers::TextureData* aDestCpuTexture,
+ ID3D11Texture2D* aSrcTexture);
+
+ static bool ReadbackTexture(DataSourceSurface* aDestCpuTexture,
+ ID3D11Texture2D* aSrcTexture,
+ uint32_t aArrayIndex = 0);
+
+ private:
+ static StaticRefPtr<ID2D1Device> mD2D1Device;
+ static StaticRefPtr<ID3D11Device> mD3D11Device;
+ static StaticRefPtr<IDWriteFactory> mDWriteFactory;
+ static bool mDWriteFactoryInitialized;
+ static StaticRefPtr<IDWriteFontCollection> mDWriteSystemFonts;
+ static StaticRefPtr<ID2D1DeviceContext> mMTDC;
+ static StaticRefPtr<ID2D1DeviceContext> mOffMTDC;
+
+ static bool ReadbackTexture(uint8_t* aDestData, int32_t aDestStride,
+ ID3D11Texture2D* aSrcTexture);
+
+ // DestTextureT can be TextureData or DataSourceSurface.
+ template <typename DestTextureT>
+ static bool ConvertSourceAndRetryReadback(DestTextureT* aDestCpuTexture,
+ ID3D11Texture2D* aSrcTexture,
+ uint32_t aArrayIndex = 0);
+
+ protected:
+ // This guards access to the singleton devices above, as well as the
+ // singleton devices in DrawTargetD2D1.
+ static StaticMutex mDeviceLock;
+ // This synchronizes access between different D2D drawtargets and their
+ // implied dependency graph.
+ static StaticMutex mDTDependencyLock;
+
+ friend class DrawTargetD2D1;
+#endif // WIN32
+};
+
+class MOZ_RAII AutoSerializeWithMoz2D final {
+ public:
+ explicit AutoSerializeWithMoz2D(BackendType aBackendType);
+ ~AutoSerializeWithMoz2D();
+
+ private:
+#if defined(WIN32)
+ RefPtr<ID2D1Multithread> mMT;
+#endif
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _MOZILLA_GFX_2D_H