Repository navigation
Conversation
When a dash ends exactly on a path vertex (dash_remaining reaches 0 exactly as the segment is exhausted), the next step of the dash iterator sees dash_remaining == 0 < seg_remaining and inv_arclen(0) == 0, so the dash's final piece is a zero-length subsegment. That piece was emitted as a zero-length LineTo at the corner, or - when the vertex is a subpath start, where the dash phase resets to exactly zero remaining - as a LineTo joining the previous subpath to the new one. Consume such a transition without producing an element and let the next step emit the following gap's MoveTo. Advancing the state to Working at the same point as before keeps the stashing behavior (and therefore the non-stable dash order) unchanged. Fixes linebender#577
Member
|
Although the solution seemingly solve the issue at hand, deeper thought is required to come up with an appropriate solution for the ecosystem and surrounding standards, e.g. SVG 1.1. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #577: when a dash transition lands exactly on a path vertex, the dash iterator emits a zero-length
LineToat the corner instead of cleanly transitioning to the next dash.Root cause
In
DashIterator::step, a dash transition is taken wheneverdash_remaining < seg_remaining, att1 = seg.inv_arclen(dash_remaining, DASH_ACCURACY). When a dash ends exactly at the end of a segment,dash_remainingreaches exactly0as the segment is exhausted; the first step on the next segment then takes the transition branch witht1 == inv_arclen(0) == 0, so the dash's "final piece" isseg.subsegment(0.0..0.0)— a zero-length subsegment, emitted as a zero-lengthLineTo.The same situation occurs at subpath starts: the dash phase is reset per subpath (
reset_phase), and when it resets to exactly zero remaining (e.g. adash_offsetequal to the first dash length), the zero-length piece is emitted as aLineTofrom the previous subpath's end to the new subpath's start — a visible line joining two disjoint subpaths. The third regression test covers this variant.Fix
When the transition lands exactly at the current point (
t1 == 0.0) while a dash is active, consume the transition without producing an element: flip to the gap, advance the dash cycle, and advance the state toWorkingat exactly the point where the old code did, so the stashing behavior (and therefore the non-stable dash order) is unchanged. The next step emits the following gap'sMoveToas usual.For the issue's example (using
line_tos, as the issue's expected output implies — a path consisting only ofmove_tos has no segments to dash, so those look like a typo):Tests
dash_transition_on_path_vertex— the issue's case, stable dash order.dash_transition_on_path_vertex_unstable_order— same case, non-stable dash order (guards the stash interleaving, which is the subtle part of this change).dash_transition_on_subpath_start— phase reset to exactly zero at a subpath boundary (guards against the subpath-joining line).Verification
I was unable to execute
cargo testin my local environment, so I validated the change by porting the iterator's logic 1:1 and differential-testing old vs. new behavior: the port reproduces every pre-existing dash test in this file exactly, and across 50,000 randomized paths × dash patterns × offsets (both stable and non-stable order) the new output is identical to the old except that the degenerate elements are gone — no other behavioral change. Locallycargo build -p kurbo --lib,cargo clippy -p kurbo --lib(no warnings) andrustfmt --checkall pass. Please rely on CI for the actual test run.