SVG: pathLength attribute don't work

RESOLVED FIXED

Status

()

Core
SVG
--
major
RESOLVED FIXED
7 years ago
6 years ago

People

(Reporter: Бражник Юрий, Assigned: Robert Longson)

Tracking

({dev-doc-complete})

Trunk
dev-doc-complete
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(5 attachments, 3 obsolete attachments)

(Reporter)

Description

7 years ago
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.151 Safari/534.16
Build Identifier: 4.0 RC1

Summary say everithing. It's just don't work. It's not working in all other browsers too, except Opera 11.01.
W3 documentation on this: http://www.w3.org/TR/SVG/paths.html#PathLengthAttribute

Reproducible: Always

Steps to Reproduce:
path d="M0,0 L100,0" pathLength="200" stroke-dasharray="100,100"
Actual Results:  
dash appears to be 100% of path istead of only 50%(100 from 200)

Expected Results:  
dash must be only 50% of path length
(Assignee)

Updated

7 years ago
Component: General → SVG
Product: Firefox → Core
QA Contact: general → general
(Assignee)

Comment 1

7 years ago
Can you add a complete testcase as an attachment using the Add an attachment link above please?
(Reporter)

Comment 2

7 years ago
Created attachment 520655 [details]
Test SVG file

This SVG must draw horisontal line from left to center(100 is 50% of 200). But in firefox 4.0 RC1 it draws line from left to right because pathLength don't work.
(Assignee)

Updated

7 years ago
Status: UNCONFIRMED → NEW
Ever confirmed: true
(Reporter)

Comment 3

7 years ago
Created attachment 520723 [details]
Example of use case

This SVG demonstrates that with pathLength attribute one can make smooth curve drawing animation without javascript(using only SMIL). To see the proper animation use Opera 11.

This functionality wuld be very helpfull in drawing, map and navigation software.
FWIW, if you're designing an app that depends on this behavior, you can get the same effect using an animation on "stroke-dashoffset". See e.g. http://hoffmann.bplaced.net/svgtest/stroke16a.svg
OS: Windows 7 → All
Hardware: x86 → All
Version: unspecified → Trunk
(Reporter)

Comment 5

7 years ago
That approach relies on precomputed path length. Using pathLength attribute we dont nead to know actual path length.

Another approach is to use javascript getTotalLength() to determine the path length and change dash length accordingly. But this approach neads javascript and all animated objects shuld have "id". Not so preaty.

Comment 6

7 years ago
A simpler method is to animate stroke-dasharray directly, not stroke-dashoffset
and you need no pathLength, just the second list element has to be large enough:
http://hoffmann.bplaced.net/svgtest/lorenz2tiny.php
Unfortunatly several viewers have problems with animation of stroke-dasharray
and one should not use a path with more than one M/m command together with
stroke-dasharray at all, because this is somehow between undefined and typically
wrong implemented.

On the other hand pathLength is basically intended to provide information about
own numerical results for the calculation of the path length to allow the viewer
to adjust several features to the intended effect, therefore the provided 
pathLength will typically only deviate slightly from the result of the viewer.

But obviously because numerics is not simple for every author, pathLength provides an important functionality to get predictable results in a simple way.
(Reporter)

Comment 7

7 years ago
(In reply to comment #6)
> A simpler method is to animate stroke-dasharray directly, not stroke-dashoffset
> and you need no pathLength, just the second list element has to be large
> enough:
> http://hoffmann.bplaced.net/svgtest/lorenz2tiny.php

The example you provide use pathLength! And it's not simpler to use stroke-dasharray...

Comment 8

7 years ago
But my calculated pathLength is only of minor importance. It is not used within 
the animation of stroke-dasharray.
You can see, that with Gecko the circle is always on the beginning of the
stroked part of the stroke-dasharray pattern, but Gecko currently ignores 
pathLength. This attribute becomes only important, if the pathLength calculation
of the viewer deviates significantly from my calculation. Because fortunately this is not the case for Gecko, you still get the intended result.

Animation of stroke-dasharray for this purpose is simpler than that of stroke-dashoffset, because you don't have to calculate the pathLength at all, if the
timing within the painting of stroke pattern is not so important. In this case
the timing is important, because it has to be the same as for the circle in motion. For this reason, the pathLength gets relevant, but you need it anyway
for each path segment to get the timing synchronised - this will be always the
task for the author. The value of the pathLength attribute is only an additional
help to improve the accuracy of the presentation of the viewer and the calculated values. If this is good enough, pathLength has no influence at all.
It matters only, if the accuracy is bad.
(Reporter)

Comment 9

7 years ago
You precalculate path length in your php script and then generate svg accordingly?

PS: my skype: brazhnyk_yuriy

Comment 10

7 years ago
Yes, for this application this is required. Else, if 1% of the active duration of
the animation does not matter, you can simply use stroke-dashoffset itself to get
an approximation of the pathLength for the last value in the values list of
the animation, if you do not use a PHP-script. For static files I typically use
this approach to get the aproximate pathLength for the last value from a reliable
viewer...
(Reporter)

Comment 11

7 years ago
You can read my 5 comment about precomputed path length and another aproach based on JavaScript...
Your approach is working in Gekko(unlike approach proposed in 4 comment) but still this is not an ultimate answer... And your approach generates huge output...
One good reason to use your method is to support devices that dont have JS or have JS turned off...

I will attach example of JS method soon...
(Assignee)

Updated

6 years ago
Assignee: nobody → longsonr
(Assignee)

Comment 12

6 years ago
Created attachment 527938 [details] [diff] [review]
patch
Attachment #527938 - Flags: review?(dholbert)
(Assignee)

Comment 13

6 years ago
Created attachment 527939 [details]
test adapted from patch
(Assignee)

Comment 14

6 years ago
Olaf, are you happy that the testcase in comment 13 should display as an entirely lime page?

Comment 15

6 years ago
Not sure, if I understand the test at all (and the behaviour might depend on
the script).
At least, because animateMotion uses calcMode paced by default, it is pretty
useless to provide keyPoints and keyTimes. 
Anyway, even for calcMode discrete, linear or spline, keyPoints, keyTimes,
keySplines etc do not depend on the absolute length of the path, therefore you
should get the same result with and without pathLength (there are for example
bugs in Operas pathLength implementation related to this and resulting in nonsense-effects ;o) - therefore to compare animateMotion with a path with
pathLength and one without could be a useful test to ensure, that bugs from
Opera are not duplicated ;o)
Up to now, concerning animateMotion I have no example, where pathLength could
influence the behaviour. Of course it has for stroke-dasharray, text on a path
etc, if you use something not relative to the pathLength. 
If the notation is relative to the pathLength, obviously this notation covers
the effect of pathLength itself. Or at least to see some deviation, one might
have to use path segments, that cause accuracy problems for the viewer in 
pathLength calculation for such segments. But because one can only provide
pathLength for the complete path, not for each segment, one can in the worst
case only see the accuracy problem of the viewer, but pathLength provided by the author cannot help to fix this.

If you write stroke-dasharray="20,20", pathLength has clearly an effect, if
there is a deviation between the authors calculation and the viewers
calculation. Authors can never note values for stroke-dasharray relative to
the pathLength. For animateMotion I think they cannot note something not
relative to the pathLength.
(Assignee)

Comment 16

6 years ago
What I'm trying to do is freeze an animation along a path half way along the path. If the pathLength is set to a different value to the actual length of the path then it should freeze at a different point shouldn't it?
(Assignee)

Comment 17

6 years ago
In http://www.w3.org/TR/SVG/animate.html#AnimateMotionElement the keyPoints text says...

Distance calculations use the user agent's distance along the path algorithm. Each progress value in the list corresponds to a value in the ‘keyTimes’ attribute list.

Comment 18

6 years ago
Created attachment 527954 [details]
extreme animateMotion sample, where pathLength, accuracy and timing model problems might matter. The frozen position of the rect and circle will depend on this.

Comment 19

6 years ago
With my sample, you can see for example differences between Opera and 
Gecko, maybe others as well - you can see it with and without pathLength.

Because for calcMode paced (the default for animateMotion) is defined, that
keyTimes are ignored, nothing can depend on it. You have to set calcMode
linear or discrete to set keyPoints and keyTimes, obviously then it is better to
have a more exiting structure like
<animateMotion dur="5s" "calcMode="discrete" keyPoints="0.7;0.1;0;1;0.5" keyTimes="0;0.3;0.7;1" fill="freeze"/> ...
(Assignee)

Comment 20

6 years ago
I'll attach a new patch.
(Assignee)

Updated

6 years ago
Attachment #527938 - Flags: review?(dholbert)
(Assignee)

Comment 21

6 years ago
Created attachment 527987 [details] [diff] [review]
updated patch

Updated reftest in this one with both calcMode=linear and calcMode=paced based on recent comments
Attachment #527938 - Attachment is obsolete: true
Attachment #527987 - Flags: review?(dholbert)
IIUC, this patch will make pathLength affect the behavior of a "keyPoints" animateMotion animation.  That doesn't make sense to me.

I interpret "keyPoints" values to be fractional progress-values from range [0,1], with 0 matching the beginning of the rendered path and 1 matching the end of the rendered path.

Even if the user provides us with their own calculation of the path's length, that shouldn't visually affect our calculation of what "50% of the way along the path" means, IMHO.  (Perhaps under-the-hood it could affect our calculations, but it should end up canceling out, I'd imagine.)
(In reply to comment #22)
> I interpret "keyPoints" values to be fractional progress-values from range
> [0,1], with 0 matching the beginning of the rendered path and 1 matching the
> end of the rendered path.

Contrast this to e.g. GetPointAtLength, which takes an actual length value.  In that case, it makes sense to me that we should interpret that (and normalize) with respect to the author's specified pathLength.

So e.g. supposing we have a 400px-long straight line for our path, with an author-specified pathLength="100".  In that case, I'd expect getPointAtLength(50) to return the path's actual center point, and your patch seems to do that, which is great.  But regardless of the pathLength attr, I'd also expect keyPoints="0.5" to put us at the path's actual center point, which I think your patch would break.

This all (comment 22 & this comment) is to say: I'm not sure I agree that we need the SVGMotionSMILAnimationFunction.* changes.
Comment on attachment 527987 [details] [diff] [review]
updated patch

>+++ b/layout/reftests/svg/pathLength-01.svg
>@@ -0,0 +1,4 @@
>+<svg viewBox="0 0 100 2" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
>+  <rect width="100%" height="100%" fill="red"/>
>+	<path d="M-100,1 L200,1" pathLength="50" stroke-dasharray="100,100" fill="none" stroke="lime" stroke-width="2"/>
>+</svg>

This test is a bit coarse - both the path itself and its stroked dash extend far to the right of the viewPort, which allows our code to be off by quite a lot without the test noticing.

To address that, could you:

 (a) Tweak this test so that it just *barely* has enough lime to pass, so we can be sure that we're scaling stroke-dasharray enough -- e.g., replace your <path> element with the following (or something like it):
>    <!-- 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"/>

 (b) Add a second testcase that ensures we're not scaling *too much* -- e.g. make a copy of your existing test, after the above tweak (or something like it), and then flip the lime vs. red colors, and change stroke-dasharray to "5".  (That will make a red stroke go *just* up to our viewport, and then be transparent across the viewport, and then start the red stroke again *just* to the right of the viewport).

>+++ b/layout/reftests/svg/smil/motion/animateMotion-mpath-pathLength-1.svg

So in this test, IIUC, you're you're using pathLength to make an animateMotion-targeted element hit the end of its path when the animation's duration is only 50% completed (and when it otherwise would only be 50% of the way along the path).

Per my previous 2 posts, I'm not sure I agree that's correct.  (Whatever we end up doing w.r.t. that, though, I agree that we need an animateMotion reftest to check the settled-on behavior.)

> nsSVGTextPathFrame::GetStartOffset()
> {
[...]
>+  val *= GetPathScale();
>+
>   if (length->IsPercentage()) {
>     nsRefPtr<gfxFlattenedPath> data = GetFlattenedPath();
>     return data ? (val * data->GetLength() / 100.0) : 0.0;
>-  } else {
>-    return val * GetPathScale();
>   }
>+  return val;

My reasoning regarding animateMotion/keyPoints applies here, too -- I'd imagine that e.g. startOffset="50%" should always place us 50% of the way along the path, regardless of the user's pathLength normalization value.

So I'd think we'd want to preserve the existing logic here -- that is, I don't think we should use GetPathScale() in the length->IsPercentage() case.  What do you think?

Also, could you add a reftest with a pathLength and a percent-valued startOffset?  Since your change in this function doesn't break any existing reftests, that leads me to believe that this is un-tested right now, which we should fix. :)

Comment 25

6 years ago
About comment 22:
This is, what I already tried to explain, typically there is no visible effect
from pathLength for animateMotion. Only if the pathLength calculation of the
viewer has low accuracy for some path segments, the pathLength may have some 
influence. For example if one uses a simple integration method together with
the parametrisation of a cubic path, the numerical result will be typically
slightly shorter than the correct length. If something like the De Casteljau's
algorithm is used to approximate the cubic curve with lines, the result will be
slightly larger than the correct length. If as in attachment 527954 [details] the path
consists of a segment of known length and one with a numerical result and a
keyPoint or the frozen end of the animation or something similar is set close
to M between those two path segments, there can be some visible difference.
Of course, if the calculation of the author is low and that of viewers is good,
the difference between expected result and rendered result will be always the
same, only if the accuracies of the viewers are different, their rendering might
get different and may depend on pathLength as well.
But the accuracy of pathLength calculation seems to be good for Gecko,
therefore it should be difficult to see an effect at all. This does not mean,
that it will fit to the expectation of an author with a low accuracy calculation ;o)
pathLength calculation of Opera is good as well, the reason why it has a wrong frozen position for the given sample is maybe an accuracy problem for timing, a pessimisation introduced already for Opera 9.5alpha.
(Assignee)

Comment 26

6 years ago
I'll remove all the animateMotion stuff and the percentage text change. I must admit I found the text in http://www.w3.org/TR/SVG/animate.html#AnimateMotionElement about the keyPoints using the user agent's distance along the path algorithm confusing as well as this text further on...

At any time t within a motion path animation of duration dur, the computed coordinate (x,y) along the motion path is determined by finding the point (x,y) which is t/dur distance along the motion path using the user agent's distance along the path algorithm.
(One other thing I just realized - we have no tests at all for getPointAtLength right now -- could you either add a mochitest for that (with/without pathLength) or file a quick followup bug on that?)
(Assignee)

Comment 28

6 years ago
Created attachment 529296 [details] [diff] [review]
address more review comments
Attachment #527987 - Attachment is obsolete: true
Attachment #527987 - Flags: review?(dholbert)
Attachment #529296 - Flags: review?(dholbert)
(Assignee)

Comment 29

6 years ago
(In reply to comment #27)
> (One other thing I just realized - we have no tests at all for getPointAtLength
> right now -- could you either add a mochitest for that (with/without
> pathLength) or file a quick followup bug on that?)

I'll file a followup.
Comment on attachment 529296 [details] [diff] [review]
address more review comments

>+++ b/layout/reftests/svg/textPath-01-ref.svg
[...]
>+  <text>
>+    <textPath xlink:href="#x" font-size="20" fill="black" startOffset="50%">Should see this</textPath>
>+  </text>
>diff --git a/layout/reftests/svg/textPath-01.svg b/layout/reftests/svg/textPath-01.svg
[...]
>+++ b/layout/reftests/svg/textPath-01.svg
[...]
>+  <text><textPath xlink:href="#x" font-size="20" fill="black" startOffset="50%">Should see this</textPath></text>
[...]

Nit: Where possible, it's nice to make the testcase & reference case easily diff-able (with the only difference being the thing that you're testing), so that people investigating test-failures can easily figure out what's actually being tested.

Could you make the above chunks match, so that the presence of |pathLength| is really the only difference between these two files?

Also: per the end of my note on animateMotion-mpath-pathLength-1.svg above, I think we need a reftest for <mpath> with keyPoints & pathLength (like you had in your previous patch, except now asserting that the pathLength *doesn't* affect us).  Something like the above textPath testcase would be nice (just two copies of the same file, with pathLength added to one).

r=dholbert with the above.
Attachment #529296 - Flags: review?(dholbert) → review+
(In reply to comment #30)
> Also: per the end of my note on animateMotion-mpath-pathLength-1.svg above, I
> think we need a reftest for <mpath> with keyPoints & pathLength

(This test isn't super-crucial to have now, since we're not expecting its behavior to change -- so if you don't have time for it right now, feel free to bundle it in with the followup getPointAtLength bug, and somebody can address it there.)
(Assignee)

Comment 32

6 years ago
Created attachment 529371 [details] [diff] [review]
hg changeset patch with extra tests
Attachment #529296 - Attachment is obsolete: true
(Assignee)

Comment 33

6 years ago
push to try http://hg.mozilla.org/try/pushloghtml?changeset=eddc7bf8d690
(Assignee)

Updated

6 years ago
Keywords: checkin-needed
(Assignee)

Comment 34

6 years ago
try was fine modulo known intermittent oranges
(Assignee)

Comment 35

6 years ago
Followups won't be necessary as I added additional tests

Comment 36

6 years ago
http://hg.mozilla.org/mozilla-central/rev/133040714411
Status: NEW → RESOLVED
Last Resolved: 6 years ago
Resolution: --- → FIXED

Updated

6 years ago
Keywords: checkin-needed
Keywords: dev-doc-needed
(Assignee)

Updated

6 years ago
Blocks: 608161
Documented the pathLength attribute:

https://developer.mozilla.org/en/SVG/Attribute/pathLength

And mentioned on Firefox 6 for developers.
Keywords: dev-doc-needed → dev-doc-complete
You need to log in before you can comment on or make changes to this bug.