diff --git a/components/style/properties/computed_value_flags.rs b/components/style/properties/computed_value_flags.rs new file mode 100644 index 00000000000..8e3dc090b77 --- /dev/null +++ b/components/style/properties/computed_value_flags.rs @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Misc information about a given computed style. + +use properties::{ComputedValues, StyleBuilder}; + +bitflags! { + /// Misc information about a given computed style. + pub flags ComputedValueFlags: u8 { + /// Whether the style or any of the ancestors has a text-decoration + /// property that should get propagated to descendants. + /// + /// text-decoration is a reset property, but gets propagated in the + /// frame/box tree. + const HAS_TEXT_DECORATION_LINE = 1 << 0, + } +} + +impl ComputedValueFlags { + /// Get the computed value flags for the initial style. + pub fn initial() -> Self { + Self::empty() + } + + /// Compute the flags for this style, given the parent style. + pub fn compute( + this_style: &StyleBuilder, + parent_style: &ComputedValues, + ) -> Self { + let mut ret = Self::empty(); + + // FIXME(emilio): This feels like it wants to look at the + // layout_parent_style, but the way it works in Gecko means it's not + // needed (we'd recascade a bit more when it changes, but that's fine), + // and this way it simplifies the code for text styles and similar. + if parent_style.flags.contains(HAS_TEXT_DECORATION_LINE) || + !this_style.get_text().clone_text_decoration_line().is_empty() { + ret.insert(HAS_TEXT_DECORATION_LINE); + } + + ret + } +} diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 83c41e407dd..5052425e2c5 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -54,9 +54,8 @@ use gecko::values::round_border_to_device_pixels; use logical_geometry::WritingMode; use media_queries::Device; use properties::animated_properties::TransitionProperty; -use properties::longhands; -use properties:: FontComputationData; -use properties::{Importance, LonghandId}; +use properties::computed_value_flags::ComputedValueFlags; +use properties::{longhands, FontComputationData, Importance, LonghandId}; use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId}; use rule_tree::StrongRuleNode; use std::fmt::{self, Debug}; @@ -75,16 +74,16 @@ pub mod style_structs { % endfor } - +// FIXME(emilio): Unify both definitions, since they're equal now. #[derive(Clone)] pub struct ComputedValues { % for style_struct in data.style_structs: ${style_struct.ident}: Arc, % endfor - custom_properties: Option>, pub writing_mode: WritingMode, pub font_computation_data: FontComputationData, + pub flags: ComputedValueFlags, /// The rule node representing the ordered list of rules matched for this /// node. Can be None for default values and text nodes. This is @@ -100,6 +99,7 @@ impl ComputedValues { pub fn new(custom_properties: Option>, writing_mode: WritingMode, font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>, + flags: ComputedValueFlags, rules: Option, visited_style: Option>, % for style_struct in data.style_structs: @@ -107,13 +107,14 @@ impl ComputedValues { % endfor ) -> Self { ComputedValues { - custom_properties: custom_properties, - writing_mode: writing_mode, + custom_properties, + writing_mode, font_computation_data: FontComputationData::new(font_size_keyword), - rules: rules, + flags, + rules, visited_style: visited_style, % for style_struct in data.style_structs: - ${style_struct.ident}: ${style_struct.ident}, + ${style_struct.ident}, % endfor } } diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs index fb3d706d0e5..640e0cc438e 100644 --- a/components/style/properties/longhand/text.mako.rs +++ b/components/style/properties/longhand/text.mako.rs @@ -150,6 +150,7 @@ ${helpers.single_keyword("unicode-bidi", <%helpers:longhand name="text-decoration-line" custom_cascade="${product == 'servo'}" + need_clone=True animation_value_type="discrete" spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line"> use std::fmt; @@ -262,7 +263,7 @@ ${helpers.single_keyword("unicode-bidi", context: &mut computed::Context, _cacheable: &mut bool, _error_reporter: &ParseErrorReporter) { - longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context); + longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context); } % endif diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 4507ea5119a..f3da270a891 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -44,6 +44,7 @@ use values::generics::text::LineHeight; use values::computed; use cascade_info::CascadeInfo; use rule_tree::{CascadeLevel, StrongRuleNode}; +use self::computed_value_flags::ComputedValueFlags; use style_adjuster::StyleAdjuster; #[cfg(feature = "servo")] use values::specified::BorderStyle; @@ -77,6 +78,8 @@ macro_rules! impl_bitflags_conversions { import os.path %> +#[path="${repr(os.path.join(os.path.dirname(__file__), 'computed_value_flags.rs'))[1:-1]}"] +pub mod computed_value_flags; #[path="${repr(os.path.join(os.path.dirname(__file__), 'declaration_block.rs'))[1:-1]}"] pub mod declaration_block; @@ -1823,10 +1826,14 @@ pub struct ComputedValues { /// The keyword behind the current font-size property, if any pub font_computation_data: FontComputationData, + /// A set of flags we use to store misc information regarding this style. + pub flags: ComputedValueFlags, + /// The rule node representing the ordered list of rules matched for this /// node. Can be None for default values and text nodes. This is /// essentially an optimization to avoid referencing the root rule node. pub rules: Option, + /// The element's computed values if visited, only computed if there's a /// relevant link for this element. A element's "relevant link" is the /// element being matched if it is a link or the nearest ancestor link. @@ -1836,23 +1843,27 @@ pub struct ComputedValues { #[cfg(feature = "servo")] impl ComputedValues { /// Construct a `ComputedValues` instance. - pub fn new(custom_properties: Option>, - writing_mode: WritingMode, - font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>, - rules: Option, - visited_style: Option>, - % for style_struct in data.active_style_structs(): - ${style_struct.ident}: Arc, - % endfor - ) -> Self { - ComputedValues { - custom_properties: custom_properties, - writing_mode: writing_mode, - font_computation_data: FontComputationData::new(font_size_keyword), - rules: rules, - visited_style: visited_style, + pub fn new( + custom_properties: Option>, + writing_mode: WritingMode, + font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>, + flags: ComputedValueFlags, + rules: Option, + visited_style: Option>, % for style_struct in data.active_style_structs(): - ${style_struct.ident}: ${style_struct.ident}, + ${style_struct.ident}: Arc, + % endfor + ) -> Self { + let font_computation_data = FontComputationData::new(font_size_keyword); + ComputedValues { + custom_properties, + writing_mode, + font_computation_data, + flags, + rules, + visited_style, + % for style_struct in data.active_style_structs(): + ${style_struct.ident}, % endfor } } @@ -2297,6 +2308,8 @@ impl<'a, T: 'a> Deref for StyleStructRef<'a, T> { /// actually cloning them, until we either build the style, or mutate the /// inherited value. pub struct StyleBuilder<'a> { + /// The style we're inheriting from. + inherited_style: &'a ComputedValues, /// The rule node representing the ordered list of rules matched for this /// node. rules: Option, @@ -2318,25 +2331,29 @@ pub struct StyleBuilder<'a> { impl<'a> StyleBuilder<'a> { /// Trivially construct a `StyleBuilder`. - pub fn new( + fn new( + inherited_style: &'a ComputedValues, + reset_style: &'a ComputedValues, rules: Option, custom_properties: Option>, writing_mode: WritingMode, font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>, visited_style: Option>, - % for style_struct in data.active_style_structs(): - ${style_struct.ident}: &'a Arc, - % endfor ) -> Self { StyleBuilder { - rules: rules, - custom_properties: custom_properties, - writing_mode: writing_mode, - font_size_keyword: font_size_keyword, - visited_style: visited_style, - % for style_struct in data.active_style_structs(): - ${style_struct.ident}: StyleStructRef::Borrowed(${style_struct.ident}), - % endfor + inherited_style, + rules, + custom_properties, + writing_mode, + font_size_keyword, + visited_style, + % for style_struct in data.active_style_structs(): + % if style_struct.inherited: + ${style_struct.ident}: StyleStructRef::Borrowed(inherited_style.${style_struct.name_lower}_arc()), + % else: + ${style_struct.ident}: StyleStructRef::Borrowed(reset_style.${style_struct.name_lower}_arc()), + % endif + % endfor } } @@ -2348,19 +2365,18 @@ impl<'a> StyleBuilder<'a> { /// Inherits style from the parent element, accounting for the default /// computed values that need to be provided as well. - pub fn for_inheritance(parent: &'a ComputedValues, default: &'a ComputedValues) -> Self { - Self::new(/* rules = */ None, - parent.custom_properties(), - parent.writing_mode, - parent.font_computation_data.font_size_keyword, - parent.clone_visited_style(), - % for style_struct in data.active_style_structs(): - % if style_struct.inherited: - parent.${style_struct.name_lower}_arc(), - % else: - default.${style_struct.name_lower}_arc(), - % endif - % endfor + pub fn for_inheritance( + parent: &'a ComputedValues, + default: &'a ComputedValues + ) -> Self { + Self::new( + parent, + default, + /* rules = */ None, + parent.custom_properties(), + parent.writing_mode, + parent.font_computation_data.font_size_keyword, + parent.clone_visited_style() ) } @@ -2423,9 +2439,11 @@ impl<'a> StyleBuilder<'a> { /// Turns this `StyleBuilder` into a proper `ComputedValues` instance. pub fn build(self) -> ComputedValues { + let flags = ComputedValueFlags::compute(&self, &self.inherited_style); ComputedValues::new(self.custom_properties, self.writing_mode, self.font_size_keyword, + flags, self.rules, self.visited_style, % for style_struct in data.active_style_structs(): @@ -2453,6 +2471,7 @@ mod lazy_static_module { use logical_geometry::WritingMode; use stylearc::Arc; use super::{ComputedValues, longhands, style_structs, FontComputationData}; + use super::computed_value_flags::ComputedValueFlags; /// The initial values for all style structs as defined by the specification. lazy_static! { @@ -2469,6 +2488,7 @@ mod lazy_static_module { % endfor custom_properties: None, writing_mode: WritingMode::empty(), + flags: ComputedValueFlags::initial(), font_computation_data: FontComputationData::default_values(), rules: None, visited_style: None, @@ -2634,33 +2654,10 @@ pub fn apply_declarations<'a, F, I>(device: &Device, ::custom_properties::finish_cascade( custom_properties, &inherited_custom_properties); - // We'd really like to own the rules here to avoid refcount traffic, but - // animation's usage of `apply_declarations` make this tricky. See bug - // 1375525. - let builder = if !flags.contains(INHERIT_ALL) { - StyleBuilder::new(Some(rules.clone()), - custom_properties, - WritingMode::empty(), - inherited_style.font_computation_data.font_size_keyword, - visited_style, - % for style_struct in data.active_style_structs(): - % if style_struct.inherited: - inherited_style.${style_struct.name_lower}_arc(), - % else: - default_style.${style_struct.name_lower}_arc(), - % endif - % endfor - ) + let reset_style = if flags.contains(INHERIT_ALL) { + inherited_style } else { - StyleBuilder::new(Some(rules.clone()), - custom_properties, - WritingMode::empty(), - inherited_style.font_computation_data.font_size_keyword, - visited_style, - % for style_struct in data.active_style_structs(): - inherited_style.${style_struct.name_lower}_arc(), - % endfor - ) + default_style }; let mut context = computed::Context { @@ -2668,7 +2665,18 @@ pub fn apply_declarations<'a, F, I>(device: &Device, device: device, inherited_style: inherited_style, layout_parent_style: layout_parent_style, - style: builder, + // We'd really like to own the rules here to avoid refcount traffic, but + // animation's usage of `apply_declarations` make this tricky. See bug + // 1375525. + style: StyleBuilder::new( + inherited_style, + reset_style, + Some(rules.clone()), + custom_properties, + WritingMode::empty(), + inherited_style.font_computation_data.font_size_keyword, + visited_style, + ), font_metrics_provider: font_metrics_provider, cached_system_font: None, in_media_query: false, @@ -2701,9 +2709,8 @@ pub fn apply_declarations<'a, F, I>(device: &Device, // virtual dispatch instead. % for category_to_cascade_now in ["early", "other"]: % if category_to_cascade_now == "early": - // Pull these out so that we can - // compute them in a specific order without - // introducing more iterations + // Pull these out so that we can compute them in a specific order + // without introducing more iterations. let mut font_size = None; let mut font_family = None; % endif