Skip whole CSS at-rule blocks in the SVG parser by brace depth

Found while testing crates/svg/src/lib.rs:510-520 (parse_css)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-28 09:00:16 +01:00
co-authored by Claude Haiku 5.5
parent af415aa6e1
commit 10e173c0e4
2 changed files with 33 additions and 3 deletions
+21 -3
View File
@@ -510,12 +510,30 @@ fn parse_css(css: &str, sheet: &mut StyleSheet) -> Result<(), Error> {
let mut rest = css.as_str();
while let Some(open) = rest.find('{') {
let sel = rest[..open].trim();
if sel.starts_with('@') {
// Skip the whole at-rule block, matching nested braces by depth.
let mut depth = 0usize;
let mut end = None;
for (i, c) in rest[open..].char_indices() {
match c {
'{' => depth = depth.saturating_add(1),
'}' => {
depth = depth.saturating_sub(1);
if depth == 0 {
end = Some(open + i + 1);
break;
}
}
_ => {}
}
}
let Some(end) = end else { break };
rest = &rest[end..];
continue;
}
let Some(close) = rest[open..].find('}') else { break };
let body = &rest[open + 1..open + close];
rest = &rest[open + close + 1..];
if sel.starts_with('@') {
continue;
}
let mut decls = parse_decls(body);
sheet.decls = sheet.decls.saturating_add(decls.len());
if sheet.decls > MAX_CSS_DECLARATIONS {
+12
View File
@@ -422,3 +422,15 @@ fn font_size_percentage_resolves_against_the_parent_font_size() {
assert!(matches!(shapes[0].2.geom, Geom::Rect { w, .. } if w == expected), "{body}: {:?}", shapes[0].2.geom);
}
}
#[test]
fn at_rule_blocks_are_skipped_by_brace_depth() {
let mut sheet = StyleSheet::default();
parse_css("@media print { .a{fill:#ff0000} .b{fill:#0000ff} } .c{fill:red}", &mut sheet).unwrap();
assert_eq!(sheet.rules.len(), 1);
assert_eq!(sheet.rules[0].classes, vec!["c".to_string()]);
let mut sheet = StyleSheet::default();
parse_css("@media x { @supports y { .c{} } .d{} } .e{fill:red}", &mut sheet).unwrap();
assert_eq!(sheet.rules.len(), 1);
assert_eq!(sheet.rules[0].classes, vec!["e".to_string()]);
}