gecko-dev/gfx/2d/2D.h

1909 строки
68 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _MOZILLA_GFX_2D_H
#define _MOZILLA_GFX_2D_H
#include "Types.h"
#include "Point.h"
#include "Rect.h"
#include "Matrix.h"
#include "Quaternion.h"
#include "UserData.h"
#include "FontVariation.h"
#include <vector>
// GenericRefCountedBase allows us to hold on to refcounted objects of any type
// (contrary to RefCounted<T> which requires knowing the type T) and, in particular,
// without having a dependency on that type. This is used for DrawTargetSkia
// to be able to hold on to a GLContext.
#include "mozilla/GenericRefCounted.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Path.h"
// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T**
// outparams using the &-operator. But it will have to do as there's no easy
// solution.
#include "mozilla/RefPtr.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/ThreadSafeWeakPtr.h"
#include "mozilla/Atomics.h"
#include "mozilla/DebugOnly.h"
#include "nsRegionFwd.h"
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
#ifndef MOZ_ENABLE_FREETYPE
#define MOZ_ENABLE_FREETYPE
#endif
#endif
struct _cairo_surface;
typedef _cairo_surface cairo_surface_t;
struct _cairo_scaled_font;
typedef _cairo_scaled_font cairo_scaled_font_t;
struct FT_LibraryRec_;
typedef FT_LibraryRec_* FT_Library;
struct FT_FaceRec_;
typedef FT_FaceRec_* FT_Face;
typedef int FT_Error;
struct ID3D11Texture2D;
struct ID3D11Device;
struct ID2D1Device;
struct IDWriteFactory;
struct IDWriteRenderingParams;
struct IDWriteFontFace;
class GrContext;
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 gfx {
class UnscaledFont;
class ScaledFont;
}
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<GradientStops>
{
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<GradientStops> mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw
target this pattern will be used with. */
Matrix mMatrix; /**< A matrix that transforms the pattern into
user space */
};
/**
* 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<GradientStops> mStops; /**< GradientStops object for this gradient, this
should match the backend type of the draw target
this pattern will be used with. */
Matrix mMatrix; //!< A matrix that transforms the pattern into user space
};
/**
* 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<SourceSurface> mSurface; //!< Surface to use for drawing
ExtendMode mExtendMode; /**< This determines how the image is extended
outside the bounds of the image */
SamplingFilter mSamplingFilter; //!< Resampling filter for resampling the image.
Matrix mMatrix; //!< Transforms the pattern into user space
IntRect mSamplingRect; /**< Rect that must not be sampled outside of,
or an empty rect if none has been specified. */
};
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<SourceSurface>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
virtual ~SourceSurface() {}
virtual SurfaceType GetType() const = 0;
virtual IntSize GetSize() const = 0;
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;
}
/**
* This function will get a DataSourceSurface for this surface, a
* DataSourceSurface's data can be accessed directly.
*/
virtual already_AddRefed<DataSourceSurface> 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<DataSourceSurface> 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<DataSourceSurface> 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<IntRect> TakeDirtyRect() {
return Nothing();
}
/**
* Indicate a region which has changed in the surface.
*/
virtual void Invalidate(const IntRect& aDirtyRect) { }
protected:
Atomic<int32_t> mMapCount;
};
/** This is an abstract object that accepts path segments. */
class PathSink : public RefCounted<PathSink>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathSink)
virtual ~PathSink() {}
/** 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<Path>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
virtual ~Path();
virtual BackendType GetBackendType() const = 0;
/** This returns a PathBuilder object that contains a copy of the contents of
* this path and is still writable.
*/
inline already_AddRefed<PathBuilder> CopyToBuilder() const {
return CopyToBuilder(GetFillRule());
}
inline already_AddRefed<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform) const {
return TransformedCopyToBuilder(aTransform, GetFillRule());
}
/** This returns a PathBuilder object that contains a copy of the contents of
* this path, converted to use the specified FillRule, and still writable.
*/
virtual already_AddRefed<PathBuilder> CopyToBuilder(FillRule aFillRule) const = 0;
virtual already_AddRefed<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
FillRule aFillRule) const = 0;
/** This function checks if a point lies within a path. It allows passing a
* transform that will transform the path to the coordinate space in which
* aPoint is given.
*/
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const = 0;
/** This function checks if a point lies within the stroke of a path using the
* specified strokeoptions. It allows passing a transform that will transform
* the path to the coordinate space in which aPoint is given.
*/
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
const Point &aPoint,
const Matrix &aTransform) const = 0;
/** This functions gets the bounds of this path. These bounds are not
* guaranteed to be tight. A transform may be specified that gives the bounds
* after application of the transform.
*/
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const = 0;
/** This function gets the bounds of the stroke of this path using the
* specified strokeoptions. These bounds are not guaranteed to be tight.
* A transform may be specified that gives the bounds after application of
* the transform.
*/
virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform = Matrix()) const = 0;
/** 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<FlattenedPath> mFlattenedPath;
};
/** The PathBuilder class allows path creation. Once finish is called on the
* pathbuilder it may no longer be written to.
*/
class PathBuilder : public PathSink
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilder, override)
/** Finish writing to the path and return a Path object that can be used for
* drawing. Future use of the builder results in a crash!
*/
virtual already_AddRefed<Path> Finish() = 0;
virtual BackendType GetBackendType() const = 0;
};
struct Glyph
{
uint32_t mIndex;
Point mPosition;
};
static inline bool operator==(const Glyph& aOne, const Glyph& aOther) {
return aOne.mIndex == aOther.mIndex && aOne.mPosition == aOther.mPosition;
}
/** This class functions as a glyph buffer that can be drawn to a DrawTarget.
* @todo XXX - This should probably contain the guts of gfxTextRun in the future as
* roc suggested. But for now it's a simple container for a glyph vector.
*/
struct GlyphBuffer
{
const Glyph *mGlyphs; //!< A pointer to a buffer of glyphs. Managed by the caller.
uint32_t mNumGlyphs; //!< Number of glyphs mGlyphs points to.
};
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<UnscaledFont>
{
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<ScaledFont>
CreateScaledFont(Float aGlyphSize,
const uint8_t* aInstanceData,
uint32_t aInstanceDataLength,
const FontVariation* aVariations,
uint32_t aNumVariations)
{
return nullptr;
}
virtual already_AddRefed<ScaledFont>
CreateScaledFontFromWRFont(Float aGlyphSize,
const wr::FontInstanceOptions* aOptions,
const wr::FontInstancePlatformOptions* aPlatformOptions,
const FontVariation* aVariations,
uint32_t aNumVariations)
{
return CreateScaledFont(aGlyphSize, nullptr, 0, aVariations, aNumVariations);
}
protected:
UnscaledFont() {}
private:
static Atomic<uint32_t> sDeletionCounter;
};
/** This class is an abstraction of a backend/platform specific font object
* at a particular size. It is passed into text drawing calls to describe
* the font used for the drawing call.
*/
class ScaledFont : public SupportsThreadSafeWeakPtr<ScaledFont>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
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<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) = 0;
/** This copies the path describing the glyphs into a PathBuilder. We use this
* API rather than a generic API to append paths because it allows easier
* implementation in some backends, and more efficient implementation in
* others.
*/
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint = nullptr) = 0;
/* 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<wr::FontInstanceOptions>* aOutOptions,
Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
std::vector<FontVariation>* 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<UnscaledFont>& 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<UnscaledFont>& aUnscaledFont)
: mUnscaledFont(aUnscaledFont)
, mSyntheticObliqueAngle(0.0f)
{}
UserData mUserData;
RefPtr<UnscaledFont> mUnscaledFont;
Float mSyntheticObliqueAngle;
private:
static Atomic<uint32_t> sDeletionCounter;
};
/**
* Derived classes hold a native font resource from which to create
* ScaledFonts.
*/
class NativeFontResource : public external::AtomicRefCounted<NativeFontResource>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource)
/**
* Creates a UnscaledFont using the font corresponding to the index.
*
* @param aIndex index for the font within the resource.
* @param aInstanceData pointer to read-only buffer of any available instance data.
* @param aInstanceDataLength the size of the instance data.
* @return an already_addrefed UnscaledFont, containing nullptr if failed.
*/
virtual already_AddRefed<UnscaledFont>
CreateUnscaledFont(uint32_t aIndex,
const uint8_t* aInstanceData,
uint32_t aInstanceDataLength) = 0;
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<DrawTarget>
{
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<SourceSurface> Snapshot() = 0;
// Snapshots the contents and returns an alpha mask
// based on the RGB values.
virtual already_AddRefed<SourceSurface> IntoLuminanceSource(LuminanceType aLuminanceType,
float aOpacity);
virtual IntSize GetSize() const = 0;
virtual IntRect GetRect() const {
return IntRect(IntPoint(0, 0), GetSize());
}
/**
* If possible returns the bits to this DrawTarget for direct manipulation. While
* the bits is locked any modifications to this DrawTarget is forbidden.
* Release takes the original data pointer for safety.
*/
virtual bool LockBits(uint8_t** aData, IntSize* aSize,
int32_t* aStride, SurfaceFormat* aFormat,
IntPoint* aOrigin = nullptr) { return false; }
virtual void ReleaseBits(uint8_t* aData) {}
/** Ensure that the DrawTarget backend has flushed all drawing operations to
* this draw target. This must be called before using the backing surface of
* this draw target outside of GFX 2D code.
*/
virtual void Flush() = 0;
/**
* 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<SourceSurface> source = Snapshot();
CopySurface(source, aSourceRect, aDestination);
}
/**
* Fill a rectangle on the DrawTarget with a certain source pattern.
*
* @param aRect Rectangle that forms the mask of this filling operation
* @param aPattern Pattern that forms the source of this filling operation
* @param aOptions Options that are applied to this operation
*/
virtual void FillRect(const Rect &aRect,
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Stroke a rectangle on the DrawTarget with a certain source pattern.
*
* @param aRect Rectangle that forms the mask of this stroking operation
* @param aPattern Pattern that forms the source of this stroking operation
* @param aOptions Options that are applied to this operation
*/
virtual void StrokeRect(const Rect &aRect,
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions = StrokeOptions(),
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Stroke a line on the DrawTarget with a certain source pattern.
*
* @param aStart Starting point of the line
* @param aEnd End point of the line
* @param aPattern Pattern that forms the source of this stroking operation
* @param aOptions Options that are applied to this operation
*/
virtual void StrokeLine(const Point &aStart,
const Point &aEnd,
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions = StrokeOptions(),
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Stroke a path on the draw target with a certain source pattern.
*
* @param aPath Path that is to be stroked
* @param aPattern Pattern that should be used for the stroke
* @param aStrokeOptions Stroke options used for this operation
* @param aOptions Draw options used for this operation
*/
virtual void Stroke(const Path *aPath,
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions = StrokeOptions(),
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Fill a path on the draw target with a certain source pattern.
*
* @param aPath Path that is to be filled
* @param aPattern Pattern that should be used for the fill
* @param aOptions Draw options used for this operation
*/
virtual void Fill(const Path *aPath,
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Fill a series of glyphs on the draw target with a certain source pattern.
*/
virtual void FillGlyphs(ScaledFont *aFont,
const GlyphBuffer &aBuffer,
const Pattern &aPattern,
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Stroke a series of glyphs on the draw target with a certain source pattern.
*/
virtual void StrokeGlyphs(ScaledFont* aFont,
const GlyphBuffer& aBuffer,
const Pattern& aPattern,
const StrokeOptions& aStrokeOptions = StrokeOptions(),
const DrawOptions& aOptions = DrawOptions());
/**
* This takes a source pattern and a mask, and composites the source pattern
* onto the destination surface using the alpha channel of the mask pattern
* as a mask for the operation.
*
* @param aSource Source pattern
* @param aMask Mask pattern
* @param aOptions Drawing options
*/
virtual void Mask(const Pattern &aSource,
const Pattern &aMask,
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* This takes a source pattern and a mask, and composites the source pattern
* onto the destination surface using the alpha channel of the mask source.
* The operation is bound by the extents of the mask.
*
* @param aSource Source pattern
* @param aMask Mask surface
* @param aOffset a transformed offset that the surface is masked at
* @param aOptions Drawing options
*/
virtual void MaskSurface(const Pattern &aSource,
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Draw aSurface using the 3D transform aMatrix. The DrawTarget's transform
* and clip are applied after the 3D transform.
*
* If the transform fails (i.e. because aMatrix is singular), false is returned and nothing is drawn.
*/
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
const Matrix4x4& aMatrix);
/**
* Push a clip to the DrawTarget.
*
* @param aPath The path to clip to
*/
virtual void PushClip(const Path *aPath) = 0;
/**
* Push an axis-aligned rectangular clip to the DrawTarget. This rectangle
* is specified in user space.
*
* @param aRect The rect to clip to
*/
virtual void PushClipRect(const Rect &aRect) = 0;
/**
* Push a clip region specifed by the union of axis-aligned rectangular
* clips to the DrawTarget. These rectangles are specified in device space.
* This must be balanced by a corresponding call to PopClip within a layer.
*
* @param aRects The rects to clip to
* @param aCount The number of rectangles
*/
virtual void PushDeviceSpaceClipRects(const IntRect* aRects, uint32_t aCount);
/** Pop a clip from the DrawTarget. A pop without a corresponding push will
* be ignored.
*/
virtual void PopClip() = 0;
/**
* Push a 'layer' to the DrawTarget, a layer is a temporary surface that all
* drawing will be redirected to, this is used for example to support group
* opacity or the masking of groups. Clips must be balanced within a layer,
* i.e. between a matching PushLayer/PopLayer pair there must be as many
* PushClip(Rect) calls as there are PopClip calls.
*
* @param aOpaque Whether the layer will be opaque
* @param aOpacity Opacity of the layer
* @param aMask Mask applied to the layer
* @param aMaskTransform Transform applied to the layer mask
* @param aBounds Optional bounds in device space to which the layer is
* limited in size.
* @param aCopyBackground Whether to copy the background into the layer, this
* is only supported when aOpaque is true.
*/
virtual void PushLayer(bool aOpaque, Float aOpacity,
SourceSurface* aMask,
const Matrix& aMaskTransform,
const IntRect& aBounds = IntRect(),
bool aCopyBackground = false) { MOZ_CRASH("GFX: PushLayer"); }
/**
* Push a 'layer' to the DrawTarget, a layer is a temporary surface that all
* drawing will be redirected to, this is used for example to support group
* opacity or the masking of groups. Clips must be balanced within a layer,
* i.e. between a matching PushLayer/PopLayer pair there must be as many
* PushClip(Rect) calls as there are PopClip calls.
*
* @param aOpaque Whether the layer will be opaque
* @param aOpacity Opacity of the layer
* @param aMask Mask applied to the layer
* @param aMaskTransform Transform applied to the layer mask
* @param aBounds Optional bounds in device space to which the layer is
* limited in size.
* @param aCopyBackground Whether to copy the background into the layer, this
* is only supported when aOpaque is true.
*/
virtual void PushLayerWithBlend(bool aOpaque, Float aOpacity,
SourceSurface* aMask,
const Matrix& aMaskTransform,
const IntRect& aBounds = IntRect(),
bool aCopyBackground = false,
CompositionOp = CompositionOp::OP_OVER) { MOZ_CRASH("GFX: PushLayerWithBlend"); }
/**
* This balances a call to PushLayer and proceeds to blend the layer back
* onto the background. This blend will blend the temporary surface back
* onto the target in device space using POINT sampling and operator over.
*/
virtual void PopLayer() { MOZ_CRASH("GFX: PopLayer"); }
/**
* Perform an in-place blur operation. This is only supported on data draw
* targets.
*/
virtual void Blur(const AlphaBoxBlur& aBlur);
/**
* Performs an in-place edge padding operation.
* aRegion is specified in device space.
*/
virtual void PadEdges(const IntRegion& aRegion);
/**
* Performs an in-place buffer unrotation operation.
*/
virtual bool Unrotate(IntPoint aRotation);
/**
* Create a SourceSurface optimized for use with this DrawTarget from
* existing bitmap data in memory.
*
* The SourceSurface does not take ownership of aData, and may be freed at any time.
*/
virtual already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat) const = 0;
/**
* Create a SourceSurface optimized for use with this DrawTarget from an
* arbitrary SourceSurface type supported by this backend. This may return
* aSourceSurface or some other existing surface.
*/
virtual already_AddRefed<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const = 0;
virtual already_AddRefed<SourceSurface> OptimizeSourceSurfaceForUnknownAlpha(SourceSurface *aSurface) const {
return OptimizeSourceSurface(aSurface);
}
/**
* Create a SourceSurface for a type of NativeSurface. This may fail if the
* draw target does not know how to deal with the type of NativeSurface passed
* in. If this succeeds, the SourceSurface takes the ownersip of the NativeSurface.
*/
virtual already_AddRefed<SourceSurface>
CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const = 0;
/**
* Create a DrawTarget whose snapshot is optimized for use with this DrawTarget.
*/
virtual already_AddRefed<DrawTarget>
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0;
/**
* Create a draw target optimized for drawing a shadow.
*
* Note that aSigma is the blur radius that must be used when we draw the
* shadow. Also note that this doesn't affect the size of the allocated
* surface, the caller is still responsible for including the shadow area in
* its size.
*/
virtual already_AddRefed<DrawTarget>
CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFormat,
float aSigma) const
{
return CreateSimilarDrawTarget(aSize, aFormat);
}
/**
* Create a similar DrawTarget whose requested size may be clipped based
* on this DrawTarget's rect transformed to the new target's space.
*/
virtual RefPtr<DrawTarget> 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<DrawTarget>
CreateSimilarRasterTarget(const IntSize& aSize, SurfaceFormat aFormat) const
{
return CreateSimilarDrawTarget(aSize, aFormat);
}
/**
* Create a path builder with the specified fillmode.
*
* We need the fill mode up front because of Direct2D.
* ID2D1SimplifiedGeometrySink requires the fill mode
* to be set before calling BeginFigure().
*/
virtual already_AddRefed<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const = 0;
/**
* Create a GradientStops object that holds information about a set of
* gradient stops, this object is required for linear or radial gradient
* patterns to represent the color stops in the gradient.
*
* @param aStops An array of gradient stops
* @param aNumStops Number of stops in the array aStops
* @param aExtendNone This describes how to extend the stop color outside of the
* gradient area.
*/
virtual already_AddRefed<GradientStops>
CreateGradientStops(GradientStop *aStops,
uint32_t aNumStops,
ExtendMode aExtendMode = ExtendMode::CLAMP) const = 0;
/**
* Create a FilterNode object that can be used to apply a filter to various
* inputs.
*
* @param aType Type of filter node to be created.
*/
virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) = 0;
Matrix GetTransform() const { return mTransform; }
/*
* 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;
#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 override { return true; }
virtual bool IsEmpty() const = 0;
virtual void Dump() = 0;
};
class DrawEventRecorder : public RefCounted<DrawEventRecorder>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
// returns true if there were any items in the recording
virtual bool Finish() = 0;
virtual ~DrawEventRecorder() { }
};
struct Tile
{
RefPtr<DrawTarget> mDrawTarget;
IntPoint mTileOrigin;
};
struct TileSet
{
Tile* mTiles;
size_t mTileCount;
};
struct Config {
LogForwarder* mLogForwarder;
int32_t mMaxTextureSize;
int32_t mMaxAllocSize;
Config()
: mLogForwarder(nullptr)
, mMaxTextureSize(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<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
static already_AddRefed<SourceSurface> CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat);
static already_AddRefed<DrawTarget>
CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
/**
* 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<DrawTargetCapture>
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<DrawTargetCapture>
CreateCaptureDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
static already_AddRefed<DrawTargetCapture>
CreateCaptureDrawTargetForData(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat,
int32_t aStride, size_t aSurfaceAllocationSize);
static already_AddRefed<DrawTarget>
CreateWrapAndRecordDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT);
static already_AddRefed<DrawTarget>
CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT, IntSize aSize);
static already_AddRefed<DrawTarget>
CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);
#ifdef XP_DARWIN
static already_AddRefed<ScaledFont>
CreateScaledFontForMacFont(CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
const 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<NativeFontResource>
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<UnscaledFont>
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<ScaledFont>
CreateScaledFontForNativeFont(const NativeFont &aNativeFont,
const RefPtr<UnscaledFont>& 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<DataSourceSurface>
CreateDataSourceSurface(const IntSize &aSize, SurfaceFormat aFormat, bool aZero = false);
/**
* This creates a simple data source surface for a certain size with a
* specific stride, which must be large enough to fit all pixels.
* It allocates new memory for the surface. This memory is freed when
* the surface is destroyed. The caller is responsible for handling the case
* where nullptr is returned. The surface is not zeroed unless requested.
*/
static already_AddRefed<DataSourceSurface>
CreateDataSourceSurfaceWithStride(const IntSize &aSize, SurfaceFormat aFormat, int32_t aStride, bool aZero = false);
typedef void (*SourceSurfaceDeallocator)(void* aClosure);
/**
* This creates a simple data source surface for some existing data. It will
* wrap this data and the data for this source surface.
*
* We can provide a custom destroying function for |aData|. This will be
* called in the surface dtor using |aDeallocator| and the |aClosure|. If
* there are errors during construction(return a nullptr surface), the caller
* is responsible for the deallocation.
*
* If there is no destroying function, the caller is responsible for
* deallocating the aData memory only after destruction of this
* DataSourceSurface.
*/
static already_AddRefed<DataSourceSurface>
CreateWrappingDataSourceSurface(uint8_t *aData,
int32_t aStride,
const IntSize &aSize,
SurfaceFormat aFormat,
SourceSurfaceDeallocator aDeallocator = nullptr,
void* aClosure = nullptr);
static void
CopyDataSourceSurface(DataSourceSurface* aSource,
DataSourceSurface* aDest);
static already_AddRefed<DrawEventRecorder>
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:
#ifdef USE_SKIA_GPU
static already_AddRefed<DrawTarget>
CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
const IntSize &aSize,
SurfaceFormat aFormat);
#endif
static void PurgeAllCaches();
static already_AddRefed<DrawTarget>
CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB);
static already_AddRefed<SourceSurface>
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<DrawTarget> CreateTiledDrawTarget(const TileSet& aTileSet);
static already_AddRefed<DrawTarget> CreateOffsetDrawTarget(DrawTarget *aDrawTarget, IntPoint aTileOrigin);
static bool DoesBackendSupportDataDrawtarget(BackendType aType);
#ifdef USE_SKIA
static already_AddRefed<DrawTarget> 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 Mutex* mFTLock;
public:
#endif
#ifdef WIN32
static already_AddRefed<DrawTarget> CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat);
/*
* Attempts to create and install a D2D1 device from the supplied Direct3D11 device.
* Returns true on success, or false on failure and leaves the D2D1/Direct3D11 devices unset.
*/
static bool SetDirect3D11Device(ID3D11Device *aDevice);
static RefPtr<ID3D11Device> GetDirect3D11Device();
static RefPtr<ID2D1Device> GetD2D1Device(uint32_t* aOutSeqNo = nullptr);
static bool HasD2D1Device();
static RefPtr<IDWriteFactory> GetDWriteFactory();
static bool SetDWriteFactory(IDWriteFactory *aFactory);
static RefPtr<IDWriteFactory> EnsureDWriteFactory();
static bool SupportsD2D1();
static uint64_t GetD2DVRAMUsageDrawTarget();
static uint64_t GetD2DVRAMUsageSourceSurface();
static void D2DCleanup();
static already_AddRefed<ScaledFont>
CreateScaledFontForDWriteFont(IDWriteFontFace* aFontFace,
const gfxFontStyle* aStyle,
const RefPtr<UnscaledFont>& aUnscaledFont,
Float aSize,
bool aUseEmbeddedBitmap,
bool aForceGDIMode,
IDWriteRenderingParams *aParams,
Float aGamma,
Float aContrast);
static void SetSystemTextQuality(uint8_t aQuality);
private:
static StaticRefPtr<ID2D1Device> mD2D1Device;
static StaticRefPtr<ID3D11Device> mD3D11Device;
static StaticRefPtr<IDWriteFactory> mDWriteFactory;
static bool mDWriteFactoryInitialized;
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