@@ -155,26 +155,30 @@ private void FlushPreparedBatch<TPixel>(
155155
156156 CompositionCoverageDefinition definition = compositionBatch . Definition ;
157157
158- // When the definition carries stroke metadata, expand the centerline
159- // path into a filled outline before rasterization.
160158 IPath rasterPath = definition . Path ;
161159 RasterizerOptions rasterizerOptions = definition . RasterizerOptions ;
162160
163- if ( definition . IsStroke )
161+ if ( definition . IsStroke && definition . StrokePattern . Length > 0 )
164162 {
165- rasterPath = definition . StrokePattern . Length > 0
166- ? rasterPath . GenerateOutline ( definition . StrokeWidth , definition . StrokePattern . Span , definition . StrokeOptions ! )
167- : rasterPath . GenerateOutline ( definition . StrokeWidth , definition . StrokeOptions ! ) ;
168-
169- // Compute the exact interest from the actual stroke outline bounds
170- // so band boundaries and coverage values match the old canvas-side path.
171- RectangleF outlineBounds = rasterPath . Bounds ;
172- outlineBounds = new RectangleF ( outlineBounds . X + 0.5F , outlineBounds . Y + 0.5F , outlineBounds . Width , outlineBounds . Height ) ;
163+ // Dashed strokes: split into dash segments on the CPU, then stroke-expand
164+ // each segment via the per-band parallel path (same as solid strokes).
165+ rasterPath = DashPathSplitter . SplitDashes ( rasterPath , definition . StrokeWidth , definition . StrokePattern . Span ) ;
166+
167+ // Recompute interest from the split path bounds with stroke expansion.
168+ float halfWidth = definition . StrokeWidth * 0.5f ;
169+ float maxExtent = halfWidth * Math . Max ( ( float ) ( definition . StrokeOptions ? . MiterLimit ?? 4.0 ) , 1.0f ) ;
170+ RectangleF pathBounds = rasterPath . Bounds ;
171+ pathBounds = new RectangleF (
172+ pathBounds . X + 0.5F - maxExtent ,
173+ pathBounds . Y + 0.5F - maxExtent ,
174+ pathBounds . Width + ( maxExtent * 2 ) ,
175+ pathBounds . Height + ( maxExtent * 2 ) ) ;
176+
173177 Rectangle interest = Rectangle . FromLTRB (
174- ( int ) MathF . Floor ( outlineBounds . Left ) ,
175- ( int ) MathF . Floor ( outlineBounds . Top ) ,
176- ( int ) MathF . Ceiling ( outlineBounds . Right ) ,
177- ( int ) MathF . Ceiling ( outlineBounds . Bottom ) ) ;
178+ ( int ) MathF . Floor ( pathBounds . Left ) ,
179+ ( int ) MathF . Floor ( pathBounds . Top ) ,
180+ ( int ) MathF . Ceiling ( pathBounds . Right ) ,
181+ ( int ) MathF . Ceiling ( pathBounds . Bottom ) ) ;
178182
179183 rasterizerOptions = new RasterizerOptions (
180184 interest ,
@@ -183,7 +187,7 @@ private void FlushPreparedBatch<TPixel>(
183187 rasterizerOptions . SamplingOrigin ,
184188 rasterizerOptions . AntialiasThreshold ) ;
185189
186- // Re-prepare commands with the actual outline interest so destination
190+ // Re-prepare commands with the dash-split interest so destination
187191 // regions and source offsets are aligned with the rasterizer.
188192 CompositionScenePlanner . ReprepareBatchCommands ( compositionBatch . Commands , target . Bounds , interest ) ;
189193 }
@@ -213,12 +217,29 @@ private void FlushPreparedBatch<TPixel>(
213217 destinationBounds ,
214218 rasterizerOptions . Interest . Top ) ;
215219
216- DefaultRasterizer . RasterizeRows (
217- rasterPath ,
218- rasterizerOptions ,
219- configuration . MemoryAllocator ,
220- operation . InvokeCoverageRow ,
221- ref reusableScratch ) ;
220+ if ( definition . IsStroke )
221+ {
222+ // All strokes (solid and dashed) use per-band parallel stroke expansion.
223+ DefaultRasterizer . RasterizeStrokeRows (
224+ rasterPath ,
225+ rasterizerOptions ,
226+ configuration . MemoryAllocator ,
227+ operation . InvokeCoverageRow ,
228+ ref reusableScratch ,
229+ definition . StrokeWidth ,
230+ definition . StrokeOptions ! . LineJoin ,
231+ definition . StrokeOptions ! . LineCap ,
232+ ( float ) definition . StrokeOptions ! . MiterLimit ) ;
233+ }
234+ else
235+ {
236+ DefaultRasterizer . RasterizeRows (
237+ rasterPath ,
238+ rasterizerOptions ,
239+ configuration . MemoryAllocator ,
240+ operation . InvokeCoverageRow ,
241+ ref reusableScratch ) ;
242+ }
222243 }
223244 finally
224245 {
0 commit comments