Bug 926258 - Remove gfxFlattenedPath as it doesn't match the abstraction we want for Moz2D. r=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 15 Oct 2013 16:23:21 +1300
changeset 165516 b37762151fbd464bec0d58217c935499a1d1f44c
parent 165515 a92cf0787b539b07e2a3711368975ad9746a466a
child 165517 21793156b6eab2ceb759819292c85c8f0342baa2
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs926258
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 926258 - Remove gfxFlattenedPath as it doesn't match the abstraction we want for Moz2D. r=roc
content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
content/svg/content/src/SVGMotionSMILAnimationFunction.h
content/svg/content/src/SVGMotionSMILPathUtils.cpp
content/svg/content/src/SVGMotionSMILPathUtils.h
content/svg/content/src/SVGMotionSMILType.cpp
content/svg/content/src/SVGMotionSMILType.h
content/svg/content/src/SVGPathData.cpp
content/svg/content/src/SVGPathData.h
content/svg/content/src/SVGPathElement.cpp
content/svg/content/src/SVGPathElement.h
content/svg/content/src/nsSVGPathGeometryElement.cpp
content/svg/content/src/nsSVGPathGeometryElement.h
gfx/thebes/gfxContext.cpp
gfx/thebes/gfxContext.h
gfx/thebes/gfxPath.cpp
gfx/thebes/gfxPath.h
layout/svg/nsSVGGlyphFrame.cpp
layout/svg/nsSVGTextFrame2.cpp
layout/svg/nsSVGTextFrame2.h
layout/svg/nsSVGTextPathFrame.cpp
layout/svg/nsSVGTextPathFrame.h
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -222,42 +222,42 @@ SVGMotionSMILAnimationFunction::
   if (pathElem) {
     const SVGPathData &path = pathElem->GetAnimPathSegList()->GetAnimValue();
     // Path data must contain of at least one path segment (if the path data
     // doesn't begin with a valid "M", then it's invalid).
     if (path.Length()) {
       bool ok =
         path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
       if (ok && mPathVertices.Length()) {
-        mPath = pathElem->GetFlattenedPath(gfxMatrix());
+        mPath = pathElem->GetPath(gfxMatrix());
       }
     }
   }
 }
 
 void
 SVGMotionSMILAnimationFunction::RebuildPathAndVerticesFromPathAttr()
 {
   const nsAString& pathSpec = GetAttr(nsGkAtoms::path)->GetStringValue();
   mPathSourceType = ePathSourceType_PathAttr;
 
-  // Generate gfxFlattenedPath from |path| attr
+  // Generate gfxPath from |path| attr
   SVGPathData path;
   nsSVGPathDataParserToInternal pathParser(&path);
 
   // We ignore any failure returned from Parse() since the SVG spec says to
   // accept all segments up to the first invalid token. Instead we must
   // explicitly check that the parse produces at least one path segment (if
   // the path data doesn't begin with a valid "M", then it's invalid).
   pathParser.Parse(pathSpec);
   if (!path.Length()) {
     return;
   }
 
-  mPath = path.ToFlattenedPath(gfxMatrix());
+  mPath = path.ToPath(gfxMatrix());
   bool ok = path.GetDistancesFromOriginToEndsOfVisibleSegments(&mPathVertices);
   if (!ok || !mPathVertices.Length()) {
     mPath = nullptr;
   }
 }
 
 // Helper to regenerate our path representation & its list of vertices
 void
@@ -287,17 +287,17 @@ SVGMotionSMILAnimationFunction::
     RebuildPathAndVerticesFromBasicAttrs(aTargetElement);
     mValueNeedsReparsingEverySample = true;
   }
   mIsPathStale = false;
 }
 
 bool
 SVGMotionSMILAnimationFunction::
-  GenerateValuesForPathAndPoints(gfxFlattenedPath* aPath,
+  GenerateValuesForPathAndPoints(gfxPath* aPath,
                                  bool aIsKeyPoints,
                                  nsTArray<double>& aPointDistances,
                                  nsTArray<nsSMILValue>& aResult)
 {
   NS_ABORT_IF_FALSE(aResult.IsEmpty(), "outparam is non-empty");
 
   // If we're using "keyPoints" as our list of input distances, then we need
   // to de-normalize from the [0, 1] scale to the [0, totalPathLen] scale.
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.h
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.h
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
 #define MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
 
-#include "gfxPath.h"  // for gfxFlattenedPath
+#include "gfxPath.h"  // for gfxPath
 #include "nsAutoPtr.h"
 #include "nsSMILAnimationFunction.h"
 #include "nsTArray.h"
 #include "SVGMotionSMILType.h"  // for RotateType
 
 class nsAttrValue;
 class nsIAtom;
 class nsIContent;
@@ -73,30 +73,30 @@ protected:
   void     UnsetRotate();
 
   // Helpers for GetValues
   void     MarkStaleIfAttributeAffectsPath(nsIAtom* aAttribute);
   void     RebuildPathAndVertices(const nsIContent* aContextElem);
   void     RebuildPathAndVerticesFromMpathElem(dom::SVGMPathElement* aMpathElem);
   void     RebuildPathAndVerticesFromPathAttr();
   void     RebuildPathAndVerticesFromBasicAttrs(const nsIContent* aContextElem);
-  bool     GenerateValuesForPathAndPoints(gfxFlattenedPath* aPath,
+  bool     GenerateValuesForPathAndPoints(gfxPath* aPath,
                                           bool aIsKeyPoints,
                                           nsTArray<double>& aPointDistances,
                                           nsTArray<nsSMILValue>& aResult);
 
   // Members
   // -------
   nsTArray<double>           mKeyPoints; // parsed from "keyPoints" attribute.
 
   RotateType                 mRotateType;  // auto, auto-reverse, or explicit.
   float                      mRotateAngle; // the angle value, if explicit.
 
-  PathSourceType             mPathSourceType; // source of our gfxFlattenedPath.
-  nsRefPtr<gfxFlattenedPath> mPath;           // representation of motion path.
+  PathSourceType             mPathSourceType; // source of our gfxPath.
+  nsRefPtr<gfxPath> mPath;           // representation of motion path.
   nsTArray<double>           mPathVertices; // distances of vertices along path.
 
   bool                       mIsPathStale;
 };
 
 } // namespace mozilla
 
 #endif // MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
--- a/content/svg/content/src/SVGMotionSMILPathUtils.cpp
+++ b/content/svg/content/src/SVGMotionSMILPathUtils.cpp
@@ -71,20 +71,20 @@ SVGMotionSMILPathUtils::PathGenerator::
   if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) {
     return false;
   }
   mGfxContext.LineTo(mGfxContext.CurrentPoint() + gfxPoint(xVal, yVal));
   aSegmentDistance = NS_hypot(xVal, yVal);
   return true;
 }
 
-already_AddRefed<gfxFlattenedPath>
+already_AddRefed<gfxPath>
 SVGMotionSMILPathUtils::PathGenerator::GetResultingPath()
 {
-  return mGfxContext.GetFlattenedPath();
+  return mGfxContext.CopyPath();
 }
 
 //----------------------------------------------------------------------
 // Helper / protected methods
 
 bool
 SVGMotionSMILPathUtils::PathGenerator::
   ParseCoordinatePair(const nsAString& aCoordPairStr,
--- a/content/svg/content/src/SVGMotionSMILPathUtils.h
+++ b/content/svg/content/src/SVGMotionSMILPathUtils.h
@@ -12,25 +12,25 @@
 #include "mozilla/Attributes.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsSMILParserUtils.h"
 #include "nsTArray.h"
 
-class gfxFlattenedPath;
+class gfxPath;
 class nsAString;
 class nsSVGElement;
 
 namespace mozilla {
 
 class SVGMotionSMILPathUtils {
 public:
-  // Class to assist in generating a gfxFlattenedPath, based on
+  // Class to assist in generating a gfxPath, based on
   // coordinates in the <animateMotion> from/by/to/values attributes.
   class PathGenerator {
   public:
     PathGenerator(const nsSVGElement* aSVGElement)
       : mSVGElement(aSVGElement),
         mGfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()),
         mHaveReceivedCommands(false)
     {}
@@ -45,31 +45,31 @@ public:
     bool LineToAbsolute(const nsAString& aCoordPairStr,
                           double& aSegmentDistance);
     bool LineToRelative(const nsAString& aCoordPairStr,
                           double& aSegmentDistance);
 
     // Accessor to let clients check if we've received any commands yet.
     inline bool HaveReceivedCommands() { return mHaveReceivedCommands; }
     // Accessor to get the finalized path
-    already_AddRefed<gfxFlattenedPath> GetResultingPath();
+    already_AddRefed<gfxPath> GetResultingPath();
 
   protected:
     // Helper methods
     bool ParseCoordinatePair(const nsAString& aStr,
                                float& aXVal, float& aYVal);
 
     // Member data
     const nsSVGElement* mSVGElement; // context for converting to user units
     gfxContext    mGfxContext;
     bool          mHaveReceivedCommands;
   };
 
   // Class to assist in passing each subcomponent of a |values| attribute to
-  // a PathGenerator, for generating a corresponding gfxFlattenedPath.
+  // a PathGenerator, for generating a corresponding gfxPath.
   class MotionValueParser : public nsSMILParserUtils::GenericValueParser
   {
   public:
     MotionValueParser(PathGenerator* aPathGenerator,
                       nsTArray<double>* aPointDistances)
       : mPathGenerator(aPathGenerator),
         mPointDistances(aPointDistances),
         mDistanceSoFar(0.0)
--- a/content/svg/content/src/SVGMotionSMILType.cpp
+++ b/content/svg/content/src/SVGMotionSMILType.cpp
@@ -27,17 +27,17 @@ enum SegmentType {
 
 // Helper Structs: containers for params to define our MotionSegment
 // (either simple translation or point-on-a-path)
 struct TranslationParams {  // Simple translation
   float mX;
   float mY;
 };
 struct PathPointParams {  // Point along a path
-  gfxFlattenedPath* mPath; // NOTE: Refcounted; need to AddRef/Release.
+  gfxPath* mPath; // NOTE: Refcounted; need to AddRef/Release.
   float mDistToPoint; // Distance from path start to the point on the path that
                       // we're interested in.
 };
 
 /**
  * Helper Struct: MotionSegment
  *
  * Instances of this class represent the points that we move between during
@@ -65,17 +65,17 @@ struct MotionSegment
     : mRotateType(eRotateType_Explicit), mRotateAngle(aRotateAngle),
       mSegmentType(eSegmentType_Translation)
   {
     mU.mTranslationParams.mX = aX;
     mU.mTranslationParams.mY = aY;
   }
 
   // Constructor for a point on a path (NOTE: AddRef's)
-  MotionSegment(gfxFlattenedPath* aPath, float aDistToPoint,
+  MotionSegment(gfxPath* aPath, float aDistToPoint,
                 RotateType aRotateType, float aRotateAngle)
     : mRotateType(aRotateType), mRotateAngle(aRotateAngle),
       mSegmentType(eSegmentType_PathPoint)
   {
     mU.mPathPointParams.mPath = aPath;
     mU.mPathPointParams.mDistToPoint = aDistToPoint;
 
     NS_ADDREF(mU.mPathPointParams.mPath); // Retain a reference to path
@@ -223,17 +223,17 @@ SVGMotionSMILType::IsEqual(const nsSMILV
     }
   }
 
   return true; // If we get here, we found no differences.
 }
 
 // Helper method for Add & CreateMatrix
 inline static void
-GetAngleAndPointAtDistance(gfxFlattenedPath* aPath, float aDistance,
+GetAngleAndPointAtDistance(gfxPath* aPath, float aDistance,
                            RotateType aRotateType,
                            gfxFloat& aRotateAngle, // in & out-param.
                            gfxPoint& aPoint)       // out-param.
 {
   gfxFloat tangentAngle;
   // NOTE: "0.0" below is distance-off-the-path. (see FindPoint documentation)
   aPoint = aPath->FindPoint(gfxPoint(aDistance, 0.0), &tangentAngle);
 
@@ -282,17 +282,17 @@ SVGMotionSMILType::Add(nsSMILValue& aDes
   const PathPointParams& srcParams = srcSeg.mU.mPathPointParams;
   const PathPointParams& dstParams = dstSeg.mU.mPathPointParams;
 
   NS_ABORT_IF_FALSE(srcSeg.mRotateType  == dstSeg.mRotateType &&
                     srcSeg.mRotateAngle == dstSeg.mRotateAngle,
                     "unexpected angle mismatch");
   NS_ABORT_IF_FALSE(srcParams.mPath == dstParams.mPath,
                     "unexpected path mismatch");
-  gfxFlattenedPath* path = srcParams.mPath;
+  gfxPath* path = srcParams.mPath;
 
   // Use destination to get our rotate angle.
   gfxFloat rotateAngle = dstSeg.mRotateAngle;
   gfxPoint dstPt;
   GetAngleAndPointAtDistance(path, dstParams.mDistToPoint, dstSeg.mRotateType,
                              rotateAngle, dstPt);
 
   // NOTE: "0.0" below is distance-off-the-path. (see FindPoint documentation)
@@ -406,17 +406,17 @@ SVGMotionSMILType::Interpolate(const nsS
   const MotionSegment& endSeg = endArr[0];
   NS_ABORT_IF_FALSE(endSeg.mSegmentType == eSegmentType_PathPoint,
                     "Expecting to be interpolating along a path");
 
   const PathPointParams& endParams = endSeg.mU.mPathPointParams;
   // NOTE: path & angle should match between start & end (since presumably
   // start & end came from the same <animateMotion> element), unless start is
   // empty. (as it would be for pure 'to' animation)
-  gfxFlattenedPath* path = endParams.mPath;
+  gfxPath* path = endParams.mPath;
   RotateType rotateType  = endSeg.mRotateType;
   float rotateAngle      = endSeg.mRotateAngle;
 
   float startDist;
   if (startArr.IsEmpty()) {
     startDist = 0.0f;
   } else {
     const MotionSegment& startSeg = startArr[0];
@@ -466,17 +466,17 @@ SVGMotionSMILType::CreateMatrix(const ns
     }
     matrix.Translate(point);
     matrix.Rotate(rotateAngle);
   }
   return matrix;
 }
 
 /* static */ nsSMILValue
-SVGMotionSMILType::ConstructSMILValue(gfxFlattenedPath* aPath,
+SVGMotionSMILType::ConstructSMILValue(gfxPath* aPath,
                                       float aDist,
                                       RotateType aRotateType,
                                       float aRotateAngle)
 {
   nsSMILValue smilVal(&SVGMotionSMILType::sSingleton);
   MotionSegmentArray& arr = ExtractMotionSegmentArray(smilVal);
 
   // AppendElement has guaranteed success here, since Init() allocates 1 slot.
--- a/content/svg/content/src/SVGMotionSMILType.h
+++ b/content/svg/content/src/SVGMotionSMILType.h
@@ -7,17 +7,17 @@
 
 #ifndef MOZILLA_SVGMOTIONSMILTYPE_H_
 #define MOZILLA_SVGMOTIONSMILTYPE_H_
 
 #include "mozilla/Attributes.h"
 #include "gfxMatrix.h"
 #include "nsISMILType.h"
 
-class gfxFlattenedPath;
+class gfxPath;
 class nsSMILValue;
 
 namespace mozilla {
 
 /**
  * MotionRotateType: Enum to indicate the type of our "rotate" attribute.
  */
 enum RotateType {
@@ -60,17 +60,17 @@ protected:
                                double aUnitDistance,
                                nsSMILValue& aResult) const MOZ_OVERRIDE;
 public:
   // Used to generate a transform matrix from an <animateMotion> nsSMILValue.
   static gfxMatrix CreateMatrix(const nsSMILValue& aSMILVal);
 
   // Used to generate a nsSMILValue for the point at the given distance along
   // the given path.
-  static nsSMILValue ConstructSMILValue(gfxFlattenedPath* aPath,
+  static nsSMILValue ConstructSMILValue(gfxPath* aPath,
                                         float aDist,
                                         RotateType aRotateType,
                                         float aRotateAngle);
 
 private:
   // Private constructor: prevent instances beyond my singleton.
   MOZ_CONSTEXPR SVGMotionSMILType() {}
 };
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -487,27 +487,27 @@ SVGPathData::ConstructPath(gfxContext *a
 
   NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
   NS_ABORT_IF_FALSE(prevSegType == segType,
                     "prevSegType should be left at the final segType");
 
   MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
 }
 
-already_AddRefed<gfxFlattenedPath>
-SVGPathData::ToFlattenedPath(const gfxMatrix& aMatrix) const
+already_AddRefed<gfxPath>
+SVGPathData::ToPath(const gfxMatrix& aMatrix) const
 {
   nsRefPtr<gfxContext> tmpCtx =
     new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
 
   tmpCtx->SetMatrix(aMatrix);
   ConstructPath(tmpCtx);
   tmpCtx->IdentityMatrix();
 
-  return tmpCtx->GetFlattenedPath();
+  return tmpCtx->CopyPath();
 }
 
 static double
 AngleOfVector(const gfxPoint& aVector)
 {
   // C99 says about atan2 "A domain error may occur if both arguments are
   // zero" and "On a domain error, the function returns an implementation-
   // defined value". In the case of atan2 the implementation-defined value
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -12,17 +12,17 @@
 #include "nsINode.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsSVGElement.h"
 #include "nsTArray.h"
 
 #include <string.h>
 
 class gfxContext;
-class gfxFlattenedPath;
+class gfxPath;
 class nsSVGPathDataParserToInternal; // IWYU pragma: keep
 
 struct gfxMatrix;
 struct nsSVGMark;
 
 namespace mozilla {
 
 /**
@@ -145,18 +145,18 @@ public:
    */
   bool GetSegmentLengths(nsTArray<double> *aLengths) const;
 
   /**
    * Returns true, except on OOM, in which case returns false.
    */
   bool GetDistancesFromOriginToEndsOfVisibleSegments(nsTArray<double> *aArray) const;
 
-  already_AddRefed<gfxFlattenedPath>
-  ToFlattenedPath(const gfxMatrix& aMatrix) const;
+  already_AddRefed<gfxPath>
+  ToPath(const gfxMatrix& aMatrix) const;
 
   void ConstructPath(gfxContext *aCtx) const;
 
   const_iterator begin() const { return mData.Elements(); }
   const_iterator end() const { return mData.Elements() + mData.Length(); }
 
   // Access to methods that can modify objects of this type is deliberately
   // limited. This is to reduce the chances of someone modifying objects of
--- a/content/svg/content/src/SVGPathElement.cpp
+++ b/content/svg/content/src/SVGPathElement.cpp
@@ -48,30 +48,30 @@ already_AddRefed<SVGAnimatedNumber>
 SVGPathElement::PathLength()
 {
   return mPathLength.ToDOMAnimatedNumber(this);
 }
 
 float
 SVGPathElement::GetTotalLength(ErrorResult& rv)
 {
-  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(gfxMatrix());
+  nsRefPtr<gfxPath> flat = GetPath(gfxMatrix());
 
   if (!flat) {
     rv.Throw(NS_ERROR_FAILURE);
     return 0.f;
   }
 
   return flat->GetLength();
 }
 
 already_AddRefed<nsISVGPoint>
 SVGPathElement::GetPointAtLength(float distance, ErrorResult& rv)
 {
-  nsRefPtr<gfxFlattenedPath> flat = GetFlattenedPath(gfxMatrix());
+  nsRefPtr<gfxPath> flat = GetPath(gfxMatrix());
   if (!flat) {
     rv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   float totalLength = flat->GetLength();
   if (mPathLength.IsExplicitlySet()) {
     float pathLength = mPathLength.GetAnimValue();
@@ -287,20 +287,20 @@ SVGPathElement::IsAttributeMapped(const 
   static const MappedAttributeEntry* const map[] = {
     sMarkersMap
   };
 
   return FindAttributeDependence(name, map) ||
     SVGPathElementBase::IsAttributeMapped(name);
 }
 
-already_AddRefed<gfxFlattenedPath>
-SVGPathElement::GetFlattenedPath(const gfxMatrix &aMatrix)
+already_AddRefed<gfxPath>
+SVGPathElement::GetPath(const gfxMatrix &aMatrix)
 {
-  return mD.GetAnimValue().ToFlattenedPath(aMatrix);
+  return mD.GetAnimValue().ToPath(aMatrix);
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 bool
 SVGPathElement::AttributeDefinesGeometry(const nsIAtom *aName)
 {
@@ -336,17 +336,17 @@ SVGPathElement::GetPathLengthScale(PathL
     if (authorsPathLengthEstimate > 0) {
       gfxMatrix matrix;
       if (aFor == eForTextPath) {
         // For textPath, a transform on the referenced path affects the
         // textPath layout, so when calculating the actual path length
         // we need to take that into account.
         matrix = PrependLocalTransformsTo(matrix);
       }
-      nsRefPtr<gfxFlattenedPath> path = GetFlattenedPath(matrix);
+      nsRefPtr<gfxPath> path = GetPath(matrix);
       if (path) {
         return path->GetLength() / authorsPathLengthEstimate;
       }
     }
   }
   return 1.0;
 }
 
--- a/content/svg/content/src/SVGPathElement.h
+++ b/content/svg/content/src/SVGPathElement.h
@@ -43,17 +43,17 @@ public:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE;
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
 
-  virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(const gfxMatrix &aMatrix) MOZ_OVERRIDE;
+  virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix) MOZ_OVERRIDE;
 
   // nsIContent interface
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   virtual SVGAnimatedPathSegList* GetAnimPathSegList() MOZ_OVERRIDE {
     return &mD;
   }
 
--- a/content/svg/content/src/nsSVGPathGeometryElement.cpp
+++ b/content/svg/content/src/nsSVGPathGeometryElement.cpp
@@ -47,13 +47,13 @@ nsSVGPathGeometryElement::IsMarkable()
   return false;
 }
 
 void
 nsSVGPathGeometryElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks)
 {
 }
 
-already_AddRefed<gfxFlattenedPath>
-nsSVGPathGeometryElement::GetFlattenedPath(const gfxMatrix &aMatrix)
+already_AddRefed<gfxPath>
+nsSVGPathGeometryElement::GetPath(const gfxMatrix &aMatrix)
 {
   return nullptr;
 }
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -3,17 +3,17 @@
  * 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 __NS_SVGPATHGEOMETRYELEMENT_H__
 #define __NS_SVGPATHGEOMETRYELEMENT_H__
 
 #include "SVGGraphicsElement.h"
 
-class gfxFlattenedPath;
+class gfxPath;
 struct gfxMatrix;
 template <class E> class nsTArray;
 
 struct nsSVGMark {
   enum Type {
     eStart,
     eMid,
     eEnd,
@@ -47,12 +47,12 @@ public:
    * This could be moved up to a more general class so it can be used for non-leaf
    * elements, but that would require care and for now there's no need.
    */
   bool GeometryDependsOnCoordCtx();
 
   virtual bool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
   virtual void ConstructPath(gfxContext *aCtx) = 0;
-  virtual already_AddRefed<gfxFlattenedPath> GetFlattenedPath(const gfxMatrix &aMatrix);
+  virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix);
 };
 
 #endif
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -1746,29 +1746,16 @@ gfxContext::GetUserStrokeExtent()
     double xmin, ymin, xmax, ymax;
     cairo_stroke_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
   } else {
     return ThebesRect(mPath->GetStrokedBounds(CurrentState().strokeOptions, mTransform));
   }
 }
 
-already_AddRefed<gfxFlattenedPath>
-gfxContext::GetFlattenedPath()
-{
-  if (mCairo) {
-    nsRefPtr<gfxFlattenedPath> path =
-        new gfxFlattenedPath(cairo_copy_path_flat(mCairo));
-    return path.forget();
-  } else {
-    // XXX - Used by SVG, needs fixing.
-    return nullptr;
-  }
-}
-
 bool
 gfxContext::HasError()
 {
   if (mCairo) {
     return cairo_status(mCairo) != CAIRO_STATUS_SUCCESS;
   } else {
     // As far as this is concerned, an Azure context is never in error.
     return false;
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -641,21 +641,16 @@ public:
     /**
      ** Extents - returns user space extent of current path
      **/
     gfxRect GetUserPathExtent();
     gfxRect GetUserFillExtent();
     gfxRect GetUserStrokeExtent();
 
     /**
-     ** Obtaining a "flattened" path - path converted to all line segments
-     **/
-    already_AddRefed<gfxFlattenedPath> GetFlattenedPath();
-
-    /**
      ** Flags
      **/
 
     enum {
         /* If this flag is set, operators other than CLEAR, SOURCE, or
          * OVER will be converted to OVER before being sent to cairo.
          *
          * This is most useful with a printing surface, where
--- a/gfx/thebes/gfxPath.cpp
+++ b/gfx/thebes/gfxPath.cpp
@@ -1,33 +1,44 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxPath.h"
 #include "gfxPoint.h"
+#include "gfxPlatform.h"
+#include "gfxASurface.h"
 
 #include "cairo.h"
 
-gfxPath::gfxPath(cairo_path_t* aPath) : mPath(aPath)
+gfxPath::gfxPath(cairo_path_t* aPath)
+  : mPath(aPath)
+  , mFlattenedPath(nullptr)
 {
 }
 
 gfxPath::~gfxPath()
 {
     cairo_path_destroy(mPath);
+    cairo_path_destroy(mFlattenedPath);
 }
 
-gfxFlattenedPath::gfxFlattenedPath(cairo_path_t* aPath) : gfxPath(aPath)
+void
+gfxPath::EnsureFlattenedPath()
 {
-}
+    if (mFlattenedPath) {
+        return;
+    }
 
-gfxFlattenedPath::~gfxFlattenedPath()
-{
+    gfxASurface* surf = gfxPlatform::GetPlatform()->ScreenReferenceSurface();
+    cairo_t* cr = cairo_create(surf->CairoSurface());
+    cairo_append_path(cr, mPath);
+    mFlattenedPath = cairo_copy_path_flat(cr);
+    cairo_destroy(cr);
 }
 
 static gfxFloat
 CalcSubLengthAndAdvance(cairo_path_data_t *aData,
                         gfxPoint &aPathStart, gfxPoint &aCurrent)
 {
     float sublength = 0;
 
@@ -57,43 +68,47 @@ CalcSubLengthAndAdvance(cairo_path_data_
             aCurrent = aPathStart;
             break;
         }
     }
     return sublength;
 }
 
 gfxFloat
-gfxFlattenedPath::GetLength()
+gfxPath::GetLength()
 {
+    EnsureFlattenedPath();
+
     gfxPoint start(0, 0);     // start of current subpath
     gfxPoint current(0, 0);   // current point
     gfxFloat length = 0;      // current summed length
 
     for (int32_t i = 0;
-         i < mPath->num_data;
-         i += mPath->data[i].header.length) {
-        length += CalcSubLengthAndAdvance(&mPath->data[i], start, current);
+         i < mFlattenedPath->num_data;
+         i += mFlattenedPath->data[i].header.length) {
+        length += CalcSubLengthAndAdvance(&mFlattenedPath->data[i], start, current);
     }
     return length;
 }
 
 gfxPoint
-gfxFlattenedPath::FindPoint(gfxPoint aOffset, gfxFloat *aAngle)
+gfxPath::FindPoint(gfxPoint aOffset, gfxFloat *aAngle)
 {
+    EnsureFlattenedPath();
+
     gfxPoint start(0, 0);     // start of current subpath
     gfxPoint current(0, 0);   // current point
     gfxFloat length = 0;      // current summed length
 
     for (int32_t i = 0;
-         i < mPath->num_data;
-         i += mPath->data[i].header.length) {
+         i < mFlattenedPath->num_data;
+         i += mFlattenedPath->data[i].header.length) {
         gfxPoint prev = current;
 
-        gfxFloat sublength = CalcSubLengthAndAdvance(&mPath->data[i],
+        gfxFloat sublength = CalcSubLengthAndAdvance(&mFlattenedPath->data[i],
                                                      start, current);
 
         gfxPoint diff = current - prev;
         if (aAngle)
             *aAngle = atan2(diff.y, diff.x);
 
         if (sublength != 0 && length + sublength >= aOffset.x) {
             gfxFloat ratio = (aOffset.x - length) / sublength;
--- a/gfx/thebes/gfxPath.h
+++ b/gfx/thebes/gfxPath.h
@@ -20,45 +20,34 @@ typedef struct cairo_path cairo_path_t;
 class gfxPath {
     NS_INLINE_DECL_REFCOUNTING(gfxPath)
 
     friend class gfxContext;
 
 protected:
     gfxPath(cairo_path_t* aPath);
 
+    void EnsureFlattenedPath();
+
 public:
     virtual ~gfxPath();
-
-protected:
-    cairo_path_t* mPath;
-};
-
-/**
- * Specialization of a path that only contains linear pieces. Can be created
- * from the existing path of a gfxContext.
- */
-class gfxFlattenedPath : public gfxPath {
-    friend class gfxContext;
-
-protected:
-    gfxFlattenedPath(cairo_path_t* aPath);
-
-public:
-    virtual ~gfxFlattenedPath();
-
+    
     /**
      * Returns calculated total length of path
      */
     gfxFloat GetLength();
 
     /**
      * Returns a point a certain distance along the path.  Return is
      * first or last point of the path if the requested length offset
      * is outside the range for the path.
      * @param aOffset offset inpath parameter space (x=length, y=normal offset)
      * @param aAngle optional - output tangent
      */
     gfxPoint FindPoint(gfxPoint aOffset,
                        gfxFloat* aAngle = nullptr);
+
+protected:
+    cairo_path_t* mPath;
+    cairo_path_t* mFlattenedPath;
 };
 
 #endif
--- a/layout/svg/nsSVGGlyphFrame.cpp
+++ b/layout/svg/nsSVGGlyphFrame.cpp
@@ -733,17 +733,17 @@ nsSVGGlyphFrame::GetCharacterPositions(n
   GetEffectiveRotate(strLength, rotateList);
 
   gfxPoint pos = mPosition;
   gfxFloat angle = 0.0;
 
   nsSVGTextPathFrame *textPath = FindTextPathParent();
 
   if (textPath) {
-    nsRefPtr<gfxFlattenedPath> data = textPath->GetFlattenedPath();
+    nsRefPtr<gfxPath> data = textPath->GetPath();
 
     // textPath frame, but invalid target
     if (!data)
       return false;
 
     if (!aCharacterPositions->SetLength(strLength))
       return false;
 
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -4632,26 +4632,26 @@ nsSVGTextFrame2::GetTextPathPathFrame(ns
                                                  nsSVGEffects::HrefProperty());
     if (!property)
       return nullptr;
   }
 
   return property->GetReferencedFrame(nsGkAtoms::svgPathGeometryFrame, nullptr);
 }
 
-already_AddRefed<gfxFlattenedPath>
-nsSVGTextFrame2::GetFlattenedTextPath(nsIFrame* aTextPathFrame)
+already_AddRefed<gfxPath>
+nsSVGTextFrame2::GetTextPath(nsIFrame* aTextPathFrame)
 {
   nsIFrame *path = GetTextPathPathFrame(aTextPathFrame);
 
   if (path) {
     nsSVGPathGeometryElement *element =
       static_cast<nsSVGPathGeometryElement*>(path->GetContent());
 
-    return element->GetFlattenedPath(element->PrependLocalTransformsTo(gfxMatrix()));
+    return element->GetPath(element->PrependLocalTransformsTo(gfxMatrix()));
   }
   return nullptr;
 }
 
 gfxFloat
 nsSVGTextFrame2::GetOffsetScale(nsIFrame* aTextPathFrame)
 {
   nsIFrame *pathFrame = GetTextPathPathFrame(aTextPathFrame);
@@ -4666,17 +4666,17 @@ gfxFloat
 nsSVGTextFrame2::GetStartOffset(nsIFrame* aTextPathFrame)
 {
   dom::SVGTextPathElement *tp =
     static_cast<dom::SVGTextPathElement*>(aTextPathFrame->GetContent());
   nsSVGLength2 *length =
     &tp->mLengthAttributes[dom::SVGTextPathElement::STARTOFFSET];
 
   if (length->IsPercentage()) {
-    nsRefPtr<gfxFlattenedPath> data = GetFlattenedTextPath(aTextPathFrame);
+    nsRefPtr<gfxPath> data = GetTextPath(aTextPathFrame);
     return data ?
              length->GetAnimValInSpecifiedUnits() * data->GetLength() / 100.0 :
              0.0;
   }
   return length->GetAnimValue(tp) * GetOffsetScale(aTextPathFrame);
 }
 
 void
@@ -4689,17 +4689,17 @@ nsSVGTextFrame2::DoTextPathLayout()
     nsIFrame* textPathFrame = it.TextPathFrame();
     if (!textPathFrame) {
       // Skip past this frame if we're not in a text path.
       it.AdvancePastCurrentFrame();
       continue;
     }
 
     // Get the path itself.
-    nsRefPtr<gfxFlattenedPath> data = GetFlattenedTextPath(textPathFrame);
+    nsRefPtr<gfxPath> data = GetTextPath(textPathFrame);
     if (!data) {
       it.AdvancePastCurrentTextPathFrame();
       continue;
     }
 
     nsIContent* textPath = textPathFrame->GetContent();
 
     gfxFloat offset = GetStartOffset(textPathFrame);
--- a/layout/svg/nsSVGTextFrame2.h
+++ b/layout/svg/nsSVGTextFrame2.h
@@ -13,17 +13,17 @@
 #include "nsStubMutationObserver.h"
 #include "nsSVGGlyphFrame.h" // for SVGTextContextPaint
 #include "nsSVGTextContainerFrame.h"
 
 class nsDisplaySVGText;
 class nsRenderingContext;
 class nsSVGTextFrame2;
 class nsTextFrame;
-class gfxFlattenedPath;
+class gfxPath;
 
 typedef nsSVGDisplayContainerFrame nsSVGTextFrame2Base;
 
 namespace mozilla {
 
 class CharIterator;
 class TextFrameIterator;
 class TextNodeCorrespondenceRecorder;
@@ -512,17 +512,17 @@ private:
    * @param aShouldPaintSVGGlyphs (out) Whether SVG glyphs in the text
    *   should be painted.
    */
   bool ShouldRenderAsPath(nsRenderingContext* aContext, nsTextFrame* aFrame,
                           bool& aShouldPaintSVGGlyphs);
 
   // Methods to get information for a <textPath> frame.
   nsIFrame* GetTextPathPathFrame(nsIFrame* aTextPathFrame);
-  already_AddRefed<gfxFlattenedPath> GetFlattenedTextPath(nsIFrame* aTextPathFrame);
+  already_AddRefed<gfxPath> GetTextPath(nsIFrame* aTextPathFrame);
   gfxFloat GetOffsetScale(nsIFrame* aTextPathFrame);
   gfxFloat GetStartOffset(nsIFrame* aTextPathFrame);
 
   DrawMode SetupCairoState(gfxContext* aContext,
                            nsIFrame* aFrame,
                            gfxTextContextPaint* aOuterContextPaint,
                            gfxTextContextPaint** aThisContextPaint);
 
--- a/layout/svg/nsSVGTextPathFrame.cpp
+++ b/layout/svg/nsSVGTextPathFrame.cpp
@@ -106,38 +106,38 @@ nsSVGTextPathFrame::GetPathFrame()
     if (!property)
       return nullptr;
   }
 
   nsIFrame *frame = property->GetReferencedFrame(nsGkAtoms::svgPathGeometryFrame, nullptr);
   return frame && frame->GetContent()->Tag() == nsGkAtoms::path ? frame : nullptr;
 }
 
-already_AddRefed<gfxFlattenedPath>
-nsSVGTextPathFrame::GetFlattenedPath()
+already_AddRefed<gfxPath>
+nsSVGTextPathFrame::GetPath()
 {
   nsIFrame *path = GetPathFrame();
 
   if (path) {
     nsSVGPathGeometryElement *element =
       static_cast<nsSVGPathGeometryElement*>(path->GetContent());
 
-    return element->GetFlattenedPath(element->PrependLocalTransformsTo(gfxMatrix()));
+    return element->GetPath(element->PrependLocalTransformsTo(gfxMatrix()));
   }
   return nullptr;
 }
  
 gfxFloat
 nsSVGTextPathFrame::GetStartOffset()
 {
   SVGTextPathElement *tp = static_cast<SVGTextPathElement*>(mContent);
   nsSVGLength2 *length = &tp->mLengthAttributes[SVGTextPathElement::STARTOFFSET];
 
   if (length->IsPercentage()) {
-    nsRefPtr<gfxFlattenedPath> data = GetFlattenedPath();
+    nsRefPtr<gfxPath> data = GetPath();
     return data ? (length->GetAnimValInSpecifiedUnits() * data->GetLength() / 100.0) : 0.0;
   }
   return length->GetAnimValue(tp) * GetOffsetScale();
 }
 
 gfxFloat
 nsSVGTextPathFrame::GetOffsetScale()
 {
--- a/layout/svg/nsSVGTextPathFrame.h
+++ b/layout/svg/nsSVGTextPathFrame.h
@@ -10,17 +10,17 @@
 #include "gfxTypes.h"
 #include "nsCOMPtr.h"
 #include "nsFrame.h"
 #include "nsISVGChildFrame.h"
 #include "nsLiteralString.h"
 #include "nsQueryFrame.h"
 #include "nsSVGTSpanFrame.h"
 
-class gfxFlattenedPath;
+class gfxPath;
 class nsIAtom;
 class nsIContent;
 class nsIFrame;
 class nsIPresShell;
 class nsStyleContext;
 
 namespace mozilla {
 class SVGNumberList;
@@ -60,17 +60,17 @@ public:
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
   {
     return MakeFrameName(NS_LITERAL_STRING("SVGTextPath"), aResult);
   }
 #endif
 
   // nsSVGTextPathFrame methods:
-  already_AddRefed<gfxFlattenedPath> GetFlattenedPath();
+  already_AddRefed<gfxPath> GetPath();
   nsIFrame *GetPathFrame();
 
   /**
    * Gets the scale by which offsets along this textPath must be scaled. This
    * scaling is due to the user provided 'pathLength' attribute on the <path>
    * element, which is a user provided estimate of the path length.
    */
   gfxFloat GetOffsetScale();