mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
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:
parent
7cbaee9bbb
commit
5c3778d6dd
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
212
gfx/2d/PathCapture.cpp
Normal 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
117
gfx/2d/PathCapture.h
Normal 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_ */
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -187,6 +187,7 @@ UNIFIED_SOURCES += [
|
||||
'Matrix.cpp',
|
||||
'Path.cpp',
|
||||
'PathCairo.cpp',
|
||||
'PathCapture.cpp',
|
||||
'PathHelpers.cpp',
|
||||
'PathRecording.cpp',
|
||||
'Quaternion.cpp',
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user