From 34c5a216918873bb1fbb72ab3177f3a0aa8777b0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 13 Jul 2017 00:48:36 +0200 Subject: [PATCH] Merge per-property substitute_variables* functions into one. --- components/style/properties/helpers.mako.rs | 181 +++++++-------- .../helpers/animated_properties.mako.rs | 37 +-- .../style/properties/properties.mako.rs | 211 ++++++++---------- 3 files changed, 187 insertions(+), 242 deletions(-) diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index a8cc751655a1..e59be7997373 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -315,7 +315,7 @@ context: &mut computed::Context, cacheable: &mut bool, cascade_info: &mut Option<<&mut CascadeInfo>) { - let declared_value = match *declaration { + let value = match *declaration { PropertyDeclaration::${property.camel_case}(ref value) => { DeclaredValue::Value(value) }, @@ -323,107 +323,98 @@ debug_assert!(id == LonghandId::${property.camel_case}); DeclaredValue::CSSWideKeyword(value) }, - PropertyDeclaration::WithVariables(id, ref value) => { - debug_assert!(id == LonghandId::${property.camel_case}); - DeclaredValue::WithVariables(value) - }, + PropertyDeclaration::WithVariables(..) => { + panic!("variables should already have been substituted") + } _ => panic!("entered the wrong cascade_property() implementation"), }; % if not property.derived_from: - { - let custom_props = context.style().custom_properties(); - let quirks_mode = context.quirks_mode; - ::properties::substitute_variables_${property.ident}( - &declared_value, &custom_props, - &mut |value| { - if let Some(ref mut cascade_info) = *cascade_info { - cascade_info.on_cascade_property(&declaration, - &value); - } - % if property.logical: - let wm = context.style.writing_mode; - % endif - <% - maybe_wm = ", wm" if property.logical else "" - maybe_cacheable = ", cacheable" if property.has_uncacheable_values == "True" else "" - props_need_device = "content list_style_type".split() if product == "gecko" else [] - maybe_device = ", context.device" if property.ident in props_need_device else "" - %> - match *value { - DeclaredValue::Value(ref specified_value) => { - % if property.ident in SYSTEM_FONT_LONGHANDS and product == "gecko": - if let Some(sf) = specified_value.get_system() { - longhands::system_font::resolve_system_font(sf, context); - } - % endif - % if property.is_vector: - // In the case of a vector property we want to pass down - // an iterator so that this can be computed without allocation - // - // However, computing requires a context, but the style struct - // being mutated is on the context. We temporarily remove it, - // mutate it, and then put it back. Vector longhands cannot - // touch their own style struct whilst computing, else this will panic. - let mut s = context.mutate_style().take_${data.current_style_struct.name_lower}(); - { - let iter = specified_value.compute_iter(context); - s.set_${property.ident}(iter ${maybe_cacheable}); - } - context.mutate_style().put_${data.current_style_struct.name_lower}(s); - % else: - let computed = specified_value.to_computed_value(context); - % if property.ident == "font_size": - longhands::font_size::cascade_specified_font_size(context, - specified_value, - computed, - inherited_style.get_font()); - % else: - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_${property.ident}(computed ${maybe_device} - ${maybe_cacheable} ${maybe_wm}); - % endif - % endif + if let Some(ref mut cascade_info) = *cascade_info { + cascade_info.on_cascade_property(&declaration, + &value); + } + % if property.logical: + let wm = context.style.writing_mode; + % endif + <% + maybe_wm = ", wm" if property.logical else "" + maybe_cacheable = ", cacheable" if property.has_uncacheable_values == "True" else "" + props_need_device = "content list_style_type".split() if product == "gecko" else [] + maybe_device = ", context.device" if property.ident in props_need_device else "" + %> + match value { + DeclaredValue::Value(ref specified_value) => { + % if property.ident in SYSTEM_FONT_LONGHANDS and product == "gecko": + if let Some(sf) = specified_value.get_system() { + longhands::system_font::resolve_system_font(sf, context); } - DeclaredValue::WithVariables(_) => unreachable!(), - DeclaredValue::CSSWideKeyword(keyword) => match keyword { - % if not data.current_style_struct.inherited: - CSSWideKeyword::Unset | - % endif - CSSWideKeyword::Initial => { - % if property.ident == "font_size": - longhands::font_size::cascade_initial_font_size(context); - % else: - // We assume that it's faster to use copy_*_from rather than - // set_*(get_initial_value()); - let initial_struct = default_style - .get_${data.current_style_struct.name_lower}(); - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .copy_${property.ident}_from(initial_struct ${maybe_wm}); - % endif - }, - % if data.current_style_struct.inherited: - CSSWideKeyword::Unset | - % endif - CSSWideKeyword::Inherit => { - // This is a bit slow, but this is rare so it shouldn't - // matter. - // - // FIXME: is it still? - *cacheable = false; - let inherited_struct = - inherited_style.get_${data.current_style_struct.name_lower}(); - - % if property.ident == "font_size": - longhands::font_size::cascade_inherit_font_size(context, inherited_struct); - % else: - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .copy_${property.ident}_from(inherited_struct ${maybe_wm}); - % endif - } + % endif + % if property.is_vector: + // In the case of a vector property we want to pass down + // an iterator so that this can be computed without allocation + // + // However, computing requires a context, but the style struct + // being mutated is on the context. We temporarily remove it, + // mutate it, and then put it back. Vector longhands cannot + // touch their own style struct whilst computing, else this will panic. + let mut s = context.mutate_style().take_${data.current_style_struct.name_lower}(); + { + let iter = specified_value.compute_iter(context); + s.set_${property.ident}(iter ${maybe_cacheable}); } + context.mutate_style().put_${data.current_style_struct.name_lower}(s); + % else: + let computed = specified_value.to_computed_value(context); + % if property.ident == "font_size": + longhands::font_size::cascade_specified_font_size(context, + specified_value, + computed, + inherited_style.get_font()); + % else: + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .set_${property.ident}(computed ${maybe_device} + ${maybe_cacheable} ${maybe_wm}); + % endif + % endif + } + DeclaredValue::WithVariables(_) => unreachable!(), + DeclaredValue::CSSWideKeyword(keyword) => match keyword { + % if not data.current_style_struct.inherited: + CSSWideKeyword::Unset | + % endif + CSSWideKeyword::Initial => { + % if property.ident == "font_size": + longhands::font_size::cascade_initial_font_size(context); + % else: + // We assume that it's faster to use copy_*_from rather than + // set_*(get_initial_value()); + let initial_struct = default_style + .get_${data.current_style_struct.name_lower}(); + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .copy_${property.ident}_from(initial_struct ${maybe_wm}); + % endif + }, + % if data.current_style_struct.inherited: + CSSWideKeyword::Unset | + % endif + CSSWideKeyword::Inherit => { + // This is a bit slow, but this is rare so it shouldn't + // matter. + // + // FIXME: is it still? + *cacheable = false; + let inherited_struct = + inherited_style.get_${data.current_style_struct.name_lower}(); + + % if property.ident == "font_size": + longhands::font_size::cascade_inherit_font_size(context, inherited_struct); + % else: + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .copy_${property.ident}_from(inherited_struct ${maybe_wm}); + % endif } - }, quirks_mode); + } } % if property.custom_cascade: diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 959b55b0a60b..abceb90629dc 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -524,7 +524,6 @@ impl AnimationValue { pub fn from_declaration(decl: &PropertyDeclaration, context: &mut Context, initial: &ComputedValues) -> Option { use properties::LonghandId; - use properties::DeclaredValue; match *decl { % for prop in data.longhands: @@ -584,40 +583,10 @@ impl AnimationValue { % endfor } }, - PropertyDeclaration::WithVariables(id, ref variables) => { + PropertyDeclaration::WithVariables(id, ref unparsed) => { let custom_props = context.style().custom_properties(); - match id { - % for prop in data.longhands: - % if prop.animatable: - LonghandId::${prop.camel_case} => { - let mut result = None; - let quirks_mode = context.quirks_mode; - ::properties::substitute_variables_${prop.ident}_slow( - &variables.css, - variables.first_token_type, - &variables.url_data, - variables.from_shorthand, - &custom_props, - &mut |v| { - let declaration = match *v { - DeclaredValue::Value(value) => { - PropertyDeclaration::${prop.camel_case}(value.clone()) - }, - DeclaredValue::CSSWideKeyword(keyword) => { - PropertyDeclaration::CSSWideKeyword(id, keyword) - }, - DeclaredValue::WithVariables(_) => unreachable!(), - }; - result = AnimationValue::from_declaration(&declaration, context, initial); - }, - quirks_mode); - result - }, - % else: - LonghandId::${prop.camel_case} => None, - % endif - % endfor - } + let substituted = unparsed.substitute_variables(id, &custom_props, context.quirks_mode); + AnimationValue::from_declaration(&substituted, context, initial) }, _ => None // non animatable properties will get included because of shorthands. ignore. } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 07b5ca077d5c..8cccbf342da1 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -268,6 +268,18 @@ static ${name}: NonCustomPropertyIdSet = NonCustomPropertyIdSet { }; +<%def name="static_longhand_id_set(name, is_member)"> +static ${name}: LonghandIdSet = LonghandIdSet { + <% + storage = [0] * ((len(data.longhands) - 1 + 32) / 32) + for i, property in enumerate(data.longhands): + if is_member(property): + storage[i / 32] |= 1 << (i % 32) + %> + storage: [${", ".join("0x%x" % word for word in storage)}] +}; + + /// A set of longhand properties #[derive(Clone, PartialEq)] pub struct LonghandIdSet { @@ -371,108 +383,6 @@ impl PropertyDeclarationIdSet { } } -% for property in data.longhands: - % if not property.derived_from: - /// Perform CSS variable substitution if needed, and execute `f` with - /// the resulting declared value. - #[allow(non_snake_case)] - fn substitute_variables_${property.ident}( - % if property.boxed: - value: &DeclaredValue>, - % else: - value: &DeclaredValue, - % endif - custom_properties: &Option>, - f: &mut F, - quirks_mode: QuirksMode) - % if property.boxed: - where F: FnMut(&DeclaredValue>) - % else: - where F: FnMut(&DeclaredValue) - % endif - { - if let DeclaredValue::WithVariables(ref with_variables) = *value { - substitute_variables_${property.ident}_slow(&with_variables.css, - with_variables.first_token_type, - &with_variables.url_data, - with_variables.from_shorthand, - custom_properties, - f, - quirks_mode); - } else { - f(value); - } - } - - #[allow(non_snake_case)] - #[inline(never)] - fn substitute_variables_${property.ident}_slow( - css: &String, - first_token_type: TokenSerializationType, - url_data: &UrlExtraData, - from_shorthand: Option, - custom_properties: &Option>, - f: &mut F, - quirks_mode: QuirksMode) - % if property.boxed: - where F: FnMut(&DeclaredValue>) - % else: - where F: FnMut(&DeclaredValue) - % endif - { - f(& - ::custom_properties::substitute(css, first_token_type, custom_properties) - .ok() - .and_then(|css| { - // As of this writing, only the base URL is used for property values: - let reporter = NullReporter; - let context = ParserContext::new(Origin::Author, - url_data, - &reporter, - None, - PARSING_MODE_DEFAULT, - quirks_mode); - let mut input = ParserInput::new(&css); - Parser::new(&mut input).parse_entirely(|input| { - match from_shorthand { - None => { - longhands::${property.ident} - ::parse_specified(&context, input).map(DeclaredValueOwned::Value) - } - Some(ShorthandId::All) => { - // No need to parse the 'all' shorthand as anything other than a CSS-wide - // keyword, after variable substitution. - Err(SelectorParseError::UnexpectedIdent("all".into()).into()) - } - % for shorthand in data.shorthands_except_all(): - % if property in shorthand.sub_properties: - Some(ShorthandId::${shorthand.camel_case}) => { - shorthands::${shorthand.ident}::parse_value(&context, input) - .map(|result| { - DeclaredValueOwned::Value(result.${property.ident}) - }) - } - % endif - % endfor - _ => unreachable!() - } - }).ok() - }) - .unwrap_or( - // Invalid at computed-value time. - DeclaredValueOwned::CSSWideKeyword( - % if property.style_struct.inherited: - CSSWideKeyword::Inherit - % else: - CSSWideKeyword::Initial - % endif - ) - ).borrow() - ); - } - % endif -% endfor - /// An enum to represent a CSS Wide keyword. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Copy, Clone, Debug, Eq, PartialEq, ToCss)] @@ -552,6 +462,11 @@ impl LonghandId { } } + fn inherited(&self) -> bool { + ${static_longhand_id_set("INHERITED", lambda p: p.style_struct.inherited)} + INHERITED.contains(*self) + } + fn shorthands(&self) -> &'static [ShorthandId] { // first generate longhand to shorthands lookup map // @@ -887,6 +802,64 @@ pub struct UnparsedValue { from_shorthand: Option, } +impl UnparsedValue { + fn substitute_variables(&self, longhand_id: LonghandId, + custom_properties: &Option>, + quirks_mode: QuirksMode) + -> PropertyDeclaration { + ::custom_properties::substitute(&self.css, self.first_token_type, custom_properties) + .ok() + .and_then(|css| { + // As of this writing, only the base URL is used for property values: + let reporter = NullReporter; + let context = ParserContext::new(Origin::Author, + &self.url_data, + &reporter, + None, + PARSING_MODE_DEFAULT, + quirks_mode); + let mut input = ParserInput::new(&css); + Parser::new(&mut input).parse_entirely(|input| { + match self.from_shorthand { + None => longhand_id.parse_value(&context, input), + Some(ShorthandId::All) => { + // No need to parse the 'all' shorthand as anything other than a CSS-wide + // keyword, after variable substitution. + Err(SelectorParseError::UnexpectedIdent("all".into()).into()) + } + % for shorthand in data.shorthands_except_all(): + Some(ShorthandId::${shorthand.camel_case}) => { + shorthands::${shorthand.ident}::parse_value(&context, input) + .map(|longhands| { + match longhand_id { + % for property in shorthand.sub_properties: + LonghandId::${property.camel_case} => { + PropertyDeclaration::${property.camel_case}( + longhands.${property.ident} + ) + } + % endfor + _ => unreachable!() + } + }) + } + % endfor + } + }) + .ok() + }) + .unwrap_or_else(|| { + // Invalid at computed-value time. + let keyword = if longhand_id.inherited() { + CSSWideKeyword::Inherit + } else { + CSSWideKeyword::Initial + }; + PropertyDeclaration::CSSWideKeyword(longhand_id, keyword) + }) + } +} + impl<'a, T: HasViewportPercentage> HasViewportPercentage for DeclaredValue<'a, T> { fn has_viewport_percentage(&self) -> bool { match *self { @@ -2814,7 +2787,17 @@ pub fn apply_declarations<'a, F, I>(device: &Device, let mut font_family = None; % endif for (declaration, cascade_level) in iter_declarations() { - let mut declaration = declaration; + let mut declaration = match *declaration { + PropertyDeclaration::WithVariables(id, ref unparsed) => { + Cow::Owned(unparsed.substitute_variables( + id, + &context.style.custom_properties, + context.quirks_mode + )) + } + ref d => Cow::Borrowed(d) + }; + let longhand_id = match declaration.id() { PropertyDeclarationId::Longhand(id) => id, PropertyDeclarationId::Custom(..) => continue, @@ -2838,16 +2821,18 @@ pub fn apply_declarations<'a, F, I>(device: &Device, CascadeLevel::UserNormal | CascadeLevel::UserImportant | CascadeLevel::UAImportant) { + let non_transparent_background; if let PropertyDeclaration::BackgroundColor(ref color) = *declaration { // Treat background-color a bit differently. If the specified // color is anything other than a fully transparent color, convert // it into the Device's default background color. - if color.is_non_transparent() { - declaration = default_background_color_decl.as_ref().unwrap(); - } + non_transparent_background = color.is_non_transparent(); } else { continue } + if non_transparent_background { + declaration = Cow::Borrowed(default_background_color_decl.as_ref().unwrap()); + } } if @@ -2868,17 +2853,17 @@ pub fn apply_declarations<'a, F, I>(device: &Device, % if category_to_cascade_now == "early": if LonghandId::FontSize == longhand_id { - font_size = Some(declaration); + font_size = Some(declaration.clone()); continue; } if LonghandId::FontFamily == longhand_id { - font_family = Some(declaration); + font_family = Some(declaration.clone()); continue; } % endif let discriminant = longhand_id as usize; - (CASCADE_PROPERTY[discriminant])(declaration, + (CASCADE_PROPERTY[discriminant])(&*declaration, inherited_style, default_style, &mut context, @@ -2902,8 +2887,8 @@ pub fn apply_declarations<'a, F, I>(device: &Device, if seen.contains(LonghandId::XLang) || font_family.is_some() { // if just the language changed, the inherited generic is all we need let mut generic = inherited_style.get_font().gecko().mGenericID; - if let Some(declaration) = font_family { - if let PropertyDeclaration::FontFamily(ref fam) = *declaration { + if let Some(ref declaration) = font_family { + if let PropertyDeclaration::FontFamily(ref fam) = **declaration { if let Some(id) = fam.single_generic() { generic = id; // In case of a specified font family with a single generic, we will @@ -2948,7 +2933,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, // during the early iteration and cascade them in order // after it. if !_skip_font_family { - if let Some(declaration) = font_family { + if let Some(ref declaration) = font_family { let discriminant = LonghandId::FontFamily as usize; (CASCADE_PROPERTY[discriminant])(declaration, @@ -2963,7 +2948,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, } } - if let Some(declaration) = font_size { + if let Some(ref declaration) = font_size { let discriminant = LonghandId::FontSize as usize; (CASCADE_PROPERTY[discriminant])(declaration, inherited_style,