Bug 988808, part 1 - Allow a PathBuilder object to be supplied to nsSVGPathGeometryElement::BuildPath() and its overrides. r=Bas
authorJonathan Watt <jwatt@jwatt.org>
Sat, 05 Jul 2014 21:53:04 +0100
changeset 192504 15767e9793354de42acf10b392b5eb70fba5e4f3
parent 192503 8b6e4d0527c3b6bd8d1d1d8a1d6747b7fbcff89b
child 192505 60d0ee6ffa30363ba039dba26584b3384dcdf4a5
push id27088
push usercbook@mozilla.com
push dateMon, 07 Jul 2014 12:19:04 +0000
treeherdermozilla-central@699348fd356b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs988808
milestone33.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 988808, part 1 - Allow a PathBuilder object to be supplied to nsSVGPathGeometryElement::BuildPath() and its overrides. r=Bas
content/svg/content/src/SVGCircleElement.cpp
content/svg/content/src/SVGCircleElement.h
content/svg/content/src/SVGContentUtils.cpp
content/svg/content/src/SVGEllipseElement.cpp
content/svg/content/src/SVGEllipseElement.h
content/svg/content/src/SVGImageElement.cpp
content/svg/content/src/SVGImageElement.h
content/svg/content/src/SVGLineElement.cpp
content/svg/content/src/SVGLineElement.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/SVGRectElement.cpp
content/svg/content/src/SVGRectElement.h
content/svg/content/src/nsSVGPathGeometryElement.h
content/svg/content/src/nsSVGPolyElement.cpp
content/svg/content/src/nsSVGPolyElement.h
--- a/content/svg/content/src/SVGCircleElement.cpp
+++ b/content/svg/content/src/SVGCircleElement.cpp
@@ -89,26 +89,26 @@ SVGCircleElement::ConstructPath(gfxConte
 
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r > 0.0f)
     aCtx->Arc(gfxPoint(x, y), r, 0, 2*M_PI);
 }
 
 TemporaryRef<Path>
-SVGCircleElement::BuildPath()
+SVGCircleElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, r;
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r <= 0.0f) {
     return nullptr;
   }
 
-  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+  RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI));
 
   return pathBuilder->Finish();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGCircleElement.h
+++ b/content/svg/content/src/SVGCircleElement.h
@@ -26,17 +26,17 @@ protected:
                                             already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
-  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> R();
 
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -4,33 +4,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Main header first:
 // This is also necessary to ensure our definition of M_SQRT1_2 is picked up
 #include "SVGContentUtils.h"
 
 // Keep others in (case-insensitive) order:
 #include "gfxMatrix.h"
+#include "gfxPlatform.h"
+#include "mozilla/gfx/2D.h"
 #include "mozilla/dom/SVGSVGElement.h"
+#include "mozilla/RefPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Types.h"
 #include "gfx2DGlue.h"
 #include "nsSVGPathDataParser.h"
 #include "SVGPathData.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::gfx;
 
 SVGSVGElement*
 SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
 {
   nsIContent *element = nullptr;
   nsIContent *ancestor = aSVGElement->GetFlattenedTreeParent();
 
   while (ancestor && ancestor->IsSVG() &&
@@ -591,10 +595,15 @@ TemporaryRef<gfx::Path>
 SVGContentUtils::GetPath(const nsAString& aPathString)
 {
   SVGPathData pathData;
   nsSVGPathDataParser parser(aPathString, &pathData);
   if (!parser.Parse()) {
     return NULL;
   }
 
-  return pathData.BuildPath(mozilla::gfx::FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 1);
+  RefPtr<DrawTarget> drawTarget =
+    gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+  RefPtr<PathBuilder> builder =
+    drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
+
+  return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1);
 }
--- a/content/svg/content/src/SVGEllipseElement.cpp
+++ b/content/svg/content/src/SVGEllipseElement.cpp
@@ -109,26 +109,26 @@ SVGEllipseElement::ConstructPath(gfxCont
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx > 0.0f && ry > 0.0f) {
     aCtx->Ellipse(gfxPoint(x, y), gfxSize(2.0*rx, 2.0*ry));
   }
 }
 
 TemporaryRef<Path>
-SVGEllipseElement::BuildPath()
+SVGEllipseElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, rx, ry;
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx <= 0.0f || ry <= 0.0f) {
     return nullptr;
   }
 
-  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+  RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   EllipseToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry));
 
   return pathBuilder->Finish();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGEllipseElement.h
+++ b/content/svg/content/src/SVGEllipseElement.h
@@ -26,17 +26,17 @@ protected:
                                              already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
-  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> Rx();
   already_AddRefed<SVGAnimatedLength> Ry();
--- a/content/svg/content/src/SVGImageElement.cpp
+++ b/content/svg/content/src/SVGImageElement.cpp
@@ -236,29 +236,29 @@ SVGImageElement::ConstructPath(gfxContex
 
   if (width <= 0 || height <= 0)
     return;
 
   aCtx->Rectangle(gfxRect(x, y, width, height));
 }
 
 TemporaryRef<Path>
-SVGImageElement::BuildPath()
+SVGImageElement::BuildPath(PathBuilder* aBuilder)
 {
   // We get called in order to get bounds for this element, and for
   // hit-testing against it. For that we just pretend to be a rectangle.
 
   float x, y, width, height;
   GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
 
   if (width <= 0 || height <= 0) {
     return nullptr;
   }
 
-  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+  RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   Rect r(x, y, width, height);
   pathBuilder->MoveTo(r.TopLeft());
   pathBuilder->LineTo(r.TopRight());
   pathBuilder->LineTo(r.BottomRight());
   pathBuilder->LineTo(r.BottomLeft());
   pathBuilder->Close();
 
--- a/content/svg/content/src/SVGImageElement.h
+++ b/content/svg/content/src/SVGImageElement.h
@@ -49,17 +49,17 @@ public:
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) MOZ_OVERRIDE;
 
   virtual EventStates IntrinsicState() const MOZ_OVERRIDE;
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
-  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   nsresult CopyInnerTo(mozilla::dom::Element* aDest);
 
--- a/content/svg/content/src/SVGLineElement.cpp
+++ b/content/svg/content/src/SVGLineElement.cpp
@@ -114,19 +114,19 @@ SVGLineElement::ConstructPath(gfxContext
 
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
 
   aCtx->MoveTo(gfxPoint(x1, y1));
   aCtx->LineTo(gfxPoint(x2, y2));
 }
 
 TemporaryRef<Path>
-SVGLineElement::BuildPath()
+SVGLineElement::BuildPath(PathBuilder* aBuilder)
 {
-  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+  RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   float x1, y1, x2, y2;
   GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
 
   pathBuilder->MoveTo(Point(x1, y1));
   pathBuilder->LineTo(Point(x2, y2));
 
   return pathBuilder->Finish();
--- a/content/svg/content/src/SVGLineElement.h
+++ b/content/svg/content/src/SVGLineElement.h
@@ -28,17 +28,17 @@ protected:
 public:
   // nsIContent interface
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
-  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X1();
   already_AddRefed<SVGAnimatedLength> Y1();
   already_AddRefed<SVGAnimatedLength> X2();
   already_AddRefed<SVGAnimatedLength> Y2();
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -297,32 +297,24 @@ ApproximateZeroLengthSubpathSquareCaps(c
         SVGPathSegUtils::IsValidType(prevSegType) &&                          \
         (!IsMoveto(prevSegType) ||                                            \
          segType == PATHSEG_CLOSEPATH)) {                                     \
       ApproximateZeroLengthSubpathSquareCaps(segStart, aCtx);                 \
     }                                                                         \
   } while(0)
 
 TemporaryRef<Path>
-SVGPathData::BuildPath(FillRule aFillRule,
+SVGPathData::BuildPath(PathBuilder* builder,
                        uint8_t aStrokeLineCap,
                        Float aStrokeWidth) const
 {
   if (mData.IsEmpty() || !IsMoveto(SVGPathSegUtils::DecodeType(mData[0]))) {
     return nullptr; // paths without an initial moveto are invalid
   }
 
-  RefPtr<DrawTarget> drawTarget =
-    gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
-  NS_ASSERTION(gfxPlatform::GetPlatform()->
-                 SupportsAzureContentForDrawTarget(drawTarget),
-               "Should support Moz2D content drawing");
-
-  RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(aFillRule);
-
   bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
   bool subpathHasLength = false;  // visual length
   bool subpathContainsNonArc = false;
 
   uint32_t segType     = PATHSEG_UNKNOWN;
   uint32_t prevSegType = PATHSEG_UNKNOWN;
   Point pathStart(0.0, 0.0); // start point of [sub]path
   Point segStart(0.0, 0.0);
@@ -809,25 +801,29 @@ SVGPathData::ConstructPath(gfxContext *a
 
   MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
 }
 
 TemporaryRef<Path>
 SVGPathData::ToPathForLengthOrPositionMeasuring() const
 {
   // Since the path that we return will not be used for painting it doesn't
-  // matter what we pass to BuildPath as aFillRule. Hawever, we do want to
-  // pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as aStrokeLineCap
-  // to avoid the insertion of extra little lines (by
+  // matter what we pass to CreatePathBuilder as aFillRule. Hawever, we do want
+  // to pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as
+  // aStrokeLineCap to avoid the insertion of extra little lines (by
   // ApproximateZeroLengthSubpathSquareCaps), in which case the value that we
   // pass as aStrokeWidth doesn't matter (since it's only used to determine the
   // length of those extra little lines).
 
   if (!mCachedPath) {
-    mCachedPath = BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
+    RefPtr<DrawTarget> drawTarget =
+      gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+    RefPtr<PathBuilder> builder =
+      drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
+    mCachedPath = BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 0);
   }
 
   return mCachedPath;
 }
 
 static double
 AngleOfVector(const Point& aVector)
 {
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -79,16 +79,17 @@ class SVGPathData
   friend class DOMSVGPathSegList;
   friend class DOMSVGPathSeg;
   friend class ::nsSVGPathDataParser;
   // nsSVGPathDataParser will not keep wrappers in sync, so consumers
   // are responsible for that!
 
   typedef gfx::DrawTarget DrawTarget;
   typedef gfx::Path Path;
+  typedef gfx::PathBuilder PathBuilder;
   typedef gfx::FillRule FillRule;
   typedef gfx::Float Float;
   typedef gfx::CapStyle CapStyle;
 
 public:
   typedef const float* const_iterator;
 
   SVGPathData(){}
@@ -161,17 +162,17 @@ public:
   /**
    * This returns a path without the extra little line segments that
    * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
    * See the comment for that function for more info on that.
    */
   TemporaryRef<Path> ToPathForLengthOrPositionMeasuring() const;
 
   void ConstructPath(gfxContext *aCtx) const;
-  TemporaryRef<Path> BuildPath(FillRule aFillRule,
+  TemporaryRef<Path> BuildPath(PathBuilder* aBuilder,
                                uint8_t aCapStyle,
                                Float aStrokeWidth) const;
 
   const_iterator begin() const { return mData.Elements(); }
   const_iterator end() const { return mData.Elements() + mData.Length(); }
 
   // memory reporting methods
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
--- a/content/svg/content/src/SVGPathElement.cpp
+++ b/content/svg/content/src/SVGPathElement.cpp
@@ -6,18 +6,20 @@
 #include "mozilla/dom/SVGPathElement.h"
 
 #include <algorithm>
 
 #include "DOMSVGPathSeg.h"
 #include "DOMSVGPathSegList.h"
 #include "DOMSVGPoint.h"
 #include "gfx2DGlue.h"
+#include "gfxPlatform.h"
 #include "mozilla/dom/SVGPathElementBinding.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsStyleStruct.h"
 #include "SVGContentUtils.h"
 
 class gfxContext;
@@ -365,17 +367,17 @@ SVGPathElement::GetPathLengthScale(PathL
       }
       return path->ComputeLength() / authorsPathLengthEstimate;
     }
   }
   return 1.0;
 }
 
 TemporaryRef<Path>
-SVGPathElement::BuildPath()
+SVGPathElement::BuildPath(PathBuilder* aBuilder)
 {
   // The Moz2D PathBuilder that our SVGPathData will be using only cares about
   // the fill rule. However, in order to fulfill the requirements of the SVG
   // spec regarding zero length sub-paths when square line caps are in use,
   // SVGPathData needs to know our stroke-linecap style and, if "square", then
   // also our stroke width. See the comment for
   // ApproximateZeroLengthSubpathSquareCaps for more info.
 
@@ -391,21 +393,30 @@ SVGPathElement::BuildPath()
     // reason we do not check for eStyleSVGPaintType_None or check the stroke
     // opacity here.
     if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
       strokeLineCap = style->mStrokeLinecap;
       strokeWidth = GetStrokeWidth();
     }
   }
 
-  // The fill rule that we pass must be the current
-  // computed value of our CSS 'fill-rule' property if the path that we return
-  // will be used for painting or hit-testing. For all other uses (bounds
-  // calculatons, length measurement, position-at-offset calculations) the fill
-  // rule that we pass doesn't matter. As a result we can just pass the current
-  // computed value regardless of who's calling us, or what they're going to do
-  // with the path that we return.
+  RefPtr<PathBuilder> builder;
+  if (aBuilder) {
+    builder = aBuilder;
+  } else {
+    RefPtr<DrawTarget> drawTarget =
+      gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+    // The fill rule that we pass must be the current computed value of our
+    // CSS 'fill-rule' property if the path that we return will be used for
+    // painting or hit-testing. For all other uses (bounds calculatons, length
+    // measurement, position-at-offset calculations) the fill rule that we pass
+    // doesn't matter. As a result we can just pass the current computed value
+    // regardless of who's calling us, or what they're going to do with the
+    // path that we return.
+    RefPtr<PathBuilder> builder =
+      drawTarget->CreatePathBuilder(GetFillRule());
+  }
 
-  return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth);
+  return mD.GetAnimValue().BuildPath(builder, strokeLineCap, strokeWidth);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/svg/content/src/SVGPathElement.h
+++ b/content/svg/content/src/SVGPathElement.h
@@ -48,17 +48,17 @@ public:
   // nsSVGSVGElement methods:
   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 TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   /**
    * This returns a path without the extra little line segments that
    * ApproximateZeroLengthSubpathSquareCaps can insert if we have square-caps.
    * See the comment for that function for more info on that.
    */
   virtual TemporaryRef<Path>
     GetPathForLengthOrPositionMeasuring() MOZ_OVERRIDE;
--- a/content/svg/content/src/SVGRectElement.cpp
+++ b/content/svg/content/src/SVGRectElement.cpp
@@ -148,26 +148,26 @@ SVGRectElement::ConstructPath(gfxContext
     ry = halfHeight;
 
   gfxSize corner(rx, ry);
   aCtx->RoundedRectangle(gfxRect(x, y, width, height),
                          gfxCornerSizes(corner, corner, corner, corner));
 }
 
 TemporaryRef<Path>
-SVGRectElement::BuildPath()
+SVGRectElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, width, height, rx, ry;
   GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
 
   if (width <= 0 || height <= 0) {
     return nullptr;
   }
 
-  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+  RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   rx = std::max(rx, 0.0f);
   ry = std::max(ry, 0.0f);
 
   if (rx == 0 && ry == 0) {
     // Optimization for the no rounded corners case.
     Rect r(x, y, width, height);
     pathBuilder->MoveTo(r.TopLeft());
--- a/content/svg/content/src/SVGRectElement.h
+++ b/content/svg/content/src/SVGRectElement.h
@@ -26,17 +26,17 @@ protected:
                                           already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
-  virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> X();
   already_AddRefed<SVGAnimatedLength> Y();
   already_AddRefed<SVGAnimatedLength> Height();
   already_AddRefed<SVGAnimatedLength> Width();
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -57,17 +57,17 @@ public:
   virtual bool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
   virtual void ConstructPath(gfxContext *aCtx) = 0;
 
   /**
    * Returns a Path that can be used to paint, hit-test or calculate bounds for
    * this element. May return nullptr if there is no [valid] path.
    */
-  virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
+  virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) = 0;
 
   virtual mozilla::TemporaryRef<Path> GetPathForLengthOrPositionMeasuring();
 
   /**
    * Returns a PathBuilder object created using the current computed value of
    * the CSS property 'fill-rule' for this element.
    */
   mozilla::TemporaryRef<PathBuilder> CreatePathBuilder();
--- a/content/svg/content/src/nsSVGPolyElement.cpp
+++ b/content/svg/content/src/nsSVGPolyElement.cpp
@@ -127,25 +127,25 @@ nsSVGPolyElement::ConstructPath(gfxConte
 
   aCtx->MoveTo(points[0]);
   for (uint32_t i = 1; i < points.Length(); ++i) {
     aCtx->LineTo(points[i]);
   }
 }
 
 TemporaryRef<Path>
-nsSVGPolyElement::BuildPath()
+nsSVGPolyElement::BuildPath(PathBuilder* aBuilder)
 {
   const SVGPointList &points = mPoints.GetAnimValue();
 
   if (points.IsEmpty()) {
     return nullptr;
   }
 
-  RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
+  RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
 
   pathBuilder->MoveTo(points[0]);
   for (uint32_t i = 1; i < points.Length(); ++i) {
     pathBuilder->LineTo(points[i]);
   }
 
   return pathBuilder->Finish();
 }
--- a/content/svg/content/src/nsSVGPolyElement.h
+++ b/content/svg/content/src/nsSVGPolyElement.h
@@ -41,17 +41,17 @@ public:
   // nsSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
   virtual bool AttributeDefinesGeometry(const nsIAtom *aName) MOZ_OVERRIDE;
   virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
   virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
-  virtual mozilla::TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
+  virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<mozilla::DOMSVGPointList> Points();
   already_AddRefed<mozilla::DOMSVGPointList> AnimatedPoints();
 
 protected:
   SVGAnimatedPointList mPoints;
 };