Parse declarations in reverse order, skip those that would be overridden.

This commit is contained in:
Simon Sapin 2014-05-06 18:31:38 +01:00
parent 8b53ea8a2c
commit 416cbf472a

View file

@ -1379,6 +1379,8 @@ mod property_bit_field {
} }
/// Declarations are stored in reverse order.
/// Overridden declarations are skipped.
pub struct PropertyDeclarationBlock { pub struct PropertyDeclarationBlock {
pub important: Arc<Vec<PropertyDeclaration>>, pub important: Arc<Vec<PropertyDeclaration>>,
pub normal: Arc<Vec<PropertyDeclaration>>, pub normal: Arc<Vec<PropertyDeclaration>>,
@ -1397,28 +1399,36 @@ pub fn parse_style_attribute(input: &str, base_url: &Url) -> PropertyDeclaration
pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &Url) -> PropertyDeclarationBlock { pub fn parse_property_declaration_list<I: Iterator<Node>>(input: I, base_url: &Url) -> PropertyDeclarationBlock {
let mut important = vec!(); let mut important_declarations = vec!();
let mut normal = vec!(); let mut normal_declarations = vec!();
for item in ErrorLoggerIterator(parse_declaration_list(input)) { let mut important_seen = PropertyBitField::new();
let mut normal_seen = PropertyBitField::new();
let items: Vec<DeclarationListItem> =
ErrorLoggerIterator(parse_declaration_list(input)).collect();
for item in items.move_iter().rev() {
match item { match item {
DeclAtRule(rule) => log_css_error( DeclAtRule(rule) => log_css_error(
rule.location, format!("Unsupported at-rule in declaration list: @{:s}", rule.name)), rule.location, format!("Unsupported at-rule in declaration list: @{:s}", rule.name)),
Declaration(Declaration{ location: l, name: n, value: v, important: i}) => { Declaration(Declaration{ location: l, name: n, value: v, important: i}) => {
// TODO: only keep the last valid declaration for a given name. // TODO: only keep the last valid declaration for a given name.
let list = if i { &mut important } else { &mut normal }; let (list, seen) = if i {
match PropertyDeclaration::parse(n, v, list, base_url) { (&mut important_declarations, &mut important_seen)
} else {
(&mut normal_declarations, &mut normal_seen)
};
match PropertyDeclaration::parse(n, v, list, base_url, seen) {
UnknownProperty => log_css_error(l, format!( UnknownProperty => log_css_error(l, format!(
"Unsupported property: {}:{}", n, v.iter().to_css())), "Unsupported property: {}:{}", n, v.iter().to_css())),
InvalidValue => log_css_error(l, format!( InvalidValue => log_css_error(l, format!(
"Invalid value: {}:{}", n, v.iter().to_css())), "Invalid value: {}:{}", n, v.iter().to_css())),
ValidDeclaration => (), ValidOrIgnoredDeclaration => (),
} }
} }
} }
} }
PropertyDeclarationBlock { PropertyDeclarationBlock {
important: Arc::new(important), important: Arc::new(important_declarations),
normal: Arc::new(normal), normal: Arc::new(normal_declarations),
} }
} }
@ -1460,64 +1470,88 @@ pub enum PropertyDeclaration {
pub enum PropertyDeclarationParseResult { pub enum PropertyDeclarationParseResult {
UnknownProperty, UnknownProperty,
InvalidValue, InvalidValue,
ValidDeclaration, ValidOrIgnoredDeclaration,
} }
impl PropertyDeclaration { impl PropertyDeclaration {
pub fn parse(name: &str, value: &[ComponentValue], pub fn parse(name: &str, value: &[ComponentValue],
result_list: &mut Vec<PropertyDeclaration>, result_list: &mut Vec<PropertyDeclaration>,
base_url: &Url) -> PropertyDeclarationParseResult { base_url: &Url,
seen: &mut PropertyBitField) -> PropertyDeclarationParseResult {
// FIXME: local variable to work around Rust #10683 // FIXME: local variable to work around Rust #10683
let name_lower = name.to_ascii_lower(); let name_lower = name.to_ascii_lower();
match name_lower.as_slice() { match name_lower.as_slice() {
% for property in LONGHANDS: % for property in LONGHANDS:
% if property.derived_from is None: % if property.derived_from is None:
"${property.name}" => result_list.push(${property.ident}_declaration( "${property.name}" => {
match longhands::${property.ident}::parse_declared(value, base_url) { if seen.get_${property.ident}() {
Some(value) => value, return ValidOrIgnoredDeclaration
None => return InvalidValue,
} }
)), match longhands::${property.ident}::parse_declared(value, base_url) {
Some(value) => {
seen.set_${property.ident}();
result_list.push(${property.ident}_declaration(value));
ValidOrIgnoredDeclaration
},
None => InvalidValue,
}
},
% else: % else:
"${property.name}" => {} "${property.name}" => UnknownProperty,
% endif % endif
% endfor % endfor
% for shorthand in SHORTHANDS: % for shorthand in SHORTHANDS:
"${shorthand.name}" => match CSSWideKeyword::parse(value) { "${shorthand.name}" => {
Some(Some(keyword)) => { if ${" && ".join("seen.get_%s()" % sub_property.ident
% for sub_property in shorthand.sub_properties: for sub_property in shorthand.sub_properties)} {
result_list.push(${sub_property.ident}_declaration( return ValidOrIgnoredDeclaration
CSSWideKeyword(keyword) }
)); match CSSWideKeyword::parse(value) {
% endfor Some(Some(keyword)) => {
},
Some(None) => {
% for sub_property in shorthand.sub_properties:
result_list.push(${sub_property.ident}_declaration(
CSSWideKeyword(${
"Inherit" if sub_property.style_struct.inherited else "Initial"})
));
% endfor
},
None => match shorthands::${shorthand.ident}::parse(value, base_url) {
Some(result) => {
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
result_list.push(${sub_property.ident}_declaration( if !seen.get_${sub_property.ident}() {
match result.${sub_property.ident} { seen.set_${sub_property.ident}();
Some(value) => SpecifiedValue(value), result_list.push(${sub_property.ident}_declaration(
None => CSSWideKeyword(Initial), CSSWideKeyword(keyword)));
} }
));
% endfor % endfor
ValidOrIgnoredDeclaration
}, },
None => return InvalidValue, Some(None) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(${sub_property.ident}_declaration(
CSSWideKeyword(${
"Inherit" if sub_property.style_struct.inherited else "Initial"
})));
}
% endfor
ValidOrIgnoredDeclaration
},
None => match shorthands::${shorthand.ident}::parse(value, base_url) {
Some(result) => {
% for sub_property in shorthand.sub_properties:
if !seen.get_${sub_property.ident}() {
seen.set_${sub_property.ident}();
result_list.push(${sub_property.ident}_declaration(
match result.${sub_property.ident} {
Some(value) => SpecifiedValue(value),
None => CSSWideKeyword(Initial),
}
));
}
% endfor
ValidOrIgnoredDeclaration
},
None => InvalidValue,
}
} }
}, },
% endfor % endfor
_ => return UnknownProperty, _ => UnknownProperty,
} }
ValidDeclaration
} }
} }
@ -1589,7 +1623,7 @@ fn cascade_with_cached_declarations(applicable_declarations: &[MatchedProperty],
let mut seen = PropertyBitField::new(); let mut seen = PropertyBitField::new();
for sub_list in applicable_declarations.iter().rev() { for sub_list in applicable_declarations.iter().rev() {
for declaration in sub_list.declarations.iter().rev() { for declaration in sub_list.declarations.iter() {
match *declaration { match *declaration {
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:
% if style_struct.inherited: % if style_struct.inherited:
@ -1789,7 +1823,7 @@ pub fn cascade(applicable_declarations: &[MatchedProperty],
let mut cacheable = true; let mut cacheable = true;
let mut seen = PropertyBitField::new(); let mut seen = PropertyBitField::new();
for sub_list in applicable_declarations.iter().rev() { for sub_list in applicable_declarations.iter().rev() {
for declaration in sub_list.declarations.iter().rev() { for declaration in sub_list.declarations.iter() {
match *declaration { match *declaration {
% for style_struct in STYLE_STRUCTS: % for style_struct in STYLE_STRUCTS:
% for property in style_struct.longhands: % for property in style_struct.longhands: