/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _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 // 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" // 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/WeakPtr.h" #include "mozilla/DebugOnly.h" #ifdef MOZ_ENABLE_FREETYPE #include #endif struct _cairo_surface; typedef _cairo_surface cairo_surface_t; struct _cairo_scaled_font; typedef _cairo_scaled_font cairo_scaled_font_t; struct _FcPattern; typedef _FcPattern FcPattern; struct FT_LibraryRec_; typedef FT_LibraryRec_* FT_Library; struct ID3D11Texture2D; struct ID3D11Device; struct ID2D1Device; struct IDWriteFactory; struct IDWriteRenderingParams; struct IDWriteFontFace; class GrContext; class SkCanvas; struct gfxFontStyle; struct CGContext; typedef struct CGContext *CGContextRef; namespace mozilla { namespace gfx { 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 RefCounted { 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; 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 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; } /** * 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) { return mUserData.Get(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() : mIsMapped(false) { } #ifdef DEBUG virtual ~DataSourceSurface() { MOZ_ASSERT(!mIsMapped, "Someone forgot to call Unmap()"); } #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 { public: explicit ScopedMap(DataSourceSurface* aSurface, MapType aType) : mSurface(aSurface) , mIsMapped(aSurface->Map(aType, &mMap)) {} virtual ~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: 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. */ 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. */ virtual bool Map(MapType, MappedSurface *aMappedSurface) { aMappedSurface->mData = GetData(); aMappedSurface->mStride = Stride(); mIsMapped = !!aMappedSurface->mData; return mIsMapped; } virtual void Unmap() { MOZ_ASSERT(mIsMapped); mIsMapped = false; } /** * Returns a DataSourceSurface with the same data as this one, but * guaranteed to have surface->GetType() == SurfaceType::DATA. */ 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) 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; } protected: bool mIsMapped; }; /** 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 RefCounted { 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) /** 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 external::AtomicRefCounted , public SupportsWeakPtr { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(UnscaledFont) MOZ_DECLARE_WEAKREFERENCE_TYPENAME(UnscaledFont) virtual ~UnscaledFont(); virtual FontType GetType() const = 0; static uint32_t DeletionCounter() { return sDeletionCounter; } protected: UnscaledFont() {} private: static 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 external::AtomicRefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont) virtual ~ScaledFont() {} typedef struct { uint32_t mTag; Float mValue; } VariationSetting; typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, uint32_t aVariationCount, const VariationSetting* aVariations, void *aBaton); typedef void (*FontInstanceDataOutput)(const uint8_t* aData, uint32_t aLength, void* aBaton); typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength, Float aFontSize, void* aBaton); virtual FontType GetType() const = 0; virtual Float GetSize() const = 0; virtual AntialiasMode GetDefaultAAMode(); /** 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; virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; } virtual bool GetFontInstanceData(FontInstanceDataOutput, void *) { return false; } virtual bool GetFontDescriptor(FontDescriptorOutput, void *) { return false; } virtual bool CanSerialize() { return false; } void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { mUserData.Add(key, userData, destroy); } void *GetUserData(UserDataKey *key) { return mUserData.Get(key); } const RefPtr& GetUnscaledFont() const { return mUnscaledFont; } protected: explicit ScaledFont(const RefPtr& aUnscaledFont) : mUnscaledFont(aUnscaledFont) {} UserData mUserData; RefPtr mUnscaledFont; }; /** * Derived classes hold a native font resource from which to create * ScaledFonts. */ class NativeFontResource : public RefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource) /** * Creates a ScaledFont using the font corresponding to the index and * the given glyph size. * * @param aIndex index for the font within the resource. * @param aGlyphSize the size of ScaledFont required. * @param aInstanceData pointer to read-only buffer of any available instance data. * @param aInstanceDataLength the size of the instance data. * @return an already_addrefed ScaledFont, containing nullptr if failed. */ virtual already_AddRefed CreateScaledFont(uint32_t aIndex, Float aGlyphSize, const uint8_t* aInstanceData, uint32_t aInstanceDataLength) = 0; virtual ~NativeFontResource() {}; }; /** This class is designed to allow passing additional glyph rendering * parameters to the glyph drawing functions. This is an empty wrapper class * merely used to allow holding on to and passing around platform specific * parameters. This is because different platforms have unique rendering * parameters. */ class GlyphRenderingOptions : public RefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions) virtual ~GlyphRenderingOptions() {} virtual FontType GetType() const = 0; protected: GlyphRenderingOptions() {} }; 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 RefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget) DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {} 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; virtual IntSize GetSize() = 0; /** * 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; /** * 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; /** * 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(), const GlyphRenderingOptions *aRenderingOptions = nullptr) = 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(), const GlyphRenderingOptions* aRenderingOptions = nullptr); /** * 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"); } /** * 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"); } /** * 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 that captures the drawing commands and can be replayed * onto a compatible DrawTarget afterwards. * * @param aSize Size of the area this DT will capture. */ virtual already_AddRefed CreateCaptureDT(const IntSize& aSize); /** * 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 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; } /** * 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; #ifdef USE_SKIA_GPU virtual bool InitWithGrContext(GrContext* aGrContext, const IntSize &aSize, SurfaceFormat aFormat) { MOZ_CRASH("GFX: InitWithGrContext"); } #endif protected: UserData mUserData; Matrix mTransform; IntRect mOpaqueRect; bool mTransformDirty : 1; bool mPermitSubpixelAA : 1; SurfaceFormat mFormat; }; class DrawTargetCapture : public DrawTarget { public: virtual bool IsCaptureDT() const { return true; } /** * Returns true if the recording only contains FillGlyph calls with * a single font and color. Returns the list of Glyphs along with * the font and color as outparams if so. */ virtual bool ContainsOnlyColoredGlyphs(RefPtr& aScaledFont, Color& aColor, std::vector& aGlyphs) = 0; }; class DrawEventRecorder : public RefCounted { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder) 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 { public: static void Init(const Config& aConfig); static void ShutDown(); static bool HasSSE2(); /** * 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); static already_AddRefed CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT); static already_AddRefed CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false); static already_AddRefed CreateScaledFontForNativeFont(const NativeFont &aNativeFont, const RefPtr& aUnscaledFont, Float aSize); #ifdef MOZ_WIDGET_GTK static already_AddRefed CreateScaledFontForFontconfigFont(cairo_scaled_font_t* aScaledFont, FcPattern* aPattern, const RefPtr& aUnscaledFont, Float aSize); #endif /** * This creates a NativeFontResource from TrueType data. * * @param aData Pointer to the data * @param aSize Size of the TrueType data * @param aVariationCount Number of VariationSetting records provided. * @param aVariations Pointer to VariationSetting records. * @param aType Type of NativeFontResource that should be created. * @return a NativeFontResource of nullptr if failed. */ static already_AddRefed CreateNativeFontResource(uint8_t *aData, uint32_t aSize, uint32_t aVariationCount, const ScaledFont::VariationSetting* aVariations, FontType aType); /** * This creates a scaled font of the given type based on font descriptor * data retrieved from ScaledFont::GetFontDescriptor. */ static already_AddRefed CreateScaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, Float aSize); /** * This creates a scaled font with an associated cairo_scaled_font_t, and * must be used when using the Cairo backend. The NativeFont and * cairo_scaled_font_t* parameters must correspond to the same font. */ static already_AddRefed CreateScaledFontWithCairo(const NativeFont &aNativeFont, const RefPtr& aUnscaledFont, Float aSize, cairo_scaled_font_t* aScaledFont); /** * 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 *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: #ifdef USE_SKIA_GPU static already_AddRefed CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext, const IntSize &aSize, SurfaceFormat aFormat); #endif static void PurgeAllCaches(); static already_AddRefed CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB); /* * 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 bool DoesBackendSupportDataDrawtarget(BackendType aType); #ifdef USE_SKIA static already_AddRefed CreateDrawTargetWithSkCanvas(SkCanvas* aCanvas); #endif #ifdef XP_DARWIN static already_AddRefed CreateCGGlyphRenderingOptions(const Color &aFontSmoothingBackgroundColor); #endif #ifdef MOZ_ENABLE_FREETYPE static void SetFTLibrary(FT_Library aFTLibrary); static FT_Library GetFTLibrary(); private: static FT_Library mFTLibrary; 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 bool SetDWriteFactory(IDWriteFactory *aFactory); static ID3D11Device *GetDirect3D11Device(); static ID2D1Device *GetD2D1Device(); static IDWriteFactory *GetDWriteFactory(); static bool SupportsD2D1(); static already_AddRefed CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams); 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); static void UpdateSystemTextQuality(); private: static ID2D1Device *mD2D1Device; static ID3D11Device *mD3D11Device; static IDWriteFactory *mDWriteFactory; #endif static DrawEventRecorder *mRecorder; }; } // namespace gfx } // namespace mozilla #endif // _MOZILLA_GFX_2D_H