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