Skip to content

Commit b9b5dc5

Browse files
committed
Bug 1837305 - Part 2: Add ShapeType for BasicShape parser. r=emilio
For outline shapes, fill-rule should be ignored. We add the flag in the parser of BasicShape, so offset-path can use this flag to ignore fill-rule. Note: "ShapeType" means this property uses filled shapes or outline shapes. For outline shapes, we ignore fill-rule. This is from the concept of `` and `` in w3c/csswg-drafts#3468 (comment) No behavir change in this patch, just add the ability for offset-path to ignore `` when combining all basic shapes into offset-path. Differential Revision: https://phabricator.services.mozilla.com/D179625
1 parent 8e1a7c8 commit b9b5dc5

File tree

2 files changed

+59
-21
lines changed

2 files changed

+59
-21
lines changed

servo/components/style/values/specified/basic_shape.rs

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ pub type ShapeRadius = generic::ShapeRadius;
5454
/// The specified value of `Polygon`
5555
pub type Polygon = generic::GenericPolygon<LengthPercentage>;
5656

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+
5770
bitflags! {
5871
/// The flags to represent which basic shapes we would like to support.
5972
///
@@ -124,7 +137,7 @@ where
124137
loop {
125138
if shape.is_none() {
126139
shape = input
127-
.try_parse(|i| BasicShape::parse(context, i, flags))
140+
.try_parse(|i| BasicShape::parse(context, i, flags, ShapeType::Filled))
128141
.ok();
129142
}
130143

@@ -204,6 +217,7 @@ impl BasicShape {
204217
context: &ParserContext,
205218
input: &mut Parser<'i, 't>,
206219
flags: AllowedBasicShapes,
220+
shape_type: ShapeType,
207221
) -> Result<Self, ParseError<'i>> {
208222
let location = input.current_source_location();
209223
let function = input.expect_function()?.clone();
@@ -219,10 +233,11 @@ impl BasicShape {
219233
Ellipse::parse_function_arguments(context, i).map(BasicShape::Ellipse)
220234
},
221235
"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)
223238
},
224239
"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)
226241
},
227242
_ => {
228243
Err(
@@ -325,18 +340,46 @@ impl Ellipse {
325340
Ok(generic::Ellipse {
326341
semiaxis_x: a,
327342
semiaxis_y: b,
328-
position: position,
343+
position,
329344
})
330345
}
331346
}
332347

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+
333376
impl Parse for Polygon {
334377
fn parse<'i, 't>(
335378
context: &ParserContext,
336379
input: &mut Parser<'i, 't>,
337380
) -> Result<Self, ParseError<'i>> {
338381
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))
340383
}
341384
}
342385

@@ -345,15 +388,9 @@ impl Polygon {
345388
fn parse_function_arguments<'i, 't>(
346389
context: &ParserContext,
347390
input: &mut Parser<'i, 't>,
391+
shape_type: ShapeType,
348392
) -> 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);
357394
let coordinates = input
358395
.parse_comma_separated(|i| {
359396
Ok(PolygonCoord(
@@ -373,24 +410,19 @@ impl Parse for Path {
373410
input: &mut Parser<'i, 't>,
374411
) -> Result<Self, ParseError<'i>> {
375412
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))
377414
}
378415
}
379416

380417
impl Path {
381418
/// Parse the inner arguments of a `path` function.
382419
fn parse_function_arguments<'i, 't>(
383420
input: &mut Parser<'i, 't>,
421+
shape_type: ShapeType,
384422
) -> Result<Self, ParseError<'i>> {
385423
use crate::values::specified::svg_path::AllowEmpty;
386424

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);
394426
let path = SVGPathData::parse(input, AllowEmpty::No)?;
395427
Ok(Path { fill, path })
396428
}

testing/web-platform/tests/css/motion/parsing/offset-path-parsing-invalid.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
test_invalid_value("offset-path", 'path("")');
1919
test_invalid_value("offset-path", 'path(" ")');
2020

21+
// We ignore `` from offset-path: path().
22+
// https://github.com/w3c/fxtf-drafts/issues/512
23+
// https://github.com/w3c/csswg-drafts/issues/7390
24+
test_invalid_value("offset-path", 'path(nonzero, "M 0 0 H 100")');
25+
test_invalid_value("offset-path", 'path(evenodd, "M 0 0 H 100")');
26+
2127
test_invalid_value("offset-path", "ray(0 sides)");
2228
test_invalid_value("offset-path", "ray(closest-side)");
2329
test_invalid_value("offset-path", "ray(closest-side 0deg closest-side)");

0 commit comments

Comments
 (0)