mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
style: Fix insertRule with layer statements before imports
We need to do a bit more nuanced check because @layer statements might go before imports. Differential Revision: https://phabricator.services.mozilla.com/D144996
This commit is contained in:
parent
819ebc5710
commit
d1a281ebbd
3 changed files with 58 additions and 31 deletions
|
@ -385,16 +385,6 @@ impl CssRule {
|
|||
}
|
||||
}
|
||||
|
||||
fn rule_state(&self) -> State {
|
||||
match *self {
|
||||
// CssRule::Charset(..) => State::Start,
|
||||
CssRule::Import(..) => State::Imports,
|
||||
CssRule::Namespace(..) => State::Namespaces,
|
||||
// TODO(emilio): Do we need something for EarlyLayers?
|
||||
_ => State::Body,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a CSS rule.
|
||||
///
|
||||
/// Returns a parsed CSS rule and the final state of the parser.
|
||||
|
|
|
@ -153,21 +153,17 @@ impl CssRulesHelpers for RawOffsetArc<Locked<CssRules>> {
|
|||
}
|
||||
|
||||
// Computes the parser state at the given index
|
||||
let insert_rule_context = InsertRuleContext {
|
||||
rule_list: &rules.0,
|
||||
index,
|
||||
};
|
||||
|
||||
let state = if nested {
|
||||
State::Body
|
||||
} else if index == 0 {
|
||||
State::Start
|
||||
} else {
|
||||
rules
|
||||
.0
|
||||
.get(index - 1)
|
||||
.map(CssRule::rule_state)
|
||||
.unwrap_or(State::Body)
|
||||
};
|
||||
|
||||
let insert_rule_context = InsertRuleContext {
|
||||
rule_list: &rules.0,
|
||||
index,
|
||||
insert_rule_context.max_rule_state_at_index(index - 1)
|
||||
};
|
||||
|
||||
// Steps 3, 4, 5, 6
|
||||
|
|
|
@ -48,6 +48,36 @@ pub struct InsertRuleContext<'a> {
|
|||
pub index: usize,
|
||||
}
|
||||
|
||||
impl<'a> InsertRuleContext<'a> {
|
||||
/// Returns the max rule state allowable for insertion at a given index in
|
||||
/// the rule list.
|
||||
pub fn max_rule_state_at_index(&self, index: usize) -> State {
|
||||
let rule = match self.rule_list.get(index) {
|
||||
Some(rule) => rule,
|
||||
None => return State::Body,
|
||||
};
|
||||
match rule {
|
||||
CssRule::Import(..) => State::Imports,
|
||||
CssRule::Namespace(..) => State::Namespaces,
|
||||
CssRule::LayerStatement(..) => {
|
||||
// If there are @import / @namespace after this layer, then
|
||||
// we're in the early-layers phase, otherwise we're in the body
|
||||
// and everything is fair game.
|
||||
let next_non_layer_statement_rule = self.rule_list[index + 1..]
|
||||
.iter()
|
||||
.find(|r| !matches!(*r, CssRule::LayerStatement(..)));
|
||||
if let Some(non_layer) = next_non_layer_statement_rule {
|
||||
if matches!(*non_layer, CssRule::Import(..) | CssRule::Namespace(..)) {
|
||||
return State::EarlyLayers;
|
||||
}
|
||||
}
|
||||
State::Body
|
||||
}
|
||||
_ => State::Body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The parser for the top-level rules in a stylesheet.
|
||||
pub struct TopLevelRuleParser<'a> {
|
||||
/// A reference to the lock we need to use to create rules.
|
||||
|
@ -105,12 +135,8 @@ impl<'b> TopLevelRuleParser<'b> {
|
|||
None => return true,
|
||||
};
|
||||
|
||||
let next_rule_state = match ctx.rule_list.get(ctx.index) {
|
||||
None => return true,
|
||||
Some(rule) => rule.rule_state(),
|
||||
};
|
||||
|
||||
if new_state > next_rule_state {
|
||||
let max_rule_state = ctx.max_rule_state_at_index(ctx.index);
|
||||
if new_state > max_rule_state {
|
||||
self.dom_error = Some(RulesMutateError::HierarchyRequest);
|
||||
return false;
|
||||
}
|
||||
|
@ -267,11 +293,23 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
|||
self.dom_error = Some(RulesMutateError::HierarchyRequest);
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !self.check_state(State::Body) {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
"layer" => {
|
||||
let state_to_check = if self.state <= State::EarlyLayers {
|
||||
// The real state depends on whether there's a block or not.
|
||||
// We don't know that yet, but the parse_block check deals
|
||||
// with that.
|
||||
State::EarlyLayers
|
||||
} else {
|
||||
State::Body
|
||||
};
|
||||
if !self.check_state(state_to_check) {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// All other rules have blocks, so we do this check early in
|
||||
// parse_block instead.
|
||||
}
|
||||
}
|
||||
|
||||
AtRuleParser::parse_prelude(&mut self.nested(), name, input)
|
||||
|
@ -284,6 +322,9 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
|||
start: &ParserState,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self::AtRule, ParseError<'i>> {
|
||||
if !self.check_state(State::Body) {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
let rule = AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)?;
|
||||
self.state = State::Body;
|
||||
Ok((start.position(), rule))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue