@@ -54,6 +54,19 @@ pub type ShapeRadius = generic::ShapeRadius;
54
54
/// The specified value of `Polygon`
55
55
pub type Polygon = generic:: GenericPolygon < LengthPercentage > ;
56
56
57
+ /// For filled shapes, we use fill-rule, and store it for path() and polygon().
58
+ /// For outline shapes, we should ignore fill-rule.
59
+ ///
60
+ /// https://github.com/w3c/fxtf-drafts/issues/512
61
+ /// https://github.com/w3c/csswg-drafts/issues/7390
62
+ /// https://github.com/w3c/csswg-drafts/issues/3468
63
+ pub enum ShapeType {
64
+ /// The CSS property uses filled shapes. The default behavior.
65
+ Filled ,
66
+ /// The CSS property uses outline shapes. This is especially useful for offset-path.
67
+ Outline ,
68
+ }
69
+
57
70
bitflags ! {
58
71
/// The flags to represent which basic shapes we would like to support.
59
72
///
@@ -124,7 +137,7 @@ where
124
137
loop {
125
138
if shape. is_none ( ) {
126
139
shape = input
127
- . try_parse ( |i| BasicShape :: parse ( context, i, flags) )
140
+ . try_parse ( |i| BasicShape :: parse ( context, i, flags, ShapeType :: Filled ) )
128
141
. ok ( ) ;
129
142
}
130
143
@@ -204,6 +217,7 @@ impl BasicShape {
204
217
context : & ParserContext ,
205
218
input : & mut Parser < ' i , ' t > ,
206
219
flags : AllowedBasicShapes ,
220
+ shape_type : ShapeType ,
207
221
) -> Result < Self , ParseError < ' i > > {
208
222
let location = input. current_source_location ( ) ;
209
223
let function = input. expect_function ( ) ?. clone ( ) ;
@@ -219,10 +233,11 @@ impl BasicShape {
219
233
Ellipse :: parse_function_arguments( context, i) . map( BasicShape :: Ellipse )
220
234
} ,
221
235
"polygon" if flags. contains( AllowedBasicShapes :: POLYGON ) => {
222
- Polygon :: parse_function_arguments( context, i) . map( BasicShape :: Polygon )
236
+ Polygon :: parse_function_arguments( context, i, shape_type)
237
+ . map( BasicShape :: Polygon )
223
238
} ,
224
239
"path" if flags. contains( AllowedBasicShapes :: PATH ) => {
225
- Path :: parse_function_arguments( i) . map( BasicShape :: Path )
240
+ Path :: parse_function_arguments( i, shape_type ) . map( BasicShape :: Path )
226
241
} ,
227
242
_ => {
228
243
Err (
@@ -325,18 +340,46 @@ impl Ellipse {
325
340
Ok ( generic:: Ellipse {
326
341
semiaxis_x : a,
327
342
semiaxis_y : b,
328
- position : position ,
343
+ position,
329
344
} )
330
345
}
331
346
}
332
347
348
+ fn parse_fill_rule < ' i , ' t > (
349
+ input : & mut Parser < ' i , ' t > ,
350
+ shape_type : ShapeType ,
351
+ ) -> FillRule {
352
+ match shape_type {
353
+ // Per [1] and [2], we ignore `` for outline shapes, so always use a default
354
+ // value.
355
+ // [1] https://github.com/w3c/csswg-drafts/issues/3468
356
+ // [2] https://github.com/w3c/csswg-drafts/issues/7390
357
+ //
358
+ // Also, per [3] and [4], we would like the ignore `` from outline shapes, e.g.
359
+ // offset-path, which means we don't parse it when setting `ShapeType::Outline`.
360
+ // This should be web compatible because the shipped "offset-path:path()" doesn't have
361
+ // `` and "offset-path:polygon()" is a new feature and still behind the
362
+ // preference.
363
+ // [3] https://github.com/w3c/fxtf-drafts/issues/512#issuecomment-1545393321
364
+ // [4] https://github.com/w3c/fxtf-drafts/issues/512#issuecomment-1555330929
365
+ ShapeType :: Outline => Default :: default ( ) ,
366
+ ShapeType :: Filled => input
367
+ . try_parse ( |i| -> Result < _ , ParseError > {
368
+ let fill = FillRule :: parse ( i) ?;
369
+ i. expect_comma ( ) ?;
370
+ Ok ( fill)
371
+ } )
372
+ . unwrap_or_default ( ) ,
373
+ }
374
+ }
375
+
333
376
impl Parse for Polygon {
334
377
fn parse < ' i , ' t > (
335
378
context : & ParserContext ,
336
379
input : & mut Parser < ' i , ' t > ,
337
380
) -> Result < Self , ParseError < ' i > > {
338
381
input. expect_function_matching ( "polygon" ) ?;
339
- input. parse_nested_block ( |i| Self :: parse_function_arguments ( context, i) )
382
+ input. parse_nested_block ( |i| Self :: parse_function_arguments ( context, i, ShapeType :: Filled ) )
340
383
}
341
384
}
342
385
@@ -345,15 +388,9 @@ impl Polygon {
345
388
fn parse_function_arguments < ' i , ' t > (
346
389
context : & ParserContext ,
347
390
input : & mut Parser < ' i , ' t > ,
391
+ shape_type : ShapeType ,
348
392
) -> Result < Self , ParseError < ' i > > {
349
- let fill = input
350
- . try_parse ( |i| -> Result < _ , ParseError > {
351
- let fill = FillRule :: parse ( i) ?;
352
- i. expect_comma ( ) ?; // only eat the comma if there is something before it
353
- Ok ( fill)
354
- } )
355
- . unwrap_or_default ( ) ;
356
-
393
+ let fill = parse_fill_rule ( input, shape_type) ;
357
394
let coordinates = input
358
395
. parse_comma_separated ( |i| {
359
396
Ok ( PolygonCoord (
@@ -373,24 +410,19 @@ impl Parse for Path {
373
410
input : & mut Parser < ' i , ' t > ,
374
411
) -> Result < Self , ParseError < ' i > > {
375
412
input. expect_function_matching ( "path" ) ?;
376
- input. parse_nested_block ( Self :: parse_function_arguments)
413
+ input. parse_nested_block ( |i| Self :: parse_function_arguments ( i , ShapeType :: Filled ) )
377
414
}
378
415
}
379
416
380
417
impl Path {
381
418
/// Parse the inner arguments of a `path` function.
382
419
fn parse_function_arguments < ' i , ' t > (
383
420
input : & mut Parser < ' i , ' t > ,
421
+ shape_type : ShapeType ,
384
422
) -> Result < Self , ParseError < ' i > > {
385
423
use crate :: values:: specified:: svg_path:: AllowEmpty ;
386
424
387
- let fill = input
388
- . try_parse ( |i| -> Result < _ , ParseError > {
389
- let fill = FillRule :: parse ( i) ?;
390
- i. expect_comma ( ) ?;
391
- Ok ( fill)
392
- } )
393
- . unwrap_or_default ( ) ;
425
+ let fill = parse_fill_rule ( input, shape_type) ;
394
426
let path = SVGPathData :: parse ( input, AllowEmpty :: No ) ?;
395
427
Ok ( Path { fill, path } )
396
428
}
0 commit comments