Open junov opened 8 years ago
Also, rendering back to back lineCaps on zero-length subpaths would match the behavior of SVG path rendering.
It sounds like there's a compelling argument in favor of removing that step, so works for me. It would be good to get a WebKit canvas person's take to make sure they are OK eventually aligning with the majority and with the proposed spec, but I don't think that should block a PR.
I took a closer look at this to make sure there aren't any weird edge case side-effects from removing step 3:
If we want to match SVG, this is what it says for square line caps: "If a subpath has zero length, then the resulting effect is that the stroke for that subpath consists solely of a square with side length equal to the stroke width, centered at the subpath's point, and oriented such that two of its sides are parallel to the effective tangent at that subpath's point. See ‘path’ element implementation notes for details on how to determine the tangent at a zero-length subpath." [1] I followed the link to the implementation notes [2] and was unable to find anything relevant to "effective tangents" on that page.
Summoning @dirkschulze : Help!
References: [1] https://www.w3.org/TR/svg-strokes/#LineCaps [2] https://svgwg.org/svg2-draft/implnote.html#PathElementImplementationNotes
cc @whatwg/canvas
@AmeliaBR could you maybe help with the SVG question in https://github.com/whatwg/html/issues/1079#issuecomment-212626882 or know someone who can?
The SVG behavior is that a zero-length path segment is drawn with line caps, but a single point (e.g., created by two consecutive move-to commands) is not.
There's a detailed algorithm in SVG 2, and it includes some edge case details (like what is the direction of a zero-length path, and what to do with a zero-length close path) that have been clarified since SVG 1.1. Browsers are mostly consistent, but an updated test suite for all the edge cases is still required.
Current behavior:
Example showing the same path in SVG and Canvas with square line caps: https://codepen.io/AmeliaBR/pen/KQKjXJ
The path includes:
As expected, all browsers draw line-caps for most zero-length SVG path segments, but with some quirks (Edge skips the zero-length arc segment, and Safari draws two double-linecap squares at different orientations for each--not sure what's going on there.)
Chrome and Safari both draw line-caps for the zero-length path segments in canvas (although they disagree on orientation & for reasons I don't understand Safari initializes a canvas to solid black).
Firefox and Edge do not draw any of the zero-length segment linecaps in canvas, conforming with the current canvas spec. (Note that I'm using a polyfill for Edge; the thin black square confirms that it can draw from a path data string.)
My opinion:
I believe it would be preferable to authors (and maybe even convenient for implementers) if canvas stroking behavior was consistent with SVG behavior, unless there is a legacy reason to maintain a difference. Since some major implementations do not match the current canvas spec, I doubt there would be a significant compat issue with changing it.
I tend to agree. (I think it would be great if eventually SVG and canvas could use a shared underlying model for paths, instead of having separate descriptions that are somehow magically intertwined (canvas accepts SVG paths after all). CSS needs this too to define its various path-related things, some of which seemingly accept SVG path syntax already.)
bumping this, as we seem to have stumbled upon a similar problem. It seems that the current browser behavior is non compatible. As Firefox is doing what SVG does (drawing), while Chrome only draws if there's a moveTo/lineTo to the same point, while Safari never draws.
We are planning to change behavior to match Firefox and SVG.
bumping this, as we seem to have stumbled upon a similar problem. It seems that the current browser behavior is non compatible. As Firefox is doing what SVG does (drawing), while Chrome only draws if there's a moveTo/lineTo to the same point, while Safari never draws.
We are planning to change behavior to match Firefox and SVG.
@fserb I notice that in https://bugs.chromium.org/p/chromium/issues/detail?id=644067, this behavior was recently changed in Blink -- but not in the way you suggest here, rather the opposite. I think that's regrettable, as it's a significant step away from the goal of a common canvas2d/svg rendering model that people in the discussion here seemed to agree was desirable.
Can you perhaps raise this with the concerned engineers/teams, and maybe get people to reconsider that change?
I believe the original comment was a bit mislead.
Points with no lines coming out of them should never occur at step 9 since those subpaths are supposed to be pruned in step 3. This is confusing.
In the previous step (8), the line dash algorithm can create such points, and these are the ones that step 9 has to handle.
So the specs made sense, but the current behavior is anyway too far from being interoperable even today, and I won't be arguing that keeping the step 3 is the best move. I guess going as close as possible to SVG would be good, but most implementations are relatively far from it.
I ran a few quick tests to see how bad the discrepancies are between implementations (along with their SVG counter parts), and it's pretty bad. Even with the latest changes done in Chrome Canary. Also even SVGs implementations aren't really 100% interoperable in the way they render line-dashes. I didn't check what SVG specs really ask there. And my reading of the canvas specs might be mislead too in some cases.
Hi Kelsey, @kdashg, since this discussion is generally positive to render the line end-caps for empty paths, I am tempting to change the spec to reflect it (#9663). What's the firefox perspective on it?
Note that Firefox's current behavior almost matches with the spec after change (https://wpt.fyi/results/html/canvas/offscreen/path-objects?label=master&label=experimental&aligned&q=2d.path.stroke.prune, failling the test meaning draw the line caps).
Mozilla think this is a good idea to standardize on yes-drawing. When we tried to match spec with this, we had web-compat issues and reverted to our draw-zero-subpath-end-caps behavior.
Edge and Safari will begin to fail these tests if this change is made. Would you update behavior to match a changed spec (and tests), @annevk (Apple) and @RafaelCintron (Microsoft)?
I discussed this with colleagues and it seems reasonable to us.
The spec is currently inconsistent with itself.
Step 3 of the "trace a path" algorithm says: "Remove from path any subpaths containing no lines (i.e. subpaths with just one point)."
In step 9, in the part that explains line caps, it says: "Points with no lines coming out of them must have two caps placed back-to-back as if it was really two points connected to each other by an infinitesimally short straight line in the direction of the point's directionality (as defined above)."
Points with no lines coming out of them should never occur at step 9 since those subpaths are supposed to be pruned in step 3. This is confusing.
Currently, implementations are not compatible. Gecko and Edge will draw back to back line caps for a zero-length subpath WebKit and Blink draw nothing.
From developer feedback on the chromium issue tracker, it seems that drawing back to back line caps is desired behavior: https://bugs.chromium.org/p/chromium/issues/detail?id=577655 Blink is being changed to match the behaviours of Gecko and Edge.
Any objections to removing step 3 of the "trace a path" algorithm? https://html.spec.whatwg.org/multipage/scripting.html#trace-a-path