mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 784573 - Fix problems converting cairo paths between user space and device space. r=joe
This commit is contained in:
parent
a362c2be73
commit
223dd80132
@ -281,6 +281,7 @@ NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions)
|
||||
|
||||
DrawTargetCairo::DrawTargetCairo()
|
||||
: mContext(nullptr)
|
||||
, mPathObserver(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -687,11 +688,6 @@ DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FILL_WINDING */) cons
|
||||
const_cast<DrawTargetCairo*>(this),
|
||||
aFillRule);
|
||||
|
||||
// Creating a PathBuilder implicitly resets our mPathObserver, as it calls
|
||||
// SetPathObserver() on us. Since this guarantees our old path is saved off,
|
||||
// it's safe to reset the path here.
|
||||
cairo_new_path(mContext);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@ -921,12 +917,6 @@ DrawTargetCairo::SetPathObserver(CairoPathContext* aPathObserver)
|
||||
void
|
||||
DrawTargetCairo::SetTransform(const Matrix& aTransform)
|
||||
{
|
||||
// We're about to logically change our transformation. Our current path will
|
||||
// need to change, because Cairo stores paths in device space.
|
||||
if (mPathObserver) {
|
||||
mPathObserver->MatrixWillChange(aTransform);
|
||||
}
|
||||
|
||||
mTransform = aTransform;
|
||||
|
||||
cairo_matrix_t mat;
|
||||
|
@ -169,7 +169,12 @@ private: // data
|
||||
cairo_surface_t* mSurface;
|
||||
IntSize mSize;
|
||||
std::vector<SourceSurfaceCairo*> mSnapshots;
|
||||
mutable RefPtr<CairoPathContext> mPathObserver;
|
||||
|
||||
// It is safe to use a regular pointer here because the CairoPathContext will
|
||||
// deregister itself on destruction. Using a RefPtr would extend the life-
|
||||
// span of the CairoPathContext. This causes a problem when
|
||||
// PathBuilderCairo.Finish()
|
||||
mutable CairoPathContext* mPathObserver;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -13,61 +13,40 @@
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget,
|
||||
FillRule aFillRule,
|
||||
const Matrix& aTransform /* = Matrix() */)
|
||||
: mTransform(aTransform)
|
||||
, mContext(aCtx)
|
||||
CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget)
|
||||
: mContext(aCtx)
|
||||
, mDrawTarget(aDrawTarget)
|
||||
, mFillRule(aFillRule)
|
||||
{
|
||||
cairo_reference(mContext);
|
||||
cairo_set_fill_rule(mContext, GfxFillRuleToCairoFillRule(mFillRule));
|
||||
|
||||
// If we don't have an identity transformation, we need to have a separate
|
||||
// context from the draw target, because we can't set a transformation on its
|
||||
// context.
|
||||
if (mDrawTarget && !mTransform.IsIdentity()) {
|
||||
DuplicateContextAndPath(mTransform);
|
||||
// A new path in the DrawTarget's context.
|
||||
aDrawTarget->SetPathObserver(this);
|
||||
cairo_new_path(mContext);
|
||||
}
|
||||
|
||||
ForgetDrawTarget();
|
||||
} else if (mDrawTarget) {
|
||||
mDrawTarget->SetPathObserver(this);
|
||||
}
|
||||
CairoPathContext::CairoPathContext(CairoPathContext& aPathContext)
|
||||
: mContext(aPathContext.mContext)
|
||||
, mDrawTarget(nullptr)
|
||||
{
|
||||
cairo_reference(mContext);
|
||||
DuplicateContextAndPath();
|
||||
}
|
||||
|
||||
CairoPathContext::~CairoPathContext()
|
||||
{
|
||||
if (mDrawTarget) {
|
||||
mDrawTarget->SetPathObserver(nullptr);
|
||||
DrawTargetCairo* drawTarget = mDrawTarget;
|
||||
ForgetDrawTarget();
|
||||
|
||||
// We need to set mDrawTarget to nullptr before we tell DrawTarget otherwise
|
||||
// we will think we need to make a defensive copy of the path.
|
||||
drawTarget->SetPathObserver(nullptr);
|
||||
}
|
||||
cairo_destroy(mContext);
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::ObserveTarget(DrawTargetCairo* aDrawTarget)
|
||||
{
|
||||
if (!aDrawTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDrawTarget) {
|
||||
mDrawTarget->SetPathObserver(nullptr);
|
||||
}
|
||||
mDrawTarget = aDrawTarget;
|
||||
|
||||
// If there is a transform on the path, then we must have a separate context
|
||||
// from the draw target, so we cannot be its observer
|
||||
if (!mTransform.IsIdentity()) {
|
||||
ForgetDrawTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
mDrawTarget->SetPathObserver(this);
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::DuplicateContextAndPath(const Matrix& aMatrix /* = Matrix() */)
|
||||
CairoPathContext::DuplicateContextAndPath()
|
||||
{
|
||||
// Duplicate the path.
|
||||
cairo_path_t* path = cairo_copy_path(mContext);
|
||||
@ -75,20 +54,31 @@ CairoPathContext::DuplicateContextAndPath(const Matrix& aMatrix /* = Matrix() */
|
||||
|
||||
// Duplicate the context.
|
||||
cairo_surface_t* surf = cairo_get_target(mContext);
|
||||
cairo_matrix_t matrix;
|
||||
cairo_get_matrix(mContext, &matrix);
|
||||
cairo_destroy(mContext);
|
||||
|
||||
mContext = cairo_create(surf);
|
||||
|
||||
// Transform the context.
|
||||
cairo_matrix_t matrix;
|
||||
GfxMatrixToCairoMatrix(aMatrix, matrix);
|
||||
cairo_transform(mContext, &matrix);
|
||||
// Set the matrix to match the source context so that the path is copied in
|
||||
// device space. After this point it doesn't matter what the transform is
|
||||
// set to because it's always swapped out before use.
|
||||
cairo_set_matrix(mContext, &matrix);
|
||||
|
||||
// Add the path, and throw away our duplicate.
|
||||
cairo_append_path(mContext, path);
|
||||
cairo_set_fill_rule(mContext, rule);
|
||||
cairo_path_destroy(path);
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::ForgetDrawTarget()
|
||||
{
|
||||
// We don't need to set the path observer back to nullptr in this case
|
||||
// because ForgetDrawTarget() is trigged when the target has been
|
||||
// grabbed by another path observer.
|
||||
mDrawTarget = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::PathWillChange()
|
||||
{
|
||||
@ -100,68 +90,22 @@ CairoPathContext::PathWillChange()
|
||||
// The context we point to is going to change from under us. To continue
|
||||
// using this path, we need to copy it to a new context.
|
||||
DuplicateContextAndPath();
|
||||
|
||||
ForgetDrawTarget();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::MatrixWillChange(const Matrix& aNewMatrix)
|
||||
{
|
||||
// Cairo paths are stored in device space. Since we logically operate in user
|
||||
// space, we want to make it so our path will be in the same location if and
|
||||
// when our path is copied out.
|
||||
// To effect this, we copy out our path (which, in Cairo, implicitly converts
|
||||
// to user space), then temporarily set the context to have the new
|
||||
// transform. We then set the path, which ensures that the points are all
|
||||
// transformed correctly. Finally, we set the matrix back to its original
|
||||
// value.
|
||||
cairo_path_t* path = cairo_copy_path(mContext);
|
||||
|
||||
cairo_matrix_t origMatrix;
|
||||
cairo_get_matrix(mContext, &origMatrix);
|
||||
|
||||
cairo_matrix_t newMatrix;
|
||||
GfxMatrixToCairoMatrix(aNewMatrix, newMatrix);
|
||||
cairo_set_matrix(mContext, &newMatrix);
|
||||
|
||||
cairo_new_path(mContext);
|
||||
cairo_append_path(mContext, path);
|
||||
cairo_path_destroy(path);
|
||||
|
||||
cairo_set_matrix(mContext, &origMatrix);
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::CopyPathTo(cairo_t* aToContext)
|
||||
CairoPathContext::CopyPathTo(cairo_t* aToContext, Matrix& aTransform)
|
||||
{
|
||||
if (aToContext != mContext) {
|
||||
cairo_set_fill_rule(aToContext, GfxFillRuleToCairoFillRule(mFillRule));
|
||||
|
||||
cairo_matrix_t origMat;
|
||||
cairo_get_matrix(aToContext, &origMat);
|
||||
|
||||
cairo_matrix_t mat;
|
||||
GfxMatrixToCairoMatrix(mTransform, mat);
|
||||
cairo_transform(aToContext, &mat);
|
||||
|
||||
// cairo_copy_path gives us a user-space copy of the path, so we don't have
|
||||
// to worry about transformations here.
|
||||
CairoTempMatrix tempMatrix(mContext, aTransform);
|
||||
cairo_path_t* path = cairo_copy_path(mContext);
|
||||
cairo_new_path(aToContext);
|
||||
cairo_append_path(aToContext, path);
|
||||
cairo_path_destroy(path);
|
||||
|
||||
cairo_set_matrix(aToContext, &origMat);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CairoPathContext::ForgetDrawTarget()
|
||||
{
|
||||
mDrawTarget = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
CairoPathContext::ContainsPath(const Path* aPath)
|
||||
{
|
||||
@ -175,38 +119,32 @@ CairoPathContext::ContainsPath(const Path* aPath)
|
||||
}
|
||||
|
||||
PathBuilderCairo::PathBuilderCairo(CairoPathContext* aPathContext,
|
||||
FillRule aFillRule,
|
||||
const Matrix& aTransform /* = Matrix() */)
|
||||
: mFillRule(aPathContext->GetFillRule())
|
||||
{
|
||||
RefPtr<DrawTargetCairo> drawTarget = aPathContext->GetDrawTarget();
|
||||
mPathContext = new CairoPathContext(*aPathContext, drawTarget, mFillRule,
|
||||
aPathContext->GetTransform() * aTransform);
|
||||
|
||||
// We need to ensure that we are allowed to modify the path currently set on
|
||||
// aPathContext. If we don't have a draw target, CairoPathContext's
|
||||
// constructor has no way to make aPathContext duplicate its path (normally,
|
||||
// calling drawTarget->SetPathObserver() would do so). In this case, we
|
||||
// explicitly make aPathContext copy out its context and path, leaving our
|
||||
// path alone.
|
||||
if (!drawTarget) {
|
||||
aPathContext->DuplicateContextAndPath();
|
||||
}
|
||||
}
|
||||
: mPathContext(aPathContext)
|
||||
, mTransform(aTransform)
|
||||
, mFillRule(aFillRule)
|
||||
{}
|
||||
|
||||
PathBuilderCairo::PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule)
|
||||
: mPathContext(new CairoPathContext(aCtx, aDrawTarget, aFillRule))
|
||||
: mPathContext(new CairoPathContext(aCtx, aDrawTarget))
|
||||
, mTransform(aDrawTarget->GetTransform())
|
||||
, mFillRule(aFillRule)
|
||||
{}
|
||||
|
||||
void
|
||||
PathBuilderCairo::MoveTo(const Point &aPoint)
|
||||
{
|
||||
PrepareForWrite();
|
||||
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
|
||||
cairo_move_to(*mPathContext, aPoint.x, aPoint.y);
|
||||
}
|
||||
|
||||
void
|
||||
PathBuilderCairo::LineTo(const Point &aPoint)
|
||||
{
|
||||
PrepareForWrite();
|
||||
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
|
||||
cairo_line_to(*mPathContext, aPoint.x, aPoint.y);
|
||||
}
|
||||
|
||||
@ -215,6 +153,8 @@ PathBuilderCairo::BezierTo(const Point &aCP1,
|
||||
const Point &aCP2,
|
||||
const Point &aCP3)
|
||||
{
|
||||
PrepareForWrite();
|
||||
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
|
||||
cairo_curve_to(*mPathContext, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y);
|
||||
}
|
||||
|
||||
@ -222,6 +162,9 @@ void
|
||||
PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
|
||||
const Point &aCP2)
|
||||
{
|
||||
PrepareForWrite();
|
||||
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
|
||||
|
||||
// We need to elevate the degree of this quadratic Bézier to cubic, so we're
|
||||
// going to add an intermediate control point, and recompute control point 1.
|
||||
// The first and last control points remain the same.
|
||||
@ -237,6 +180,7 @@ PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
|
||||
void
|
||||
PathBuilderCairo::Close()
|
||||
{
|
||||
PrepareForWrite();
|
||||
cairo_close_path(*mPathContext);
|
||||
}
|
||||
|
||||
@ -250,6 +194,7 @@ PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
|
||||
Point
|
||||
PathBuilderCairo::CurrentPoint() const
|
||||
{
|
||||
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
|
||||
double x, y;
|
||||
cairo_get_current_point(*mPathContext, &x, &y);
|
||||
return Point(x, y);
|
||||
@ -258,11 +203,7 @@ PathBuilderCairo::CurrentPoint() const
|
||||
TemporaryRef<Path>
|
||||
PathBuilderCairo::Finish()
|
||||
{
|
||||
RefPtr<PathCairo> path = new PathCairo(*mPathContext,
|
||||
mPathContext->GetDrawTarget(),
|
||||
mFillRule,
|
||||
mPathContext->GetTransform());
|
||||
return path;
|
||||
return new PathCairo(mPathContext, mTransform, mFillRule);
|
||||
}
|
||||
|
||||
TemporaryRef<CairoPathContext>
|
||||
@ -271,43 +212,63 @@ PathBuilderCairo::GetPathContext()
|
||||
return mPathContext;
|
||||
}
|
||||
|
||||
PathCairo::PathCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule, const Matrix& aTransform)
|
||||
: mPathContext(new CairoPathContext(aCtx, aDrawTarget, aFillRule, aTransform))
|
||||
void
|
||||
PathBuilderCairo::PrepareForWrite()
|
||||
{
|
||||
// Only PathBuilder and PathCairo maintain references to CairoPathContext.
|
||||
// DrawTarget does not. If we're sharing a reference to the context then we
|
||||
// need to create a copy that we can modify. This provides copy on write
|
||||
// behaviour.
|
||||
if (mPathContext->refCount() != 1) {
|
||||
mPathContext = new CairoPathContext(*mPathContext);
|
||||
}
|
||||
}
|
||||
|
||||
PathCairo::PathCairo(CairoPathContext* aPathContext, Matrix& aTransform,
|
||||
FillRule aFillRule)
|
||||
: mPathContext(aPathContext)
|
||||
, mTransform(aTransform)
|
||||
, mFillRule(aFillRule)
|
||||
{}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
PathCairo::CopyToBuilder(FillRule aFillRule) const
|
||||
{
|
||||
// Note: This PathBuilderCairo constructor causes our mPathContext to copy
|
||||
// out the path, since the path builder is going to change the path on us.
|
||||
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mPathContext);
|
||||
return builder;
|
||||
return new PathBuilderCairo(mPathContext, aFillRule, mTransform);
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
|
||||
{
|
||||
// Note: This PathBuilderCairo constructor causes our mPathContext to copy
|
||||
// out the path, since the path builder is going to change the path on us.
|
||||
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mPathContext,
|
||||
aTransform);
|
||||
return builder;
|
||||
// We are given the transform we would apply from device space to user space.
|
||||
// However in cairo our path is in device space so we view the transform as
|
||||
// being the other way round. We therefore need to apply the inverse transform
|
||||
// to our current cairo transform.
|
||||
Matrix inverse = aTransform;
|
||||
inverse.Invert();
|
||||
|
||||
return new PathBuilderCairo(mPathContext, aFillRule, mTransform * inverse);
|
||||
}
|
||||
|
||||
bool
|
||||
PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
|
||||
{
|
||||
CairoTempMatrix(*mPathContext, mTransform);
|
||||
|
||||
Matrix inverse = aTransform;
|
||||
inverse.Invert();
|
||||
Point transformed = inverse * aPoint;
|
||||
|
||||
// Needs the correct fill rule set.
|
||||
cairo_set_fill_rule(*mPathContext, GfxFillRuleToCairoFillRule(mFillRule));
|
||||
return cairo_in_fill(*mPathContext, transformed.x, transformed.y);
|
||||
}
|
||||
|
||||
Rect
|
||||
PathCairo::GetBounds(const Matrix &aTransform) const
|
||||
{
|
||||
CairoTempMatrix(*mPathContext, mTransform);
|
||||
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
cairo_path_extents(*mPathContext, &x1, &y1, &x2, &y2);
|
||||
@ -319,6 +280,8 @@ Rect
|
||||
PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
||||
const Matrix &aTransform) const
|
||||
{
|
||||
CairoTempMatrix(*mPathContext, mTransform);
|
||||
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
SetCairoStrokeOptions(*mPathContext, aStrokeOptions);
|
||||
@ -337,13 +300,8 @@ PathCairo::GetPathContext()
|
||||
void
|
||||
PathCairo::CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget)
|
||||
{
|
||||
if (mPathContext->GetContext() != aContext) {
|
||||
mPathContext->CopyPathTo(aContext);
|
||||
|
||||
// Since aDrawTarget wants us to be the current path on its context, we
|
||||
// should also listen to it for updates to that path (as an optimization).
|
||||
mPathContext->ObserveTarget(aDrawTarget);
|
||||
}
|
||||
mPathContext->CopyPathTo(aContext, mTransform);
|
||||
cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,74 +37,57 @@ class DrawTargetCairo;
|
||||
class CairoPathContext : public RefCounted<CairoPathContext>
|
||||
{
|
||||
public:
|
||||
// Construct a CairoPathContext and set it to be the path observer of
|
||||
// aDrawTarget. Optionally, this path can be transformed by aMatrix.
|
||||
CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget,
|
||||
FillRule aFillRule,
|
||||
const Matrix& aMatrix = Matrix());
|
||||
// Construct a new empty CairoPathContext that uses the given draw target and
|
||||
// its cairo context. Using the existing context may save having to copy the
|
||||
// path later.
|
||||
CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget);
|
||||
|
||||
// Copy the path.
|
||||
CairoPathContext(CairoPathContext& aPathContext);
|
||||
|
||||
~CairoPathContext();
|
||||
|
||||
// Copy the path on mContext to be the path on aToContext, if they aren't the
|
||||
// same.
|
||||
void CopyPathTo(cairo_t* aToContext);
|
||||
// same. At this point we set the fill rule for the destination context as
|
||||
// there is little point in doing this earlier.
|
||||
void CopyPathTo(cairo_t* aToContext, Matrix& aTransform);
|
||||
|
||||
// This method must be called by the draw target before it changes the path
|
||||
// currently on the cairo context.
|
||||
void PathWillChange();
|
||||
|
||||
// This method must be called by the draw target whenever it is going to
|
||||
// change the current transformation on mContext.
|
||||
void MatrixWillChange(const Matrix& aMatrix);
|
||||
|
||||
// This method must be called as the draw target is dying. In this case, we
|
||||
// forget our reference to the draw target, and become the only reference to
|
||||
// our context.
|
||||
void ForgetDrawTarget();
|
||||
|
||||
// Create a duplicate context, and copy this path to that context. Optionally,
|
||||
// the new context can be transformed.
|
||||
void DuplicateContextAndPath(const Matrix& aMatrix = Matrix());
|
||||
// Create a duplicate context, and copy this path to that context.
|
||||
void DuplicateContextAndPath();
|
||||
|
||||
// Returns true if this CairoPathContext represents path.
|
||||
bool ContainsPath(const Path* path);
|
||||
|
||||
// add ourselves as an observer of aDrawTarget, if possible
|
||||
// if we succeed, then mDrawTarget is set to aDrawTarget
|
||||
void ObserveTarget(DrawTargetCairo* aDrawTarget);
|
||||
|
||||
cairo_t* GetContext() const { return mContext; }
|
||||
DrawTargetCairo* GetDrawTarget() const { return mDrawTarget; }
|
||||
Matrix GetTransform() const { return mTransform; }
|
||||
FillRule GetFillRule() const { return mFillRule; }
|
||||
|
||||
operator cairo_t* () const { return mContext; }
|
||||
|
||||
private: // methods
|
||||
CairoPathContext(const CairoPathContext&) MOZ_DELETE;
|
||||
|
||||
private: // data
|
||||
Matrix mTransform;
|
||||
cairo_t* mContext;
|
||||
// Not a RefPtr to avoid cycles.
|
||||
DrawTargetCairo* mDrawTarget;
|
||||
FillRule mFillRule;
|
||||
};
|
||||
|
||||
class PathBuilderCairo : public PathBuilder
|
||||
{
|
||||
public:
|
||||
// This constructor implicitly takes ownership of aCtx by calling
|
||||
// aDrawTarget->SetPathObserver(). Therefore, if the draw target has a path
|
||||
// observer, this constructor will cause it to copy out its path.
|
||||
// The path currently set on aCtx is not changed.
|
||||
// Creates a new empty path. It also implicitly takes ownership of aCtx by
|
||||
// calling aDrawTarget->SetPathObserver(). Therefore, if the draw target has a
|
||||
// path observer, this constructor will cause it to copy out its path.
|
||||
PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule);
|
||||
|
||||
// This constructor, called with a CairoPathContext*, implicitly takes
|
||||
// ownership of the path, and therefore makes aPathContext copy out its path
|
||||
// regardless of whether it has a pointer to a DrawTargetCairo.
|
||||
// The path currently set on aPathContext is not changed.
|
||||
explicit PathBuilderCairo(CairoPathContext* aPathContext,
|
||||
const Matrix& aTransform = Matrix());
|
||||
// Creates a path builder out of an existing CairoPathContext with a new fill
|
||||
// rule and transform.
|
||||
PathBuilderCairo(CairoPathContext* aContext, FillRule aFillRule, const Matrix& aTransform = Matrix());
|
||||
|
||||
virtual void MoveTo(const Point &aPoint);
|
||||
virtual void LineTo(const Point &aPoint);
|
||||
@ -121,18 +104,18 @@ public:
|
||||
|
||||
TemporaryRef<CairoPathContext> GetPathContext();
|
||||
|
||||
private: // methods
|
||||
void SetFillRule(FillRule aFillRule);
|
||||
|
||||
private: // data
|
||||
void PrepareForWrite();
|
||||
|
||||
RefPtr<CairoPathContext> mPathContext;
|
||||
Matrix mTransform;
|
||||
FillRule mFillRule;
|
||||
};
|
||||
|
||||
class PathCairo : public Path
|
||||
{
|
||||
public:
|
||||
PathCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule, const Matrix& aTransform);
|
||||
PathCairo(CairoPathContext* aPathContex, Matrix& aTransform, FillRule aFillRule);
|
||||
|
||||
virtual BackendType GetBackendType() const { return BACKEND_CAIRO; }
|
||||
|
||||
@ -158,6 +141,7 @@ public:
|
||||
|
||||
private:
|
||||
RefPtr<CairoPathContext> mPathContext;
|
||||
Matrix mTransform;
|
||||
FillRule mFillRule;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user