pub struct Contour {
pub points: Vec<Point>,
pub closed: bool,
pub has_segments: bool,
}Expand description
One flattened contour. closed is METADATA from the path’s Close verb
(Impeller’s EndContour(origin, with_close)) — never inferred from point
coincidence, so an open contour that happens to end at its start keeps
its caps. Closed contours end with the start point repeated: the closing
edge is part of the polyline (dashing and length walks see it); the
stroker drops the duplicate and joins at the seam instead of capping.
Fields§
§points: Vec<Point>§closed: bool§has_segments: boolThis contour was DRAWN, not merely positioned: some verb after the
opening move_to produced geometry.
close counts. That is the subtle part, and it is deliberate: a
closepath emits the closing edge, so move_to(p) + close() is an
explicit zero-length SUBPATH and strokes exactly like move_to(p) +
line_to(p). Only a bare move_to with nothing after it paints
nothing. Impeller frames it the same way — its Close() calls
SegmentEncountered() — and Skia converts move+close into a
zero-length line for every non-butt cap.
Metadata from the path walk, for the same reason closed is: point
coincidence cannot answer it. All three of move_to(p),
move_to(p) line_to(p) and move_to(p) close() reduce to the
identical single point, and the first strokes differently from the
other two — nothing under any cap, versus a circle under round caps
and a square under square caps (SVG 2 §13.4; Chrome agrees).
Both references keep the same bit: Skia’s fSegmentCount, which
finishContour requires to be positive before it emits anything, and
Impeller’s contour_has_segments_, which gates BeginContour.