forked from mirrors/gecko-dev
Bug 1884879 - [css-syntax] [css-nesting] Implement recent spec change about blocks and custom / non-custom properties. r=firefox-style-system-reviewers,zrhoffman
From https://github.com/w3c/csswg-drafts/issues/9317 Do some gymnastics to avoid rewinding unnecessarily, since this is super-hot code. Differential Revision: https://phabricator.services.mozilla.com/D207797
This commit is contained in:
parent
13f6ad5ef7
commit
de356745d0
2 changed files with 113 additions and 72 deletions
|
|
@ -690,6 +690,68 @@ impl ShorthandId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_non_custom_property_declaration_value_into<'i>(
|
||||||
|
declarations: &mut SourcePropertyDeclaration,
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, '_>,
|
||||||
|
start: &cssparser::ParserState,
|
||||||
|
parse_entirely_into: impl FnOnce(&mut SourcePropertyDeclaration, &mut Parser<'i, '_>) -> Result<(), ParseError<'i>>,
|
||||||
|
parsed_wide_keyword: impl FnOnce(&mut SourcePropertyDeclaration, CSSWideKeyword),
|
||||||
|
parsed_custom: impl FnOnce(&mut SourcePropertyDeclaration, custom_properties::VariableValue),
|
||||||
|
) -> Result<(), ParseError<'i>> {
|
||||||
|
let mut starts_with_curly_block = false;
|
||||||
|
if let Ok(token) = input.next() {
|
||||||
|
match token {
|
||||||
|
cssparser::Token::Ident(ref ident) => match CSSWideKeyword::from_ident(ident) {
|
||||||
|
Ok(wk) => {
|
||||||
|
if input.expect_exhausted().is_ok() {
|
||||||
|
return Ok(parsed_wide_keyword(declarations, wk));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(()) => {},
|
||||||
|
},
|
||||||
|
cssparser::Token::CurlyBracketBlock => {
|
||||||
|
starts_with_curly_block = true;
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
input.reset(&start);
|
||||||
|
input.look_for_var_or_env_functions();
|
||||||
|
let err = match parse_entirely_into(declarations, input) {
|
||||||
|
Ok(()) => {
|
||||||
|
input.seen_var_or_env_functions();
|
||||||
|
return Ok(());
|
||||||
|
},
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Look for var(), env() and top-level curly blocks after the error.
|
||||||
|
let start_pos = start.position();
|
||||||
|
let mut at_start = start_pos == input.position();
|
||||||
|
let mut invalid = false;
|
||||||
|
while let Ok(token) = input.next() {
|
||||||
|
if matches!(token, cssparser::Token::CurlyBracketBlock) {
|
||||||
|
if !starts_with_curly_block || !at_start {
|
||||||
|
invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if starts_with_curly_block {
|
||||||
|
invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
at_start = false;
|
||||||
|
}
|
||||||
|
if !input.seen_var_or_env_functions() || invalid {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
input.reset(start);
|
||||||
|
let value = custom_properties::VariableValue::parse(input, &context.url_data)?;
|
||||||
|
parsed_custom(declarations, value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
impl PropertyDeclaration {
|
impl PropertyDeclaration {
|
||||||
fn with_variables_from_shorthand(&self, shorthand: ShorthandId) -> Option<&str> {
|
fn with_variables_from_shorthand(&self, shorthand: ShorthandId) -> Option<&str> {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
@ -793,57 +855,49 @@ impl PropertyDeclaration {
|
||||||
};
|
};
|
||||||
match non_custom_id.longhand_or_shorthand() {
|
match non_custom_id.longhand_or_shorthand() {
|
||||||
Ok(longhand_id) => {
|
Ok(longhand_id) => {
|
||||||
let declaration = input
|
parse_non_custom_property_declaration_value_into(
|
||||||
.try_parse(CSSWideKeyword::parse)
|
declarations,
|
||||||
.map(|keyword| PropertyDeclaration::css_wide_keyword(longhand_id, keyword))
|
context,
|
||||||
.or_else(|()| {
|
input,
|
||||||
input.look_for_var_or_env_functions();
|
&start,
|
||||||
input.parse_entirely(|input| longhand_id.parse_value(context, input))
|
|declarations, input| {
|
||||||
})
|
let decl = input.parse_entirely(|input| longhand_id.parse_value(context, input))?;
|
||||||
.or_else(|err| {
|
declarations.push(decl);
|
||||||
while let Ok(_) = input.next() {} // Look for var() after the error.
|
Ok(())
|
||||||
if !input.seen_var_or_env_functions() {
|
},
|
||||||
return Err(err);
|
|declarations, wk| {
|
||||||
}
|
declarations.push(PropertyDeclaration::css_wide_keyword(longhand_id, wk));
|
||||||
input.reset(&start);
|
},
|
||||||
let variable_value =
|
|declarations, variable_value| {
|
||||||
custom_properties::VariableValue::parse(input, &context.url_data)?;
|
declarations.push(PropertyDeclaration::WithVariables(VariableDeclaration {
|
||||||
Ok(PropertyDeclaration::WithVariables(VariableDeclaration {
|
|
||||||
id: longhand_id,
|
id: longhand_id,
|
||||||
value: Arc::new(UnparsedValue {
|
value: Arc::new(UnparsedValue {
|
||||||
variable_value,
|
variable_value,
|
||||||
from_shorthand: None,
|
from_shorthand: None,
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
})?;
|
}
|
||||||
declarations.push(declaration)
|
)?;
|
||||||
},
|
},
|
||||||
Err(shorthand_id) => {
|
Err(shorthand_id) => {
|
||||||
if let Ok(keyword) = input.try_parse(CSSWideKeyword::parse) {
|
parse_non_custom_property_declaration_value_into(
|
||||||
|
declarations,
|
||||||
|
context,
|
||||||
|
input,
|
||||||
|
&start,
|
||||||
|
// Not using parse_entirely here: each ShorthandId::parse_into function needs
|
||||||
|
// to do so *before* pushing to `declarations`.
|
||||||
|
|declarations, input| shorthand_id.parse_into(declarations, context, input),
|
||||||
|
|declarations, wk| {
|
||||||
if shorthand_id == ShorthandId::All {
|
if shorthand_id == ShorthandId::All {
|
||||||
declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
|
declarations.all_shorthand = AllShorthand::CSSWideKeyword(wk)
|
||||||
} else {
|
} else {
|
||||||
for longhand in shorthand_id.longhands() {
|
for longhand in shorthand_id.longhands() {
|
||||||
declarations
|
declarations.push(PropertyDeclaration::css_wide_keyword(longhand, wk));
|
||||||
.push(PropertyDeclaration::css_wide_keyword(longhand, keyword));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
input.look_for_var_or_env_functions();
|
|declarations, variable_value| {
|
||||||
// Not using parse_entirely here: each
|
|
||||||
// ${shorthand.ident}::parse_into function needs to do so
|
|
||||||
// *before* pushing to `declarations`.
|
|
||||||
shorthand_id
|
|
||||||
.parse_into(declarations, context, input)
|
|
||||||
.or_else(|err| {
|
|
||||||
while let Ok(_) = input.next() {} // Look for var() after the error.
|
|
||||||
if !input.seen_var_or_env_functions() {
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
input.reset(&start);
|
|
||||||
let variable_value =
|
|
||||||
custom_properties::VariableValue::parse(input, &context.url_data)?;
|
|
||||||
let unparsed = Arc::new(UnparsedValue {
|
let unparsed = Arc::new(UnparsedValue {
|
||||||
variable_value,
|
variable_value,
|
||||||
from_shorthand: Some(shorthand_id),
|
from_shorthand: Some(shorthand_id),
|
||||||
|
|
@ -860,9 +914,8 @@ impl PropertyDeclaration {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
|
)?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if let Some(use_counters) = context.use_counters {
|
if let Some(use_counters) = context.use_counters {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
[var-with-blocks.html]
|
|
||||||
[Trailing block, leading var()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Leading block, trailing var()]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[In-block var() with trailing token]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[In-block var() with leading token]
|
|
||||||
expected: FAIL
|
|
||||||
Loading…
Reference in a new issue