mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
style: Don't remain in an invalid state when encountering an at-rule in the wrong place.
Currently, attempting to parse an at-rule that is out of place, such as an @import rule after a regular style rule, will cause the parser state to be set to Invalid. This will cause any following at-rule to be rejected until we encounter a regular style rule, at which point we'll go back to the Body state. There's nothing in the CSS specs about needing to reject all following at-rules (or, as the comment above Invalid says, ignoring the entire rest of the style sheet).
This commit is contained in:
parent
6b320eaad3
commit
9c0ce7847f
3 changed files with 31 additions and 20 deletions
|
@ -255,18 +255,19 @@ impl CssRule {
|
||||||
shared_lock: &shared_lock,
|
shared_lock: &shared_lock,
|
||||||
loader: loader,
|
loader: loader,
|
||||||
state: state,
|
state: state,
|
||||||
|
had_hierarchy_error: false,
|
||||||
namespaces: Some(&mut *guard),
|
namespaces: Some(&mut *guard),
|
||||||
};
|
};
|
||||||
|
|
||||||
match parse_one_rule(&mut input, &mut rule_parser) {
|
parse_one_rule(&mut input, &mut rule_parser)
|
||||||
Ok(result) => Ok((result, rule_parser.state)),
|
.map(|result| (result, rule_parser.state))
|
||||||
Err(_) => {
|
.map_err(|_| {
|
||||||
Err(match rule_parser.state {
|
if rule_parser.take_had_hierarchy_error() {
|
||||||
State::Invalid => SingleRuleParseError::Hierarchy,
|
SingleRuleParseError::Hierarchy
|
||||||
_ => SingleRuleParseError::Syntax,
|
} else {
|
||||||
})
|
SingleRuleParseError::Syntax
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,10 @@ pub struct TopLevelRuleParser<'a> {
|
||||||
pub context: ParserContext<'a>,
|
pub context: ParserContext<'a>,
|
||||||
/// The current state of the parser.
|
/// The current state of the parser.
|
||||||
pub state: State,
|
pub state: State,
|
||||||
|
/// Whether we have tried to parse was invalid due to being in the wrong
|
||||||
|
/// place (e.g. an @import rule was found while in the `Body` state). Reset
|
||||||
|
/// to `false` when `take_had_hierarchy_error` is called.
|
||||||
|
pub had_hierarchy_error: bool,
|
||||||
/// The namespace map we use for parsing. Needs to start as `Some()`, and
|
/// The namespace map we use for parsing. Needs to start as `Some()`, and
|
||||||
/// will be taken out after parsing namespace rules, and that reference will
|
/// will be taken out after parsing namespace rules, and that reference will
|
||||||
/// be moved to `ParserContext`.
|
/// be moved to `ParserContext`.
|
||||||
|
@ -71,6 +75,16 @@ impl<'b> TopLevelRuleParser<'b> {
|
||||||
pub fn state(&self) -> State {
|
pub fn state(&self) -> State {
|
||||||
self.state
|
self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether we previously tried to parse a rule that was invalid
|
||||||
|
/// due to being in the wrong place (e.g. an @import rule was found after
|
||||||
|
/// a regular style rule). The state of this flag is reset when this
|
||||||
|
/// function is called.
|
||||||
|
pub fn take_had_hierarchy_error(&mut self) -> bool {
|
||||||
|
let had_hierarchy_error = self.had_hierarchy_error;
|
||||||
|
self.had_hierarchy_error = false;
|
||||||
|
had_hierarchy_error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The current state of the parser.
|
/// The current state of the parser.
|
||||||
|
@ -84,9 +98,6 @@ pub enum State {
|
||||||
Namespaces = 3,
|
Namespaces = 3,
|
||||||
/// We're parsing the main body of the stylesheet.
|
/// We're parsing the main body of the stylesheet.
|
||||||
Body = 4,
|
Body = 4,
|
||||||
/// We've found an invalid state (as, a namespace rule after style rules),
|
|
||||||
/// and the rest of the stylesheet should be ignored.
|
|
||||||
Invalid = 5,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -153,8 +164,8 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
match_ignore_ascii_case! { &*name,
|
match_ignore_ascii_case! { &*name,
|
||||||
"import" => {
|
"import" => {
|
||||||
if self.state > State::Imports {
|
if self.state > State::Imports {
|
||||||
self.state = State::Invalid;
|
|
||||||
// "@import must be before any rule but @charset"
|
// "@import must be before any rule but @charset"
|
||||||
|
self.had_hierarchy_error = true;
|
||||||
return Err(StyleParseError::UnexpectedImportRule.into())
|
return Err(StyleParseError::UnexpectedImportRule.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,8 +191,8 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
},
|
},
|
||||||
"namespace" => {
|
"namespace" => {
|
||||||
if self.state > State::Namespaces {
|
if self.state > State::Namespaces {
|
||||||
self.state = State::Invalid;
|
|
||||||
// "@namespace must be before any rule but @charset and @import"
|
// "@namespace must be before any rule but @charset and @import"
|
||||||
|
self.had_hierarchy_error = true;
|
||||||
return Err(StyleParseError::UnexpectedNamespaceRule.into())
|
return Err(StyleParseError::UnexpectedNamespaceRule.into())
|
||||||
}
|
}
|
||||||
self.state = State::Namespaces;
|
self.state = State::Namespaces;
|
||||||
|
@ -221,14 +232,12 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
},
|
},
|
||||||
// @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
|
// @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
|
||||||
// anything left is invalid.
|
// anything left is invalid.
|
||||||
"charset" => return Err(StyleParseError::UnexpectedCharsetRule.into()),
|
"charset" => {
|
||||||
|
self.had_hierarchy_error = true;
|
||||||
|
return Err(StyleParseError::UnexpectedCharsetRule.into())
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// Don't allow starting with an invalid state
|
|
||||||
if self.state > State::Body {
|
|
||||||
self.state = State::Invalid;
|
|
||||||
return Err(StyleParseError::UnspecifiedError.into());
|
|
||||||
}
|
|
||||||
self.state = State::Body;
|
self.state = State::Body;
|
||||||
|
|
||||||
// "Freeze" the namespace map (no more namespace rules can be parsed
|
// "Freeze" the namespace map (no more namespace rules can be parsed
|
||||||
|
|
|
@ -337,6 +337,7 @@ impl Stylesheet {
|
||||||
loader: stylesheet_loader,
|
loader: stylesheet_loader,
|
||||||
context: context,
|
context: context,
|
||||||
state: State::Start,
|
state: State::Start,
|
||||||
|
had_hierarchy_error: false,
|
||||||
namespaces: Some(namespaces),
|
namespaces: Some(namespaces),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue