Bug 376929 - Remove direct use of cairo from SVG path generation.r=jwatt, sr=roc
authortor@cs.brown.edu
Mon, 16 Apr 2007 13:57:09 -0700
changeset 565 5715af6a3dcd07679bfa45592a07e2bcfdd5fce3
parent 564 093fd63f120523ff3218e095f64b339cd9a46f6e
child 566 28d0baf84fba7352b3f986f66f50f9f8518cabcb
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt, roc
bugs376929
milestone1.9a4pre
Bug 376929 - Remove direct use of cairo from SVG path generation.r=jwatt, sr=roc
content/svg/content/src/nsSVGCircleElement.cpp
content/svg/content/src/nsSVGEllipseElement.cpp
content/svg/content/src/nsSVGImageElement.cpp
content/svg/content/src/nsSVGLineElement.cpp
content/svg/content/src/nsSVGMatrix.h
content/svg/content/src/nsSVGPathDataParser.h
content/svg/content/src/nsSVGPathElement.cpp
content/svg/content/src/nsSVGPathElement.h
content/svg/content/src/nsSVGPathGeometryElement.cpp
content/svg/content/src/nsSVGPathGeometryElement.h
content/svg/content/src/nsSVGPolyElement.cpp
content/svg/content/src/nsSVGPolyElement.h
content/svg/content/src/nsSVGPolygonElement.cpp
content/svg/content/src/nsSVGRectElement.cpp
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/svg/base/src/nsSVGGlyphFrame.h
layout/svg/base/src/nsSVGPathGeometryFrame.cpp
layout/svg/base/src/nsSVGTextFrame.cpp
layout/svg/base/src/nsSVGTextPathFrame.cpp
layout/svg/base/src/nsSVGTextPathFrame.h
--- a/content/svg/content/src/nsSVGCircleElement.cpp
+++ b/content/svg/content/src/nsSVGCircleElement.cpp
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGCircleElement.h"
 #include "nsSVGLength2.h"
 #include "nsGkAtoms.h"
 #include "nsSVGUtils.h"
+#include "gfxContext.h"
 
 typedef nsSVGPathGeometryElement nsSVGCircleElementBase;
 
 class nsSVGCircleElement : public nsSVGCircleElementBase,
                            public nsIDOMSVGCircleElement
 {
 protected:
   friend nsresult NS_NewSVGCircleElement(nsIContent **aResult,
@@ -58,17 +59,17 @@ public:
   NS_DECL_NSIDOMSVGCIRCLEELEMENT
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGCircleElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGCircleElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGCircleElementBase::)
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
 
   enum { CX, CY, R };
@@ -142,17 +143,17 @@ nsSVGCircleElement::GetLengthInfo()
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               NS_ARRAY_LENGTH(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 void
-nsSVGCircleElement::ConstructPath(cairo_t *aCtx)
+nsSVGCircleElement::ConstructPath(gfxContext *aCtx)
 {
   float x, y, r;
 
   GetAnimatedLengthValues(&x, &y, &r, nsnull);
 
   if (r > 0.0f)
-    cairo_arc(aCtx, x, y, r, 0, 2*M_PI);
+    aCtx->Arc(gfxPoint(x, y), r, 0, 2*M_PI);
 }
--- a/content/svg/content/src/nsSVGEllipseElement.cpp
+++ b/content/svg/content/src/nsSVGEllipseElement.cpp
@@ -37,16 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGEllipseElement.h"
 #include "nsSVGLength2.h"
 #include "nsGkAtoms.h"
 #include "nsSVGUtils.h"
+#include "gfxContext.h"
 
 typedef nsSVGPathGeometryElement nsSVGEllipseElementBase;
 
 class nsSVGEllipseElement : public nsSVGEllipseElementBase,
                             public nsIDOMSVGEllipseElement
 {
 protected:
   friend nsresult NS_NewSVGEllipseElement(nsIContent **aResult,
@@ -59,17 +60,17 @@ public:
   NS_DECL_NSIDOMSVGELLIPSEELEMENT
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGEllipseElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGEllipseElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGEllipseElementBase::)
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
 
   enum { CX, CY, RX, RY };
@@ -150,22 +151,22 @@ nsSVGEllipseElement::GetLengthInfo()
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               NS_ARRAY_LENGTH(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 void
-nsSVGEllipseElement::ConstructPath(cairo_t *aCtx)
+nsSVGEllipseElement::ConstructPath(gfxContext *aCtx)
 {
   float x, y, rx, ry;
 
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nsnull);
 
   if (rx > 0.0f && ry > 0.0f) {
-    cairo_save(aCtx);
-    cairo_translate(aCtx, x, y);
-    cairo_scale(aCtx, rx, ry);
-    cairo_arc(aCtx, 0, 0, 1, 0, 2 * M_PI);
-    cairo_restore(aCtx);
+    aCtx->Save();
+    aCtx->Translate(gfxPoint(x, y));
+    aCtx->Scale(rx, ry);
+    aCtx->Arc(gfxPoint(0, 0), 1, 0, 2 * M_PI);
+    aCtx->Restore();
   }
 }
--- a/content/svg/content/src/nsSVGImageElement.cpp
+++ b/content/svg/content/src/nsSVGImageElement.cpp
@@ -47,16 +47,17 @@
 #include "nsSVGPreserveAspectRatio.h"
 #include "imgIContainer.h"
 #include "imgIDecoderObserver.h"
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGImageElement.h"
 #include "nsIDOMSVGURIReference.h"
 #include "nsImageLoadingContent.h"
 #include "nsSVGLength2.h"
+#include "gfxContext.h"
 
 class nsIDOMSVGAnimatedString;
 class nsIDOMSVGAnimatedPreserveAspectRatio;
 
 typedef nsSVGPathGeometryElement nsSVGImageElementBase;
 
 class nsSVGImageElement : public nsSVGImageElementBase,
                           public nsIDOMSVGImageElement,
@@ -91,17 +92,17 @@ public:
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers);
 
   virtual PRInt32 IntrinsicState() const;
 
   NS_IMETHODIMP_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
 
   void GetSrc(nsAString& src);
@@ -348,19 +349,19 @@ nsSVGImageElement::IsAttributeMapped(con
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 /* For the purposes of the update/invalidation logic pretend to
    be a rectangle. */
 void
-nsSVGImageElement::ConstructPath(cairo_t *aCtx)
+nsSVGImageElement::ConstructPath(gfxContext *aCtx)
 {
   float x, y, width, height;
 
   GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
 
   if (width == 0 || height == 0)
     return;
 
-  cairo_rectangle(aCtx, x, y, width, height);
+  aCtx->Rectangle(gfxRect(x, y, width, height));
 }
--- a/content/svg/content/src/nsSVGLineElement.cpp
+++ b/content/svg/content/src/nsSVGLineElement.cpp
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGLineElement.h"
 #include "nsSVGLength2.h"
 #include "nsGkAtoms.h"
+#include "gfxContext.h"
 
 typedef nsSVGPathGeometryElement nsSVGLineElementBase;
 
 class nsSVGLineElement : public nsSVGLineElementBase,
                          public nsIDOMSVGLineElement
 {
 protected:
   friend nsresult NS_NewSVGLineElement(nsIContent **aResult,
@@ -63,17 +64,17 @@ public:
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGLineElementBase::)
 
   // nsIContent interface
   NS_IMETHODIMP_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
 
   // nsSVGPathGeometryElement methods:
   virtual PRBool IsMarkable() { return PR_TRUE; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
 
   enum { X1, Y1, X2, Y2 };
@@ -180,17 +181,17 @@ nsSVGLineElement::GetMarkPoints(nsTArray
 
   float angle = atan2(y2 - y1, x2 - x1);
 
   aMarks->AppendElement(nsSVGMark(x1, y1, angle));
   aMarks->AppendElement(nsSVGMark(x2, y2, angle));
 }
 
 void
-nsSVGLineElement::ConstructPath(cairo_t *aCtx)
+nsSVGLineElement::ConstructPath(gfxContext *aCtx)
 {
   float x1, y1, x2, y2;
 
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nsnull);
 
-  cairo_move_to(aCtx, x1, y1);
-  cairo_line_to(aCtx, x2, y2);
+  aCtx->MoveTo(gfxPoint(x1, y1));
+  aCtx->LineTo(gfxPoint(x2, y2));
 }
--- a/content/svg/content/src/nsSVGMatrix.h
+++ b/content/svg/content/src/nsSVGMatrix.h
@@ -35,17 +35,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __NS_SVGMATRIX_H__
 #define __NS_SVGMATRIX_H__
 
 #include "nsIDOMSVGMatrix.h"
-#include "cairo.h"
 
 nsresult
 NS_NewSVGMatrix(nsIDOMSVGMatrix** result,
                 float a = 1.0f, float b = 0.0f,
                 float c = 0.0f, float d = 1.0f,
                 float e = 0.0f, float f = 0.0f);
 
 #endif //__NS_SVGMATRIX_H__
--- a/content/svg/content/src/nsSVGPathDataParser.h
+++ b/content/svg/content/src/nsSVGPathDataParser.h
@@ -40,17 +40,16 @@
 #define __NS_SVGPATHDATAPARSER_H__
 
 #include "nsSVGDataParser.h"
 #include "nsCOMPtr.h"
 #include "nsVoidArray.h"
 #include "nsCOMArray.h"
 #include "nsIDOMSVGPathSeg.h"
 #include "nsTArray.h"
-#include <cairo.h>
 
 class nsSVGPathList;
 
 ////////////////////////////////////////////////////////////////////////
 // nsSVGPathDataParser: a simple recursive descent parser that builds
 // nsIDOMPathSegs from path data strings. The grammar for path data
 // can be found in SVG CR 20001102, chapter 8.
 
--- a/content/svg/content/src/nsSVGPathElement.cpp
+++ b/content/svg/content/src/nsSVGPathElement.cpp
@@ -42,16 +42,17 @@
 #include "nsSVGPathSeg.h"
 #include "nsCOMPtr.h"
 #include "nsIFrame.h"
 #include "nsSVGPathDataParser.h"
 #include "nsSVGPathElement.h"
 #include "nsISVGValueUtils.h"
 #include "nsSVGUtils.h"
 #include "nsSVGPoint.h"
+#include "gfxContext.h"
 
 nsSVGElement::NumberInfo nsSVGPathElement::sNumberInfo = 
                                                   { &nsGkAtoms::pathLength, 0 };
 
 NS_IMPL_NS_NEW_SVG_ELEMENT(Path)
 
 //----------------------------------------------------------------------
 // nsISupports methods
@@ -98,46 +99,45 @@ nsSVGPathElement::GetPathLength(nsIDOMSV
 }
 
 /* float getTotalLength (); */
 NS_IMETHODIMP
 nsSVGPathElement::GetTotalLength(float *_retval)
 {
   *_retval = 0;
 
-  nsAutoPtr<nsSVGFlattenedPath> flat(GetFlattenedPath(nsnull));
+  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(nsnull);
 
   if (!flat)
     return NS_ERROR_FAILURE;
 
   *_retval = flat->GetLength();
 
   return NS_OK;
 }
 
 /* nsIDOMSVGPoint getPointAtLength (in float distance); */
 NS_IMETHODIMP
 nsSVGPathElement::GetPointAtLength(float distance, nsIDOMSVGPoint **_retval)
 {
-  nsAutoPtr<nsSVGFlattenedPath> flat(GetFlattenedPath(nsnull));
+  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(nsnull);
   if (!flat)
     return NS_ERROR_FAILURE;
 
   float totalLength = flat->GetLength();
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::pathLength)) {
     float pathLength = mPathLength.GetAnimValue();
     distance *= totalLength / pathLength;
   }
   distance = PR_MAX(0,           distance);
   distance = PR_MIN(totalLength, distance);
 
-  float x, y, angle;
-  flat->FindPoint(0, distance, 0, &x, &y, &angle);
+  gfxPoint pt = flat->FindPoint(gfxPoint(distance, 0));
 
-  return NS_NewSVGPoint(_retval, x, y);
+  return NS_NewSVGPoint(_retval, pt.x, pt.y);
 }
 
 /* unsigned long getPathSegAtLength (in float distance); */
 NS_IMETHODIMP
 nsSVGPathElement::GetPathSegAtLength(float distance, PRUint32 *_retval)
 {
   //Check if mSegments is null
   nsresult rv = CreatePathSegList();
@@ -466,53 +466,30 @@ nsSVGPathElement::DidModifySVGObservable
     mSegments = deathGrip;
 
     return rv;
   }
 
   return nsSVGPathElementBase::DidModifySVGObservable(observable, aModType);
 }
 
-nsSVGFlattenedPath *
+already_AddRefed<gfxFlattenedPath>
 nsSVGPathElement::GetFlattenedPath(nsIDOMSVGMatrix *aMatrix)
 {
-  cairo_surface_t *dummySurface =
-    cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
-  if (!dummySurface)
-    return nsnull;
-
-  cairo_t *ctx = cairo_create(dummySurface);
-  if (cairo_status(ctx) != CAIRO_STATUS_SUCCESS) {
-    cairo_destroy(ctx);
-    cairo_surface_destroy(dummySurface);
-    return nsnull;
-  }
+  gfxContext ctx(nsSVGUtils::GetThebesComputationalSurface());
 
   if (aMatrix) {
-    cairo_matrix_t matrix = nsSVGUtils::ConvertSVGMatrixToCairo(aMatrix);
-    cairo_set_matrix(ctx, &matrix);
+    ctx.SetMatrix(nsSVGUtils::ConvertSVGMatrixToThebes(aMatrix));
   }
 
-  mPathData.Playback(ctx);
-
-  cairo_identity_matrix(ctx);
-
-  cairo_path_t *path = cairo_copy_path_flat(ctx);
-
-  cairo_destroy(ctx);
-  cairo_surface_destroy(dummySurface);
+  mPathData.Playback(&ctx);
 
-  if (!path)
-    return nsnull;
+  ctx.IdentityMatrix();
 
-  nsSVGFlattenedPath *retval = new nsSVGFlattenedPath(path);
-  if (!retval)
-    cairo_path_destroy(path);
-
-  return retval;
+  return ctx.GetFlattenedPath();
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 PRBool
 nsSVGPathElement::IsDependentAttribute(nsIAtom *aName)
 {
@@ -989,132 +966,44 @@ nsSVGPathList::Clear()
     free(mArguments);
     mArguments = nsnull;
   }
   mNumCommands = 0;
   mNumArguments = 0;
 }
 
 void
-nsSVGPathList::Playback(cairo_t *aCtx)
+nsSVGPathList::Playback(gfxContext *aCtx)
 {
   float *args = mArguments;
   for (PRUint32 i = 0; i < mNumCommands; i++) {
     PRUint8 command =
       NS_REINTERPRET_CAST(PRUint8*, mArguments + mNumArguments)[i / 4];
     command = (command >> (2 * (i % 4))) & 0x3;
     switch (command) {
     case MOVETO:
-      cairo_move_to(aCtx, args[0], args[1]);
+      aCtx->MoveTo(gfxPoint(args[0], args[1]));
       args += 2;
       break;
     case LINETO:
-      cairo_line_to(aCtx, args[0], args[1]);
+      aCtx->LineTo(gfxPoint(args[0], args[1]));
       args += 2;
       break;
     case CURVETO:
-      cairo_curve_to(aCtx,
-                     args[0], args[1], args[2], args[3], args[4], args[5]);
+      aCtx->CurveTo(gfxPoint(args[0], args[1]),
+                    gfxPoint(args[2], args[3]),
+                    gfxPoint(args[4], args[5]));
       args += 6;
       break;
     case CLOSEPATH:
-      cairo_close_path(aCtx);
+      aCtx->ClosePath();
       break;
     default:
       break;
     }
   }
 }
 
-//==================================================================
-// nsSVGFlattenedPath
-
-static float
-CalcSubLengthAndAdvance(cairo_path_data_t *aData,
-                        float *aPathStartX, float *aPathStartY,
-                        float *aCurrentX, float *aCurrentY)
-{
-  float sublength = 0;
-
-  switch (aData->header.type) {
-    case CAIRO_PATH_MOVE_TO:
-    {
-      *aCurrentX = *aPathStartX = aData[1].point.x;
-      *aCurrentY = *aPathStartY = aData[1].point.y;
-      break;
-    }
-    case CAIRO_PATH_LINE_TO:
-    {
-      float dx = aData[1].point.x - *aCurrentX;
-      float dy = aData[1].point.y - *aCurrentY;
-      sublength = sqrt(dx * dx + dy * dy);
-      *aCurrentX = aData[1].point.x;
-      *aCurrentY = aData[1].point.y;
-      break;
-    }
-    case CAIRO_PATH_CURVE_TO:
-      /* should never happen with a flattened path */
-      NS_WARNING("curve_to in flattened path");
-      break;
-    case CAIRO_PATH_CLOSE_PATH:
-    {
-      float dx = *aPathStartX - *aCurrentX;
-      float dy = *aPathStartY - *aCurrentY;
-      sublength = sqrt(dx * dx + dy * dy);
-      *aCurrentX = *aPathStartX;
-      *aCurrentY = *aPathStartY;
-      break;
-    }
-  }
-  return sublength;
-}
-
-float
-nsSVGFlattenedPath::GetLength()
-{
-  float length = 0;      // current summed length
-  float sx = 0, sy = 0;  // start of current subpath
-  float x = 0, y = 0;    // current point
-
-  for (PRInt32 i = 0; i < mPath->num_data; i += mPath->data[i].header.length) {
-    length += CalcSubLengthAndAdvance(&mPath->data[i], &sx, &sy, &x, &y);
-  }
-  return length;
-}
-
 void
-nsSVGFlattenedPath::FindPoint(float aAdvance, float aXOffset, float aYOffset,
-                              float *aX, float *aY, float *aAngle)
-{
-  float length = 0;      // current summed length
-  float sx = 0, sy = 0;  // start of current subpath
-  float x = 0, y = 0;    // current point
-  float midpoint = aXOffset + aAdvance/2;
-
-  for (PRInt32 i = 0; i < mPath->num_data; i += mPath->data[i].header.length) {
-    float prevX = x;
-    float prevY = y;
-    float sublength = CalcSubLengthAndAdvance(&mPath->data[i],
-                                              &sx, &sy, &x, &y);
-
-    if (sublength != 0 && length + sublength >= midpoint) {
-      float ratio = (aXOffset - length) / sublength;
-      *aX = prevX * (1.0f - ratio) + x * ratio;
-      *aY = prevY * (1.0f - ratio) + y * ratio;
-
-      float dx = x - prevX;
-      float dy = y - prevY;
-      *aAngle = atan2(dy, dx);
-
-      float normalization = 1.0 / sqrt(dx * dx + dy * dy);
-      *aX += - aYOffset * dy * normalization;
-      *aY +=   aYOffset * dx * normalization;
-      return;
-    }
-    length += sublength;
-  }
-}
-
-void
-nsSVGPathElement::ConstructPath(cairo_t *aCtx)
+nsSVGPathElement::ConstructPath(gfxContext *aCtx)
 {
   mPathData.Playback(aCtx);
 }
--- a/content/svg/content/src/nsSVGPathElement.h
+++ b/content/svg/content/src/nsSVGPathElement.h
@@ -38,55 +38,38 @@
 
 #ifndef __NS_SVGPATHELEMENT_H__
 #define __NS_SVGPATHELEMENT_H__
 
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGPathElement.h"
 #include "nsIDOMSVGAnimatedPathData.h"
 #include "nsSVGNumber2.h"
-#include "cairo.h"
+#include "gfxPath.h"
+
+class gfxContext;
 
 class nsSVGPathList
 {
 friend class nsSVGPathDataParserToInternal;
 
 public:
   enum { MOVETO, LINETO, CURVETO, CLOSEPATH };
   nsSVGPathList() : mArguments(nsnull), mNumCommands(0), mNumArguments(0) {}
   ~nsSVGPathList() { Clear(); }
-  void Playback(cairo_t *aCtx);
+  void Playback(gfxContext *aCtx);
 
 protected:
   void Clear();
 
   float   *mArguments;
   PRUint32 mNumCommands;
   PRUint32 mNumArguments;
 };
 
-class nsSVGFlattenedPath
-{
-private:
-  cairo_path_t *mPath;
-
-public:
-  nsSVGFlattenedPath(cairo_path_t *aPath) : mPath(aPath) {}
-  ~nsSVGFlattenedPath() { if (mPath) cairo_path_destroy(mPath); }
-
-  // Returns calculated length of path
-  float GetLength();
-
-  // Finds a point aXOffset along this path, for a character with
-  // aAdvance wide, offset from the path by aYOffset.  Returns
-  // position and angle.
-  void FindPoint(float aAdvance, float aXOffset, float aYOffset,
-                 float *aX, float *aY, float *aAngle);
-};
-
 typedef nsSVGPathGeometryElement nsSVGPathElementBase;
 
 class nsSVGPathElement : public nsSVGPathElementBase,
                          public nsIDOMSVGPathElement,
                          public nsIDOMSVGAnimatedPathData
 {
 friend class nsSVGPathFrame;
 
@@ -114,19 +97,19 @@ public:
   // nsISVGValueObserver
   NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable,
                                      nsISVGValue::modificationType aModType);
 
   // nsSVGPathGeometryElement methods:
   virtual PRBool IsDependentAttribute(nsIAtom *aName);
   virtual PRBool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
-  virtual nsSVGFlattenedPath *GetFlattenedPath(nsIDOMSVGMatrix *aMatrix);
+  virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(nsIDOMSVGMatrix *aMatrix);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual NumberAttributesInfo GetNumberInfo();
   virtual nsresult BeforeSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
                                  const nsAString* aValue, PRBool aNotify);
--- a/content/svg/content/src/nsSVGPathGeometryElement.cpp
+++ b/content/svg/content/src/nsSVGPathGeometryElement.cpp
@@ -61,13 +61,13 @@ nsSVGPathGeometryElement::IsMarkable()
   return PR_FALSE;
 }
 
 void
 nsSVGPathGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
 {
 }
 
-nsSVGFlattenedPath *
+already_AddRefed<gfxFlattenedPath>
 nsSVGPathGeometryElement::GetFlattenedPath(nsIDOMSVGMatrix *aMatrix)
 {
   return nsnull;
 }
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -34,34 +34,34 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __NS_SVGPATHGEOMETRYELEMENT_H__
 #define __NS_SVGPATHGEOMETRYELEMENT_H__
 
 #include "nsSVGGraphicElement.h"
 #include "nsTArray.h"
-#include "cairo.h"
+#include "gfxPath.h"
 
 struct nsSVGMark {
   float x, y, angle;
   nsSVGMark(float aX, float aY, float aAngle) :
     x(aX), y(aY), angle(aAngle) {}
 };
 
-class nsSVGFlattenedPath;
 class nsIDOMSVGMatrix;
+class gfxContext;
 
 typedef nsSVGGraphicElement nsSVGPathGeometryElementBase;
 
 class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
 {
 public:
   nsSVGPathGeometryElement(nsINodeInfo *aNodeInfo);
 
   virtual PRBool IsDependentAttribute(nsIAtom *aName);
   virtual PRBool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
-  virtual void ConstructPath(cairo_t *aCtx) = 0;
-  virtual nsSVGFlattenedPath *GetFlattenedPath(nsIDOMSVGMatrix *aMatrix);
+  virtual void ConstructPath(gfxContext *aCtx) = 0;
+  virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(nsIDOMSVGMatrix *aMatrix);
 };
 
 #endif
--- a/content/svg/content/src/nsSVGPolyElement.cpp
+++ b/content/svg/content/src/nsSVGPolyElement.cpp
@@ -30,16 +30,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPolyElement.h"
+#include "gfxContext.h"
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase)
 NS_IMPL_RELEASE_INHERITED(nsSVGPolyElement,nsSVGPolyElementBase)
 
 NS_INTERFACE_MAP_BEGIN(nsSVGPolyElement)
@@ -153,17 +154,17 @@ nsSVGPolyElement::GetMarkPoints(nsTArray
     px = x;
     py = y;
   }
 
   aMarks->ElementAt(aMarks->Length() - 1).angle = prevAngle;
 }
 
 void
-nsSVGPolyElement::ConstructPath(cairo_t *aCtx)
+nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
 {
   if (!mPoints)
     return;
 
   PRUint32 count;
   mPoints->GetNumberOfItems(&count);
   if (count == 0)
     return;
@@ -172,14 +173,14 @@ nsSVGPolyElement::ConstructPath(cairo_t 
   for (i = 0; i < count; ++i) {
     nsCOMPtr<nsIDOMSVGPoint> point;
     mPoints->GetItem(i, getter_AddRefs(point));
 
     float x, y;
     point->GetX(&x);
     point->GetY(&y);
     if (i == 0)
-      cairo_move_to(aCtx, x, y);
+      aCtx->MoveTo(gfxPoint(x, y));
     else
-      cairo_line_to(aCtx, x, y);
+      aCtx->LineTo(gfxPoint(x, y));
   }
 }
 
--- a/content/svg/content/src/nsSVGPolyElement.h
+++ b/content/svg/content/src/nsSVGPolyElement.h
@@ -38,16 +38,18 @@
 #include "nsCOMPtr.h"
 #include "nsIDOMSVGPoint.h"
 #include "nsSVGPointList.h"
 #include "nsIDOMSVGAnimatedPoints.h"
 #include "nsSVGUtils.h"
 
 typedef nsSVGPathGeometryElement nsSVGPolyElementBase;
 
+class gfxContext;
+
 class nsSVGPolyElement : public nsSVGPolyElementBase,
                          public nsIDOMSVGAnimatedPoints
 {
 protected:
   nsSVGPolyElement(nsINodeInfo* aNodeInfo);
   nsresult Init();
 
 public:
@@ -58,15 +60,15 @@ public:
 
   // nsIContent interface
   NS_IMETHODIMP_(PRBool) IsAttributeMapped(const nsIAtom* name) const;
   
   // nsSVGPathGeometryElement methods:
   virtual PRBool IsDependentAttribute(nsIAtom *aName);
   virtual PRBool IsMarkable() { return PR_TRUE; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
 protected:
   nsCOMPtr<nsIDOMSVGPointList> mPoints;
 
 };
 
--- a/content/svg/content/src/nsSVGPolygonElement.cpp
+++ b/content/svg/content/src/nsSVGPolygonElement.cpp
@@ -33,16 +33,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPolyElement.h"
 #include "nsIDOMSVGPolygonElement.h"
+#include "gfxContext.h"
 
 typedef nsSVGPolyElement nsSVGPolygonElementBase;
 
 class nsSVGPolygonElement : public nsSVGPolygonElementBase,
                             public nsIDOMSVGPolygonElement
 {
 protected:
   friend nsresult NS_NewSVGPolygonElement(nsIContent **aResult,
@@ -57,17 +58,17 @@ public:
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGPolygonElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGPolygonElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGPolygonElementBase::)
 
   // nsSVGPathGeometryElement methods:
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 };
 
 NS_IMPL_NS_NEW_SVG_ELEMENT(Polygon)
 
 //----------------------------------------------------------------------
 // nsISupports methods
@@ -110,17 +111,17 @@ nsSVGPolygonElement::GetMarkPoints(nsTAr
     float angle = atan2(startMark->y - endMark->y, startMark->x - endMark->x);
 
     endMark->angle = nsSVGUtils::AngleBisect(angle, endMark->angle);
     startMark->angle = nsSVGUtils::AngleBisect(angle, startMark->angle);
   }
 }
 
 void
-nsSVGPolygonElement::ConstructPath(cairo_t *aCtx)
+nsSVGPolygonElement::ConstructPath(gfxContext *aCtx)
 {
   nsSVGPolygonElementBase::ConstructPath(aCtx);
   // the difference between a polyline and a polygon is that the
   // polygon is closed:
-  cairo_close_path(aCtx);
+  aCtx->ClosePath();
 }
 
 
--- a/content/svg/content/src/nsSVGRectElement.cpp
+++ b/content/svg/content/src/nsSVGRectElement.cpp
@@ -36,16 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGPathGeometryElement.h"
 #include "nsIDOMSVGRectElement.h"
 #include "nsSVGLength2.h"
 #include "nsGkAtoms.h"
+#include "gfxContext.h"
 
 typedef nsSVGPathGeometryElement nsSVGRectElementBase;
 
 class nsSVGRectElement : public nsSVGRectElementBase,
                          public nsIDOMSVGRectElement
 {
 protected:
   friend nsresult NS_NewSVGRectElement(nsIContent **aResult,
@@ -58,17 +59,17 @@ public:
   NS_DECL_NSIDOMSVGRECTELEMENT
 
   // xxx I wish we could use virtual inheritance
   NS_FORWARD_NSIDOMNODE(nsSVGRectElementBase::)
   NS_FORWARD_NSIDOMELEMENT(nsSVGRectElementBase::)
   NS_FORWARD_NSIDOMSVGELEMENT(nsSVGRectElementBase::)
 
   // nsSVGPathGeometryElement methods:
-  virtual void ConstructPath(cairo_t *aCtx);
+  virtual void ConstructPath(gfxContext *aCtx);
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
 protected:
 
   virtual LengthAttributesInfo GetLengthInfo();
  
   enum { X, Y, WIDTH, HEIGHT, RX, RY };
@@ -163,30 +164,30 @@ nsSVGRectElement::GetLengthInfo()
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               NS_ARRAY_LENGTH(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 void
-nsSVGRectElement::ConstructPath(cairo_t *aCtx)
+nsSVGRectElement::ConstructPath(gfxContext *aCtx)
 {
   float x, y, width, height, rx, ry;
 
   GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nsnull);
 
   /* In a perfect world, this would be handled by the DOM, and
      return a DOM exception. */
   if (width <= 0 || height <= 0 || ry < 0 || rx < 0)
     return;
 
   /* optimize the no rounded corners case */
   if (rx == 0 && ry == 0) {
-    cairo_rectangle(aCtx, x, y, width, height);
+    aCtx->Rectangle(gfxRect(x, y, width, height));
     return;
   }
 
   /* Clamp rx and ry to half the rect's width and height respectively. */
   float halfWidth  = width/2;
   float halfHeight = height/2;
   if (rx > halfWidth)
     rx = halfWidth;
@@ -213,31 +214,35 @@ nsSVGRectElement::ConstructPath(cairo_t 
 
   // Conversion factor used for ellipse to bezier conversion.
   // Gives radial error of 0.0273% in circular case.
   // See comp.graphics.algorithms FAQ 4.04
   const float magic = 4*(sqrt(2.)-1)/3;
   const float magic_x = magic*rx;
   const float magic_y = magic*ry;
 
-  cairo_move_to(aCtx, x+rx, y);
-  cairo_line_to(aCtx, x+width-rx, y);
-  cairo_curve_to(aCtx,
-                 x+width-rx + magic_x, y,
-                 x+width, y+ry-magic_y,
-                 x+width, y+ry);
-  cairo_line_to(aCtx, x+width, y+height-ry);
-  cairo_curve_to(aCtx,
-                 x+width, y+height-ry + magic_y,
-                 x+width-rx + magic_x, y+height,
-                 x+width-rx, y+height);
-  cairo_line_to(aCtx, x+rx, y+height);
-  cairo_curve_to(aCtx,
-                 x+rx - magic_x, y+height,
-                 x, y+height-ry + magic_y,
-                 x, y+height-ry);
-  cairo_line_to(aCtx, x, y+ry);
-  cairo_curve_to(aCtx,
-                 x, y+ry - magic_y,
-                 x+rx - magic_x, y,
-                 x+rx, y);
-  cairo_close_path(aCtx);
+  aCtx->MoveTo(gfxPoint(x + rx, y));
+  aCtx->LineTo(gfxPoint(x + width - rx, y));
+
+  aCtx->CurveTo(gfxPoint(x + width - rx + magic_x, y),
+                gfxPoint(x + width, y + ry - magic_y),
+                gfxPoint(x + width, y + ry));
+
+  aCtx->LineTo(gfxPoint(x + width, y + height - ry));
+
+  aCtx->CurveTo(gfxPoint(x + width, y + height - ry + magic_y),
+                gfxPoint(x + width - rx + magic_x, y+height),
+                gfxPoint(x + width - rx, y + height));
+
+  aCtx->LineTo(gfxPoint(x + rx, y + height));
+
+  aCtx->CurveTo(gfxPoint(x + rx - magic_x, y + height),
+                gfxPoint(x, y + height - ry + magic_y),
+                gfxPoint(x, y + height - ry));
+
+  aCtx->LineTo(gfxPoint(x, y + ry));
+
+  aCtx->CurveTo(gfxPoint(x, y + ry - magic_y),
+                gfxPoint(x + rx - magic_x, y),
+                gfxPoint(x + rx, y));
+
+  aCtx->ClosePath();
 }
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -551,17 +551,17 @@ nsSVGGlyphFrame::GetCharacterPosition(gf
 
   nsSVGTextPathFrame *textPath = FindTextPathParent();
 
   /* we're an ordinary fragment - return */
   /* XXX: we might want to use this for individual x/y/dx/dy adjustment */
   if (!textPath)
     return NS_OK;
 
-  nsAutoPtr<nsSVGFlattenedPath> data(textPath->GetFlattenedPath());
+  nsRefPtr<gfxFlattenedPath> data = textPath->GetFlattenedPath();
 
   /* textPath frame, but invalid target */
   if (!data)
     return NS_ERROR_FAILURE;
 
   float length = data->GetLength();
   PRUint32 strLength = aText.Length();
 
@@ -573,35 +573,35 @@ nsSVGGlyphFrame::GetCharacterPosition(gf
   float x = mX;
   for (PRUint32 i = 0; i < strLength; i++) {
 
     cairo_text_extents_t extent;
 
     cairo_text_extents(ctx,
                        NS_ConvertUTF16toUTF8(Substring(aText, i, 1)).get(),
                        &extent);
-    float advance = extent.x_advance;
+    float halfAdvance = extent.x_advance / 2.0;
 
     /* have we run off the end of the path? */
-    if (x + advance / 2 > length)
+    if (x + halfAdvance > length)
       break;
 
     /* check that we've advanced to the start of the path */
-    if (x + advance / 2 >= 0.0f) {
+    if (x + halfAdvance >= 0.0f) {
       cp[i].draw = PR_TRUE;
 
       // add y (normal)
       // add rotation
       // move point back along tangent
-      data->FindPoint(advance, x, mY,
-                      &(cp[i].x),
-                      &(cp[i].y),
-                      &(cp[i].angle));
+      gfxPoint pt = data->FindPoint(gfxPoint(x + halfAdvance, mY),
+                                    &(cp[i].angle));
+      cp[i].x = pt.x - cos(cp[i].angle) * halfAdvance;
+      cp[i].y = pt.y - sin(cp[i].angle) * halfAdvance;
     }
-    x += advance;
+    x += 2 * halfAdvance;
   }
 
   *aCharacterPosition = cp;
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
--- a/layout/svg/base/src/nsSVGGlyphFrame.h
+++ b/layout/svg/base/src/nsSVGGlyphFrame.h
@@ -146,19 +146,19 @@ public:
   NS_IMETHOD_(float) GetSubStringLength(PRUint32 charnum, PRUint32 fragmentChars);
   NS_IMETHOD_(PRInt32) GetCharNumAtPosition(nsIDOMSVGPoint *point);
   NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetFirstGlyphFragment();
   NS_IMETHOD_(nsISVGGlyphFragmentLeaf *) GetNextGlyphFragment();
   NS_IMETHOD_(void) SetWhitespaceHandling(PRUint8 aWhitespaceHandling);
 
 protected:
   struct nsSVGCharacterPosition {
-    PRBool draw;
+    gfxFloat angle;
     float x, y;
-    float angle;
+    PRBool draw;
   };
 
   // VC6 does not allow the inner class to access protected members
   // of the outer class
   class nsSVGAutoGlyphHelperContext;
   friend class nsSVGAutoGlyphHelperContext;
 
   // A helper class to deal with temporary cairo contexts.
--- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp
@@ -664,28 +664,27 @@ nsSVGPathGeometryFrame::Render(nsSVGRend
 void
 nsSVGPathGeometryFrame::GeneratePath(gfxContext* aContext)
 {
   nsCOMPtr<nsIDOMSVGMatrix> ctm;
   GetCanvasTM(getter_AddRefs(ctm));
   NS_ASSERTION(ctm, "graphic source didn't specify a ctm");
 
   gfxMatrix matrix = nsSVGUtils::ConvertSVGMatrixToThebes(ctm);
-  cairo_t *ctx = aContext->GetCairo();
 
   if (matrix.IsSingular()) {
     aContext->IdentityMatrix();
     aContext->NewPath();
     return;
   }
 
   aContext->Multiply(matrix);
 
   aContext->NewPath();
-  NS_STATIC_CAST(nsSVGPathGeometryElement*, mContent)->ConstructPath(ctx);
+  NS_STATIC_CAST(nsSVGPathGeometryElement*, mContent)->ConstructPath(aContext);
 }
 
 PRUint16
 nsSVGPathGeometryFrame::GetHittestMask()
 {
   PRUint16 mask = 0;
 
   switch(GetStyleSVG()->mPointerEvents) {
--- a/layout/svg/base/src/nsSVGTextFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextFrame.cpp
@@ -315,17 +315,17 @@ GetSingleValue(nsISVGGlyphFragmentLeaf *
   if (count) {
     nsCOMPtr<nsIDOMSVGLength> length;
     list->GetItem(0, getter_AddRefs(length));
     length->GetValue(val);
 
     nsSVGTextPathFrame *textPath = fragment->FindTextPathParent();
 
     if (textPath) {
-      nsAutoPtr<nsSVGFlattenedPath> data(textPath->GetFlattenedPath());
+      nsRefPtr<gfxFlattenedPath> data = textPath->GetFlattenedPath();
       if (!data)
         return;
 
       nsIFrame *pathFrame = textPath->GetPathFrame();
       if (!pathFrame)
         return;
 
       /* check for % sizing of textpath */
--- a/layout/svg/base/src/nsSVGTextPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextPathFrame.cpp
@@ -182,17 +182,17 @@ nsSVGTextPathFrame::GetPathFrame() {
 
   nsSVGUtils::GetReferencedFrame(&path, targetURI, mContent,
                                  PresContext()->PresShell());
   if (!path || (path->GetType() != nsGkAtoms::svgPathGeometryFrame))
     return nsnull;
   return path;
 }
 
-nsSVGFlattenedPath *
+already_AddRefed<gfxFlattenedPath>
 nsSVGTextPathFrame::GetFlattenedPath() {
   nsIFrame *path = GetPathFrame();
   if (!path)
     return nsnull;
 
   if (!mSegments) {
     nsCOMPtr<nsIDOMSVGAnimatedPathData> data =
       do_QueryInterface(path->GetContent());
--- a/layout/svg/base/src/nsSVGTextPathFrame.h
+++ b/layout/svg/base/src/nsSVGTextPathFrame.h
@@ -39,18 +39,17 @@
 
 #include "nsSVGTSpanFrame.h"
 #include "nsISVGValueObserver.h"
 #include "nsWeakReference.h"
 #include "nsIDOMSVGAnimatedString.h"
 #include "nsIDOMSVGPathSegList.h"
 #include "nsSVGLengthList.h"
 #include "nsIDOMSVGLength.h"
-
-class nsSVGFlattenedPath;
+#include "gfxPath.h"
 
 typedef nsSVGTSpanFrame nsSVGTextPathFrameBase;
 
 class nsSVGTextPathFrame : public nsSVGTextPathFrameBase,
                            public nsISVGValueObserver
 {
 public:
   nsSVGTextPathFrame(nsStyleContext* aContext) : nsSVGTextPathFrameBase(aContext) {}
@@ -78,17 +77,17 @@ public:
 
   // nsISVGValueObserver interface:
   NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable,
                                      nsISVGValue::modificationType aModType);
   NS_IMETHOD DidModifySVGObservable(nsISVGValue* observable,
                                     nsISVGValue::modificationType aModType);
 
   // nsSVGTextPathFrame methods:
-  nsSVGFlattenedPath *GetFlattenedPath();
+  already_AddRefed<gfxFlattenedPath> GetFlattenedPath();
   nsIFrame *GetPathFrame();
 
    // nsISupports interface:
   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
 private:
   NS_IMETHOD_(nsrefcnt) AddRef() { return 1; }
   NS_IMETHOD_(nsrefcnt) Release() { return 1; }