@@ -18,6 +18,7 @@ public struct CompositionCommand
1818 private readonly Matrix4x4 transform ;
1919 private readonly IReadOnlyList < IPath > ? clipPaths ;
2020 private readonly ShapeOptions shapeOptions ;
21+ private readonly bool enforceFillOrientation ;
2122
2223 private CompositionCommand (
2324 int definitionKey ,
@@ -29,7 +30,8 @@ private CompositionCommand(
2930 Pen ? pen ,
3031 Matrix4x4 transform ,
3132 IReadOnlyList < IPath > ? clipPaths ,
32- ShapeOptions shapeOptions )
33+ ShapeOptions shapeOptions ,
34+ bool enforceFillOrientation )
3335 {
3436 this . DefinitionKey = definitionKey ;
3537 this . sourcePath = sourcePath ;
@@ -42,6 +44,7 @@ private CompositionCommand(
4244 this . transform = transform ;
4345 this . clipPaths = clipPaths ;
4446 this . shapeOptions = shapeOptions ;
47+ this . enforceFillOrientation = enforceFillOrientation ;
4548 }
4649
4750 /// <summary>
@@ -92,6 +95,10 @@ private CompositionCommand(
9295 /// <param name="rasterizerOptions">Rasterizer options used to generate coverage.</param>
9396 /// <param name="shapeOptions">Shape options for clip operations.</param>
9497 /// <param name="transform">Transform matrix to apply during preparation.</param>
98+ /// <param name="enforceFillOrientation">
99+ /// When <see langword="true"/>, preparation normalizes closed contour orientation before rasterization.
100+ /// Callers should only enable this when they explicitly want contour winding rewritten.
101+ /// </param>
95102 /// <param name="destinationOffset">Absolute destination offset where coverage is composited.</param>
96103 /// <param name="pen">Optional pen for stroke commands. The batcher expands strokes to fills.</param>
97104 /// <param name="clipPaths">Optional clip paths to apply during preparation.</param>
@@ -103,6 +110,7 @@ public static CompositionCommand Create(
103110 in RasterizerOptions rasterizerOptions ,
104111 ShapeOptions shapeOptions ,
105112 Matrix4x4 transform ,
113+ bool enforceFillOrientation ,
106114 Point destinationOffset = default ,
107115 Pen ? pen = null ,
108116 IReadOnlyList < IPath > ? clipPaths = null )
@@ -119,7 +127,8 @@ public static CompositionCommand Create(
119127 pen ,
120128 transform ,
121129 clipPaths ,
122- shapeOptions ) ;
130+ shapeOptions ,
131+ enforceFillOrientation ) ;
123132 }
124133
125134 /// <summary>
@@ -178,7 +187,7 @@ internal void Prepare(GeometryPreparationCache? geometryCache = null)
178187 /// </summary>
179188 /// <returns>The geometry preparation cache key.</returns>
180189 internal readonly GeometryPreparationCache . GeometryPreparationKey CreateGeometryPreparationKey ( )
181- => new ( this . sourcePath , this . transform , this . pen , this . clipPaths , this . shapeOptions ) ;
190+ => new ( this . sourcePath , this . transform , this . pen , this . clipPaths , this . shapeOptions , this . enforceFillOrientation ) ;
182191
183192 /// <summary>
184193 /// Builds prepared geometry for this command without consulting any external cache.
@@ -207,7 +216,7 @@ internal readonly PreparedGeometry BuildPreparedGeometry()
207216 }
208217
209218 // Line preparation happens here so backends no longer need to traverse IPath.
210- return PreparedGeometry . Create ( path , enforceFillOrientation : this . pen is null ) ;
219+ return PreparedGeometry . Create ( path , enforceFillOrientation : this . enforceFillOrientation ) ;
211220 }
212221
213222 /// <summary>
0 commit comments