servo: Merge #20046 - style: Move most of allowed_in to NonCustomPropertyId (from emilio:less-dumb); r=nox

Also simplify the servo property id to gecko property id conversion to be faster
and less repetitive.

This is in preparation of some patches to properly allow disabled longhands on enabled shorthands, something that we don't contemplate right now.

Source-Repo: https://github.com/servo/servo
Source-Revision: bdbb298bac881d8cf773739e4d7018080b40beb6

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : b8f44fa55ebde80b40339e69a71b94f95f112e11
This commit is contained in:
Emilio Cobos Álvarez 2018-02-14 13:23:07 -05:00
parent 495816f593
commit 2dc83028d1

View File

@ -413,10 +413,112 @@ pub mod animated_properties {
<%include file="/helpers/animated_properties.mako.rs" /> <%include file="/helpers/animated_properties.mako.rs" />
} }
/// A longhand or shorthand porperty /// A longhand or shorthand property.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct NonCustomPropertyId(usize); pub struct NonCustomPropertyId(usize);
impl NonCustomPropertyId {
#[cfg(feature = "gecko")]
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
static MAP: [nsCSSPropertyID; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
% for property in data.longhands:
${helpers.to_nscsspropertyid(property.ident)},
% endfor
% for property in data.shorthands:
${helpers.to_nscsspropertyid(property.ident)},
% endfor
% for property in data.all_aliases():
${helpers.alias_to_nscsspropertyid(property.ident)},
% endfor
];
MAP[self.0]
}
fn allowed_in(self, context: &ParserContext) -> bool {
debug_assert!(
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("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)}
match context.rule_type() {
CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(self) => {
return false;
}
CssRuleType::Page if DISALLOWED_IN_PAGE_RULE.contains(self) => {
return false;
}
_ => {}
}
// The semantics of these are kinda hard to reason about, what follows
// is a description of the different combinations that can happen with
// these three sets.
//
// Experimental properties are generally controlled by prefs, but an
// experimental property explicitly enabled in certain context (UA or
// chrome sheets) is always usable in the context regardless of the
// pref value.
//
// Non-experimental properties are either normal properties which are
// usable everywhere, or internal-only properties which are only usable
// in certain context they are explicitly enabled in.
${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("EXPERIMENTAL", lambda p: p.experimental(product))}
${id_set("ALWAYS_ENABLED", lambda p: (not p.experimental(product)) and p.enabled_in_content())}
let passes_pref_check = || {
% if product == "servo":
static PREF_NAME: [Option< &str>; ${len(data.longhands) + len(data.shorthands)}] = [
% for property in data.longhands + data.shorthands:
% if property.servo_pref:
Some("${property.servo_pref}"),
% else:
None,
% endif
% endfor
];
let pref = match PREF_NAME[self.0] {
None => return true,
Some(pref) => pref,
};
PREFS.get(pref).as_boolean().unwrap_or(false)
% else:
unsafe { structs::nsCSSProps_gPropertyEnabled[self.to_nscsspropertyid() as usize] }
% endif
};
if ALWAYS_ENABLED.contains(self) {
return true
}
if EXPERIMENTAL.contains(self) && passes_pref_check() {
return true
}
if context.stylesheet_origin == Origin::UserAgent &&
ENABLED_IN_UA_SHEETS.contains(self)
{
return true
}
if context.chrome_rules_enabled() && ENABLED_IN_CHROME.contains(self) {
return true
}
false
}
}
impl From<LonghandId> for NonCustomPropertyId { impl From<LonghandId> for NonCustomPropertyId {
fn from(id: LonghandId) -> Self { fn from(id: LonghandId) -> Self {
NonCustomPropertyId(id as usize) NonCustomPropertyId(id as usize)
@ -816,14 +918,9 @@ impl LonghandId {
/// Converts from a LonghandId to an adequate nsCSSPropertyID. /// Converts from a LonghandId to an adequate nsCSSPropertyID.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[inline]
pub fn to_nscsspropertyid(self) -> nsCSSPropertyID { pub fn to_nscsspropertyid(self) -> nsCSSPropertyID {
match self { NonCustomPropertyId::from(self).to_nscsspropertyid()
% for property in data.longhands:
LonghandId::${property.camel_case} => {
${helpers.to_nscsspropertyid(property.ident)}
}
% endfor
}
} }
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -1038,14 +1135,9 @@ impl ShorthandId {
/// Converts from a ShorthandId to an adequate nsCSSPropertyID. /// Converts from a ShorthandId to an adequate nsCSSPropertyID.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[inline]
pub fn to_nscsspropertyid(self) -> nsCSSPropertyID { pub fn to_nscsspropertyid(self) -> nsCSSPropertyID {
match self { NonCustomPropertyId::from(self).to_nscsspropertyid()
% for property in data.shorthands:
ShorthandId::${property.camel_case} => {
${helpers.to_nscsspropertyid(property.ident)}
}
% endfor
}
} }
/// Get the longhand ids that form this shorthand. /// Get the longhand ids that form this shorthand.
@ -1521,19 +1613,6 @@ impl PropertyId {
} }
} }
/// Returns an nsCSSPropertyID.
#[cfg(feature = "gecko")]
#[allow(non_upper_case_globals)]
pub fn to_nscsspropertyid(&self) -> Result<nsCSSPropertyID, ()> {
match *self {
PropertyId::Longhand(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(())
}
}
/// Given this property id, get it either as a shorthand or as a /// Given this property id, get it either as a shorthand or as a
/// `PropertyDeclarationId`. /// `PropertyDeclarationId`.
pub fn as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId> { pub fn as_shorthand(&self) -> Result<ShorthandId, PropertyDeclarationId> {
@ -1571,86 +1650,7 @@ impl PropertyId {
PropertyId::LonghandAlias(_, alias_id) => alias_id.into(), PropertyId::LonghandAlias(_, alias_id) => alias_id.into(),
}; };
debug_assert!( id.allowed_in(context)
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("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)}
match context.rule_type() {
CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(id) => {
return false;
}
CssRuleType::Page if DISALLOWED_IN_PAGE_RULE.contains(id) => {
return false;
}
_ => {}
}
// The semantics of these are kinda hard to reason about, what follows
// is a description of the different combinations that can happen with
// these three sets.
//
// Experimental properties are generally controlled by prefs, but an
// experimental property explicitly enabled in certain context (UA or
// chrome sheets) is always usable in the context regardless of the
// pref value.
//
// Non-experimental properties are either normal properties which are
// usable everywhere, or internal-only properties which are only usable
// in certain context they are explicitly enabled in.
${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("EXPERIMENTAL", lambda p: p.experimental(product))}
${id_set("ALWAYS_ENABLED", lambda p: (not p.experimental(product)) and p.enabled_in_content())}
let passes_pref_check = || {
% if product == "servo":
static PREF_NAME: [Option< &str>; ${len(data.longhands) + len(data.shorthands)}] = [
% for property in data.longhands + data.shorthands:
% if property.servo_pref:
Some("${property.servo_pref}"),
% else:
None,
% endif
% endfor
];
let pref = match PREF_NAME[id.0] {
None => return true,
Some(pref) => pref,
};
PREFS.get(pref).as_boolean().unwrap_or(false)
% else:
unsafe { structs::nsCSSProps_gPropertyEnabled[self.to_nscsspropertyid().unwrap() as usize] }
% endif
};
if ALWAYS_ENABLED.contains(id) {
return true
}
if EXPERIMENTAL.contains(id) && passes_pref_check() {
return true
}
if context.stylesheet_origin == Origin::UserAgent &&
ENABLED_IN_UA_SHEETS.contains(id)
{
return true
}
if context.chrome_rules_enabled() && ENABLED_IN_CHROME.contains(id) {
return true
}
false
} }
} }
@ -3859,23 +3859,6 @@ impl fmt::Debug for AliasId {
} }
} }
impl AliasId {
/// Returns an nsCSSPropertyID.
#[cfg(feature = "gecko")]
#[allow(non_upper_case_globals)]
pub fn to_nscsspropertyid(&self) -> nsCSSPropertyID {
use gecko_bindings::structs::*;
match *self {
% for property in data.all_aliases():
AliasId::${property.camel_case} => {
${helpers.alias_to_nscsspropertyid(property.ident)}
},
% endfor
}
}
}
// FIXME(emilio): This macro doesn't account for experimental properties, so // FIXME(emilio): This macro doesn't account for experimental properties, so
// even with the pref disabled you can set them from CSSOM in Servo. // even with the pref disabled you can set them from CSSOM in Servo.
#[macro_export] #[macro_export]