Bug 918613: Convert cairo path code to use cairo_path_t. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Sat, 28 Sep 2013 16:39:49 +0200
changeset 266 48925be98818ce5167bac7d799c205d3bc862955
parent 265 1e75b499ee273ac29503e862637c8551473726de
child 267 90f9e3a4f117f362b0f318fe7c2fdb3410557cfc
push id174
push userbschouten@mozilla.com
push dateSat, 28 Sep 2013 14:40:10 +0000
reviewersjrmuizel
bugs918613
Bug 918613: Convert cairo path code to use cairo_path_t. r=jrmuizel
2D.h
DrawTargetCairo.cpp
DrawTargetCairo.h
Makefile.cairo
PathCairo.cpp
PathCairo.h
ScaledFontBase.cpp
ScaledFontBase.h
ScaledFontCairo.cpp
ScaledFontCairo.h
ScaledFontDWrite.cpp
ScaledFontDWrite.h
ScaledFontNVpr.h
gfx2d.vcxproj
--- a/2D.h
+++ b/2D.h
@@ -491,17 +491,17 @@ public:
    */
   virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) = 0;
 
   /* This copies the path describing the glyphs into a PathBuilder. We use this
    * API rather than a generic API to append paths because it allows easier
    * implementation in some backends, and more efficient implementation in
    * others.
    */
-  virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder) = 0;
+  virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint = nullptr) = 0;
 
   virtual bool GetFontFileData(FontFileDataOutput, void *) { return false; }
 
   void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) {
     mUserData.Add(key, userData, destroy);
   }
   void *GetUserData(UserDataKey *key) {
     return mUserData.Get(key);
--- a/DrawTargetCairo.cpp
+++ b/DrawTargetCairo.cpp
@@ -32,16 +32,18 @@
 #include "cairo-win32.h"
 #endif
 
 #include <algorithm>
 
 namespace mozilla {
 namespace gfx {
 
+cairo_surface_t *DrawTargetCairo::mDummySurface;
+
 namespace {
 
 // An RAII class to prepare to draw a context and optional path. Saves and
 // restores the context on construction/destruction.
 class AutoPrepareForDrawing
 {
 public:
   AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx)
@@ -389,25 +391,21 @@ NeedIntermediateSurface(const Pattern& a
   if (aOptions.mAlpha == 1.0)
     return false;
 
   return true;
 }
 
 DrawTargetCairo::DrawTargetCairo()
   : mContext(nullptr)
-  , mPathObserver(nullptr)
 {
 }
 
 DrawTargetCairo::~DrawTargetCairo()
 {
-  if (mPathObserver) {
-    mPathObserver->ForgetDrawTarget();
-  }
   cairo_destroy(mContext);
   if (mSurface) {
     cairo_surface_destroy(mSurface);
   }
 }
 
 IntSize
 DrawTargetCairo::GetSize()
@@ -440,16 +438,28 @@ DrawTargetCairo::Flush()
 }
 
 void
 DrawTargetCairo::PrepareForDrawing(cairo_t* aContext, const Path* aPath /* = nullptr */)
 {
   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,
                              const Rect &aSource,
                              const DrawSurfaceOptions &aSurfOptions,
                              const DrawOptions &aOptions)
 {
   AutoPrepareForDrawing prep(this, mContext);
@@ -719,33 +729,33 @@ DrawTargetCairo::Stroke(const Path *aPat
                         const DrawOptions &aOptions /* = DrawOptions() */)
 {
   AutoPrepareForDrawing prep(this, mContext, aPath);
 
   if (aPath->GetBackendType() != BACKEND_CAIRO)
     return;
 
   PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
-  path->CopyPathTo(mContext, this);
+  path->SetPathOnContext(mContext);
 
   DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE);
 }
 
 void
 DrawTargetCairo::Fill(const Path *aPath,
                       const Pattern &aPattern,
                       const DrawOptions &aOptions /* = DrawOptions() */)
 {
   AutoPrepareForDrawing prep(this, mContext, aPath);
 
   if (aPath->GetBackendType() != BACKEND_CAIRO)
     return;
 
   PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
-  path->CopyPathTo(mContext, this);
+  path->SetPathOnContext(mContext);
 
   DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
 }
 
 void
 DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
                             const GlyphBuffer &aBuffer,
                             const Pattern &aPattern,
@@ -847,17 +857,17 @@ DrawTargetCairo::PushClip(const Path *aP
   if (aPath->GetBackendType() != BACKEND_CAIRO) {
     return;
   }
 
   WillChange(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);
 }
 
 void
 DrawTargetCairo::PushClipRect(const Rect& aRect)
 {
   WillChange();
   cairo_save(mContext);
@@ -872,19 +882,17 @@ DrawTargetCairo::PopClip()
 {
   // save/restore does not affect the path, so no need to call WillChange()
   cairo_restore(mContext);
 }
 
 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;
 }
 
 void
 DrawTargetCairo::ClearSurfaceForUnboundedSource(const CompositionOp &aOperator)
 {
   if (aOperator != OP_SOURCE)
@@ -1101,31 +1109,16 @@ DrawTargetCairo::MarkSnapshotIndependent
     mSnapshot = nullptr;
   }
 }
 
 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
 DrawTargetCairo::SetTransform(const Matrix& aTransform)
 {
   mTransform = aTransform;
 
   cairo_matrix_t mat;
--- a/DrawTargetCairo.h
+++ b/DrawTargetCairo.h
@@ -139,24 +139,24 @@ public:
                         ExtendMode aExtendMode = EXTEND_CLAMP) const;
 
   virtual void *GetNativeSurface(NativeSurfaceType aType);
 
   bool Init(cairo_surface_t* aSurface, const IntSize& aSize);
   bool Init(const IntSize& aSize, SurfaceFormat aFormat);
   bool Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
 
-  void SetPathObserver(CairoPathContext* aPathObserver);
-
   virtual void SetTransform(const Matrix& aTransform);
 
   // Call to set up aContext for drawing (with the current transform, etc).
   // Pass the path you're going to be using if you have one.
   // 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);
 
   enum DrawPatternType { DRAW_FILL, DRAW_STROKE };
   void DrawPattern(const Pattern& aPattern,
                    const StrokeOptions& aStrokeOptions,
@@ -178,20 +178,15 @@ private: // methods
 private: // data
   cairo_t* mContext;
   cairo_surface_t* mSurface;
   IntSize mSize;
 
   // 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;
 };
 
 }
 }
 
 #endif // _MOZILLA_GFX_DRAWTARGET_CAIRO_H_
--- a/Makefile.cairo
+++ b/Makefile.cairo
@@ -2,17 +2,17 @@
 HAS_CAIRO=$(shell pkg-config cairo && echo YES)
 ifneq ($(HAS_CAIRO),YES)
 $(error Cairo package not found)
 endif
 
 CXXFLAGS += `pkg-config --cflags cairo`
 LIBS += `pkg-config --libs cairo`
 MOZ2D_PLAYER2D_LIBS += $(shell pkg-config --libs cairo)
-DEFINES  += USE_CAIRO MOZ_ENABLE_FREETYPE
+DEFINES  += USE_CAIRO MOZ_ENABLE_FREETYPE USE_CAIRO_SCALED_FONT
 
 MOZ2D_CPPSRCS += \
   DrawTargetCairo.cpp \
   PathCairo.cpp \
   ScaledFontCairo.cpp \
   SourceSurfaceCairo.cpp \
   $(NULL)
 
--- a/PathCairo.cpp
+++ b/PathCairo.cpp
@@ -8,315 +8,287 @@
 #include "DrawTargetCairo.h"
 #include "Logging.h"
 #include "PathHelpers.h"
 #include "HelpersCairo.h"
 
 namespace mozilla {
 namespace gfx {
 
-CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget)
- : mContext(aCtx)
- , mDrawTarget(aDrawTarget)
-{
-  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()
+PathBuilderCairo::PathBuilderCairo(FillRule aFillRule)
+  : mFillRule(aFillRule)
 {
-  // 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
 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.
   // This formula can be found on http://fontforge.sourceforge.net/bezier.html
   Point CP0 = CurrentPoint();
   Point CP1 = (CP0 + aCP1 * 2.0) / 3.0;
   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
 PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
                      float aEndAngle, bool aAntiClockwise)
 {
   ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
 }
 
 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
 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);
 }
 
 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
+{
+  // 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
 {
-  mPathContext->CopyPathTo(aContext, mTransform);
-  cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule));
+  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]);
+    }
+  }
 }
 
 }
 }
--- a/PathCairo.h
+++ b/PathCairo.h
@@ -3,124 +3,59 @@
  * 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_PATH_CAIRO_H_
 #define MOZILLA_GFX_PATH_CAIRO_H_
 
 #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);
   virtual void BezierTo(const Point &aCP1,
                         const Point &aCP2,
                         const Point &aCP3);
   virtual void QuadraticBezierTo(const Point &aCP1,
                                  const Point &aCP2);
   virtual void Close();
   virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle,
                    float aEndAngle, bool aAntiClockwise = false);
   virtual Point CurrentPoint() const;
   virtual TemporaryRef<Path> Finish();
 
-  TemporaryRef<CairoPathContext> GetPathContext();
+private: // data
+  friend class PathCairo;
 
-private: // data
-  void PrepareForWrite();
-
-  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; }
 
   virtual TemporaryRef<PathBuilder> CopyToBuilder(FillRule aFillRule = FILL_WINDING) const;
   virtual TemporaryRef<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
                                                              FillRule aFillRule = FILL_WINDING) const;
 
   virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
@@ -131,25 +66,24 @@ public:
 
   virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
 
   virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                                 const Matrix &aTransform = Matrix()) const;
 
   virtual FillRule GetFillRule() const { return mFillRule; }
 
-  TemporaryRef<CairoPathContext> GetPathContext();
+  void SetPathOnContext(cairo_t *aContext) const;
 
-  // 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 AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform = nullptr) const;
+private:
+  void EnsureContainingContext() const;
 
-private:
-  RefPtr<CairoPathContext> mPathContext;
-  Matrix mTransform;
   FillRule mFillRule;
+  std::vector<cairo_path_data_t> mPathData;
+  mutable cairo_t *mContainingContext;
+  Point mCurrentPoint;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_PATH_CAIRO_H_ */
--- a/ScaledFontBase.cpp
+++ b/ScaledFontBase.cpp
@@ -8,43 +8,45 @@
 #ifdef USE_SKIA
 #include "PathSkia.h"
 #include "core/SkPaint.h"
 #include "core/SkPath.h"
 #endif
 
 #ifdef USE_CAIRO
 #include "PathCairo.h"
+#include "DrawTargetCairo.h"
+#include "HelpersCairo.h"
 #endif
 
 #include <vector>
 #include <cmath>
 
 using namespace std;
 
 namespace mozilla {
 namespace gfx {
 
 ScaledFontBase::~ScaledFontBase()
 {
 #ifdef USE_SKIA
   SkSafeUnref(mTypeface);
 #endif
-#ifdef USE_CAIRO
+#ifdef USE_CAIRO_SCALED_FONT
   cairo_scaled_font_destroy(mScaledFont);
 #endif
 }
 
 ScaledFontBase::ScaledFontBase(Float aSize)
   : mSize(aSize)
 {
 #ifdef USE_SKIA
   mTypeface = nullptr;
 #endif
-#ifdef USE_CAIRO
+#ifdef USE_CAIRO_SCALED_FONT
   mScaledFont = nullptr;
 #endif
 }
 
 TemporaryRef<Path>
 ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
 {
 #ifdef USE_SKIA
@@ -69,54 +71,95 @@ ScaledFontBase::GetPathForGlyphs(const G
     paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
     return new PathSkia(path, FILL_WINDING);
   }
 #endif
 #ifdef USE_CAIRO
   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);
     for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
       glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
       glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
       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)
 {
-  // XXX - implement me
-  MOZ_ASSERT(false);
-  return;
+#ifdef USE_CAIRO
+  PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
+
+  
+  cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());
+
+  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);
+  for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
+    glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
+    glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
+    glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
+  }
+
+  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
 }
 
-#ifdef USE_CAIRO
+#ifdef USE_CAIRO_SCALED_FONT
 void
 ScaledFontBase::SetCairoScaledFont(cairo_scaled_font_t* font)
 {
   MOZ_ASSERT(!mScaledFont);
 
+  if (font == mScaledFont)
+    return;
+ 
+  if (mScaledFont)
+    cairo_scaled_font_destroy(mScaledFont);
+
   mScaledFont = font;
   cairo_scaled_font_reference(mScaledFont);
 }
 
 void
 ScaledFontBase::InitScaledFontFromFace(cairo_font_face_t* aFace)
 {
   cairo_matrix_t sizeMatrix;
--- a/ScaledFontBase.h
+++ b/ScaledFontBase.h
@@ -23,17 +23,17 @@ namespace gfx {
 class ScaledFontBase : public ScaledFont
 {
 public:
   ScaledFontBase(Float aSize);
   virtual ~ScaledFontBase();
 
   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; }
 
 #ifdef USE_SKIA
   virtual SkTypeface* GetSkTypeface() { return mTypeface; }
 #endif
 
   // Not true, but required to instantiate a ScaledFontBase.
--- a/ScaledFontCairo.cpp
+++ b/ScaledFontCairo.cpp
@@ -66,34 +66,16 @@ ScaledFontCairo::~ScaledFontCairo()
 {
 #ifdef MOZ_ENABLE_FREETYPE
   if (mFTFace) {
     FT_Done_Face(mFTFace);
   }
 #endif
 }
 
-void
-ScaledFontCairo::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder)
-{
-  PathBuilderCairo *builder = static_cast<PathBuilderCairo*>(aBuilder);
-
-  // Convert our GlyphBuffer into an array of Cairo glyphs.
-  RefPtr<CairoPathContext> context = builder->GetPathContext();
-  vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
-  for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
-    glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
-    glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
-    glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
-  }
-
-  cairo_set_scaled_font(*context, mScaledFont);
-  cairo_glyph_path(*context, &glyphs.front(), aBuffer.mNumGlyphs);
-}
-
 #if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
 SkTypeface* ScaledFontCairo::GetSkTypeface()
 {
   if (!mTypeface) {
     cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(mScaledFont);
     FT_Face face = cairo_ft_scaled_font_lock_face(mScaledFont);
 
     int style = SkTypeface::kNormal;
--- a/ScaledFontCairo.h
+++ b/ScaledFontCairo.h
@@ -14,18 +14,16 @@ namespace gfx {
 class ScaledFontCairo : public ScaledFontBase
 {
 public:
 
   ScaledFontCairo(cairo_scaled_font_t* aScaledFont, Float aSize);
   ScaledFontCairo(const uint8_t* aData, uint32_t aFileSize, uint32_t aIndex, Float aSize);
   ~ScaledFontCairo();
 
-  virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder);
-
 #if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
   virtual SkTypeface* GetSkTypeface();
 #endif
 
 private:
 #ifdef MOZ_ENABLE_FREETYPE
   FT_Face mFTFace;
 #endif
--- a/ScaledFontDWrite.cpp
+++ b/ScaledFontDWrite.cpp
@@ -319,17 +319,17 @@ ScaledFontDWrite::GetPathForGlyphs(const
     static_cast<PathBuilderD2D*>(pathBuilder.get());
 
   CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
 
   return pathBuilder->Finish();
 }
 
 void
-ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder)
+ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *)
 {
   // XXX - Check path builder type!
   PathBuilderD2D *pathBuilderD2D =
     static_cast<PathBuilderD2D*>(aBuilder);
 
   CopyGlyphsToSink(aBuffer, pathBuilderD2D->GetSink());
 }
 
--- a/ScaledFontDWrite.h
+++ b/ScaledFontDWrite.h
@@ -21,17 +21,17 @@ public:
     : mFontFace(aFont)
     , ScaledFontBase(aSize)
   {}
   ScaledFontDWrite(uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize);
 
   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);
 
   virtual bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton);
 
   virtual AntialiasMode GetDefaultAAMode();
 
 #ifdef USE_SKIA
--- a/ScaledFontNVpr.h
+++ b/ScaledFontNVpr.h
@@ -53,17 +53,18 @@ public:
 
   virtual TemporaryRef<Path> GetPathForGlyphs(const GlyphBuffer &aBuffer,
                                               const DrawTarget *aTarget)
   {
     return nullptr;
   }
 
   virtual void CopyGlyphsToBuilder(const GlyphBuffer &aBuffer,
-                                   PathBuilder *aBuilder)
+                                   PathBuilder *aBuilder,
+                                   const Matrix *aTransformHint)
   {}
 
 private:
   ScaledFontNVpr(TemporaryRef<FontNVpr> aFont, GLfloat aSize);
 
   const RefPtr<FontNVpr> mFont;
   const GLfloat mSize;
   const GLfloat mInverseSize;
--- a/gfx2d.vcxproj
+++ b/gfx2d.vcxproj
@@ -78,16 +78,18 @@
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <PreprocessorDefinitions>USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <Optimization>Disabled</Optimization>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <MinimalRebuild>false</MinimalRebuild>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Windows</SubSystem>
       <EntryPointSymbol>
       </EntryPointSymbol>
     </Link>
@@ -95,22 +97,24 @@
       <Command>
       </Command>
       <Message>
       </Message>
     </PreBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug (With Skia)|Win32'">
     <ClCompile>
-      <PreprocessorDefinitions>USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN;USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN;USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD;USE_CAIRO_SCALED_FONT</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <Optimization>Disabled</Optimization>
       <AdditionalIncludeDirectories>$(ProjectDir)/../cairo/src;$(ProjectDir)/..;$(ProjectDir)/../skia/include;$(ProjectDir)/../skia/include/core;$(ProjectDir)/../skia/include/utils;$(ProjectDir)/../skia/include/gpu;$(ProjectDir)/../skia/include/config</AdditionalIncludeDirectories>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <MinimalRebuild>false</MinimalRebuild>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Windows</SubSystem>
       <EntryPointSymbol>
       </EntryPointSymbol>
     </Link>
@@ -123,32 +127,34 @@
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <ClCompile>
       <PreprocessorDefinitions>USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <AdditionalIncludeDirectories>./</AdditionalIncludeDirectories>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Windows</SubSystem>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release (With Skia)|Win32'">
     <ClCompile>
-      <PreprocessorDefinitions>USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD</PreprocessorDefinitions>
+      <PreprocessorDefinitions>USE_NVPR;_USE_MATH_DEFINES;INITGUID;USE_D2D1_1;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions);USE_SKIA;USE_CAIRO;CAIRO_WIN32_STATIC_BUILD;USE_CAIRO_SCALED_FONT</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <AdditionalIncludeDirectories>$(ProjectDir)/../cairo/src;$(ProjectDir)/..;$(ProjectDir)/../skia/include;$(ProjectDir)/../skia/include/core;$(ProjectDir)/../skia/include/utils;$(ProjectDir)/../skia/include/gpu;$(ProjectDir)/../skia/include/config</AdditionalIncludeDirectories>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
     </ClCompile>
     <Link>
       <TargetMachine>MachineX86</TargetMachine>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Windows</SubSystem>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
     </Link>