mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Add a pref checking mechanism for alias properties
This commit is contained in:
parent
4d10d39e8f
commit
6893446b71
9 changed files with 161 additions and 44 deletions
|
@ -744,7 +744,8 @@ impl LayoutThread {
|
|||
Msg::RegisterPaint(name, mut properties, painter) => {
|
||||
debug!("Registering the painter");
|
||||
let properties = properties.drain(..)
|
||||
.filter_map(|name| PropertyId::parse(&*name).ok().map(|id| (name.clone(), id)))
|
||||
.filter_map(|name| PropertyId::parse(&*name, None)
|
||||
.ok().map(|id| (name.clone(), id)))
|
||||
.filter(|&(_, ref id)| id.as_shorthand().is_err())
|
||||
.collect();
|
||||
let registered_painter = RegisteredPainterImpl {
|
||||
|
|
|
@ -296,7 +296,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
|
||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
|
||||
fn GetPropertyValue(&self, property: DOMString) -> DOMString {
|
||||
let id = if let Ok(id) = PropertyId::parse(&property) {
|
||||
let id = if let Ok(id) = PropertyId::parse(&property, None) {
|
||||
id
|
||||
} else {
|
||||
// Unkwown property
|
||||
|
@ -307,7 +307,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
|
||||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertypriority
|
||||
fn GetPropertyPriority(&self, property: DOMString) -> DOMString {
|
||||
let id = if let Ok(id) = PropertyId::parse(&property) {
|
||||
let id = if let Ok(id) = PropertyId::parse(&property, None) {
|
||||
id
|
||||
} else {
|
||||
// Unkwown property
|
||||
|
@ -331,7 +331,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
priority: DOMString)
|
||||
-> ErrorResult {
|
||||
// Step 3
|
||||
let id = if let Ok(id) = PropertyId::parse(&property) {
|
||||
let id = if let Ok(id) = PropertyId::parse(&property, None) {
|
||||
id
|
||||
} else {
|
||||
// Unknown property
|
||||
|
@ -348,7 +348,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
}
|
||||
|
||||
// Step 2 & 3
|
||||
let id = match PropertyId::parse(&property) {
|
||||
let id = match PropertyId::parse(&property, None) {
|
||||
Ok(id) => id,
|
||||
Err(..) => return Ok(()), // Unkwown property
|
||||
};
|
||||
|
@ -380,7 +380,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
return Err(Error::NoModificationAllowed);
|
||||
}
|
||||
|
||||
let id = if let Ok(id) = PropertyId::parse(&property) {
|
||||
let id = if let Ok(id) = PropertyId::parse(&property, None) {
|
||||
id
|
||||
} else {
|
||||
// Unkwown property, cannot be there to remove.
|
||||
|
|
|
@ -265,6 +265,18 @@ class Shorthand(object):
|
|||
transitionable = property(get_transitionable)
|
||||
|
||||
|
||||
class Alias(object):
|
||||
def __init__(self, name, original):
|
||||
self.name = name
|
||||
self.ident = to_rust_ident(name)
|
||||
self.camel_case = to_camel_case(self.ident)
|
||||
self.gecko_pref_ident = to_rust_ident(name)
|
||||
self.internal = original.internal
|
||||
self.experimental = original.experimental
|
||||
self.allowed_in_page_rule = original.allowed_in_page_rule
|
||||
self.allowed_in_keyframe_block = original.allowed_in_keyframe_block
|
||||
|
||||
|
||||
class Method(object):
|
||||
def __init__(self, name, return_type=None, arg_types=None, is_mut=False):
|
||||
self.name = name
|
||||
|
@ -311,7 +323,9 @@ class PropertiesData(object):
|
|||
self.longhands = []
|
||||
self.longhands_by_name = {}
|
||||
self.derived_longhands = {}
|
||||
self.longhand_aliases = []
|
||||
self.shorthands = []
|
||||
self.shorthand_aliases = []
|
||||
|
||||
def new_style_struct(self, *args, **kwargs):
|
||||
style_struct = StyleStruct(*args, **kwargs)
|
||||
|
@ -335,6 +349,7 @@ class PropertiesData(object):
|
|||
|
||||
longhand = Longhand(self.current_style_struct, name, **kwargs)
|
||||
self.add_prefixed_aliases(longhand)
|
||||
self.longhand_aliases += list(map(lambda x: Alias(x, longhand), longhand.alias))
|
||||
self.current_style_struct.longhands.append(longhand)
|
||||
self.longhands.append(longhand)
|
||||
self.longhands_by_name[name] = longhand
|
||||
|
@ -352,8 +367,12 @@ class PropertiesData(object):
|
|||
sub_properties = [self.longhands_by_name[s] for s in sub_properties]
|
||||
shorthand = Shorthand(name, sub_properties, *args, **kwargs)
|
||||
self.add_prefixed_aliases(shorthand)
|
||||
self.shorthand_aliases += list(map(lambda x: Alias(x, shorthand), shorthand.alias))
|
||||
self.shorthands.append(shorthand)
|
||||
return shorthand
|
||||
|
||||
def shorthands_except_all(self):
|
||||
return [s for s in self.shorthands if s.name != "all"]
|
||||
|
||||
def all_aliases(self):
|
||||
return self.longhand_aliases + self.shorthand_aliases
|
||||
|
|
|
@ -947,7 +947,8 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
|
|||
|
||||
fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
|
||||
-> Result<Importance, ParseError<'i>> {
|
||||
let id = match PropertyId::parse(&name) {
|
||||
let prop_context = PropertyParserContext::new(self.context);
|
||||
let id = match PropertyId::parse(&name, Some(&prop_context)) {
|
||||
Ok(id) => id,
|
||||
Err(()) => {
|
||||
return Err(if is_non_mozilla_vendor_identifier(&name) {
|
||||
|
|
|
@ -3505,7 +3505,7 @@ fn static_assert() {
|
|||
Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr());
|
||||
}
|
||||
|
||||
if let Ok(prop_id) = PropertyId::parse(&feature.0.to_string()) {
|
||||
if let Ok(prop_id) = PropertyId::parse(&feature.0.to_string(), None) {
|
||||
match prop_id.as_shorthand() {
|
||||
Ok(shorthand) => {
|
||||
for longhand in shorthand.longhands() {
|
||||
|
|
|
@ -246,10 +246,16 @@ impl From<ShorthandId> for NonCustomPropertyId {
|
|||
}
|
||||
}
|
||||
|
||||
/// A set of longhand properties
|
||||
impl From<AliasId> for NonCustomPropertyId {
|
||||
fn from(id: AliasId) -> Self {
|
||||
NonCustomPropertyId(id as usize + ${len(data.longhands) + len(data.shorthands)})
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of all properties
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct NonCustomPropertyIdSet {
|
||||
storage: [u32; (${len(data.longhands) + len(data.shorthands)} - 1 + 32) / 32]
|
||||
storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32]
|
||||
}
|
||||
|
||||
impl NonCustomPropertyIdSet {
|
||||
|
@ -264,7 +270,7 @@ impl NonCustomPropertyIdSet {
|
|||
<%def name="static_non_custom_property_id_set(name, is_member)">
|
||||
static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet {
|
||||
<%
|
||||
storage = [0] * ((len(data.longhands) + len(data.shorthands) - 1 + 32) / 32)
|
||||
storage = [0] * ((len(data.longhands) + len(data.shorthands) + len(data.all_aliases()) - 1 + 32) / 32)
|
||||
for i, property in enumerate(data.longhands + data.shorthands):
|
||||
if is_member(property):
|
||||
storage[i / 32] |= 1 << (i % 32)
|
||||
|
@ -1003,33 +1009,75 @@ impl PropertyId {
|
|||
/// Returns a given property from the string `s`.
|
||||
///
|
||||
/// Returns Err(()) for unknown non-custom properties
|
||||
pub fn parse(property_name: &str) -> Result<Self, ()> {
|
||||
/// If caller wants to provide a different context, it can be provided with
|
||||
/// Some(context), if None is given, default setting for PropertyParserContext
|
||||
/// will be used. It is `Origin::Author` for stylesheet_origin and
|
||||
/// `CssRuleType::Style` for rule_type.
|
||||
pub fn parse(property_name: &str, context: Option< &PropertyParserContext>) -> Result<Self, ()> {
|
||||
if let Ok(name) = ::custom_properties::parse_name(property_name) {
|
||||
return Ok(PropertyId::Custom(::custom_properties::Name::from(name)))
|
||||
}
|
||||
|
||||
// FIXME(https://github.com/rust-lang/rust/issues/33156): remove this enum and use PropertyId
|
||||
// when stable Rust allows destructors in statics.
|
||||
// ShorthandAlias is not used in servo build. That's why we need to allow dead_code.
|
||||
#[allow(dead_code)]
|
||||
pub enum StaticId {
|
||||
Longhand(LonghandId),
|
||||
Shorthand(ShorthandId),
|
||||
LonghandAlias(LonghandId, AliasId),
|
||||
ShorthandAlias(ShorthandId, AliasId),
|
||||
}
|
||||
ascii_case_insensitive_phf_map! {
|
||||
static_id -> StaticId = {
|
||||
% for (kind, properties) in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]:
|
||||
% for property in properties:
|
||||
% for name in [property.name] + property.alias:
|
||||
"${name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
|
||||
"${property.name}" => StaticId::${kind}(${kind}Id::${property.camel_case}),
|
||||
% for name in property.alias:
|
||||
"${name}" => {
|
||||
StaticId::${kind}Alias(${kind}Id::${property.camel_case},
|
||||
AliasId::${to_camel_case(name)})
|
||||
},
|
||||
% endfor
|
||||
% endfor
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
match static_id(property_name) {
|
||||
Some(&StaticId::Longhand(id)) => Ok(PropertyId::Longhand(id)),
|
||||
Some(&StaticId::Shorthand(id)) => Ok(PropertyId::Shorthand(id)),
|
||||
None => Err(()),
|
||||
}
|
||||
|
||||
let default;
|
||||
let context = match context {
|
||||
Some(context) => context,
|
||||
None => {
|
||||
default = PropertyParserContext {
|
||||
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)) => {
|
||||
(PropertyId::Longhand(id), None)
|
||||
},
|
||||
Some(&StaticId::Shorthand(id)) => {
|
||||
(PropertyId::Shorthand(id), None)
|
||||
},
|
||||
Some(&StaticId::LonghandAlias(id, alias)) => {
|
||||
(PropertyId::Longhand(id), Some(alias))
|
||||
},
|
||||
Some(&StaticId::ShorthandAlias(id, alias)) => {
|
||||
(PropertyId::Shorthand(id), Some(alias))
|
||||
},
|
||||
None => return Err(()),
|
||||
};
|
||||
id.check_allowed_in(alias, context).map_err(|_| ())?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
/// Returns a property id from Gecko's nsCSSPropertyID.
|
||||
|
@ -1111,22 +1159,26 @@ impl PropertyId {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_allowed_in(&self, rule_type: CssRuleType, stylesheet_origin: Origin)
|
||||
fn check_allowed_in(&self, alias: Option<AliasId>, context: &PropertyParserContext)
|
||||
-> Result<(), PropertyDeclarationParseError<'static>> {
|
||||
let id: NonCustomPropertyId;
|
||||
match *self {
|
||||
// Custom properties are allowed everywhere
|
||||
PropertyId::Custom(_) => return Ok(()),
|
||||
if let Some(alias_id) = alias {
|
||||
id = alias_id.into();
|
||||
} else {
|
||||
match *self {
|
||||
// Custom properties are allowed everywhere
|
||||
PropertyId::Custom(_) => return Ok(()),
|
||||
|
||||
PropertyId::Shorthand(shorthand_id) => id = shorthand_id.into(),
|
||||
PropertyId::Longhand(longhand_id) => id = longhand_id.into(),
|
||||
PropertyId::Shorthand(shorthand_id) => id = shorthand_id.into(),
|
||||
PropertyId::Longhand(longhand_id) => id = longhand_id.into(),
|
||||
}
|
||||
}
|
||||
|
||||
<% 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 rule_type {
|
||||
match context.rule_type {
|
||||
CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(id) => {
|
||||
return Err(PropertyDeclarationParseError::AnimationPropertyInKeyframeBlock)
|
||||
}
|
||||
|
@ -1136,7 +1188,6 @@ impl PropertyId {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
// For properties that are experimental but not internal, the pref will
|
||||
// control its availability in all sheets. For properties that are
|
||||
// both experimental and internal, the pref only controls its
|
||||
|
@ -1151,7 +1202,7 @@ impl PropertyId {
|
|||
static EXPERIMENTAL: NonCustomPropertyIdSet = NonCustomPropertyIdSet {
|
||||
<%
|
||||
grouped = []
|
||||
properties = data.longhands + data.shorthands
|
||||
properties = data.longhands + data.shorthands + data.all_aliases()
|
||||
while properties:
|
||||
grouped.append(properties[:32])
|
||||
properties = properties[32:]
|
||||
|
@ -1185,14 +1236,16 @@ impl PropertyId {
|
|||
}
|
||||
% endif
|
||||
% if product == "gecko":
|
||||
use gecko_bindings::structs;
|
||||
let id = self.to_nscsspropertyid().unwrap();
|
||||
let id = match alias {
|
||||
Some(alias_id) => alias_id.to_nscsspropertyid().unwrap(),
|
||||
None => self.to_nscsspropertyid().unwrap(),
|
||||
};
|
||||
unsafe { structs::nsCSSProps_gPropertyEnabled[id as usize] }
|
||||
% endif
|
||||
};
|
||||
|
||||
if INTERNAL.contains(id) {
|
||||
if stylesheet_origin != Origin::UserAgent {
|
||||
if context.stylesheet_origin != Origin::UserAgent {
|
||||
if EXPERIMENTAL.contains(id) {
|
||||
if !passes_pref_check() {
|
||||
return Err(PropertyDeclarationParseError::ExperimentalProperty);
|
||||
|
@ -1211,6 +1264,25 @@ impl PropertyId {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parsing Context for PropertyId.
|
||||
pub struct PropertyParserContext {
|
||||
/// 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 {
|
||||
stylesheet_origin: context.stylesheet_origin,
|
||||
rule_type: context.rule_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Servo's representation for a property declaration.
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub enum PropertyDeclaration {
|
||||
|
@ -1478,12 +1550,6 @@ impl PropertyDeclaration {
|
|||
id: PropertyId, context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<(), PropertyDeclarationParseError<'i>> {
|
||||
assert!(declarations.is_empty());
|
||||
let rule_type = context.rule_type();
|
||||
debug_assert!(rule_type == CssRuleType::Keyframe ||
|
||||
rule_type == CssRuleType::Page ||
|
||||
rule_type == CssRuleType::Style,
|
||||
"Declarations are only expected inside a keyframe, page, or style rule.");
|
||||
id.check_allowed_in(rule_type, context.stylesheet_origin)?;
|
||||
match id {
|
||||
PropertyId::Custom(name) => {
|
||||
let value = match input.try(|i| CSSWideKeyword::parse(i)) {
|
||||
|
@ -3428,6 +3494,33 @@ pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
|
|||
}
|
||||
}
|
||||
|
||||
/// An identifier for a given alias property.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum AliasId {
|
||||
% for i, property in enumerate(data.all_aliases()):
|
||||
/// ${property.name}
|
||||
${property.camel_case} = ${i},
|
||||
% endfor
|
||||
}
|
||||
|
||||
impl AliasId {
|
||||
/// Returns an nsCSSPropertyID.
|
||||
#[cfg(feature = "gecko")]
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub fn to_nscsspropertyid(&self) -> Result<nsCSSPropertyID, ()> {
|
||||
use gecko_bindings::structs::*;
|
||||
|
||||
match *self {
|
||||
% for property in data.all_aliases():
|
||||
AliasId::${property.camel_case} => {
|
||||
Ok(${helpers.alias_to_nscsspropertyid(property.ident)})
|
||||
},
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! css_properties_accessors {
|
||||
($macro_name: ident) => {
|
||||
|
|
|
@ -8,7 +8,7 @@ use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser, Parse
|
|||
use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule, SourceLocation};
|
||||
use error_reporting::{NullReporter, ContextualParseError};
|
||||
use parser::ParserContext;
|
||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
|
||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId, PropertyParserContext};
|
||||
use properties::{PropertyDeclarationId, LonghandId, SourcePropertyDeclaration};
|
||||
use properties::LonghandIdSet;
|
||||
use properties::animated_properties::AnimatableLonghand;
|
||||
|
@ -532,7 +532,9 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> {
|
|||
|
||||
fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
|
||||
-> Result<(), ParseError<'i>> {
|
||||
let id = PropertyId::parse(&name)
|
||||
let property_context = PropertyParserContext::new(self.context);
|
||||
|
||||
let id = PropertyId::parse(&name, Some(&property_context))
|
||||
.map_err(|()| PropertyDeclarationParseError::UnknownProperty(name))?;
|
||||
match PropertyDeclaration::parse_into(self.declarations, id, self.context, input) {
|
||||
Ok(()) => {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
use cssparser::{BasicParseError, ParseError as CssParseError, ParserInput};
|
||||
use cssparser::{Delimiter, parse_important, Parser, SourceLocation, Token};
|
||||
use parser::ParserContext;
|
||||
use properties::{PropertyId, PropertyDeclaration, SourcePropertyDeclaration};
|
||||
use properties::{PropertyId, PropertyDeclaration, PropertyParserContext, SourcePropertyDeclaration};
|
||||
use selectors::parser::SelectorParseError;
|
||||
use servo_arc::Arc;
|
||||
use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
|
||||
|
@ -247,10 +247,11 @@ impl Declaration {
|
|||
input.parse_entirely(|input| {
|
||||
let prop = input.expect_ident().unwrap().as_ref().to_owned();
|
||||
input.expect_colon().unwrap();
|
||||
let id = PropertyId::parse(&prop)
|
||||
.map_err(|_| StyleParseError::UnspecifiedError)?;
|
||||
let mut declarations = SourcePropertyDeclaration::new();
|
||||
let context = ParserContext::new_with_rule_type(cx, Some(CssRuleType::Style));
|
||||
let property_context = PropertyParserContext::new(&context);
|
||||
let id = PropertyId::parse(&prop, Some(&property_context))
|
||||
.map_err(|_| StyleParseError::UnspecifiedError)?;
|
||||
let mut declarations = SourcePropertyDeclaration::new();
|
||||
input.parse_until_before(Delimiter::Bang, |input| {
|
||||
PropertyDeclaration::parse_into(&mut declarations, id, &context, input)
|
||||
.map_err(|e| StyleParseError::PropertyDeclaration(e).into())
|
||||
|
|
|
@ -2190,7 +2190,7 @@ pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(declarations: RawServoDe
|
|||
macro_rules! get_property_id_from_property {
|
||||
($property: ident, $ret: expr) => {{
|
||||
let property = unsafe { $property.as_ref().unwrap().as_str_unchecked() };
|
||||
match PropertyId::parse(property.into()) {
|
||||
match PropertyId::parse(property.into(), None) {
|
||||
Ok(property_id) => property_id,
|
||||
Err(_) => { return $ret; }
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue