Bug 702696 - Path length scale factor should not be affected by the 'transform' attribute. r=dholbert.
authorJonathan Watt <jwatt@jwatt.org>
Mon, 21 Nov 2011 21:22:19 +0000
changeset 80594 f8970ab040372501edcdf604d3104fd3f7e021fb
parent 80593 ec384df0ce7783eac46bcb811396629257497328
child 80595 816d3aca13c42a39f317852e66f3e92f49fe7254
push id21511
push userbmo@edmorley.co.uk
push dateTue, 22 Nov 2011 02:38:00 +0000
treeherdermozilla-central@b8955ff00aae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs702696
milestone11.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 702696 - Path length scale factor should not be affected by the 'transform' attribute. r=dholbert.
content/svg/content/src/nsSVGPathElement.cpp
content/svg/content/src/nsSVGPathElement.h
layout/reftests/svg/reftest.list
layout/reftests/svg/stroke-dasharray-and-pathLength-01.svg
layout/reftests/svg/textPath-02.svg
layout/svg/base/src/nsSVGGeometryFrame.cpp
layout/svg/base/src/nsSVGTextPathFrame.cpp
--- a/content/svg/content/src/nsSVGPathElement.cpp
+++ b/content/svg/content/src/nsSVGPathElement.cpp
@@ -422,22 +422,30 @@ nsSVGPathElement::GetMarkPoints(nsTArray
 
 void
 nsSVGPathElement::ConstructPath(gfxContext *aCtx)
 {
   mD.GetAnimValue().ConstructPath(aCtx);
 }
 
 gfxFloat
-nsSVGPathElement::GetPathLengthScale()
+nsSVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
 {
+  NS_ABORT_IF_FALSE(aFor == eForTextPath || aFor == eForStroking,
+                    "Unknown enum");
   if (mPathLength.IsExplicitlySet()) {
-
-    nsRefPtr<gfxFlattenedPath> flat =
-      GetFlattenedPath(PrependLocalTransformTo(gfxMatrix()));
-    float pathLength = mPathLength.GetAnimValue();
-
-    if (flat && pathLength != 0) {
-      return flat->GetLength() / pathLength;
+    float authorsPathLengthEstimate = mPathLength.GetAnimValue();
+    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 = PrependLocalTransformTo(gfxMatrix());
+      }
+      nsRefPtr<gfxFlattenedPath> path = GetFlattenedPath(matrix);
+      if (path) {
+        return path->GetLength() / authorsPathLengthEstimate;
+      }
     }
   }
   return 1.0;
 }
--- a/content/svg/content/src/nsSVGPathElement.h
+++ b/content/svg/content/src/nsSVGPathElement.h
@@ -93,22 +93,27 @@ public:
   virtual SVGAnimatedPathSegList* GetAnimPathSegList() {
     return &mD;
   }
 
   virtual nsIAtom* GetPathDataAttrName() const {
     return nsGkAtoms::d;
   }
 
+  enum PathLengthScaleForType {
+    eForTextPath,
+    eForStroking
+  };
+
   /**
    * Gets the ratio of the actual path length to the content author's estimated
    * length (as provided by the <path> element's 'pathLength' attribute). This
    * is used to scale stroke dashing, and to scale offsets along a textPath.
    */
-  gfxFloat GetPathLengthScale();
+  gfxFloat GetPathLengthScale(PathLengthScaleForType aFor);
 
 protected:
 
   // nsSVGElement method
   virtual NumberAttributesInfo GetNumberInfo();
 
   SVGAnimatedPathSegList mD;
   nsSVGNumber2 mPathLength;
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -221,19 +221,21 @@ fails-if(Android) != text-language-00.xh
 fails-if(Android) random-if(gtk2Widget) != text-language-01.xhtml text-language-01-ref.xhtml # Fails on Linux tryserver due to lack of CJK fonts.
 == text-layout-01.svg text-layout-01-ref.svg
 == text-layout-02.svg text-layout-02-ref.svg
 == text-layout-03.svg text-layout-03-ref.svg
 == text-layout-04.svg text-layout-04-ref.svg
 == text-layout-05.svg text-layout-05-ref.svg
 == text-scale-01.svg text-scale-01-ref.svg
 == text-stroke-scaling-01.svg text-stroke-scaling-01-ref.svg
+== stroke-dasharray-and-pathLength-01.svg pass.svg
 == stroke-linecap-square-w-zero-length-segs-01.svg pass.svg
 == stroke-linecap-square-w-zero-length-segs-02.svg pass.svg
 == textPath-01.svg textPath-01-ref.svg
+== textPath-02.svg pass.svg
 == text-style-01a.svg text-style-01-ref.svg
 == text-style-01b.svg text-style-01-ref.svg
 == text-style-01c.svg text-style-01-ref.svg
 == text-style-01d.svg text-style-01-ref.svg
 == text-style-01e.svg text-style-01-ref.svg
 == thin-stroke-01.svg pass.svg
 == tspan-dxdy-01.svg tspan-dxdy-ref.svg
 == tspan-dxdy-02.svg tspan-dxdy-ref.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/stroke-dasharray-and-pathLength-01.svg
@@ -0,0 +1,20 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg">
+  <title>Test stroke-dasharray with pathLength and scaling</title>
+  <rect width="100%" height="100%" fill="lime"/>
+  <!--
+    Here we set the 'pathLength' to twice the actual length of the path,
+    which should cause the stroke-dasharray values to be scaled down by one
+    half. Visually, this should effectively cancel out the 2x scaling along
+    the x-axis introduced by the 'transform' attribute.
+  -->
+  <path d="M0.5,10 L100.5,10" stroke="red" stroke-width="18" stroke-dasharray="18 22" pathLength="200" transform="scale(2,1)"/>
+  <rect x="1" y="1" width="18" height="18" fill="lime"/>
+  <rect x="41" y="1" width="18" height="18" fill="lime"/>
+  <rect x="81" y="1" width="18" height="18" fill="lime"/>
+  <rect x="121" y="1" width="18" height="18" fill="lime"/>
+  <rect x="161" y="1" width="18" height="18" fill="lime"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/textPath-02.svg
@@ -0,0 +1,15 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
+  <title>Test effect on startOffset of a scale transform on a textPath's path</title>
+  <defs>
+    <path id="path" d="M20,20 C20,150 150,150 150,20" pathLength="100" transform="scale(2,1)" fill="none" stroke="black"/>
+  </defs>
+  <rect width="100%" height="100%" fill="lime"/>
+  <text y="50">
+    <textPath xlink:href="#path" font-size="20" fill="red" startOffset="50">FAIL</textPath>
+  </text>
+  <rect x="160" y="80" width="100" height="60" fill="lime"/>
+</svg>
--- a/layout/svg/base/src/nsSVGGeometryFrame.cpp
+++ b/layout/svg/base/src/nsSVGGeometryFrame.cpp
@@ -115,18 +115,18 @@ nsSVGGeometryFrame::GetStrokeDashArray(g
   if (count) {
     const nsStyleCoord *dasharray = GetStyleSVG()->mStrokeDasharray;
     nsPresContext *presContext = PresContext();
     gfxFloat totalLength = 0.0f;
 
     gfxFloat pathScale = 1.0;
 
     if (mContent->Tag() == nsGkAtoms::path) {
-      pathScale =
-        static_cast<nsSVGPathElement*>(mContent)->GetPathLengthScale();
+      pathScale = static_cast<nsSVGPathElement*>(mContent)->
+                    GetPathLengthScale(nsSVGPathElement::eForStroking);
       if (pathScale <= 0) {
         return NS_OK;
       }
     }
 
     dashes = new gfxFloat[count];
     if (dashes) {
       for (PRUint32 i = 0; i < count; i++) {
--- a/layout/svg/base/src/nsSVGTextPathFrame.cpp
+++ b/layout/svg/base/src/nsSVGTextPathFrame.cpp
@@ -172,17 +172,17 @@ nsSVGTextPathFrame::GetStartOffset()
 gfxFloat
 nsSVGTextPathFrame::GetOffsetScale()
 {
   nsIFrame *pathFrame = GetPathFrame();
   if (!pathFrame)
     return 1.0;
 
   return static_cast<nsSVGPathElement*>(pathFrame->GetContent())->
-    GetPathLengthScale();
+    GetPathLengthScale(nsSVGPathElement::eForTextPath);
 }
 
 //----------------------------------------------------------------------
 // nsIFrame methods
 
 NS_IMETHODIMP
 nsSVGTextPathFrame::AttributeChanged(PRInt32         aNameSpaceID,
                                      nsIAtom*        aAttribute,