mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01: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.
|
/// Parse a CSS rule.
|
||||||
///
|
///
|
||||||
/// Returns a parsed CSS rule and the final state of the parser.
|
/// 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
|
// Computes the parser state at the given index
|
||||||
|
let insert_rule_context = InsertRuleContext {
|
||||||
|
rule_list: &rules.0,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
|
||||||
let state = if nested {
|
let state = if nested {
|
||||||
State::Body
|
State::Body
|
||||||
} else if index == 0 {
|
} else if index == 0 {
|
||||||
State::Start
|
State::Start
|
||||||
} else {
|
} else {
|
||||||
rules
|
insert_rule_context.max_rule_state_at_index(index - 1)
|
||||||
.0
|
|
||||||
.get(index - 1)
|
|
||||||
.map(CssRule::rule_state)
|
|
||||||
.unwrap_or(State::Body)
|
|
||||||
};
|
|
||||||
|
|
||||||
let insert_rule_context = InsertRuleContext {
|
|
||||||
rule_list: &rules.0,
|
|
||||||
index,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Steps 3, 4, 5, 6
|
// Steps 3, 4, 5, 6
|
||||||
|
|
|
@ -48,6 +48,36 @@ pub struct InsertRuleContext<'a> {
|
||||||
pub index: usize,
|
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.
|
/// The parser for the top-level rules in a stylesheet.
|
||||||
pub struct TopLevelRuleParser<'a> {
|
pub struct TopLevelRuleParser<'a> {
|
||||||
/// A reference to the lock we need to use to create rules.
|
/// A reference to the lock we need to use to create rules.
|
||||||
|
@ -105,12 +135,8 @@ impl<'b> TopLevelRuleParser<'b> {
|
||||||
None => return true,
|
None => return true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let next_rule_state = match ctx.rule_list.get(ctx.index) {
|
let max_rule_state = ctx.max_rule_state_at_index(ctx.index);
|
||||||
None => return true,
|
if new_state > max_rule_state {
|
||||||
Some(rule) => rule.rule_state(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if new_state > next_rule_state {
|
|
||||||
self.dom_error = Some(RulesMutateError::HierarchyRequest);
|
self.dom_error = Some(RulesMutateError::HierarchyRequest);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -267,12 +293,24 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
self.dom_error = Some(RulesMutateError::HierarchyRequest);
|
self.dom_error = Some(RulesMutateError::HierarchyRequest);
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
|
return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
|
||||||
},
|
},
|
||||||
_ => {}
|
"layer" => {
|
||||||
}
|
let state_to_check = if self.state <= State::EarlyLayers {
|
||||||
|
// The real state depends on whether there's a block or not.
|
||||||
if !self.check_state(State::Body) {
|
// 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));
|
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)
|
AtRuleParser::parse_prelude(&mut self.nested(), name, input)
|
||||||
}
|
}
|
||||||
|
@ -284,6 +322,9 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
start: &ParserState,
|
start: &ParserState,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self::AtRule, ParseError<'i>> {
|
) -> 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)?;
|
let rule = AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)?;
|
||||||
self.state = State::Body;
|
self.state = State::Body;
|
||||||
Ok((start.position(), rule))
|
Ok((start.position(), rule))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue