style: Move property allowance tests to PropertyId::parse_into.

It's not only more consistent (since we have a proper ParserContext there), but
also fixes a bunch of bugs where Gecko accidentally exposes and allows setting
internal state because of conversions from nsCSSPropertyID to PropertyId.

This adds the extra complexity of caring about aliases for longer, but that's
probably not a big deal in practice, since we also have PropertyDeclarationId.

MozReview-Commit-ID: C2Js8PfloxQ
This commit is contained in:
Emilio Cobos Álvarez 2017-11-21 13:33:35 +01:00
parent 5905f8d3ea
commit 8de554f334
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
9 changed files with 137 additions and 135 deletions

View file

@ -689,9 +689,11 @@ pub fn process_resolved_style_request<'a, N>(context: &LayoutContext,
let styles = resolve_style(&mut context, element, RuleInclusion::All, false, pseudo.as_ref()); let styles = resolve_style(&mut context, element, RuleInclusion::All, false, pseudo.as_ref());
let style = styles.primary(); let style = styles.primary();
let longhand_id = match *property { let longhand_id = match *property {
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => id, PropertyId::Longhand(id) => id,
// Firefox returns blank strings for the computed value of shorthands, // Firefox returns blank strings for the computed value of shorthands,
// so this should be web-compatible. // so this should be web-compatible.
PropertyId::ShorthandAlias(..) |
PropertyId::Shorthand(_) => return String::new(), PropertyId::Shorthand(_) => return String::new(),
PropertyId::Custom(ref name) => { PropertyId::Custom(ref name) => {
return style.computed_value_to_string(PropertyDeclarationId::Custom(name)) return style.computed_value_to_string(PropertyDeclarationId::Custom(name))
@ -737,12 +739,12 @@ where
let style = &*layout_el.resolved_style(); let style = &*layout_el.resolved_style();
let longhand_id = match *property { let longhand_id = match *property {
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => id, PropertyId::Longhand(id) => id,
// Firefox returns blank strings for the computed value of shorthands, // Firefox returns blank strings for the computed value of shorthands,
// so this should be web-compatible. // so this should be web-compatible.
PropertyId::ShorthandAlias(..) |
PropertyId::Shorthand(_) => return String::new(), PropertyId::Shorthand(_) => return String::new(),
PropertyId::Custom(ref name) => { PropertyId::Custom(ref name) => {
return style.computed_value_to_string(PropertyDeclarationId::Custom(name)) return style.computed_value_to_string(PropertyDeclarationId::Custom(name))
} }

View file

@ -742,7 +742,7 @@ impl LayoutThread {
Msg::RegisterPaint(name, mut properties, painter) => { Msg::RegisterPaint(name, mut properties, painter) => {
debug!("Registering the painter"); debug!("Registering the painter");
let properties = properties.drain(..) let properties = properties.drain(..)
.filter_map(|name| PropertyId::parse(&*name, None) .filter_map(|name| PropertyId::parse(&*name)
.ok().map(|id| (name.clone(), id))) .ok().map(|id| (name.clone(), id)))
.filter(|&(_, ref id)| id.as_shorthand().is_err()) .filter(|&(_, ref id)| id.as_shorthand().is_err())
.collect(); .collect();

View file

@ -299,7 +299,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
fn GetPropertyValue(&self, property: DOMString) -> DOMString { fn GetPropertyValue(&self, property: DOMString) -> DOMString {
let id = if let Ok(id) = PropertyId::parse(&property, None) { let id = if let Ok(id) = PropertyId::parse(&property) {
id id
} else { } else {
// Unkwown property // Unkwown property
@ -310,7 +310,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority // https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
fn GetPropertyPriority(&self, property: DOMString) -> DOMString { fn GetPropertyPriority(&self, property: DOMString) -> DOMString {
let id = if let Ok(id) = PropertyId::parse(&property, None) { let id = if let Ok(id) = PropertyId::parse(&property) {
id id
} else { } else {
// Unkwown property // Unkwown property
@ -334,7 +334,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
priority: DOMString) priority: DOMString)
-> ErrorResult { -> ErrorResult {
// Step 3 // Step 3
let id = if let Ok(id) = PropertyId::parse(&property, None) { let id = if let Ok(id) = PropertyId::parse(&property) {
id id
} else { } else {
// Unknown property // Unknown property
@ -351,7 +351,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
} }
// Step 2 & 3 // Step 2 & 3
let id = match PropertyId::parse(&property, None) { let id = match PropertyId::parse(&property) {
Ok(id) => id, Ok(id) => id,
Err(..) => return Ok(()), // Unkwown property Err(..) => return Ok(()), // Unkwown property
}; };
@ -383,7 +383,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
return Err(Error::NoModificationAllowed); return Err(Error::NoModificationAllowed);
} }
let id = if let Ok(id) = PropertyId::parse(&property, None) { let id = if let Ok(id) = PropertyId::parse(&property) {
id id
} else { } else {
// Unkwown property, cannot be there to remove. // Unkwown property, cannot be there to remove.

View file

@ -560,7 +560,8 @@ impl PropertyDeclarationBlock {
/// ///
/// Returns whether any declaration was actually removed. /// Returns whether any declaration was actually removed.
pub fn remove_property(&mut self, property: &PropertyId) -> bool { pub fn remove_property(&mut self, property: &PropertyId) -> bool {
if let PropertyId::Longhand(id) = *property { let longhand_id = property.longhand_id();
if let Some(id) = longhand_id {
if !self.longhands.contains(id) { if !self.longhands.contains(id) {
return false return false
} }
@ -584,7 +585,7 @@ impl PropertyDeclarationBlock {
!remove !remove
}); });
if let PropertyId::Longhand(_) = *property { if longhand_id.is_some() {
debug_assert!(removed_at_least_one); debug_assert!(removed_at_least_one);
} }
removed_at_least_one removed_at_least_one
@ -681,7 +682,7 @@ impl PropertyDeclarationBlock {
/// property. /// property.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool { pub fn has_css_wide_keyword(&self, property: &PropertyId) -> bool {
if let PropertyId::Longhand(id) = *property { if let Some(id) = property.longhand_id() {
if !self.longhands.contains(id) { if !self.longhands.contains(id) {
return false return false
} }
@ -1092,12 +1093,14 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
type Declaration = Importance; type Declaration = Importance;
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>) fn parse_value<'t>(
-> Result<Importance, ParseError<'i>> { &mut self,
let prop_context = PropertyParserContext::new(self.context); name: CowRcStr<'i>,
let id = match PropertyId::parse(&name, Some(&prop_context)) { input: &mut Parser<'i, 't>,
) -> Result<Importance, ParseError<'i>> {
let id = match PropertyId::parse(&name) {
Ok(id) => id, Ok(id) => id,
Err(()) => { Err(..) => {
return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) { return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) {
StyleParseErrorKind::UnknownVendorProperty StyleParseErrorKind::UnknownVendorProperty
} else { } else {
@ -1107,7 +1110,6 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
}; };
input.parse_until_before(Delimiter::Bang, |input| { input.parse_until_before(Delimiter::Bang, |input| {
PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input) PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input)
.map_err(|e| e.into())
})?; })?;
let importance = match input.try(parse_important) { let importance = match input.try(parse_important) {
Ok(()) => Importance::Important, Ok(()) => Importance::Important,

View file

@ -3560,7 +3560,7 @@ fn static_assert() {
Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr()); Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr());
} }
if let Ok(prop_id) = PropertyId::parse(&feature.0.to_string(), None) { if let Ok(prop_id) = PropertyId::parse(&feature.0.to_string()) {
match prop_id.as_shorthand() { match prop_id.as_shorthand() {
Ok(shorthand) => { Ok(shorthand) => {
for longhand in shorthand.longhands() { for longhand in shorthand.longhands() {

View file

@ -604,7 +604,8 @@ impl LonghandId {
/// Returns a longhand id from Gecko's nsCSSPropertyID. /// Returns a longhand id from Gecko's nsCSSPropertyID.
pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> { pub fn from_nscsspropertyid(id: nsCSSPropertyID) -> Result<Self, ()> {
match PropertyId::from_nscsspropertyid(id) { match PropertyId::from_nscsspropertyid(id) {
Ok(PropertyId::Longhand(id)) => Ok(id), Ok(PropertyId::Longhand(id)) |
Ok(PropertyId::LonghandAlias(id, _)) => Ok(id),
_ => Err(()), _ => Err(()),
} }
} }
@ -1052,8 +1053,10 @@ impl<'a> PropertyDeclarationId<'a> {
match *self { match *self {
PropertyDeclarationId::Longhand(id) => { PropertyDeclarationId::Longhand(id) => {
match *other { match *other {
PropertyId::Longhand(other_id) => id == other_id, PropertyId::Longhand(other_id) |
PropertyId::Shorthand(shorthand) => self.is_longhand_of(shorthand), PropertyId::LonghandAlias(other_id, _) => id == other_id,
PropertyId::Shorthand(shorthand) |
PropertyId::ShorthandAlias(shorthand, _) => self.is_longhand_of(shorthand),
PropertyId::Custom(_) => false, PropertyId::Custom(_) => false,
} }
} }
@ -1094,6 +1097,10 @@ pub enum PropertyId {
Longhand(LonghandId), Longhand(LonghandId),
/// A shorthand property. /// A shorthand property.
Shorthand(ShorthandId), Shorthand(ShorthandId),
/// An alias for a longhand property.
LonghandAlias(LonghandId, AliasId),
/// An alias for a shorthand property.
ShorthandAlias(ShorthandId, AliasId),
/// A custom property. /// A custom property.
Custom(::custom_properties::Name), Custom(::custom_properties::Name),
} }
@ -1111,6 +1118,8 @@ impl ToCss for PropertyId {
match *self { match *self {
PropertyId::Longhand(id) => dest.write_str(id.name()), PropertyId::Longhand(id) => dest.write_str(id.name()),
PropertyId::Shorthand(id) => dest.write_str(id.name()), PropertyId::Shorthand(id) => dest.write_str(id.name()),
PropertyId::LonghandAlias(id, _) => dest.write_str(id.name()),
PropertyId::ShorthandAlias(id, _) => dest.write_str(id.name()),
PropertyId::Custom(_) => { PropertyId::Custom(_) => {
serialize_identifier(&self.name(), dest) serialize_identifier(&self.name(), dest)
} }
@ -1119,17 +1128,26 @@ impl ToCss for PropertyId {
} }
impl PropertyId { impl PropertyId {
/// Return the longhand id that this property id represents.
#[inline]
pub fn longhand_id(&self) -> Option<LonghandId> {
Some(match *self {
PropertyId::Longhand(id) => id,
PropertyId::LonghandAlias(id, _) => id,
_ => return None,
})
}
/// Returns a given property from the string `s`. /// Returns a given property from the string `s`.
/// ///
/// Returns Err(()) for unknown non-custom properties /// Returns Err(()) for unknown non-custom properties.
/// If caller wants to provide a different context, it can be provided with pub fn parse(property_name: &str) -> Result<Self, ()> {
/// Some(context), if None is given, default setting for PropertyParserContext // FIXME(https://github.com/rust-lang/rust/issues/33156): remove this
/// will be used. It is `Origin::Author` for stylesheet_origin and // enum and use PropertyId when stable Rust allows destructors in
/// `CssRuleType::Style` for rule_type. // statics.
pub fn parse(property_name: &str, context: Option< &PropertyParserContext>) -> Result<Self, ()> { //
// FIXME(https://github.com/rust-lang/rust/issues/33156): remove this enum and use PropertyId // ShorthandAlias is not used in the Servo build.
// when stable Rust allows destructors in statics. // That's why we need to allow dead_code.
// ShorthandAlias is not used in servo build. That's why we need to allow dead_code.
#[allow(dead_code)] #[allow(dead_code)]
pub enum StaticId { pub enum StaticId {
Longhand(LonghandId), Longhand(LonghandId),
@ -1153,42 +1171,25 @@ impl PropertyId {
} }
} }
let default; Ok(match static_id(property_name) {
let context = match context {
Some(context) => context,
None => {
default = PropertyParserContext {
chrome_rules_enabled: false,
stylesheet_origin: Origin::Author,
rule_type: CssRuleType::Style,
};
&default
}
};
let rule_type = context.rule_type;
debug_assert!(matches!(rule_type, CssRuleType::Keyframe |
CssRuleType::Page |
CssRuleType::Style),
"Declarations are only expected inside a keyframe, page, or style rule.");
let (id, alias) = match static_id(property_name) {
Some(&StaticId::Longhand(id)) => { Some(&StaticId::Longhand(id)) => {
(PropertyId::Longhand(id), None) PropertyId::Longhand(id)
}, },
Some(&StaticId::Shorthand(id)) => { Some(&StaticId::Shorthand(id)) => {
(PropertyId::Shorthand(id), None) PropertyId::Shorthand(id)
}, },
Some(&StaticId::LonghandAlias(id, alias)) => { Some(&StaticId::LonghandAlias(id, alias)) => {
(PropertyId::Longhand(id), Some(alias)) PropertyId::LonghandAlias(id, alias)
}, },
Some(&StaticId::ShorthandAlias(id, alias)) => { Some(&StaticId::ShorthandAlias(id, alias)) => {
(PropertyId::Shorthand(id), Some(alias)) PropertyId::ShorthandAlias(id, alias)
}, },
None => return ::custom_properties::parse_name(property_name) None => {
.map(|name| PropertyId::Custom(::custom_properties::Name::from(name))), return ::custom_properties::parse_name(property_name).map(|name| {
}; PropertyId::Custom(::custom_properties::Name::from(name))
id.check_allowed_in(alias, context)?; })
Ok(id) },
})
} }
/// Returns a property id from Gecko's nsCSSPropertyID. /// Returns a property id from Gecko's nsCSSPropertyID.
@ -1203,7 +1204,10 @@ impl PropertyId {
} }
% for alias in property.alias: % for alias in property.alias:
${helpers.alias_to_nscsspropertyid(alias)} => { ${helpers.alias_to_nscsspropertyid(alias)} => {
Ok(PropertyId::Longhand(LonghandId::${property.camel_case})) Ok(PropertyId::LonghandAlias(
LonghandId::${property.camel_case},
AliasId::${to_camel_case(alias)}
))
} }
% endfor % endfor
% endfor % endfor
@ -1213,7 +1217,10 @@ impl PropertyId {
} }
% for alias in property.alias: % for alias in property.alias:
${helpers.alias_to_nscsspropertyid(alias)} => { ${helpers.alias_to_nscsspropertyid(alias)} => {
Ok(PropertyId::Shorthand(ShorthandId::${property.camel_case})) Ok(PropertyId::ShorthandAlias(
ShorthandId::${property.camel_case},
AliasId::${to_camel_case(alias)}
))
} }
% endfor % endfor
% endfor % endfor
@ -1228,6 +1235,8 @@ impl PropertyId {
match *self { match *self {
PropertyId::Longhand(id) => Ok(id.to_nscsspropertyid()), PropertyId::Longhand(id) => Ok(id.to_nscsspropertyid()),
PropertyId::Shorthand(id) => Ok(id.to_nscsspropertyid()), PropertyId::Shorthand(id) => Ok(id.to_nscsspropertyid()),
PropertyId::LonghandAlias(_, alias) => Ok(alias.to_nscsspropertyid()),
PropertyId::ShorthandAlias(_, alias) => Ok(alias.to_nscsspropertyid()),
_ => Err(()) _ => Err(())
} }
} }
@ -1236,7 +1245,9 @@ impl PropertyId {
/// `PropertyDeclarationId`. /// `PropertyDeclarationId`.
pub fn as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId> { pub fn as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId> {
match *self { match *self {
PropertyId::ShorthandAlias(id, _) |
PropertyId::Shorthand(id) => Ok(id), PropertyId::Shorthand(id) => Ok(id),
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => Err(PropertyDeclarationId::Longhand(id)), PropertyId::Longhand(id) => Err(PropertyDeclarationId::Longhand(id)),
PropertyId::Custom(ref name) => Err(PropertyDeclarationId::Custom(name)), PropertyId::Custom(ref name) => Err(PropertyDeclarationId::Custom(name)),
} }
@ -1245,7 +1256,9 @@ impl PropertyId {
/// Returns the name of the property without CSS escaping. /// Returns the name of the property without CSS escaping.
pub fn name(&self) -> Cow<'static, str> { pub fn name(&self) -> Cow<'static, str> {
match *self { match *self {
PropertyId::ShorthandAlias(id, _) |
PropertyId::Shorthand(id) => id.name().into(), PropertyId::Shorthand(id) => id.name().into(),
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => id.name().into(), PropertyId::Longhand(id) => id.name().into(),
PropertyId::Custom(ref name) => { PropertyId::Custom(ref name) => {
use std::fmt::Write; use std::fmt::Write;
@ -1256,34 +1269,34 @@ impl PropertyId {
} }
} }
fn check_allowed_in( fn allowed_in(&self, context: &ParserContext) -> bool {
&self, let id: NonCustomPropertyId = match *self {
alias: Option<AliasId>,
context: &PropertyParserContext,
) -> Result<(), ()> {
let id: NonCustomPropertyId;
if let Some(alias_id) = alias {
id = alias_id.into();
} else {
match *self {
// Custom properties are allowed everywhere // Custom properties are allowed everywhere
PropertyId::Custom(_) => return Ok(()), PropertyId::Custom(_) => return true,
PropertyId::Shorthand(shorthand_id) => shorthand_id.into(),
PropertyId::Longhand(longhand_id) => longhand_id.into(),
PropertyId::ShorthandAlias(_, alias_id) => alias_id.into(),
PropertyId::LonghandAlias(_, alias_id) => alias_id.into(),
};
PropertyId::Shorthand(shorthand_id) => id = shorthand_id.into(), debug_assert!(
PropertyId::Longhand(longhand_id) => id = longhand_id.into(), matches!(
} context.rule_type(),
} CssRuleType::Keyframe | CssRuleType::Page | CssRuleType::Style
),
"Declarations are only expected inside a keyframe, page, or style rule."
);
<% id_set = static_non_custom_property_id_set %> <% id_set = static_non_custom_property_id_set %>
${id_set("DISALLOWED_IN_KEYFRAME_BLOCK", lambda p: not p.allowed_in_keyframe_block)} ${id_set("DISALLOWED_IN_KEYFRAME_BLOCK", lambda p: not p.allowed_in_keyframe_block)}
${id_set("DISALLOWED_IN_PAGE_RULE", lambda p: not p.allowed_in_page_rule)} ${id_set("DISALLOWED_IN_PAGE_RULE", lambda p: not p.allowed_in_page_rule)}
match context.rule_type { match context.rule_type() {
CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(id) => { CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(id) => {
return Err(()); return false;
} }
CssRuleType::Page if DISALLOWED_IN_PAGE_RULE.contains(id) => { CssRuleType::Page if DISALLOWED_IN_PAGE_RULE.contains(id) => {
return Err(()) return false;
} }
_ => {} _ => {}
} }
@ -1303,7 +1316,7 @@ impl PropertyId {
${id_set("ENABLED_IN_UA_SHEETS", lambda p: p.explicitly_enabled_in_ua_sheets())} ${id_set("ENABLED_IN_UA_SHEETS", lambda p: p.explicitly_enabled_in_ua_sheets())}
${id_set("ENABLED_IN_CHROME", lambda p: p.explicitly_enabled_in_chrome())} ${id_set("ENABLED_IN_CHROME", lambda p: p.explicitly_enabled_in_chrome())}
${id_set("EXPERIMENTAL", lambda p: p.experimental(product))} ${id_set("EXPERIMENTAL", lambda p: p.experimental(product))}
${id_set("ALWAYS_ENABLED", lambda p: not p.experimental(product) and p.enabled_in_content())} ${id_set("ALWAYS_ENABLED", lambda p: (not p.experimental(product)) and p.enabled_in_content())}
let passes_pref_check = || { let passes_pref_check = || {
% if product == "servo": % if product == "servo":
@ -1323,56 +1336,29 @@ impl PropertyId {
PREFS.get(pref).as_boolean().unwrap_or(false) PREFS.get(pref).as_boolean().unwrap_or(false)
% else: % else:
let id = match alias { unsafe { structs::nsCSSProps_gPropertyEnabled[self.to_nscsspropertyid().unwrap() as usize] }
Some(alias_id) => alias_id.to_nscsspropertyid().unwrap(),
None => self.to_nscsspropertyid().unwrap(),
};
unsafe { structs::nsCSSProps_gPropertyEnabled[id as usize] }
% endif % endif
}; };
if ALWAYS_ENABLED.contains(id) { if ALWAYS_ENABLED.contains(id) {
return Ok(()) return true
} }
if EXPERIMENTAL.contains(id) && passes_pref_check() { if EXPERIMENTAL.contains(id) && passes_pref_check() {
return Ok(()) return true
} }
if context.stylesheet_origin == Origin::UserAgent && if context.stylesheet_origin == Origin::UserAgent &&
ENABLED_IN_UA_SHEETS.contains(id) ENABLED_IN_UA_SHEETS.contains(id)
{ {
return Ok(()) return true
} }
if context.chrome_rules_enabled && ENABLED_IN_CHROME.contains(id) { if context.chrome_rules_enabled() && ENABLED_IN_CHROME.contains(id) {
return Ok(()) return true
} }
Err(()) false
}
}
/// Parsing Context for PropertyId.
pub struct PropertyParserContext {
/// Whether the property is parsed in a chrome:// stylesheet.
pub chrome_rules_enabled: bool,
/// The Origin of the stylesheet, whether it's a user,
/// author or user-agent stylesheet.
pub stylesheet_origin: Origin,
/// The current rule type, if any.
pub rule_type: CssRuleType,
}
impl PropertyParserContext {
/// Creates a PropertyParserContext with given stylesheet origin and rule type.
pub fn new(context: &ParserContext) -> Self {
Self {
chrome_rules_enabled: context.chrome_rules_enabled(),
stylesheet_origin: context.stylesheet_origin,
rule_type: context.rule_type(),
}
} }
} }
@ -1635,6 +1621,13 @@ impl PropertyDeclaration {
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<(), ParseError<'i>> { ) -> Result<(), ParseError<'i>> {
assert!(declarations.is_empty()); assert!(declarations.is_empty());
if !id.allowed_in(context) {
return Err(input.new_custom_error(
StyleParseErrorKind::UnknownProperty(name)
));
}
let start = input.state(); let start = input.state();
match id { match id {
PropertyId::Custom(property_name) => { PropertyId::Custom(property_name) => {
@ -1651,6 +1644,7 @@ impl PropertyDeclaration {
declarations.push(PropertyDeclaration::Custom(property_name, value)); declarations.push(PropertyDeclaration::Custom(property_name, value));
Ok(()) Ok(())
} }
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => { PropertyId::Longhand(id) => {
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| { input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| {
@ -1680,6 +1674,7 @@ impl PropertyDeclaration {
declarations.push(declaration) declarations.push(declaration)
}) })
} }
PropertyId::ShorthandAlias(id, _) |
PropertyId::Shorthand(id) => { PropertyId::Shorthand(id) => {
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) { if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) {
@ -3592,13 +3587,13 @@ impl AliasId {
/// Returns an nsCSSPropertyID. /// Returns an nsCSSPropertyID.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub fn to_nscsspropertyid(&self) -> Result<nsCSSPropertyID, ()> { pub fn to_nscsspropertyid(&self) -> nsCSSPropertyID {
use gecko_bindings::structs::*; use gecko_bindings::structs::*;
match *self { match *self {
% for property in data.all_aliases(): % for property in data.all_aliases():
AliasId::${property.camel_case} => { AliasId::${property.camel_case} => {
Ok(${helpers.alias_to_nscsspropertyid(property.ident)}) ${helpers.alias_to_nscsspropertyid(property.ident)}
}, },
% endfor % endfor
} }

View file

@ -9,7 +9,7 @@ use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, Source
use error_reporting::{NullReporter, ContextualParseError, ParseErrorReporter}; use error_reporting::{NullReporter, ContextualParseError, ParseErrorReporter};
use parser::{ParserContext, ParserErrorContext}; use parser::{ParserContext, ParserErrorContext};
use properties::{DeclarationSource, Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId}; use properties::{DeclarationSource, Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
use properties::{PropertyDeclarationId, PropertyParserContext, LonghandId, SourcePropertyDeclaration}; use properties::{PropertyDeclarationId, LonghandId, SourcePropertyDeclaration};
use properties::LonghandIdSet; use properties::LonghandIdSet;
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
use servo_arc::Arc; use servo_arc::Arc;
@ -581,19 +581,22 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> {
type Declaration = (); type Declaration = ();
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>) fn parse_value<'t>(
-> Result<(), ParseError<'i>> { &mut self,
let property_context = PropertyParserContext::new(self.context); name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
let id = PropertyId::parse(&name, Some(&property_context)).map_err(|()| { ) -> Result<(), ParseError<'i>> {
let id = PropertyId::parse(&name).map_err(|()| {
input.new_custom_error(StyleParseErrorKind::UnknownProperty(name.clone())) input.new_custom_error(StyleParseErrorKind::UnknownProperty(name.clone()))
})?; })?;
match PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input) {
Ok(()) => { // TODO(emilio): Shouldn't this use parse_entirely?
// In case there is still unparsed text in the declaration, we should roll back. PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input)?;
input.expect_exhausted().map_err(|e| e.into())
} // In case there is still unparsed text in the declaration, we should
Err(e) => Err(e.into()) // roll back.
} input.expect_exhausted()?;
Ok(())
} }
} }

View file

@ -9,7 +9,7 @@ use cssparser::{ParseError as CssParseError, ParserInput};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parser::ParserContext; use parser::ParserContext;
use properties::{PropertyId, PropertyDeclaration, PropertyParserContext, SourcePropertyDeclaration}; use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use servo_arc::Arc; use servo_arc::Arc;
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
@ -259,9 +259,8 @@ impl Declaration {
let prop = input.expect_ident().unwrap().as_ref().to_owned(); let prop = input.expect_ident().unwrap().as_ref().to_owned();
input.expect_colon().unwrap(); input.expect_colon().unwrap();
let property_context = PropertyParserContext::new(&context); let id = PropertyId::parse(&prop)
let id = PropertyId::parse(&prop, Some(&property_context)) .map_err(|_| input.new_custom_error(()))?;
.map_err(|()| input.new_custom_error(()))?;
let mut declarations = SourcePropertyDeclaration::new(); let mut declarations = SourcePropertyDeclaration::new();
input.parse_until_before(Delimiter::Bang, |input| { input.parse_until_before(Delimiter::Bang, |input| {

View file

@ -2443,7 +2443,8 @@ where
url_data, url_data,
reporter, reporter,
parsing_mode, parsing_mode,
quirks_mode) quirks_mode,
)
} }
#[no_mangle] #[no_mangle]
@ -2690,7 +2691,7 @@ pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
macro_rules! get_property_id_from_property { macro_rules! get_property_id_from_property {
($property: ident, $ret: expr) => {{ ($property: ident, $ret: expr) => {{
let property = $property.as_ref().unwrap().as_str_unchecked(); let property = $property.as_ref().unwrap().as_str_unchecked();
match PropertyId::parse(property.into(), None) { match PropertyId::parse(property.into()) {
Ok(property_id) => property_id, Ok(property_id) => property_id,
Err(_) => { return $ret; } Err(_) => { return $ret; }
} }