Description
Closed-shape strokes are rendered as inside-only (drawn after fill, outer edge on the shape boundary). This looks correct in the common case, but corners degrade visually when:
strokeWidth is large relative to the shape's dimensions, or
cornerRadius is small (e.g. 0) while strokeWidth is non-trivial
Why it happens
The inside stroke band is inset inward by strokeWidth. At a tight corner the inner miter vertex extends further inward than expected — it can overshoot into the opposite side of the shape or produce a visible notch. With cornerRadius=0 the outer edge is clean (it sits exactly on the boundary) but the inner join geometry is a raw miter with no softening.
The mergedCorner + emitJoinArc path in MeshFactory::addQuadraticStrokePath only fires when two distinct samples end up within halfW * 0.75 of each other (e.g. dense font-glyph junctions). Plain cornerRadius=0 rectangles deduplicate down to exactly 4 corner samples, so the merge never triggers and the raw miter is used.
Repro
# Obvious at extreme ratios:
Rectangle(width=0.5, height=0.5, strokeWidth=0.2, cornerRadius=0)
# Or large shape with large stroke:
Rectangle(width=6, height=4, strokeWidth=0.5, cornerRadius=0)
Possible fix
For the inside-only path, replace the miter join at corners with a bevel or round join — or clamp the inward miter extension to min(miterLen, half_short_side - halfW) so it never overshoots the shape interior.
Description
Closed-shape strokes are rendered as inside-only (drawn after fill, outer edge on the shape boundary). This looks correct in the common case, but corners degrade visually when:
strokeWidthis large relative to the shape's dimensions, orcornerRadiusis small (e.g. 0) whilestrokeWidthis non-trivialWhy it happens
The inside stroke band is inset inward by
strokeWidth. At a tight corner the inner miter vertex extends further inward than expected — it can overshoot into the opposite side of the shape or produce a visible notch. WithcornerRadius=0the outer edge is clean (it sits exactly on the boundary) but the inner join geometry is a raw miter with no softening.The
mergedCorner+emitJoinArcpath inMeshFactory::addQuadraticStrokePathonly fires when two distinct samples end up withinhalfW * 0.75of each other (e.g. dense font-glyph junctions). PlaincornerRadius=0rectangles deduplicate down to exactly 4 corner samples, so the merge never triggers and the raw miter is used.Repro
Possible fix
For the inside-only path, replace the miter join at corners with a bevel or round join — or clamp the inward miter extension to
min(miterLen, half_short_side - halfW)so it never overshoots the shape interior.