From 5c7632f4c496bc48c67111f18a4b0cb2986fbad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 26 Jun 2017 22:50:43 +0200 Subject: [PATCH 1/3] style: Add some flags to the computed values. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow us to fix propagation of text-decoration, and also to implement inlinization of ruby kids. Signed-off-by: Emilio Cobos Álvarez --- .../style/properties/computed_value_flags.rs | 45 ++++++ components/style/properties/gecko.mako.rs | 19 +-- .../style/properties/longhand/text.mako.rs | 3 +- .../style/properties/properties.mako.rs | 149 +++++++++--------- 4 files changed, 135 insertions(+), 81 deletions(-) create mode 100644 components/style/properties/computed_value_flags.rs 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 From 1c2fcb16ca5ab522f23d73800185be8011d5a91c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 26 Jun 2017 15:19:18 -0700 Subject: [PATCH 2/3] style: Cleanup duplicated code in the definition of ComputedValues. --- components/style/properties/gecko.mako.rs | 159 +----------------- .../style/properties/properties.mako.rs | 110 ++++++++++-- 2 files changed, 101 insertions(+), 168 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 5052425e2c5..f3c1df9cf6e 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -11,7 +11,6 @@ <%namespace name="helpers" file="/helpers.mako.rs" /> use app_units::Au; -use custom_properties::ComputedValuesMap; use gecko_bindings::bindings; % for style_struct in data.style_structs: use gecko_bindings::structs::${style_struct.gecko_ffi_name}; @@ -54,17 +53,14 @@ use gecko::values::round_border_to_device_pixels; use logical_geometry::WritingMode; use media_queries::Device; use properties::animated_properties::TransitionProperty; -use properties::computed_value_flags::ComputedValueFlags; -use properties::{longhands, FontComputationData, Importance, LonghandId}; -use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId}; -use rule_tree::StrongRuleNode; +use properties::{longhands, ComputedValues, LonghandId, PropertyDeclarationId}; use std::fmt::{self, Debug}; use std::mem::{forget, transmute, zeroed}; use std::ptr; use stylearc::Arc; use std::cmp; use values::{Auto, CustomIdent, Either, KeyframesName}; -use values::computed::{Shadow, ToComputedValue}; +use values::computed::Shadow; use values::specified::length::Percentage; use computed_values::border_style; @@ -74,157 +70,6 @@ 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 - /// 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. - visited_style: Option>, -} - -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: - ${style_struct.ident}: Arc, - % endfor - ) -> Self { - ComputedValues { - custom_properties, - writing_mode, - font_computation_data: FontComputationData::new(font_size_keyword), - flags, - rules, - visited_style: visited_style, - % for style_struct in data.style_structs: - ${style_struct.ident}, - % endfor - } - } - - pub fn default_values(pres_context: RawGeckoPresContextBorrowed) -> Arc { - Arc::new(ComputedValues { - custom_properties: None, - writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious - font_computation_data: FontComputationData::default_values(), - rules: None, - visited_style: None, - % for style_struct in data.style_structs: - ${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context), - % endfor - }) - } - - #[inline] - pub fn is_display_contents(&self) -> bool { - self.get_box().clone_display() == longhands::display::computed_value::T::contents - } - - /// Returns true if the value of the `content` property would make a - /// pseudo-element not rendered. - #[inline] - pub fn ineffective_content_property(&self) -> bool { - self.get_counters().ineffective_content_property() - } - - % for style_struct in data.style_structs: - #[inline] - pub fn clone_${style_struct.name_lower}(&self) -> Arc { - self.${style_struct.ident}.clone() - } - #[inline] - pub fn get_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} { - &self.${style_struct.ident} - } - - pub fn ${style_struct.name_lower}_arc(&self) -> &Arc { - &self.${style_struct.ident} - } - - #[inline] - pub fn mutate_${style_struct.name_lower}(&mut self) -> &mut style_structs::${style_struct.name} { - Arc::make_mut(&mut self.${style_struct.ident}) - } - % endfor - - /// Gets a reference to the rule node. Panic if no rule node exists. - pub fn rules(&self) -> &StrongRuleNode { - self.rules.as_ref().unwrap() - } - - /// Gets a reference to the visited style, if any. - pub fn get_visited_style(&self) -> Option<<&Arc> { - self.visited_style.as_ref() - } - - /// Gets a reference to the visited style. Panic if no visited style exists. - pub fn visited_style(&self) -> &Arc { - self.get_visited_style().unwrap() - } - - /// Clone the visited style. Used for inheriting parent styles in - /// StyleBuilder::for_inheritance. - pub fn clone_visited_style(&self) -> Option> { - self.visited_style.clone() - } - - pub fn custom_properties(&self) -> Option> { - self.custom_properties.clone() - } - - #[allow(non_snake_case)] - pub fn has_moz_binding(&self) -> bool { - !self.get_box().gecko.mBinding.mPtr.mRawPtr.is_null() - } - - // FIXME(bholley): Implement this properly. - #[inline] - pub fn is_multicol(&self) -> bool { false } - - pub fn to_declaration_block(&self, property: PropertyDeclarationId) -> PropertyDeclarationBlock { - match property { - % for prop in data.longhands: - % if prop.animatable: - PropertyDeclarationId::Longhand(LonghandId::${prop.camel_case}) => { - PropertyDeclarationBlock::with_one( - PropertyDeclaration::${prop.camel_case}( - % if prop.boxed: - Box::new( - % endif - longhands::${prop.ident}::SpecifiedValue::from_computed_value( - &self.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}()) - % if prop.boxed: - ) - % endif - ), - Importance::Normal - ) - }, - % endif - % endfor - PropertyDeclarationId::Custom(_name) => unimplemented!(), - _ => unimplemented!() - } - } -} - <%def name="declare_style_struct(style_struct)"> pub struct ${style_struct.gecko_struct_name} { gecko: ${style_struct.gecko_ffi_name}, diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index f3da270a891..02629ec6f74 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1801,9 +1801,6 @@ pub mod style_structs { % endfor -#[cfg(feature = "gecko")] -pub use gecko_properties::ComputedValues; - /// A legacy alias for a servo-version of ComputedValues. Should go away soon. #[cfg(feature = "servo")] pub type ServoComputedValues = ComputedValues; @@ -1814,8 +1811,7 @@ pub type ServoComputedValues = ComputedValues; /// every kind of style struct. /// /// When needed, the structs may be copied in order to get mutated. -#[cfg(feature = "servo")] -#[cfg_attr(feature = "servo", derive(Clone))] +#[derive(Clone)] pub struct ComputedValues { % for style_struct in data.active_style_structs(): ${style_struct.ident}: Arc, @@ -1840,7 +1836,6 @@ pub struct ComputedValues { visited_style: Option>, } -#[cfg(feature = "servo")] impl ComputedValues { /// Construct a `ComputedValues` instance. pub fn new( @@ -1868,9 +1863,6 @@ impl ComputedValues { } } - /// Get the initial computed values. - pub fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES } - % for style_struct in data.active_style_structs(): /// Clone the ${style_struct.name} struct. #[inline] @@ -1897,6 +1889,30 @@ impl ComputedValues { } % endfor + /// Get the initial computed values. + #[cfg(feature = "servo")] + pub fn initial_values() -> &'static Self { &*INITIAL_SERVO_VALUES } + + /// Get the default computed values for a given document. + /// + /// This takes into account zoom, etc. + #[cfg(feature = "gecko")] + pub fn default_values( + pres_context: bindings::RawGeckoPresContextBorrowed + ) -> Arc { + Arc::new(ComputedValues { + custom_properties: None, + writing_mode: WritingMode::empty(), // FIXME(bz): This seems dubious + font_computation_data: FontComputationData::default_values(), + flags: ComputedValueFlags::initial(), + rules: None, + visited_style: None, + % for style_struct in data.style_structs: + ${style_struct.ident}: style_structs::${style_struct.name}::default(pres_context), + % endfor + }) + } + /// Gets a reference to the rule node. Panic if no rule node exists. pub fn rules(&self) -> &StrongRuleNode { self.rules.as_ref().unwrap() @@ -1929,23 +1945,77 @@ impl ComputedValues { /// /// Cloning the Arc here is fine because it only happens in the case where /// we have custom properties, and those are both rare and expensive. - fn custom_properties(&self) -> Option> { + pub fn custom_properties(&self) -> Option> { self.custom_properties.clone() } + /// Get a declaration block representing the computed value for a given + /// property. + /// + /// Currently only implemented for animated properties. + pub fn to_declaration_block( + &self, + property: PropertyDeclarationId + ) -> PropertyDeclarationBlock { + use values::computed::ToComputedValue; + + match property { + % for prop in data.longhands: + % if prop.animatable: + PropertyDeclarationId::Longhand(LonghandId::${prop.camel_case}) => { + PropertyDeclarationBlock::with_one( + PropertyDeclaration::${prop.camel_case}( + % if prop.boxed: + Box::new( + % endif + longhands::${prop.ident}::SpecifiedValue::from_computed_value( + &self.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}()) + % if prop.boxed: + ) + % endif + ), + Importance::Normal + ) + }, + % endif + % endfor + PropertyDeclarationId::Custom(_name) => unimplemented!(), + _ => unimplemented!() + } + } + /// Whether this style has a -moz-binding value. This is always false for /// Servo for obvious reasons. + #[inline] + #[cfg(feature = "servo")] pub fn has_moz_binding(&self) -> bool { false } + /// Whether this style has a -moz-binding value. + #[inline] + #[cfg(feature = "gecko")] + pub fn has_moz_binding(&self) -> bool { + !self.get_box().gecko().mBinding.mPtr.mRawPtr.is_null() + } + /// Returns whether this style's display value is equal to contents. /// /// Since this isn't supported in Servo, this is always false for Servo. + #[inline] + #[cfg(feature = "servo")] pub fn is_display_contents(&self) -> bool { false } + /// Returns whether this style's display value is equal to contents. #[inline] + #[cfg(feature = "gecko")] + pub fn is_display_contents(&self) -> bool { + self.get_box().clone_display() == longhands::display::computed_value::T::contents + } + /// Returns whether the "content" property for the given style is completely /// ineffective, and would yield an empty `::before` or `::after` /// pseudo-element. + #[inline] + #[cfg(feature = "servo")] pub fn ineffective_content_property(&self) -> bool { use properties::longhands::content::computed_value::T; match self.get_counters().content { @@ -1954,8 +2024,23 @@ impl ComputedValues { } } - /// Whether the current style is multicolumn. + /// Returns true if the value of the `content` property would make a + /// pseudo-element not rendered. #[inline] + #[cfg(feature = "gecko")] + pub fn ineffective_content_property(&self) -> bool { + self.get_counters().ineffective_content_property() + } + + #[inline] + #[cfg(feature = "gecko")] + /// Whether the current style is multicolumn. + /// FIXME(bholley): Implement this properly. + pub fn is_multicol(&self) -> bool { false } + + #[inline] + #[cfg(feature = "servo")] + /// Whether the current style is multicolumn. pub fn is_multicol(&self) -> bool { let style = self.get_column(); match style.column_width { @@ -1966,7 +2051,10 @@ impl ComputedValues { } } } +} +#[cfg(feature = "servo")] +impl ComputedValues { /// Resolves the currentColor keyword. /// /// Any color value from computed values (except for the 'color' property From 69e650ea6838942dc65d4cfb75fa77544ff4319e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Mon, 26 Jun 2017 15:30:13 -0700 Subject: [PATCH 3/3] style: Fix propagation of text-decoration lines. --- components/style/gecko/restyle_damage.rs | 7 +++-- components/style/matching.rs | 37 +++++++++++++++--------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/components/style/gecko/restyle_damage.rs b/components/style/gecko/restyle_damage.rs index 9d443b23baf..e9be48644ca 100644 --- a/components/style/gecko/restyle_damage.rs +++ b/components/style/gecko/restyle_damage.rs @@ -47,9 +47,10 @@ impl GeckoRestyleDamage { /// them, but Gecko has an interesting optimization when they mark accessed /// structs, so they effectively only diff structs that have ever been /// accessed from layout. - pub fn compute_style_difference(source: &nsStyleContext, - new_style: &Arc) - -> StyleDifference { + pub fn compute_style_difference( + source: &nsStyleContext, + new_style: &Arc + ) -> StyleDifference { // TODO(emilio): Const-ify this? let context = source as *const nsStyleContext as *mut nsStyleContext; let mut any_style_changed: bool = false; diff --git a/components/style/matching.rs b/components/style/matching.rs index ab51de215c4..3dd209c780a 100644 --- a/components/style/matching.rs +++ b/components/style/matching.rs @@ -98,15 +98,6 @@ pub enum ChildCascadeRequirement { MustCascadeDescendants, } -impl From for ChildCascadeRequirement { - fn from(change: StyleChange) -> ChildCascadeRequirement { - match change { - StyleChange::Unchanged => ChildCascadeRequirement::CanSkipCascade, - StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren, - } - } -} - bitflags! { /// Flags that represent the result of replace_rules. pub flags RulesChanged: u8 { @@ -778,6 +769,8 @@ trait PrivateMatchMethods: TElement { new_values: &Arc, pseudo: Option<&PseudoElement>) -> ChildCascadeRequirement { + use properties::computed_value_flags::*; + // Don't accumulate damage if we're in a restyle for reconstruction. if shared_context.traversal_flags.for_reconstruct() { return ChildCascadeRequirement::MustCascadeChildren; @@ -793,13 +786,26 @@ trait PrivateMatchMethods: TElement { let skip_applying_damage = restyle.reconstructed_self_or_ancestor(); - let difference = self.compute_style_difference(&old_values, - &new_values, - pseudo); + let difference = + self.compute_style_difference(&old_values, &new_values, pseudo); + if !skip_applying_damage { restyle.damage |= difference.damage; } - difference.change.into() + + match difference.change { + StyleChange::Unchanged => { + // We need to cascade the children in order to ensure the + // correct propagation of text-decoration-line, which is a reset + // property. + if old_values.flags.contains(HAS_TEXT_DECORATION_LINE) != + new_values.flags.contains(HAS_TEXT_DECORATION_LINE) { + return ChildCascadeRequirement::MustCascadeChildren; + } + ChildCascadeRequirement::CanSkipCascade + }, + StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren, + } } /// Computes and applies restyle damage unless we've already maxed it out. @@ -813,7 +819,10 @@ trait PrivateMatchMethods: TElement { -> ChildCascadeRequirement { let difference = self.compute_style_difference(&old_values, &new_values, pseudo); restyle.damage |= difference.damage; - difference.change.into() + match difference.change { + StyleChange::Changed => ChildCascadeRequirement::MustCascadeChildren, + StyleChange::Unchanged => ChildCascadeRequirement::CanSkipCascade, + } } #[cfg(feature = "servo")]