Bug 1519739: Attempt to create Direct2D paths on the paint thread. r=rhunt

Differential Revision: https://phabricator.services.mozilla.com/D16433

--HG--
extra : rebase_source : 98c1a0461d7498d2658de54ded796025c7a0beb6
This commit is contained in:
Bas Schouten 2019-01-14 01:16:17 +01:00
parent 7cbaee9bbb
commit 5c3778d6dd
17 changed files with 509 additions and 116 deletions

View File

@ -10,6 +10,7 @@
#include "gfxPlatform.h"
#include "SourceSurfaceCapture.h"
#include "FilterNodeCapture.h"
#include "PathCapture.h"
namespace mozilla {
namespace gfx {
@ -332,6 +333,15 @@ RefPtr<DrawTarget> DrawTargetCaptureImpl::CreateSimilarRasterTarget(
return mRefDT->CreateSimilarDrawTarget(aSize, aFormat);
}
already_AddRefed<PathBuilder> DrawTargetCaptureImpl::CreatePathBuilder(
FillRule aFillRule) const {
if (mRefDT->GetBackendType() == BackendType::DIRECT2D1_1) {
return MakeRefPtr<PathBuilderCapture>(aFillRule, mRefDT).forget();
}
return mRefDT->CreatePathBuilder(aFillRule);
}
already_AddRefed<FilterNode> DrawTargetCaptureImpl::CreateFilter(
FilterType aType) {
if (mRefDT->GetBackendType() == BackendType::DIRECT2D1_1) {

View File

@ -121,9 +121,7 @@ class DrawTargetCaptureImpl : public DrawTargetCapture {
const IntSize &aSize, SurfaceFormat aFormat) const override;
virtual already_AddRefed<PathBuilder> CreatePathBuilder(
FillRule aFillRule = FillRule::FILL_WINDING) const override {
return mRefDT->CreatePathBuilder(aFillRule);
}
FillRule aFillRule = FillRule::FILL_WINDING) const override;
virtual already_AddRefed<GradientStops> CreateGradientStops(
GradientStop *aStops, uint32_t aNumStops,

View File

@ -12,6 +12,7 @@
#include "SourceSurfaceD2D1.h"
#include "SourceSurfaceDual.h"
#include "RadialGradientEffectD2D1.h"
#include "PathCapture.h"
#include "HelpersD2D.h"
#include "FilterNodeD2D1.h"
@ -588,11 +589,16 @@ void DrawTargetD2D1::StrokeLine(const Point &aStart, const Point &aEnd,
void DrawTargetD2D1::Stroke(const Path *aPath, const Pattern &aPattern,
const StrokeOptions &aStrokeOptions,
const DrawOptions &aOptions) {
if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
const Path *path = aPath;
if (aPath->GetBackendType() == BackendType::CAPTURE) {
path = static_cast<const PathCapture *>(aPath)->GetRealizedPath();
}
if (path->GetBackendType() != BackendType::DIRECT2D1_1) {
gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
return;
}
const PathD2D *d2dPath = static_cast<const PathD2D *>(aPath);
const PathD2D *d2dPath = static_cast<const PathD2D *>(path);
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
@ -610,11 +616,16 @@ void DrawTargetD2D1::Stroke(const Path *aPath, const Pattern &aPattern,
void DrawTargetD2D1::Fill(const Path *aPath, const Pattern &aPattern,
const DrawOptions &aOptions) {
if (!aPath || aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
const Path *path = aPath;
if (aPath && aPath->GetBackendType() == BackendType::CAPTURE) {
path = static_cast<const PathCapture *>(aPath)->GetRealizedPath();
}
if (!path || path->GetBackendType() != BackendType::DIRECT2D1_1) {
gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
return;
}
const PathD2D *d2dPath = static_cast<const PathD2D *>(aPath);
const PathD2D *d2dPath = static_cast<const PathD2D *>(path);
PrepareForDrawing(aOptions.mCompositionOp, aPattern);
@ -804,7 +815,12 @@ void DrawTargetD2D1::PushClipGeometry(ID2D1Geometry *aGeometry,
}
void DrawTargetD2D1::PushClip(const Path *aPath) {
if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
const Path *path = aPath;
if (aPath->GetBackendType() == BackendType::CAPTURE) {
path = static_cast<const PathCapture *>(aPath)->GetRealizedPath();
}
if (path->GetBackendType() != BackendType::DIRECT2D1_1) {
gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
return;
}
@ -812,7 +828,7 @@ void DrawTargetD2D1::PushClip(const Path *aPath) {
return;
}
RefPtr<PathD2D> pathD2D = static_cast<PathD2D *>(const_cast<Path *>(aPath));
RefPtr<PathD2D> pathD2D = static_cast<PathD2D *>(const_cast<Path *>(path));
PushClipGeometry(pathD2D->GetGeometry(), D2DMatrix(mTransform));
}

View File

@ -507,6 +507,7 @@ bool Factory::DoesBackendSupportDataDrawtarget(BackendType aType) {
case BackendType::DIRECT2D:
case BackendType::DIRECT2D1_1:
case BackendType::RECORDING:
case BackendType::CAPTURE:
case BackendType::NONE:
case BackendType::BACKEND_LAST:
case BackendType::WEBRENDER_TEXT:

View File

@ -861,6 +861,93 @@ class DCCommandSink : public ID2D1CommandSink {
ID2D1DeviceContext *mCtx;
};
class MOZ_STACK_CLASS AutoRestoreFP {
public:
AutoRestoreFP() {
// save the current floating point control word
_controlfp_s(&savedFPSetting, 0, 0);
UINT unused;
// set the floating point control word to its default value
_controlfp_s(&unused, _CW_DEFAULT, MCW_PC);
}
~AutoRestoreFP() {
UINT unused;
// restore the saved floating point control word
_controlfp_s(&unused, savedFPSetting, MCW_PC);
}
private:
UINT savedFPSetting;
};
// Note that overrides of ID2D1SimplifiedGeometrySink methods in this class may
// get called from D2D with nonstandard floating point settings (see comments in
// bug 1134549) - use AutoRestoreFP to reset the floating point control word to
// what we expect
class StreamingGeometrySink : public ID2D1SimplifiedGeometrySink {
public:
explicit StreamingGeometrySink(PathSink *aSink) : mSink(aSink) {}
HRESULT STDMETHODCALLTYPE QueryInterface(const IID &aIID, void **aPtr) {
if (!aPtr) {
return E_POINTER;
}
if (aIID == IID_IUnknown) {
*aPtr = static_cast<IUnknown *>(this);
return S_OK;
} else if (aIID == IID_ID2D1SimplifiedGeometrySink) {
*aPtr = static_cast<ID2D1SimplifiedGeometrySink *>(this);
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() { return 1; }
ULONG STDMETHODCALLTYPE Release() { return 1; }
// We ignore SetFillMode, this depends on the destination sink.
STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE aMode) { return; }
STDMETHOD_(void, BeginFigure)
(D2D1_POINT_2F aPoint, D2D1_FIGURE_BEGIN aBegin) {
AutoRestoreFP resetFloatingPoint;
mSink->MoveTo(ToPoint(aPoint));
}
STDMETHOD_(void, AddLines)(const D2D1_POINT_2F *aLines, UINT aCount) {
AutoRestoreFP resetFloatingPoint;
for (UINT i = 0; i < aCount; i++) {
mSink->LineTo(ToPoint(aLines[i]));
}
}
STDMETHOD_(void, AddBeziers)
(const D2D1_BEZIER_SEGMENT *aSegments, UINT aCount) {
AutoRestoreFP resetFloatingPoint;
for (UINT i = 0; i < aCount; i++) {
mSink->BezierTo(ToPoint(aSegments[i].point1),
ToPoint(aSegments[i].point2),
ToPoint(aSegments[i].point3));
}
}
STDMETHOD(Close)() { /* Should never be called! */
return S_OK;
}
STDMETHOD_(void, SetSegmentFlags)
(D2D1_PATH_SEGMENT aFlags) { /* Should never be called! */
}
STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END aEnd) {
AutoRestoreFP resetFloatingPoint;
if (aEnd == D2D1_FIGURE_END_CLOSED) {
return mSink->Close();
}
}
private:
PathSink *mSink;
};
} // namespace gfx
} // namespace mozilla

212
gfx/2d/PathCapture.cpp Normal file
View File

@ -0,0 +1,212 @@
/* -*- 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/. */
#include "PathCapture.h"
namespace mozilla {
namespace gfx {
using namespace std;
void PathBuilderCapture::MoveTo(const Point &aPoint) {
PathOp op;
op.mType = PathOp::OP_MOVETO;
op.mP1 = aPoint;
mPathOps.push_back(op);
mCurrentPoint = aPoint;
}
void PathBuilderCapture::LineTo(const Point &aPoint) {
PathOp op;
op.mType = PathOp::OP_LINETO;
op.mP1 = aPoint;
mPathOps.push_back(op);
mCurrentPoint = aPoint;
}
void PathBuilderCapture::BezierTo(const Point &aCP1, const Point &aCP2,
const Point &aCP3) {
PathOp op;
op.mType = PathOp::OP_BEZIERTO;
op.mP1 = aCP1;
op.mP2 = aCP2;
op.mP3 = aCP3;
mPathOps.push_back(op);
mCurrentPoint = aCP3;
}
void PathBuilderCapture::QuadraticBezierTo(const Point &aCP1,
const Point &aCP2) {
PathOp op;
op.mType = PathOp::OP_QUADRATICBEZIERTO;
op.mP1 = aCP1;
op.mP2 = aCP2;
mPathOps.push_back(op);
mCurrentPoint = aCP2;
}
void PathBuilderCapture::Arc(const Point &aOrigin, float aRadius,
float aStartAngle, float aEndAngle,
bool aAntiClockwise) {
PathOp op;
op.mType = PathOp::OP_ARC;
op.mP1 = aOrigin;
op.mRadius = aRadius;
op.mStartAngle = aStartAngle;
op.mEndAngle = aEndAngle;
op.mAntiClockwise = aAntiClockwise;
mPathOps.push_back(op);
}
void PathBuilderCapture::Close() {
PathOp op;
op.mType = PathOp::OP_CLOSE;
mPathOps.push_back(op);
}
Point PathBuilderCapture::CurrentPoint() const { return mCurrentPoint; }
already_AddRefed<Path> PathBuilderCapture::Finish() {
return MakeAndAddRef<PathCapture>(std::move(mPathOps), mFillRule, mDT,
mCurrentPoint);
}
already_AddRefed<PathBuilder> PathCapture::CopyToBuilder(
FillRule aFillRule) const {
RefPtr<PathBuilderCapture> capture = new PathBuilderCapture(aFillRule, mDT);
capture->mPathOps = mPathOps;
capture->mCurrentPoint = mCurrentPoint;
return capture.forget();
}
already_AddRefed<PathBuilder> PathCapture::TransformedCopyToBuilder(
const Matrix &aTransform, FillRule aFillRule) const {
RefPtr<PathBuilderCapture> capture = new PathBuilderCapture(aFillRule, mDT);
typedef std::vector<PathOp> pathOpVec;
for (pathOpVec::const_iterator iter = mPathOps.begin();
iter != mPathOps.end(); iter++) {
PathOp newPathOp;
newPathOp.mType = iter->mType;
if (newPathOp.mType == PathOp::OpType::OP_ARC) {
struct ArcTransformer {
ArcTransformer(pathOpVec &aVector, const Matrix &aTransform)
: mVector(&aVector), mTransform(&aTransform) {}
void BezierTo(const Point &aCP1, const Point &aCP2, const Point &aCP3) {
PathOp newPathOp;
newPathOp.mType = PathOp::OP_BEZIERTO;
newPathOp.mP1 = mTransform->TransformPoint(aCP1);
newPathOp.mP2 = mTransform->TransformPoint(aCP2);
newPathOp.mP3 = mTransform->TransformPoint(aCP3);
mVector->push_back(newPathOp);
}
void LineTo(const Point &aPoint) {
PathOp newPathOp;
newPathOp.mType = PathOp::OP_BEZIERTO;
newPathOp.mP1 = mTransform->TransformPoint(aPoint);
mVector->push_back(newPathOp);
}
pathOpVec *mVector;
const Matrix *mTransform;
};
ArcTransformer arcTransformer(capture->mPathOps, aTransform);
ArcToBezier(&arcTransformer, iter->mP1,
Size(iter->mRadius, iter->mRadius), iter->mStartAngle,
iter->mEndAngle, iter->mAntiClockwise);
} else {
if (sPointCount[newPathOp.mType] >= 1) {
newPathOp.mP1 = aTransform.TransformPoint(iter->mP1);
}
if (sPointCount[newPathOp.mType] >= 2) {
newPathOp.mP2 = aTransform.TransformPoint(iter->mP2);
}
if (sPointCount[newPathOp.mType] >= 3) {
newPathOp.mP3 = aTransform.TransformPoint(iter->mP3);
}
capture->mPathOps.push_back(newPathOp);
}
}
capture->mCurrentPoint = aTransform.TransformPoint(mCurrentPoint);
return capture.forget();
}
bool PathCapture::ContainsPoint(const Point &aPoint,
const Matrix &aTransform) const {
if (!EnsureRealizedPath()) {
return false;
}
return mRealizedPath->ContainsPoint(aPoint, aTransform);
}
bool PathCapture::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
const Point &aPoint,
const Matrix &aTransform) const {
if (!EnsureRealizedPath()) {
return false;
}
return mRealizedPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform);
}
Rect PathCapture::GetBounds(const Matrix &aTransform) const {
if (!EnsureRealizedPath()) {
return Rect();
}
return mRealizedPath->GetBounds(aTransform);
}
Rect PathCapture::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform) const {
if (!EnsureRealizedPath()) {
return Rect();
}
return mRealizedPath->GetStrokedBounds(aStrokeOptions, aTransform);
}
void PathCapture::StreamToSink(PathSink *aSink) const {
for (const PathOp &op : mPathOps) {
switch (op.mType) {
case PathOp::OP_MOVETO:
aSink->MoveTo(op.mP1);
break;
case PathOp::OP_LINETO:
aSink->LineTo(op.mP1);
break;
case PathOp::OP_BEZIERTO:
aSink->BezierTo(op.mP1, op.mP2, op.mP3);
break;
case PathOp::OP_QUADRATICBEZIERTO:
aSink->QuadraticBezierTo(op.mP1, op.mP2);
break;
case PathOp::OP_ARC:
aSink->Arc(op.mP1, op.mRadius, op.mStartAngle, op.mEndAngle,
op.mAntiClockwise);
break;
case PathOp::OP_CLOSE:
aSink->Close();
break;
}
}
}
bool PathCapture::EnsureRealizedPath() const {
RefPtr<PathBuilder> builder = mDT->CreatePathBuilder(mFillRule);
if (!builder) {
return false;
}
StreamToSink(builder);
mRealizedPath = builder->Finish();
return true;
}
Path *PathCapture::GetRealizedPath() const {
if (!EnsureRealizedPath()) {
return nullptr;
}
return mRealizedPath.get();
}
} // namespace gfx
} // namespace mozilla

117
gfx/2d/PathCapture.h Normal file
View File

@ -0,0 +1,117 @@
/* -*- 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_PATHCAPTURE_H_
#define MOZILLA_GFX_PATHCAPTURE_H_
#include "2D.h"
#include <vector>
#include <ostream>
#include "PathHelpers.h"
namespace mozilla {
namespace gfx {
class PathCapture;
class PathBuilderCapture : public PathBuilder {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderCapture, override)
PathBuilderCapture(FillRule aFillRule, DrawTarget *aDT)
: mFillRule(aFillRule), mDT(aDT) {}
/* 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) override;
/* Add a linesegment to the current figure */
virtual void LineTo(const Point &aPoint) override;
/* Add a cubic bezier curve to the current figure */
virtual void BezierTo(const Point &aCP1, const Point &aCP2,
const Point &aCP3) override;
/* Add a quadratic bezier curve to the current figure */
virtual void QuadraticBezierTo(const Point &aCP1, const Point &aCP2) override;
/* Add an arc to the current figure */
virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise) override;
/* 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() override;
/* Point the current subpath is at - or where the next subpath will start
* if there is no active subpath.
*/
virtual Point CurrentPoint() const override;
virtual already_AddRefed<Path> Finish() override;
virtual BackendType GetBackendType() const override {
return BackendType::CAPTURE;
}
private:
friend class PathCapture;
FillRule mFillRule;
std::vector<PathOp> mPathOps;
Point mCurrentPoint;
RefPtr<DrawTarget> mDT;
};
class PathCapture : public Path {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCapture, override)
PathCapture(const std::vector<PathOp> aOps, FillRule aFillRule,
DrawTarget *aDT, const Point &aCurrentPoint)
: mPathOps(aOps),
mFillRule(aFillRule),
mDT(aDT),
mCurrentPoint(aCurrentPoint) {}
virtual BackendType GetBackendType() const override {
return BackendType::CAPTURE;
}
virtual already_AddRefed<PathBuilder> CopyToBuilder(
FillRule aFillRule) const override;
virtual already_AddRefed<PathBuilder> TransformedCopyToBuilder(
const Matrix &aTransform, FillRule aFillRule) const override;
virtual bool ContainsPoint(const Point &aPoint,
const Matrix &aTransform) const override;
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
const Point &aPoint,
const Matrix &aTransform) const override;
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const override;
virtual Rect GetStrokedBounds(
const StrokeOptions &aStrokeOptions,
const Matrix &aTransform = Matrix()) const override;
virtual void StreamToSink(PathSink *aSink) const override;
virtual FillRule GetFillRule() const override { return mFillRule; }
Path *GetRealizedPath() const;
private:
bool EnsureRealizedPath() const;
mutable RefPtr<Path> mRealizedPath;
std::vector<PathOp> mPathOps;
FillRule mFillRule;
RefPtr<DrawTarget> mDT;
Point mCurrentPoint;
};
} // namespace gfx
} // namespace mozilla
#endif /* MOZILLA_GFX_PATHCAPTURE_H_ */

View File

@ -91,93 +91,6 @@ class OpeningGeometrySink : public ID2D1SimplifiedGeometrySink {
bool mNeedsFigureEnded;
};
class MOZ_STACK_CLASS AutoRestoreFP {
public:
AutoRestoreFP() {
// save the current floating point control word
_controlfp_s(&savedFPSetting, 0, 0);
UINT unused;
// set the floating point control word to its default value
_controlfp_s(&unused, _CW_DEFAULT, MCW_PC);
}
~AutoRestoreFP() {
UINT unused;
// restore the saved floating point control word
_controlfp_s(&unused, savedFPSetting, MCW_PC);
}
private:
UINT savedFPSetting;
};
// Note that overrides of ID2D1SimplifiedGeometrySink methods in this class may
// get called from D2D with nonstandard floating point settings (see comments in
// bug 1134549) - use AutoRestoreFP to reset the floating point control word to
// what we expect
class StreamingGeometrySink : public ID2D1SimplifiedGeometrySink {
public:
explicit StreamingGeometrySink(PathSink *aSink) : mSink(aSink) {}
HRESULT STDMETHODCALLTYPE QueryInterface(const IID &aIID, void **aPtr) {
if (!aPtr) {
return E_POINTER;
}
if (aIID == IID_IUnknown) {
*aPtr = static_cast<IUnknown *>(this);
return S_OK;
} else if (aIID == IID_ID2D1SimplifiedGeometrySink) {
*aPtr = static_cast<ID2D1SimplifiedGeometrySink *>(this);
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() { return 1; }
ULONG STDMETHODCALLTYPE Release() { return 1; }
// We ignore SetFillMode, this depends on the destination sink.
STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE aMode) { return; }
STDMETHOD_(void, BeginFigure)
(D2D1_POINT_2F aPoint, D2D1_FIGURE_BEGIN aBegin) {
AutoRestoreFP resetFloatingPoint;
mSink->MoveTo(ToPoint(aPoint));
}
STDMETHOD_(void, AddLines)(const D2D1_POINT_2F *aLines, UINT aCount) {
AutoRestoreFP resetFloatingPoint;
for (UINT i = 0; i < aCount; i++) {
mSink->LineTo(ToPoint(aLines[i]));
}
}
STDMETHOD_(void, AddBeziers)
(const D2D1_BEZIER_SEGMENT *aSegments, UINT aCount) {
AutoRestoreFP resetFloatingPoint;
for (UINT i = 0; i < aCount; i++) {
mSink->BezierTo(ToPoint(aSegments[i].point1),
ToPoint(aSegments[i].point2),
ToPoint(aSegments[i].point3));
}
}
STDMETHOD(Close)() { /* Should never be called! */
return S_OK;
}
STDMETHOD_(void, SetSegmentFlags)
(D2D1_PATH_SEGMENT aFlags) { /* Should never be called! */
}
STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END aEnd) {
AutoRestoreFP resetFloatingPoint;
if (aEnd == D2D1_FIGURE_END_CLOSED) {
return mSink->Close();
}
}
private:
PathSink *mSink;
};
PathBuilderD2D::~PathBuilderD2D() {}
void PathBuilderD2D::MoveTo(const Point &aPoint) {

View File

@ -15,6 +15,46 @@
namespace mozilla {
namespace gfx {
struct PathOp {
PathOp() {}
~PathOp() {}
enum OpType {
OP_MOVETO = 0,
OP_LINETO,
OP_BEZIERTO,
OP_QUADRATICBEZIERTO,
OP_ARC,
OP_CLOSE
};
OpType mType;
Point mP1;
#if !defined(__GNUC__) || __GNUC__ >= 7
union {
struct {
Point mP2;
Point mP3;
};
struct {
float mRadius;
float mStartAngle;
float mEndAngle;
bool mAntiClockwise;
};
};
#else
Point mP2;
Point mP3;
float mRadius;
float mStartAngle;
float mEndAngle;
bool mAntiClockwise;
#endif
};
const int32_t sPointCount[] = {1, 1, 3, 2, 0, 0};
// Kappa constant for 90-degree angle
const Float kKappaFactor = 0.55191497064665766025f;

View File

@ -16,23 +16,6 @@
namespace mozilla {
namespace gfx {
struct PathOp {
enum OpType {
OP_MOVETO = 0,
OP_LINETO,
OP_BEZIERTO,
OP_QUADRATICBEZIERTO,
OP_CLOSE
};
OpType mType;
Point mP1;
Point mP2;
Point mP3;
};
const int32_t sPointCount[] = {1, 1, 3, 2, 0, 0};
class PathRecording;
class DrawEventRecorderPrivate;

View File

@ -2635,6 +2635,9 @@ inline bool RecordedPathCreation::PlayEvent(Translator *aTranslator) const {
case PathOp::OP_QUADRATICBEZIERTO:
builder->QuadraticBezierTo(op.mP1, op.mP2);
break;
case PathOp::OP_ARC:
MOZ_ASSERT_UNREACHABLE("Recordings should not contain arc operations");
break;
case PathOp::OP_CLOSE:
builder->Close();
break;

View File

@ -11,6 +11,7 @@
#include "Logging.h"
#include "mozilla/FontPropertyTypes.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "HelpersD2D.h"
#include "dwrite_3.h"
@ -191,6 +192,12 @@ void ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
PathBuilder* aBuilder,
const Matrix* aTransformHint) {
BackendType backendType = aBuilder->GetBackendType();
if (backendType == BackendType::CAPTURE) {
StreamingGeometrySink sink(aBuilder);
CopyGlyphsToSink(aBuffer, &sink);
return;
}
if (backendType != BackendType::DIRECT2D &&
backendType != BackendType::DIRECT2D1_1) {
ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aTransformHint);
@ -236,7 +243,7 @@ void ScaledFontDWrite::GetGlyphDesignMetrics(const uint16_t* aGlyphs,
}
void ScaledFontDWrite::CopyGlyphsToSink(const GlyphBuffer& aBuffer,
ID2D1GeometrySink* aSink) {
ID2D1SimplifiedGeometrySink* aSink) {
std::vector<UINT16> indices;
std::vector<FLOAT> advances;
std::vector<DWRITE_GLYPH_OFFSET> offsets;

View File

@ -44,7 +44,8 @@ class ScaledFontDWrite final : public ScaledFontBase {
void CopyGlyphsToBuilder(const GlyphBuffer& aBuffer, PathBuilder* aBuilder,
const Matrix* aTransformHint) override;
void CopyGlyphsToSink(const GlyphBuffer& aBuffer, ID2D1GeometrySink* aSink);
void CopyGlyphsToSink(const GlyphBuffer& aBuffer,
ID2D1SimplifiedGeometrySink* aSink);
void GetGlyphDesignMetrics(const uint16_t* aGlyphIndices, uint32_t aNumGlyphs,
GlyphMetrics* aGlyphMetrics) override;

View File

@ -266,6 +266,7 @@ enum class BackendType : int8_t {
RECORDING,
DIRECT2D1_1,
WEBRENDER_TEXT,
CAPTURE, // Used for paths
// Add new entries above this line.
BACKEND_LAST

View File

@ -187,6 +187,7 @@ UNIFIED_SOURCES += [
'Matrix.cpp',
'Path.cpp',
'PathCairo.cpp',
'PathCapture.cpp',
'PathHelpers.cpp',
'PathRecording.cpp',
'Quaternion.cpp',

View File

@ -188,7 +188,8 @@ void gfxContext::SetPath(Path* path) {
MOZ_ASSERT(path->GetBackendType() == mDT->GetBackendType() ||
path->GetBackendType() == BackendType::RECORDING ||
(mDT->GetBackendType() == BackendType::DIRECT2D1_1 &&
path->GetBackendType() == BackendType::DIRECT2D));
path->GetBackendType() == BackendType::DIRECT2D) ||
path->GetBackendType() == BackendType::CAPTURE);
mPath = path;
mPathBuilder = nullptr;
mPathIsRect = false;

View File

@ -117,6 +117,8 @@ inline const char* GetBackendName(mozilla::gfx::BackendType aBackend) {
return "direct2d 1.1";
case mozilla::gfx::BackendType::WEBRENDER_TEXT:
return "webrender text";
case mozilla::gfx::BackendType::CAPTURE:
return "capture";
case mozilla::gfx::BackendType::NONE:
return "none";
case mozilla::gfx::BackendType::BACKEND_LAST: