/* -*- 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 // GenericRefCountedBase allows us to hold on to refcounted objects of any type // (contrary to RefCounted 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 ID3D11Texture2D; struct ID3D11Device; struct ID2D1Device; struct ID2D1DeviceContext; 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 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; }; struct NativeFont { NativeFontType mType; void *mFont; }; /** * 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. */ }; /** * 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. }; /** * 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. */ }; /** * 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 external::AtomicRefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops) virtual ~GradientStops() {} virtual BackendType GetBackendType() const = 0; virtual bool IsValid() const { return true; } protected: GradientStops() {} }; /** * 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() {} virtual PatternType GetType() const = 0; protected: Pattern() {} }; class ColorPattern : public Pattern { public: // Explicit because consumers should generally use ToDeviceColor when // creating a ColorPattern. explicit ColorPattern(const Color &aColor) : mColor(aColor) {} virtual PatternType GetType() const override { return PatternType::COLOR; } Color 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. */ class LinearGradientPattern : public Pattern { public: /// For constructor parameter description, see member data documentation. LinearGradientPattern(const Point &aBegin, const Point &aEnd, GradientStops *aStops, const Matrix &aMatrix = Matrix()) : mBegin(aBegin), mEnd(aEnd), mStops(aStops), mMatrix(aMatrix) {} virtual PatternType GetType() const override { return PatternType::LINEAR_GRADIENT; } 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. */ RefPtr 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 */ }; /** * 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. */ class RadialGradientPattern : public Pattern { public: /// For constructor parameter description, see member data documentation. RadialGradientPattern(const Point &aCenter1, const Point &aCenter2, Float aRadius1, Float aRadius2, GradientStops *aStops, const Matrix &aMatrix = Matrix()) : mCenter1(aCenter1), mCenter2(aCenter2), mRadius1(aRadius1), mRadius2(aRadius2), mStops(aStops), mMatrix(aMatrix) {} virtual PatternType GetType() const override { return PatternType::RADIAL_GRADIENT; } 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. RefPtr 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 }; /** * 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. */ class SurfacePattern : public Pattern { public: /// For constructor parameter description, see member data documentation. SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode, const Matrix &aMatrix = Matrix(), SamplingFilter aSamplingFilter = SamplingFilter::GOOD, const IntRect &aSamplingRect = IntRect()) : mSurface(aSourceSurface), mExtendMode(aExtendMode), mSamplingFilter(aSamplingFilter), mMatrix(aMatrix), mSamplingRect(aSamplingRect) {} virtual PatternType GetType() const override { return PatternType::SURFACE; } RefPtr 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. */ }; class StoredPattern; class DrawTargetCaptureImpl; /** * 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 external::AtomicRefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface) virtual ~SourceSurface() {} 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; /** 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 { SurfaceType type = GetType(); return type == SurfaceType::DATA || type == SurfaceType::DATA_SHARED || type == SurfaceType::DATA_RECYCLING_SHARED; } /** * This function will get a DataSourceSurface for this surface, a * DataSourceSurface's data can be accessed directly. */ virtual already_AddRefed GetDataSurface() = 0; /** 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); } protected: friend class DrawTargetCaptureImpl; friend class StoredPattern; // This is for internal use, it ensures the SourceSurface's data remains // valid during the lifetime of the SourceSurface. // @todo XXX - We need something better here :(. But we may be able to get rid // of CreateWrappingDataSourceSurface in the future. virtual void GuaranteePersistance() {} UserData 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; int32_t mStride; }; 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: explicit 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; } bool IsMapped() const { return mIsMapped; } private: ScopedMap(const ScopedMap &aOther) = delete; ScopedMap &operator=(const ScopedMap &aOther) = delete; RefPtr mSurface; MappedSurface mMap; bool mIsMapped; }; virtual 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. */ virtual already_AddRefed GetDataSurface() override; /** * Add the size of the underlying data buffer to the aggregate. */ virtual void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t &aHeapSizeOut, size_t &aNonHeapSizeOut, size_t &aExtHandlesOut, uint64_t &aExtIdOut) const {} /** * 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 TakeDirtyRect() { return Nothing(); } /** * Indicate a region which has changed in the surface. */ virtual void Invalidate(const IntRect &aDirtyRect) {} protected: Atomic mMapCount; }; /** This is an abstract object that accepts path segments. */ class PathSink : public RefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSink) virtual ~PathSink() {} /** 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; /** Point the current subpath is at - or where the next subpath will start * if there is no active subpath. */ virtual Point CurrentPoint() const = 0; }; 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 { 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 CopyToBuilder() const { return CopyToBuilder(GetFillRule()); } inline already_AddRefed 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 CopyToBuilder( FillRule aFillRule) const = 0; virtual already_AddRefed 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; /** 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 Point ComputePointAtLength(Float aLength, Point *aTangent = nullptr); protected: Path(); void EnsureFlattenedPath(); RefPtr 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 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. }; struct GlyphMetrics { // Horizontal distance from the origin to the leftmost side of the bounding // box of the drawn glyph. This can be negative! Float mXBearing; // Horizontal distance from the origin of this glyph to the origin of the // next glyph. Float mXAdvance; // Vertical distance from the origin to the topmost side of the bounding box // of the drawn glyph. Float mYBearing; // Vertical distance from the origin of this glyph to the origin of the next // glyph, this is used when drawing vertically and will typically be 0. Float mYAdvance; // Width of the glyph's black box. Float mWidth; // Height of the glyph's black box. Float mHeight; }; class UnscaledFont : public SupportsThreadSafeWeakPtr { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFont) MOZ_DECLARE_THREADSAFEWEAKREFERENCE_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 (*WRFontDescriptorOutput)(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 GetWRFontDescriptor(WRFontDescriptorOutput, void *) { return false; } virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; } virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; } virtual already_AddRefed CreateScaledFont( Float aGlyphSize, const uint8_t *aInstanceData, uint32_t aInstanceDataLength, const FontVariation *aVariations, uint32_t aNumVariations) { return nullptr; } virtual already_AddRefed 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() {} private: static Atomic 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 { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont) MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(ScaledFont) virtual ~ScaledFont(); virtual FontType GetType() const = 0; virtual Float GetSize() const = 0; virtual AntialiasMode GetDefaultAAMode(); 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 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; /* This gets the metrics of a set of glyphs for the current font face. */ virtual void GetGlyphDesignMetrics(const uint16_t *aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics *aGlyphMetrics) = 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 *aOutOptions, Maybe *aOutPlatformOptions, std::vector *aOutVariations) { return false; } virtual bool CanSerialize() { return false; } virtual bool HasVariationSettings() { 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 &GetUnscaledFont() const { return mUnscaledFont; } virtual cairo_scaled_font_t *GetCairoScaledFont() { return nullptr; } virtual void SetCairoScaledFont(cairo_scaled_font_t *font) {} Float GetSyntheticObliqueAngle() const { return mSyntheticObliqueAngle; } void SetSyntheticObliqueAngle(Float aAngle) { mSyntheticObliqueAngle = aAngle; } protected: explicit ScaledFont(const RefPtr &aUnscaledFont) : mUnscaledFont(aUnscaledFont), mSyntheticObliqueAngle(0.0f) {} UserData mUserData; RefPtr mUnscaledFont; Float mSyntheticObliqueAngle; private: static Atomic sDeletionCounter; }; /** * Derived classes hold a native font resource from which to create * ScaledFonts. */ class NativeFontResource : public external::AtomicRefCounted { 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 CreateUnscaledFont( uint32_t aIndex, const uint8_t *aInstanceData, uint32_t aInstanceDataLength) = 0; virtual ~NativeFontResource() {} }; class DrawTargetCapture; /** 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 { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget) DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false), mFormat(SurfaceFormat::UNKNOWN) {} virtual ~DrawTarget() {} virtual bool IsValid() const { return true; }; virtual DrawTargetType GetType() const = 0; virtual BackendType GetBackendType() const = 0; virtual bool IsRecording() const { return false; } virtual bool IsCaptureDT() const { return false; } /** * 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 Snapshot() = 0; // Snapshots the contents and returns an alpha mask // based on the RGB values. virtual already_AddRefed 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; /** * Realize a DrawTargetCapture onto the draw target. * * @param aSource Capture DrawTarget to draw * @param aTransform Transform to apply when replaying commands */ virtual void DrawCapturedDT(DrawTargetCapture *aCaptureDT, const Matrix &aTransform); /** * 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; virtual void DrawDependentSurface( uint64_t aId, const Rect &aDest, const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), const DrawOptions &aOptions = DrawOptions()) { 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 aColor Color of the drawn shadow * @param aOffset Offset of the shadow * @param aSigma Sigma used for the guassian filter kernel * @param aOperator Composition operator used */ virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator) = 0; /** * 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 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 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 OptimizeSourceSurface( SourceSurface *aSurface) const = 0; virtual already_AddRefed 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 CreateSourceSurfaceFromNativeSurface( const NativeSurface &aSurface) const = 0; /** * Create a DrawTarget whose snapshot is optimized for use with this * DrawTarget. */ virtual already_AddRefed CreateSimilarDrawTarget( const IntSize &aSize, SurfaceFormat aFormat) const = 0; /** * 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 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 CreateShadowDrawTarget( const IntSize &aSize, SurfaceFormat aFormat, float aSigma) const { return CreateSimilarDrawTarget(aSize, aFormat); } /** * Create a similar DrawTarget whose requested size may be clipped based * on this DrawTarget's rect transformed to the new target's space. */ virtual RefPtr CreateClippedDrawTarget( const IntSize &aMaxSize, const Matrix &aTransform, SurfaceFormat aFormat) const { return CreateSimilarDrawTarget(aMaxSize, aFormat); } /** * 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 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 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 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 CreateFilter(FilterType aType) = 0; Matrix GetTransform() const { return mTransform; } /* * Get the metrics of a glyph, including any additional spacing that is taken * during rasterization to this backends (for example because of antialiasing * filters. * * aScaledFont The scaled font used when drawing. * aGlyphIndices An array of indices for the glyphs whose the metrics are * wanted * aNumGlyphs The amount of elements in aGlyphIndices * aGlyphMetrics The glyph metrics */ virtual void GetGlyphRasterizationMetrics(ScaledFont *aScaledFont, const uint16_t *aGlyphIndices, uint32_t aNumGlyphs, GlyphMetrics *aGlyphMetrics) { aScaledFont->GetGlyphDesignMetrics(aGlyphIndices, aNumGlyphs, aGlyphMetrics); } /** * 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 IsDualDrawTarget() const { return false; } 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; protected: UserData mUserData; Matrix mTransform; IntRect mOpaqueRect; bool mTransformDirty : 1; bool mPermitSubpixelAA : 1; SurfaceFormat mFormat; }; class DrawTargetCapture : public DrawTarget { public: virtual bool IsCaptureDT() const override { return true; } virtual bool IsEmpty() const = 0; virtual void Dump() = 0; }; class DrawEventRecorder : public RefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder) // returns true if there were any items in the recording virtual bool Finish() = 0; virtual ~DrawEventRecorder() {} }; struct Tile { RefPtr mDrawTarget; IntPoint mTileOrigin; }; struct TileSet { Tile *mTiles; size_t mTileCount; }; struct Config { LogForwarder *mLogForwarder; int32_t mMaxTextureSize; int32_t mMaxAllocSize; Config() : mLogForwarder(nullptr), mMaxTextureSize(8192), 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 that the given buffer size doesn't exceed the allocation limit. */ static bool CheckBufferSize(int32_t bufSize); /** 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 CreateDrawTargetForCairoSurface( cairo_surface_t *aSurface, const IntSize &aSize, SurfaceFormat *aFormat = nullptr); static already_AddRefed CreateSourceSurfaceForCairoSurface( cairo_surface_t *aSurface, const IntSize &aSize, SurfaceFormat aFormat); static already_AddRefed CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); /** * Create a DrawTarget that captures the drawing commands to eventually be * replayed onto the DrawTarget provided. An optional byte size can be * provided as a limit for the CaptureCommandList. When the limit is reached, * the CaptureCommandList will be replayed to the target and then cleared. * * @param aSize Size of the area this DT will capture. * @param aFlushBytes The byte limit at which to flush the CaptureCommandList */ static already_AddRefed CreateCaptureDrawTargetForTarget( gfx::DrawTarget *aTarget, size_t aFlushBytes = 0); /** * Create a DrawTarget that captures the drawing commands and can be replayed * onto a compatible DrawTarget afterwards. * * @param aSize Size of the area this DT will capture. */ static already_AddRefed CreateCaptureDrawTarget( BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); static already_AddRefed CreateCaptureDrawTargetForData( BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat, int32_t aStride, size_t aSurfaceAllocationSize); static already_AddRefed CreateWrapAndRecordDrawTarget( DrawEventRecorder *aRecorder, DrawTarget *aDT); static already_AddRefed CreateRecordingDrawTarget( DrawEventRecorder *aRecorder, DrawTarget *aDT, IntSize aSize); static already_AddRefed CreateDrawTargetForData( BackendType aBackend, unsigned char *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false); #ifdef XP_DARWIN static already_AddRefed CreateScaledFontForMacFont( CGFontRef aCGFont, const RefPtr &aUnscaledFont, Float aSize, const Color &aFontSmoothingBackgroundColor, bool aUseFontSmoothing = true, 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 aBackendType Type of the reference DrawTarget the font should be * created for. * @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 CreateNativeFontResource( uint8_t *aData, uint32_t aSize, BackendType aBackendType, 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 CreateUnscaledFontFromFontDescriptor( FontType aType, const uint8_t *aData, uint32_t aDataLength, uint32_t aIndex); /** * Creates a ScaledFont from the supplied NativeFont. * * If aScaledFont is supplied, this creates a scaled font with an associated * cairo_scaled_font_t. The NativeFont and cairo_scaled_font_t* parameters * must correspond to the same font. */ static already_AddRefed CreateScaledFontForNativeFont( const NativeFont &aNativeFont, const RefPtr &aUnscaledFont, Float aSize, cairo_scaled_font_t *aScaledFont = nullptr); /** * 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 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 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 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 already_AddRefed CreateEventRecorderForFile( const char_type *aFilename); static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder); 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 CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB); static already_AddRefed CreateDualSourceSurface( SourceSurface *sourceA, SourceSurface *sourceB); /* * This creates a new tiled DrawTarget. When a tiled drawtarget is used the * drawing is distributed over number of tiles which may each hold an * individual offset. The tiles in the set must each have the same backend * and format. */ static already_AddRefed CreateTiledDrawTarget( const TileSet &aTileSet); static already_AddRefed CreateOffsetDrawTarget( DrawTarget *aDrawTarget, IntPoint aTileOrigin); static bool DoesBackendSupportDataDrawtarget(BackendType aType); #ifdef USE_SKIA static already_AddRefed CreateDrawTargetWithSkCanvas( SkCanvas *aCanvas); #endif #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 FT_Face NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t *aData, size_t aDataSize, int aFaceIndex); 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 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 GetDirect3D11Device(); static RefPtr GetD2D1Device(uint32_t *aOutSeqNo = nullptr); static bool HasD2D1Device(); static RefPtr GetDWriteFactory(); static RefPtr EnsureDWriteFactory(); static bool SupportsD2D1(); static RefPtr GetDWriteSystemFonts( bool aUpdate = false); static RefPtr GetD2DDeviceContext(); static uint64_t GetD2DVRAMUsageDrawTarget(); static uint64_t GetD2DVRAMUsageSourceSurface(); static void D2DCleanup(); static already_AddRefed CreateScaledFontForDWriteFont( IDWriteFontFace *aFontFace, const gfxFontStyle *aStyle, const RefPtr &aUnscaledFont, Float aSize, bool aUseEmbeddedBitmap, bool aForceGDIMode, IDWriteRenderingParams *aParams, Float aGamma, Float aContrast); static void SetSystemTextQuality(uint8_t aQuality); private: static StaticRefPtr mD2D1Device; static StaticRefPtr mD3D11Device; static StaticRefPtr mDWriteFactory; static bool mDWriteFactoryInitialized; static StaticRefPtr mDWriteSystemFonts; static StaticRefPtr mMTDC; static StaticRefPtr mOffMTDC; 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 private: static DrawEventRecorder *mRecorder; }; } // namespace gfx } // namespace mozilla #endif // _MOZILLA_GFX_2D_H