Bug 643419 - pathLength should affect stroke-dasharray. r=dholbert

This commit is contained in:
Robert Longson 2011-05-01 19:26:20 +01:00
parent d0281e5301
commit a93f118660
16 changed files with 200 additions and 34 deletions

View File

@ -127,6 +127,7 @@ nsSVGNumber2::SetBaseValueString(const nsAString &aValueAsString,
}
mBaseVal = val;
mIsBaseSet = PR_TRUE;
if (!mIsAnimated) {
mAnimVal = mBaseVal;
}
@ -155,6 +156,7 @@ nsSVGNumber2::SetBaseValue(float aValue,
PRBool aDoSetAttr)
{
mBaseVal = aValue;
mIsBaseSet = PR_TRUE;
if (!mIsAnimated) {
mAnimVal = mBaseVal;
}

View File

@ -56,6 +56,7 @@ public:
mAnimVal = mBaseVal = aValue;
mAttrEnum = aAttrEnum;
mIsAnimated = PR_FALSE;
mIsBaseSet = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -70,6 +71,14 @@ public:
float GetAnimValue() const
{ return mAnimVal; }
// Returns PR_TRUE if the animated value of this number has been explicitly
// set (either by animation, or by taking on the base value which has been
// explicitly set by markup or a DOM call), PR_FALSE otherwise.
// If this returns PR_FALSE, the animated value is still valid, that is,
// useable, and represents the default base value of the attribute.
PRBool IsExplicitlySet() const
{ return mIsAnimated || mIsBaseSet; }
nsresult ToDOMAnimatedNumber(nsIDOMSVGAnimatedNumber **aResult,
nsSVGElement* aSVGElement);
#ifdef MOZ_SMIL
@ -83,6 +92,7 @@ private:
float mBaseVal;
PRUint8 mAttrEnum; // element specified tracking for attribute
PRPackedBool mIsAnimated;
PRPackedBool mIsBaseSet;
public:
struct DOMAnimatedNumber : public nsIDOMSVGAnimatedNumber

View File

@ -122,8 +122,11 @@ nsSVGPathElement::GetPointAtLength(float distance, nsIDOMSVGPoint **_retval)
return NS_ERROR_FAILURE;
float totalLength = flat->GetLength();
if (HasAttr(kNameSpaceID_None, nsGkAtoms::pathLength)) {
if (mPathLength.IsExplicitlySet()) {
float pathLength = mPathLength.GetAnimValue();
if (pathLength <= 0) {
return NS_ERROR_FAILURE;
}
distance *= totalLength / pathLength;
}
distance = NS_MAX(0.f, distance);
@ -400,11 +403,8 @@ nsSVGPathElement::GetFlattenedPath(const gfxMatrix &aMatrix)
PRBool
nsSVGPathElement::AttributeDefinesGeometry(const nsIAtom *aName)
{
if (aName == nsGkAtoms::d ||
aName == nsGkAtoms::pathLength)
return PR_TRUE;
return PR_FALSE;
return aName == nsGkAtoms::d ||
aName == nsGkAtoms::pathLength;
}
PRBool
@ -425,3 +425,18 @@ nsSVGPathElement::ConstructPath(gfxContext *aCtx)
mD.GetAnimValue().ConstructPath(aCtx);
}
gfxFloat
nsSVGPathElement::GetScale()
{
if (mPathLength.IsExplicitlySet()) {
nsRefPtr<gfxFlattenedPath> flat =
GetFlattenedPath(PrependLocalTransformTo(gfxMatrix()));
float pathLength = mPathLength.GetAnimValue();
if (flat && pathLength != 0) {
return flat->GetLength() / pathLength;
}
}
return 1.0;
}

View File

@ -55,7 +55,6 @@ class nsSVGPathElement : public nsSVGPathElementBase,
public nsIDOMSVGAnimatedPathData
{
friend class nsSVGPathFrame;
friend class nsSVGTextPathFrame;
protected:
friend nsresult NS_NewSVGPathElement(nsIContent **aResult,
@ -99,6 +98,8 @@ public:
return nsGkAtoms::d;
}
gfxFloat GetScale();
protected:
// nsSVGElement method

View File

@ -73,6 +73,7 @@ _TEST_FILES = \
test_nonAnimStrings.xhtml \
test_pathAnimInterpolation.xhtml \
test_pathSeg.xhtml \
test_pointAtLength.xhtml \
test_pointer-events.xhtml \
test_pointer-events-2.xhtml \
test_scientific.html \

View File

@ -0,0 +1,50 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=643419
-->
<head>
<title>Test getPointAtLength</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script class="testbody" type="text/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
function run()
{
var p1 = document.getElementById("p1");
var point = p1.getPointAtLength(200);
is(point.x, 200);
is(point.y, 50);
// set the pathLength to twice its actual length
p1.setAttribute("pathLength", "800");
var point = p1.getPointAtLength(200);
is(point.x, 100);
is(point.y, 50);
SimpleTest.finish();
}
window.addEventListener("load", run, false);
]]>
</script>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=643419">Mozilla Bug 643419</a>
<p id="display"></p>
<div id="content">
<svg xmlns="http://www.w3.org/2000/svg" width="750">
<defs>
<path id="p1" d="M 0 50 h 400"/>
</defs>
</svg>
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg viewBox="0 0 100 2" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="red"/>
<!-- This path is really 400 units long (and its halfway point is at the
right edge of our viewBox). We use pathLength to normalize its length
to 20, though, so the first 10-unit-long dash in stroke-dasharray ends
up covering 10/20 = 1/2 of the path. This covers the whole viewBox. -->
<path d="M-100,1 h400" pathLength="20" stroke-dasharray="10" fill="none" stroke="lime" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 677 B

View File

@ -0,0 +1,13 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg viewBox="0 0 100 2" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="lime"/>
<!-- This path is really 400 units long (and its halfway point is at the
right edge of our viewBox). We use pathLength to normalize its length
to 20, though, so the first 5-unit-long dash in stroke-dasharray ends
up covering 5/20 = 1/4 of the path. The hole in the dasharray spans
the viewBox -->
<path d="M-100,1 h400" pathLength="20" stroke-dasharray="5" fill="none" stroke="red" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 695 B

View File

@ -152,6 +152,8 @@ random-if(gtk2Widget) == objectBoundingBox-and-fePointLight-01.svg objectBoundin
== path-02.svg pass.svg
== path-03.svg pass.svg
== path-04.svg pass.svg
== pathLength-01.svg pass.svg
== pathLength-02.svg pass.svg
== pattern-invalid-01.svg pattern-invalid-01-ref.svg
== pattern-live-01a.svg pattern-live-01-ref.svg
== pattern-live-01b.svg pattern-live-01-ref.svg
@ -198,6 +200,7 @@ fails-if(Android) random-if(gtk2Widget) != text-language-01.xhtml text-language-
== text-stroke-scaling-01.svg text-stroke-scaling-01-ref.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
== 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

View File

@ -0,0 +1,31 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" class="reftest-wait">
<title>Test that pathLength of paths has no effect in animation</title>
<defs>
<path id="path" pathLength="100" d="M-200,0 h400" />
</defs>
<script xlink:href="../smil-util.js" type="text/javascript"/>
<script type="text/javascript">
function doTest() {
setTimeAndSnapshot(0.5, true);
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
<rect width="100%" height="100%" fill="lime"/>
<!-- calcMode="linear" -->
<rect x="10" y="10" width="100" height="100" fill="red"/>
<rect x="10" y="10" width="100" height="100" fill="lime">
<animateMotion dur="1s" keyPoints="0;1" keyTimes="0;1" calcMode="linear">
<mpath xlink:href="#path" />
</animateMotion>
</rect>
<!-- calcMode="paced" -->
<rect x="10" y="110" width="100" height="100" fill="red"/>
<rect x="10" y="110" width="100" height="100" fill="lime">
<animateMotion dur="1s">
<mpath xlink:href="#path" />
</animateMotion>
</rect>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -3,7 +3,6 @@
== animateMotion-by-1.svg lime.svg
== animateMotion-from-to-1.svg lime.svg
== animateMotion-mpath-target-transform-1.svg lime.svg
== animateMotion-rotate-1a.svg lime.svg
== animateMotion-rotate-1b.svg lime.svg
== animateMotion-rotate-2.svg lime.svg
@ -12,4 +11,6 @@
== animateMotion-values-paced-1b.svg animateMotion-values-paced-1-ref.svg
# Tests involving <mpath> sub-element
== animateMotion-mpath-pathLength-1.svg lime.svg
== animateMotion-mpath-targetChange-1.svg lime.svg
== animateMotion-mpath-target-transform-1.svg lime.svg

View File

@ -0,0 +1,16 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference to check that percentage startOffset ignores pathLength</title>
<defs>
<path id="x" d="M 0 100 h 400"/>
</defs>
<text>
<textPath xlink:href="#x" font-size="20" fill="black" startOffset="50%">Should see this</textPath>
</text>
</svg>

After

Width:  |  Height:  |  Size: 487 B

View File

@ -0,0 +1,16 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Testcase to check that percentage startOffset ignores pathLength</title>
<defs>
<path id="x" pathLength="20" d="M 0 100 h 400"/>
</defs>
<text>
<textPath xlink:href="#x" font-size="20" fill="black" startOffset="50%">Should see this</textPath>
</text>
</svg>

After

Width:  |  Height:  |  Size: 503 B

View File

@ -35,6 +35,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nsPresContext.h"
#include "nsSVGPathElement.h"
#include "nsSVGUtils.h"
#include "nsSVGGeometryFrame.h"
#include "nsSVGPaintServerFrame.h"
@ -116,13 +117,22 @@ nsSVGGeometryFrame::GetStrokeDashArray(gfxFloat **aDashes, PRUint32 *aCount)
nsPresContext *presContext = PresContext();
gfxFloat totalLength = 0.0f;
gfxFloat pathScale = 1.0;
if (mContent->Tag() == nsGkAtoms::path) {
pathScale = static_cast<nsSVGPathElement*>(mContent)->GetScale();
if (pathScale <= 0) {
return NS_OK;
}
}
dashes = new gfxFloat[count];
if (dashes) {
for (PRUint32 i = 0; i < count; i++) {
dashes[i] =
nsSVGUtils::CoordToFloat(presContext,
ctx,
dasharray[i]);
dasharray[i]) * pathScale;
if (dashes[i] < 0.0f) {
delete [] dashes;
return NS_OK;

View File

@ -142,20 +142,16 @@ already_AddRefed<gfxFlattenedPath>
nsSVGTextPathFrame::GetFlattenedPath()
{
nsIFrame *path = GetPathFrame();
return path ? GetFlattenedPath(path) : nsnull;
if (path) {
nsSVGPathGeometryElement *element =
static_cast<nsSVGPathGeometryElement*>(path->GetContent());
return element->GetFlattenedPath(element->PrependLocalTransformTo(gfxMatrix()));
}
return nsnull;
}
already_AddRefed<gfxFlattenedPath>
nsSVGTextPathFrame::GetFlattenedPath(nsIFrame *path)
{
NS_PRECONDITION(path, "Unexpected null path");
nsSVGPathGeometryElement *element =
static_cast<nsSVGPathGeometryElement*>(path->GetContent());
return element->GetFlattenedPath(element->PrependLocalTransformTo(gfxMatrix()));
}
gfxFloat
nsSVGTextPathFrame::GetStartOffset()
{
@ -169,9 +165,8 @@ nsSVGTextPathFrame::GetStartOffset()
if (length->IsPercentage()) {
nsRefPtr<gfxFlattenedPath> data = GetFlattenedPath();
return data ? (val * data->GetLength() / 100.0) : 0.0;
} else {
return val * GetPathScale();
}
return val * GetPathScale();
}
gfxFloat
@ -181,14 +176,7 @@ nsSVGTextPathFrame::GetPathScale()
if (!pathFrame)
return 1.0;
nsSVGPathElement *path = static_cast<nsSVGPathElement*>(pathFrame->GetContent());
float pl = path->mPathLength.GetAnimValue();
if (pl == 0.0f)
return 1.0;
nsRefPtr<gfxFlattenedPath> data = GetFlattenedPath(pathFrame);
return data ? data->GetLength() / pl : 1.0;
return static_cast<nsSVGPathElement*>(pathFrame->GetContent())->GetScale();
}
//----------------------------------------------------------------------

View File

@ -91,9 +91,6 @@ protected:
virtual void GetXY(SVGUserUnitList *aX, SVGUserUnitList *aY);
virtual void GetDxDy(SVGUserUnitList *aDx, SVGUserUnitList *aDy);
virtual const SVGNumberList *GetRotate();
private:
already_AddRefed<gfxFlattenedPath> GetFlattenedPath(nsIFrame *path);
};
#endif