diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 9fd15478ac3..b350f7a8d78 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -2171,9 +2171,8 @@ impl FragmentDisplayListBuilding for Fragment { } // Create display items for text decorations. - let text_decorations = self.style() - .get_inheritedtext() - ._servo_text_decorations_in_effect; + let text_decorations = + self.style().get_inheritedtext().text_decorations_in_effect; let stacking_relative_content_box = LogicalRect::from_physical( self.style.writing_mode, diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 51ed2b88348..ac7f9e427f7 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -145,10 +145,10 @@ def arg_to_bool(arg): class Longhand(object): - def __init__(self, style_struct, name, spec=None, animation_value_type=None, derived_from=None, keyword=None, - predefined_type=None, custom_cascade=False, servo_pref=None, gecko_pref=None, + def __init__(self, style_struct, name, spec=None, animation_value_type=None, keyword=None, + predefined_type=None, servo_pref=None, gecko_pref=None, enabled_in="content", need_index=False, - custom_cascade_function=None, gecko_ffi_name=None, + gecko_ffi_name=None, allowed_in_keyframe_block=True, cast_type='u8', logical=False, alias=None, extra_prefixes=None, boxed=False, flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False, @@ -164,8 +164,6 @@ class Longhand(object): self.style_struct = style_struct self.servo_pref = servo_pref self.gecko_pref = gecko_pref - self.custom_cascade = custom_cascade - self.custom_cascade_function = custom_cascade_function if custom_cascade else None # For enabled_in, the setup is as follows: # It needs to be one of the four values: ["", "ua", "chrome", "content"] # * "chrome" implies "ua", and implies that they're explicitly @@ -177,7 +175,6 @@ class Longhand(object): self.enabled_in = enabled_in self.need_index = need_index self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case - self.derived_from = (derived_from or "").split() self.cast_type = cast_type self.logical = arg_to_bool(logical) self.alias = alias.split() if alias else [] @@ -241,7 +238,6 @@ class Shorthand(object): self.spec = spec self.ident = to_rust_ident(name) self.camel_case = to_camel_case(self.ident) - self.derived_from = None self.servo_pref = servo_pref self.gecko_pref = gecko_pref self.sub_properties = sub_properties @@ -365,7 +361,6 @@ class PropertiesData(object): self.current_style_struct = None self.longhands = [] self.longhands_by_name = {} - self.derived_longhands = {} self.longhand_aliases = [] self.shorthands = [] self.shorthand_aliases = [] @@ -397,9 +392,6 @@ class PropertiesData(object): self.longhands.append(longhand) self.longhands_by_name[name] = longhand - for name in longhand.derived_from: - self.derived_longhands.setdefault(name, []).append(longhand) - return longhand def declare_shorthand(self, name, sub_properties, products="gecko servo", *args, **kwargs): diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 5be81b59f88..becef724657 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -260,14 +260,12 @@ %> /// ${property.spec} pub mod ${property.ident} { - % if not property.derived_from: - #[allow(unused_imports)] - use cssparser::{Parser, BasicParseError, Token}; - #[allow(unused_imports)] - use parser::{Parse, ParserContext}; - #[allow(unused_imports)] - use properties::{UnparsedValue, ShorthandId}; - % endif + #[allow(unused_imports)] + use cssparser::{Parser, BasicParseError, Token}; + #[allow(unused_imports)] + use parser::{Parse, ParserContext}; + #[allow(unused_imports)] + use properties::{UnparsedValue, ShorthandId}; #[allow(unused_imports)] use values::{Auto, Either, None_, Normal}; #[allow(unused_imports)] @@ -319,106 +317,95 @@ Some(LonghandId::${property.camel_case}); % endif - % if not property.derived_from: - match value { - DeclaredValue::Value(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 not property.style_struct.inherited and property.logical: - context.rule_cache_conditions.borrow_mut() - .set_writing_mode_dependency(context.builder.writing_mode); - % 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.builder.take_${data.current_style_struct.name_lower}(); - { - let iter = specified_value.compute_iter(context); - s.set_${property.ident}(iter); - } - context.builder.put_${data.current_style_struct.name_lower}(s); - % else: - % if property.boxed: - let computed = (**specified_value).to_computed_value(context); - % else: - let computed = specified_value.to_computed_value(context); - % endif - % if property.ident == "font_size": - specified::FontSize::cascade_specified_font_size( - context, - &specified_value, - computed, - ); - % else: - context.builder.set_${property.ident}(computed) - % 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": - computed::FontSize::cascade_initial_font_size(context); - % else: - context.builder.reset_${property.ident}(); - % endif - }, - % if data.current_style_struct.inherited: - CSSWideKeyword::Unset | - % endif - CSSWideKeyword::Inherit => { - % if not property.style_struct.inherited: - context.rule_cache_conditions.borrow_mut().set_uncacheable(); - % endif - % if property.ident == "font_size": - computed::FontSize::cascade_inherit_font_size(context); - % else: - context.builder.inherit_${property.ident}(); - % endif + match value { + DeclaredValue::Value(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 not property.style_struct.inherited and property.logical: + context.rule_cache_conditions.borrow_mut() + .set_writing_mode_dependency(context.builder.writing_mode); + % 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.builder.take_${data.current_style_struct.name_lower}(); + { + let iter = specified_value.compute_iter(context); + s.set_${property.ident}(iter); + } + context.builder.put_${data.current_style_struct.name_lower}(s); + % else: + % if property.boxed: + let computed = (**specified_value).to_computed_value(context); + % else: + let computed = specified_value.to_computed_value(context); + % endif + % if property.ident == "font_size": + specified::FontSize::cascade_specified_font_size( + context, + &specified_value, + computed, + ); + % else: + context.builder.set_${property.ident}(computed) + % 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": + computed::FontSize::cascade_initial_font_size(context); + % else: + context.builder.reset_${property.ident}(); + % endif + }, + % if data.current_style_struct.inherited: + CSSWideKeyword::Unset | + % endif + CSSWideKeyword::Inherit => { + % if not property.style_struct.inherited: + context.rule_cache_conditions.borrow_mut().set_uncacheable(); + % endif + % if property.ident == "font_size": + computed::FontSize::cascade_inherit_font_size(context); + % else: + context.builder.inherit_${property.ident}(); + % endif } } - - % if property.custom_cascade and property.custom_cascade_function: - ${property.custom_cascade_function}(declaration, context); - % elif property.custom_cascade: - cascade_property_custom(declaration, context); - % endif - % else: - // Do not allow stylesheets to set derived properties. - % endif - } - % if not property.derived_from: - pub fn parse_declared<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - % if property.allow_quirks: - parse_quirky(context, input, specified::AllowQuirks::Yes) - % else: - parse(context, input) - % endif - % if property.boxed: - .map(Box::new) - % endif - .map(PropertyDeclaration::${property.camel_case}) } - % endif + } + + pub fn parse_declared<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + % if property.allow_quirks: + parse_quirky(context, input, specified::AllowQuirks::Yes) + % else: + parse(context, input) + % endif + % if property.boxed: + .map(Box::new) + % endif + .map(PropertyDeclaration::${property.camel_case}) + } } diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 62dea66052d..d1b26de1154 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -20,8 +20,6 @@ ${helpers.predefined_type( initial_specified_value="specified::Display::inline()", animation_value_type="discrete", needs_context=False, - custom_cascade= product == 'servo', - custom_cascade_function="specified::Display::cascade_property_custom", flags="APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-display/#propdef-display", )} diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 830886a9569..a9ae76fe9a3 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -132,68 +132,6 @@ ${helpers.predefined_type("word-spacing", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-text/#propdef-word-spacing")} -<%helpers:longhand name="-servo-text-decorations-in-effect" - derived_from="display text-decoration" - products="servo" - animation_value_type="none" - spec="Nonstandard (Internal property used by Servo)"> - use std::fmt; - use style_traits::ToCss; - - #[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] - pub struct SpecifiedValue { - pub underline: bool, - pub overline: bool, - pub line_through: bool, - } - - trivial_to_computed_value!(SpecifiedValue); - - pub mod computed_value { - pub type T = super::SpecifiedValue; - } - - impl ToCss for SpecifiedValue { - fn to_css(&self, _: &mut W) -> fmt::Result where W: fmt::Write { - // Web compat doesn't matter here. - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - SpecifiedValue::default() - } - - fn derive(context: &Context) -> computed_value::T { - // Start with no declarations if this is an atomic inline-level box; otherwise, start with the - // declarations in effect and add in the text decorations that this block specifies. - let mut result = match context.style().get_box().clone_display() { - super::display::computed_value::T::InlineBlock | - super::display::computed_value::T::InlineTable => get_initial_value(), - _ => context.builder.get_parent_inheritedtext().clone__servo_text_decorations_in_effect() - }; - - result.underline |= context.style().get_text().has_underline(); - result.overline |= context.style().get_text().has_overline(); - result.line_through |= context.style().get_text().has_line_through(); - - result - } - - #[inline] - pub fn derive_from_text_decoration(context: &mut Context) { - let derived = derive(context); - context.builder.set__servo_text_decorations_in_effect(derived); - } - - #[inline] - pub fn derive_from_display(context: &mut Context) { - let derived = derive(context); - context.builder.set__servo_text_decorations_in_effect(derived); - } - - <%helpers:single_keyword_computed name="white-space" values="normal pre nowrap pre-wrap pre-line" extra_gecko_values="-moz-pre-space" diff --git a/components/style/properties/longhand/text.mako.rs b/components/style/properties/longhand/text.mako.rs index fed1ce65c80..2c8bf1b52ff 100644 --- a/components/style/properties/longhand/text.mako.rs +++ b/components/style/properties/longhand/text.mako.rs @@ -29,8 +29,6 @@ ${helpers.predefined_type("text-decoration-line", "TextDecorationLine", "specified::TextDecorationLine::none()", initial_specified_value="specified::TextDecorationLine::none()", - custom_cascade= product == 'servo', - custom_cascade_function="specified::TextDecorationLine::cascade_property_custom", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-line")} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index c75fd6db958..5cd5f78bc97 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -570,13 +570,7 @@ impl LonghandId { match *self { % for property in data.longhands: LonghandId::${property.camel_case} => { - % if not property.derived_from: - longhands::${property.ident}::parse_declared(context, input) - % else: - Err(input.new_custom_error( - StyleParseErrorKind::UnknownProperty("${property.ident}".into()) - )) - % endif + longhands::${property.ident}::parse_declared(context, input) } % endfor } @@ -1454,10 +1448,8 @@ impl ToCss for PropertyDeclaration { { match *self { % for property in data.longhands: - % if not property.derived_from: - PropertyDeclaration::${property.camel_case}(ref value) => - value.to_css(dest), - % endif + PropertyDeclaration::${property.camel_case}(ref value) => + value.to_css(dest), % endfor PropertyDeclaration::CSSWideKeyword(_, keyword) => keyword.to_css(dest), PropertyDeclaration::WithVariables(_, ref with_variables) => { @@ -1474,9 +1466,6 @@ impl ToCss for PropertyDeclaration { Ok(()) }, PropertyDeclaration::Custom(_, ref value) => value.borrow().to_css(dest), - % if any(property.derived_from for property in data.longhands): - _ => Err(fmt::Error), - % endif } } } @@ -1859,6 +1848,13 @@ pub mod style_structs { /// The ${longhand.name} computed value. pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T, % endfor + % if style_struct.name == "InheritedText": + /// The "used" text-decorations that apply to this box. + /// + /// FIXME(emilio): This is technically a box-tree concept, and + /// would be nice to move away from style. + pub text_decorations_in_effect: ::values::computed::text::TextDecorationsInEffect, + % endif % if style_struct.name == "Font": /// The font hash, used for font caching. pub hash: u64, @@ -1870,9 +1866,8 @@ pub mod style_structs { % endif } % if style_struct.name == "Font": - - impl PartialEq for ${style_struct.name} { - fn eq(&self, other: &${style_struct.name}) -> bool { + impl PartialEq for Font { + fn eq(&self, other: &Font) -> bool { self.hash == other.hash % for longhand in style_struct.longhands: && self.${longhand.ident} == other.${longhand.ident} @@ -3074,6 +3069,9 @@ mod lazy_static_module { % for longhand in style_struct.longhands: ${longhand.ident}: longhands::${longhand.ident}::get_initial_value(), % endfor + % if style_struct.name == "InheritedText": + text_decorations_in_effect: ::values::computed::text::TextDecorationsInEffect::default(), + % endif % if style_struct.name == "Font": hash: 0, % endif @@ -3644,7 +3642,7 @@ macro_rules! css_properties_accessors { $macro_name! { % for kind, props in [("Longhand", data.longhands), ("Shorthand", data.shorthands)]: % for property in props: - % if not property.derived_from and property.enabled_in_content(): + % if property.enabled_in_content(): % for name in [property.name] + property.alias: % if '-' in name: [${to_rust_ident(name).capitalize()}, Set${to_rust_ident(name).capitalize()}, diff --git a/components/style/servo/restyle_damage.rs b/components/style/servo/restyle_damage.rs index 68a1145cbd9..f3bb6ef3d63 100644 --- a/components/style/servo/restyle_damage.rs +++ b/components/style/servo/restyle_damage.rs @@ -280,7 +280,7 @@ fn compute_damage(old: &ComputedValues, new: &ComputedValues) -> ServoRestyleDam get_border.border_top_left_radius, get_border.border_top_right_radius, get_border.border_bottom_left_radius, get_border.border_bottom_right_radius, get_position.z_index, get_box._servo_overflow_clip_box, - get_inheritedtext._servo_text_decorations_in_effect, + get_inheritedtext.text_decorations_in_effect, get_pointing.cursor, get_pointing.pointer_events, get_effects.box_shadow, get_effects.clip, get_inheritedtext.text_shadow, get_effects.filter, get_effects.mix_blend_mode, get_inheritedbox.image_rendering, diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index c54191b14c7..052d80dbe22 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -420,6 +420,21 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { } } + /// Computes the used text decoration for Servo. + /// + /// FIXME(emilio): This is a layout tree concept, should move away from + /// style, since otherwise we're going to have the same subtle bugs WebKit + /// and Blink have with this very same thing. + #[cfg(feature = "servo")] + fn adjust_for_text_decorations_in_effect(&mut self) { + use values::computed::text::TextDecorationsInEffect; + + let decorations_in_effect = TextDecorationsInEffect::from_style(&self.style); + if self.style.get_inheritedtext().text_decorations_in_effect != decorations_in_effect { + self.style.mutate_inheritedtext().text_decorations_in_effect = decorations_in_effect; + } + } + #[cfg(feature = "gecko")] fn should_suppress_linebreak( &self, @@ -614,6 +629,10 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { { self.adjust_for_ruby(layout_parent_style, flags); } + #[cfg(feature = "servo")] + { + self.adjust_for_text_decorations_in_effect(); + } self.set_bits(); } } diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index bb849b813f9..27c198a46a5 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -4,6 +4,8 @@ //! Computed types for text properties. +#[cfg(feature = "servo")] +use properties::StyleBuilder; use std::fmt; use style_traits::ToCss; use values::{CSSInteger, CSSFloat}; @@ -103,3 +105,45 @@ impl ToCss for TextDecorationLine { Ok(()) } } + +/// A struct that represents the _used_ value of the text-decoration property. +/// +/// FIXME(emilio): This is done at style resolution time, though probably should +/// be done at layout time, otherwise we need to account for display: contents +/// and similar stuff when we implement it. +/// +/// FIXME(emilio): Also, should be just a bitfield instead of three bytes. +#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] +pub struct TextDecorationsInEffect { + /// Whether an underline is in effect. + pub underline: bool, + /// Whether an overline decoration is in effect. + pub overline: bool, + /// Whether a line-through style is in effect. + pub line_through: bool, +} + +impl TextDecorationsInEffect { + /// Computes the text-decorations in effect for a given style. + #[cfg(feature = "servo")] + pub fn from_style(style: &StyleBuilder) -> Self { + use values::computed::Display; + + // Start with no declarations if this is an atomic inline-level box; + // otherwise, start with the declarations in effect and add in the text + // decorations that this block specifies. + let mut result = match style.get_box().clone_display() { + Display::InlineBlock | + Display::InlineTable => Self::default(), + _ => style.get_parent_inheritedtext().text_decorations_in_effect.clone(), + }; + + let text_style = style.get_text(); + + result.underline |= text_style.has_underline(); + result.overline |= text_style.has_overline(); + result.line_through |= text_style.has_line_through(); + + result + } +} diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index a141855d62f..8f046887fe4 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -7,15 +7,11 @@ use Atom; use cssparser::Parser; use parser::{Parse, ParserContext}; -#[cfg(feature = "servo")] -use properties::{longhands, PropertyDeclaration}; use selectors::parser::SelectorParseErrorKind; use std::fmt; use style_traits::{ParseError, ToCss, StyleParseErrorKind}; use values::CustomIdent; use values::KeyframesName; -#[cfg(feature = "servo")] -use values::computed::Context; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; use values::generics::box_::VerticalAlign as GenericVerticalAlign; use values::specified::{AllowQuirks, Number}; @@ -220,16 +216,6 @@ impl Display { other => other, } } - - #[cfg(feature = "servo")] - #[inline] - /// Custom cascade for the `display` property in servo - pub fn cascade_property_custom( - _declaration: &PropertyDeclaration, - context: &mut Context - ) { - longhands::_servo_text_decorations_in_effect::derive_from_display(context); - } } /// A specified value for the `vertical-align` property. diff --git a/components/style/values/specified/text.rs b/components/style/values/specified/text.rs index caca98ab3f2..d9e05b50057 100644 --- a/components/style/values/specified/text.rs +++ b/components/style/values/specified/text.rs @@ -6,8 +6,6 @@ use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; -#[cfg(feature = "servo")] -use properties::{longhands, PropertyDeclaration}; use selectors::parser::SelectorParseErrorKind; #[allow(unused_imports)] use std::ascii::AsciiExt; use std::fmt; @@ -281,13 +279,6 @@ impl TextDecorationLine { pub fn none() -> Self { TextDecorationLine::NONE } - - #[cfg(feature = "servo")] - #[inline] - /// Custom cascade for the text-decoration-line property in servo - pub fn cascade_property_custom(_declaration: &PropertyDeclaration, context: &mut Context) { - longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context); - } } impl Parse for TextDecorationLine {