Bug 918613: Convert cairo path code to use cairo_path_t. r=jrmuizel

This commit is contained in:
Bas Schouten 2013-09-28 16:20:24 +02:00
parent ee910abc00
commit d457c68e85
12 changed files with 234 additions and 316 deletions

View File

@ -505,7 +505,7 @@ public:
* implementation in some backends, and more efficient implementation in
* others.
*/
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder) = 0;
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint = nullptr) = 0;
virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; }

View File

@ -37,6 +37,8 @@
namespace mozilla {
namespace gfx {
cairo_surface_t *DrawTargetCairo::mDummySurface;
namespace {
// An RAII class to prepare to draw a context and optional path. Saves and
@ -378,15 +380,11 @@ NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions)
DrawTargetCairo::DrawTargetCairo()
: mContext(nullptr)
, mPathObserver(nullptr)
{
}
DrawTargetCairo::~DrawTargetCairo()
{
if (mPathObserver) {
mPathObserver->ForgetDrawTarget();
}
cairo_destroy(mContext);
if (mSurface) {
cairo_surface_destroy(mSurface);
@ -429,6 +427,18 @@ DrawTargetCairo::PrepareForDrawing(cairo_t* aContext, const Path* aPath /* = nul
WillChange(aPath);
}
cairo_surface_t*
DrawTargetCairo::GetDummySurface()
{
if (mDummySurface) {
return mDummySurface;
}
mDummySurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
return mDummySurface;
}
void
DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
const Rect &aDest,
@ -708,7 +718,7 @@ DrawTargetCairo::Stroke(const Path *aPath,
return;
PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
path->CopyPathTo(mContext, this);
path->SetPathOnContext(mContext);
DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE);
}
@ -724,7 +734,7 @@ DrawTargetCairo::Fill(const Path *aPath,
return;
PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
path->CopyPathTo(mContext, this);
path->SetPathOnContext(mContext);
DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
}
@ -836,7 +846,7 @@ DrawTargetCairo::PushClip(const Path *aPath)
cairo_save(mContext);
PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
path->CopyPathTo(mContext, this);
path->SetPathOnContext(mContext);
cairo_clip_preserve(mContext);
}
@ -861,9 +871,7 @@ DrawTargetCairo::PopClip()
TemporaryRef<PathBuilder>
DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FILL_WINDING */) const
{
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mContext,
const_cast<DrawTargetCairo*>(this),
aFillRule);
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
return builder;
}
@ -1071,21 +1079,6 @@ void
DrawTargetCairo::WillChange(const Path* aPath /* = nullptr */)
{
MarkSnapshotIndependent();
if (mPathObserver &&
(!aPath || !mPathObserver->ContainsPath(aPath))) {
mPathObserver->PathWillChange();
mPathObserver = nullptr;
}
}
void
DrawTargetCairo::SetPathObserver(CairoPathContext* aPathObserver)
{
if (mPathObserver && mPathObserver != aPathObserver) {
mPathObserver->PathWillChange();
}
mPathObserver = aPathObserver;
}
void

View File

@ -142,8 +142,6 @@ public:
bool Init(cairo_surface_t* aSurface, const IntSize& aSize);
void SetPathObserver(CairoPathContext* aPathObserver);
virtual void SetTransform(const Matrix& aTransform);
// Call to set up aContext for drawing (with the current transform, etc).
@ -151,6 +149,8 @@ public:
// Implicitly calls WillChange(aPath).
void PrepareForDrawing(cairo_t* aContext, const Path* aPath = nullptr);
static cairo_surface_t *GetDummySurface();
private: // methods
// Init cairo surface without doing a cairo_surface_reference() call.
bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize);
@ -181,12 +181,7 @@ private: // data
// The latest snapshot of this surface. This needs to be told when this
// target is modified. We keep it alive as a cache.
RefPtr<SourceSurfaceCairo> mSnapshot;
// 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;
static cairo_surface_t *mDummySurface;
};
}

View File

@ -13,138 +13,37 @@
namespace mozilla {
namespace gfx {
CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget)
: mContext(aCtx)
, mDrawTarget(aDrawTarget)
PathBuilderCairo::PathBuilderCairo(FillRule aFillRule)
: mFillRule(aFillRule)
{
cairo_reference(mContext);
// A new path in the DrawTarget's context.
aDrawTarget->SetPathObserver(this);
cairo_new_path(mContext);
}
CairoPathContext::CairoPathContext(CairoPathContext& aPathContext)
: mContext(aPathContext.mContext)
, mDrawTarget(nullptr)
{
cairo_reference(mContext);
DuplicateContextAndPath();
}
CairoPathContext::~CairoPathContext()
{
if (mDrawTarget) {
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::DuplicateContextAndPath()
{
// Duplicate the path.
cairo_path_t* path = cairo_copy_path(mContext);
// 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);
// 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_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()
{
// Once we've copied out the context's path, there's no use to holding on to
// the draw target. Thus, there's nothing for us to do if we're independent
// of the draw target, since we'll have already copied out the context's
// path.
if (mDrawTarget) {
// 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::CopyPathTo(cairo_t* aToContext, Matrix& aTransform)
{
if (aToContext != mContext) {
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);
}
}
bool
CairoPathContext::ContainsPath(const Path* aPath)
{
if (aPath->GetBackendType() != BACKEND_CAIRO) {
return false;
}
const PathCairo* path = static_cast<const PathCairo*>(aPath);
RefPtr<CairoPathContext> ctx = const_cast<PathCairo*>(path)->GetPathContext();
return ctx == this;
}
PathBuilderCairo::PathBuilderCairo(CairoPathContext* aPathContext,
FillRule aFillRule,
const Matrix& aTransform /* = Matrix() */)
: mPathContext(aPathContext)
, mTransform(aTransform)
, mFillRule(aFillRule)
{}
PathBuilderCairo::PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule 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);
cairo_path_data_t data;
data.header.type = CAIRO_PATH_MOVE_TO;
data.header.length = 2;
mPathData.push_back(data);
data.point.x = aPoint.x;
data.point.y = aPoint.y;
mPathData.push_back(data);
mBeginPoint = mCurrentPoint = aPoint;
}
void
PathBuilderCairo::LineTo(const Point &aPoint)
{
PrepareForWrite();
CairoTempMatrix tempMatrix(*mPathContext, mTransform);
cairo_line_to(*mPathContext, aPoint.x, aPoint.y);
cairo_path_data_t data;
data.header.type = CAIRO_PATH_LINE_TO;
data.header.length = 2;
mPathData.push_back(data);
data.point.x = aPoint.x;
data.point.y = aPoint.y;
mPathData.push_back(data);
mCurrentPoint = aPoint;
}
void
@ -152,18 +51,27 @@ 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);
cairo_path_data_t data;
data.header.type = CAIRO_PATH_CURVE_TO;
data.header.length = 4;
mPathData.push_back(data);
data.point.x = aCP1.x;
data.point.y = aCP1.y;
mPathData.push_back(data);
data.point.x = aCP2.x;
data.point.y = aCP2.y;
mPathData.push_back(data);
data.point.x = aCP3.x;
data.point.y = aCP3.y;
mPathData.push_back(data);
mCurrentPoint = aCP3;
}
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.
@ -173,14 +81,32 @@ PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0;
Point CP3 = aCP2;
cairo_curve_to(*mPathContext, CP1.x, CP1.y, CP2.x, CP2.y, CP3.x, CP3.y);
cairo_path_data_t data;
data.header.type = CAIRO_PATH_CURVE_TO;
data.header.length = 4;
mPathData.push_back(data);
data.point.x = CP1.x;
data.point.y = CP1.y;
mPathData.push_back(data);
data.point.x = CP2.x;
data.point.y = CP2.y;
mPathData.push_back(data);
data.point.x = CP3.x;
data.point.y = CP3.y;
mPathData.push_back(data);
mCurrentPoint = aCP2;
}
void
PathBuilderCairo::Close()
{
PrepareForWrite();
cairo_close_path(*mPathContext);
cairo_path_data_t data;
data.header.type = CAIRO_PATH_CLOSE_PATH;
data.header.length = 1;
mPathData.push_back(data);
mCurrentPoint = mBeginPoint;
}
void
@ -193,74 +119,78 @@ 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((Float)x, (Float)y);
return mCurrentPoint;
}
TemporaryRef<Path>
PathBuilderCairo::Finish()
{
return new PathCairo(mPathContext, mTransform, mFillRule);
return new PathCairo(mFillRule, mPathData, mCurrentPoint);
}
TemporaryRef<CairoPathContext>
PathBuilderCairo::GetPathContext()
PathCairo::PathCairo(FillRule aFillRule, std::vector<cairo_path_data_t> &aPathData, const Point &aCurrentPoint)
: mFillRule(aFillRule)
, mContainingContext(nullptr)
, mCurrentPoint(aCurrentPoint)
{
return mPathContext;
mPathData.swap(aPathData);
}
void
PathBuilderCairo::PrepareForWrite()
PathCairo::PathCairo(cairo_t *aContext)
: mFillRule(FILL_WINDING)
, mContainingContext(nullptr)
{
// 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);
cairo_path_t *path = cairo_copy_path(aContext);
// XXX - mCurrentPoint is not properly set here, the same is true for the
// D2D Path code, we never require current point when hitting this codepath
// but this should be fixed.
for (int i = 0; i < path->num_data; i++) {
mPathData.push_back(path->data[i]);
}
cairo_path_destroy(path);
}
PathCairo::~PathCairo()
{
if (mContainingContext) {
cairo_destroy(mContainingContext);
}
}
PathCairo::PathCairo(CairoPathContext* aPathContext, Matrix& aTransform,
FillRule aFillRule)
: mPathContext(aPathContext)
, mTransform(aTransform)
, mFillRule(aFillRule)
{}
TemporaryRef<PathBuilder>
PathCairo::CopyToBuilder(FillRule aFillRule) const
{
return new PathBuilderCairo(mPathContext, aFillRule, mTransform);
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
builder->mPathData = mPathData;
builder->mCurrentPoint = mCurrentPoint;
return builder;
}
TemporaryRef<PathBuilder>
PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
{
// 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();
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
return new PathBuilderCairo(mPathContext, aFillRule, mTransform * inverse);
AppendPathToBuilder(builder, &aTransform);
builder->mCurrentPoint = aTransform * mCurrentPoint;
return builder;
}
bool
PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
{
CairoTempMatrix temp(*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);
EnsureContainingContext();
return cairo_in_fill(mContainingContext, transformed.x, transformed.y);
}
bool
@ -268,24 +198,25 @@ PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
const Point &aPoint,
const Matrix &aTransform) const
{
CairoTempMatrix temp(*mPathContext, mTransform);
Matrix inverse = aTransform;
inverse.Invert();
Point transformed = inverse * aPoint;
SetCairoStrokeOptions(*mPathContext, aStrokeOptions);
return cairo_in_stroke(*mPathContext, transformed.x, transformed.y);
EnsureContainingContext();
SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
return cairo_in_stroke(mContainingContext, transformed.x, transformed.y);
}
Rect
PathCairo::GetBounds(const Matrix &aTransform) const
{
CairoTempMatrix temp(*mPathContext, mTransform);
EnsureContainingContext();
double x1, y1, x2, y2;
cairo_path_extents(*mPathContext, &x1, &y1, &x2, &y2);
cairo_path_extents(mContainingContext, &x1, &y1, &x2, &y2);
Rect bounds(Float(x1), Float(y1), Float(x2 - x1), Float(y2 - y1));
return aTransform.TransformBounds(bounds);
}
@ -294,28 +225,69 @@ Rect
PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
const Matrix &aTransform) const
{
CairoTempMatrix temp(*mPathContext, mTransform);
EnsureContainingContext();
double x1, y1, x2, y2;
SetCairoStrokeOptions(*mPathContext, aStrokeOptions);
SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
cairo_stroke_extents(*mPathContext, &x1, &y1, &x2, &y2);
cairo_stroke_extents(mContainingContext, &x1, &y1, &x2, &y2);
Rect bounds((Float)x1, (Float)y1, (Float)(x2 - x1), (Float)(y2 - y1));
return aTransform.TransformBounds(bounds);
}
TemporaryRef<CairoPathContext>
PathCairo::GetPathContext()
void
PathCairo::EnsureContainingContext() const
{
return mPathContext;
if (mContainingContext) {
return;
}
mContainingContext = cairo_create(DrawTargetCairo::GetDummySurface());
SetPathOnContext(mContainingContext);
}
void
PathCairo::CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget)
PathCairo::SetPathOnContext(cairo_t *aContext) const
{
mPathContext->CopyPathTo(aContext, mTransform);
// Needs the correct fill rule set.
cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule));
cairo_new_path(aContext);
if (mPathData.size()) {
cairo_path_t path;
path.data = const_cast<cairo_path_data_t*>(&mPathData.front());
path.num_data = mPathData.size();
path.status = CAIRO_STATUS_SUCCESS;
cairo_append_path(aContext, &path);
}
}
void
PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform) const
{
if (aTransform) {
int i = 0;
while (i < mPathData.size()) {
uint32_t pointCount = mPathData[i].header.length - 1;
aBuilder->mPathData.push_back(mPathData[i]);
i++;
for (int c = 0; c < pointCount; c++) {
cairo_path_data_t data;
Point newPoint = *aTransform * Point(mPathData[i].point.x, mPathData[i].point.y);
data.point.x = newPoint.x;
data.point.y = newPoint.y;
aBuilder->mPathData.push_back(data);
i++;
}
}
} else {
for (int i = 0; i < mPathData.size(); i++) {
aBuilder->mPathData.push_back(mPathData[i]);
}
}
}
}

View File

@ -8,86 +8,18 @@
#include "2D.h"
#include "cairo.h"
#include <vector>
namespace mozilla {
namespace gfx {
class DrawTargetCairo;
// A reference to a cairo context that can maintain and set a path.
//
// This class exists to make it possible for us to not construct paths manually
// using cairo_path_t, which in the common case is a speed and memory
// optimization (as the cairo_t maintains the path for us, and we don't have to
// use cairo_append_path). Instead, we can share a cairo_t with a DrawTarget,
// and have it inform us when we need to make a copy of the path.
//
// Exactly one Path* object represents the current path on a given DrawTarget's
// context. That Path* object registers its CairoPathContext with the
// DrawTarget it's associated with. If that DrawTarget is going to change its
// path, it has to tell the CairoPathContext beforehand so the path can be
// saved off.
// The path ownership is transferred to every new instance of CairoPathContext
// in the constructor. We inform the draw target of the new context object,
// which causes us to save off a copy of the path, as we're not going to be
// informed upon changes any more.
// Any transformation on aCtx is not applied to this path, though a path can be
// transformed separately from its context by passing a matrix to the
// constructor.
class CairoPathContext : public RefCounted<CairoPathContext>
{
public:
// 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. 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 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.
void DuplicateContextAndPath();
// Returns true if this CairoPathContext represents path.
bool ContainsPath(const Path* path);
cairo_t* GetContext() const { return mContext; }
DrawTargetCairo* GetDrawTarget() const { return mDrawTarget; }
operator cairo_t* () const { return mContext; }
private: // data
cairo_t* mContext;
// Not a RefPtr to avoid cycles.
DrawTargetCairo* mDrawTarget;
};
class PathCairo;
class PathBuilderCairo : public PathBuilder
{
public:
// 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);
// 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());
PathBuilderCairo(FillRule aFillRule);
virtual void MoveTo(const Point &aPoint);
virtual void LineTo(const Point &aPoint);
@ -102,20 +34,23 @@ public:
virtual Point CurrentPoint() const;
virtual TemporaryRef<Path> Finish();
TemporaryRef<CairoPathContext> GetPathContext();
private: // data
void PrepareForWrite();
friend class PathCairo;
RefPtr<CairoPathContext> mPathContext;
Matrix mTransform;
FillRule mFillRule;
std::vector<cairo_path_data_t> mPathData;
// It's easiest to track this here, parsing the path data to find the current
// point is a little tricky.
Point mCurrentPoint;
Point mBeginPoint;
};
class PathCairo : public Path
{
public:
PathCairo(CairoPathContext* aPathContex, Matrix& aTransform, FillRule aFillRule);
PathCairo(FillRule aFillRule, std::vector<cairo_path_data_t> &aPathData, const Point &aCurrentPoint);
PathCairo(cairo_t *aContext);
~PathCairo();
virtual BackendType GetBackendType() const { return BACKEND_CAIRO; }
@ -136,17 +71,16 @@ public:
virtual FillRule GetFillRule() const { return mFillRule; }
TemporaryRef<CairoPathContext> GetPathContext();
// Set this path to be the current path for aContext (if it's not already
// aContext's path). You must pass the draw target associated with the
// context as aDrawTarget.
void CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget);
void SetPathOnContext(cairo_t *aContext) const;
void AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform = nullptr) const;
private:
RefPtr<CairoPathContext> mPathContext;
Matrix mTransform;
void EnsureContainingContext() const;
FillRule mFillRule;
std::vector<cairo_path_data_t> mPathData;
mutable cairo_t *mContainingContext;
Point mCurrentPoint;
};
}

View File

@ -13,6 +13,8 @@
#ifdef USE_CAIRO
#include "PathCairo.h"
#include "DrawTargetCairo.h"
#include "HelpersCairo.h"
#endif
#include <vector>
@ -74,13 +76,18 @@ ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *a
if (aTarget->GetType() == BACKEND_CAIRO) {
MOZ_ASSERT(mScaledFont);
RefPtr<PathBuilder> builder_iface = aTarget->CreatePathBuilder();
PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(builder_iface.get());
DrawTarget *dt = const_cast<DrawTarget*>(aTarget);
cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NATIVE_SURFACE_CAIRO_CONTEXT));
// Manually build the path for the PathBuilder.
RefPtr<CairoPathContext> context = builder->GetPathContext();
bool isNewContext = !ctx;
if (!ctx) {
ctx = cairo_create(DrawTargetCairo::GetDummySurface());
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
cairo_set_matrix(ctx, &mat);
}
cairo_set_scaled_font(*context, mScaledFont);
cairo_set_scaled_font(ctx, mScaledFont);
// Convert our GlyphBuffer into an array of Cairo glyphs.
std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
@ -90,23 +97,33 @@ ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *a
glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
}
cairo_glyph_path(*context, &glyphs[0], aBuffer.mNumGlyphs);
cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
return builder->Finish();
RefPtr<PathCairo> newPath = new PathCairo(ctx);
if (isNewContext) {
cairo_destroy(ctx);
}
return newPath;
}
#endif
return nullptr;
}
void
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder)
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint)
{
#ifdef USE_CAIRO
PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
RefPtr<CairoPathContext> context = builder->GetPathContext();
cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());
cairo_set_scaled_font(*context, mScaledFont);
if (aTransformHint) {
cairo_matrix_t mat;
GfxMatrixToCairoMatrix(*aTransformHint, mat);
cairo_set_matrix(ctx, &mat);
}
// Convert our GlyphBuffer into an array of Cairo glyphs.
std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
@ -116,7 +133,13 @@ ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBu
glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
}
cairo_glyph_path(*context, &glyphs[0], aBuffer.mNumGlyphs);
cairo_set_scaled_font(ctx, mScaledFont);
cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
cairo_destroy(ctx);
cairoPath->AppendPathToBuilder(builder);
#endif
}

View File

@ -33,7 +33,7 @@ public:
virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder);
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint);
float GetSize() { return mSize; }

View File

@ -324,7 +324,7 @@ ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget
}
void
ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder)
ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *)
{
// XXX - Check path builder type!
PathBuilderD2D *pathBuilderD2D =

View File

@ -26,7 +26,7 @@ public:
virtual FontType GetType() const { return FONT_DWRITE; }
virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder);
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint);
void CopyGlyphsToSink(const GlyphBuffer &aBuffer, ID2D1GeometrySink *aSink);

View File

@ -102,7 +102,7 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT
}
void
ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder)
ScaledFontMac::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *)
{
PathBuilderCG *pathBuilderCG =
static_cast<PathBuilderCG*>(aBuilder);

View File

@ -25,7 +25,7 @@ public:
virtual SkTypeface* GetSkTypeface();
#endif
virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget);
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder);
virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint);
virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
private:

View File

@ -2330,7 +2330,8 @@ struct GlyphBufferAzure {
}
if (aDrawMode & gfxFont::GLYPH_PATH) {
aThebesContext->EnsurePathBuilder();
aFont->CopyGlyphsToBuilder(buf, aThebesContext->mPathBuilder);
Matrix mat = aDT->GetTransform();
aFont->CopyGlyphsToBuilder(buf, aThebesContext->mPathBuilder, &mat);
}
if ((aDrawMode & (gfxFont::GLYPH_STROKE | gfxFont::GLYPH_STROKE_UNDERNEATH)) ==
gfxFont::GLYPH_STROKE) {