servo: Merge #19211 - Move text-decoration-line out of mako (from KiChjang:text-decoration-line); r=emilio
authorKeith Yeung <kungfukeith11@gmail.com>
Tue, 14 Nov 2017 15:34:10 -0600
changeset 443551 3e225193ee6831d6a8c9b2aa48f0c2bb0eca8892
parent 443550 f4c15a88c937e8b3940f5c1922142a6ffb137320
child 443552 1c0878e0a9b7c9ac619650d7b2f57bbf8ffab94b
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #19211 - Move text-decoration-line out of mako (from KiChjang:text-decoration-line); r=emilio Part of #19015. Source-Repo: https://github.com/servo/servo Source-Revision: 6f1d9a198fa3f060f3eae28f13ac248b0b1186ce
servo/components/style/macros.rs
servo/components/style/properties/data.py
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/longhand/text.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/computed/text.rs
servo/components/style/values/specified/mod.rs
servo/components/style/values/specified/text.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/style/macros.rs
+++ b/servo/components/style/macros.rs
@@ -119,8 +119,25 @@ macro_rules! define_keyword_type {
             ) -> Result<$name, ::style_traits::ParseError<'i>> {
                 input.expect_ident_matching($css).map(|_| $name).map_err(|e| e.into())
             }
         }
 
         impl $crate::values::animated::AnimatedValueAsComputed for $name {}
     };
 }
+
+#[cfg(feature = "gecko")]
+macro_rules! impl_bitflags_conversions {
+    ($name: ident) => {
+        impl From<u8> for $name {
+            fn from(bits: u8) -> $name {
+                $name::from_bits(bits).expect("bits contain valid flag")
+            }
+        }
+
+        impl From<$name> for u8 {
+            fn from(v: $name) -> u8 {
+                v.bits()
+            }
+        }
+    };
+}
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -142,32 +142,33 @@ def arg_to_bool(arg):
         return arg
     assert arg in ["True", "False"]
     return arg == "True"
 
 
 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, experimental=False, internal=False,
-                 need_index=False, gecko_ffi_name=None,
+                 need_index=False, custom_cascade_function=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,
                  gecko_pref_ident=None, vector=False, need_animatable=False):
         self.name = name
         if not spec:
             raise TypeError("Spec should be specified for %s" % name)
         self.spec = spec
         self.keyword = keyword
         self.predefined_type = predefined_type
         self.ident = to_rust_ident(name)
         self.camel_case = to_camel_case(self.ident)
         self.style_struct = style_struct
         self.experimental = ("layout.%s.enabled" % name) if experimental else None
         self.custom_cascade = custom_cascade
+        self.custom_cascade_function = custom_cascade_function if custom_cascade else None
         self.internal = internal
         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 []
         self.extra_prefixes = extra_prefixes.split() if extra_prefixes else []
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -389,17 +389,19 @@
                                 computed::FontSize::cascade_inherit_font_size(context);
                             % else:
                                 context.builder.inherit_${property.ident}();
                             % endif
                         }
                     }
                 }
 
-                % if property.custom_cascade:
+                % 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>(
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -20,137 +20,25 @@
                           flags="APPLIES_TO_PLACEHOLDER",
                           spec="https://drafts.csswg.org/css-ui/#propdef-text-overflow")}
 
 ${helpers.single_keyword("unicode-bidi",
                          "normal embed isolate bidi-override isolate-override plaintext",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-writing-modes/#propdef-unicode-bidi")}
 
-<%helpers:longhand name="text-decoration-line"
-                   custom_cascade="${product == 'servo'}"
-                   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">
-    use std::fmt;
-    use style_traits::ToCss;
-
-    bitflags! {
-        #[derive(MallocSizeOf, ToComputedValue)]
-        pub struct SpecifiedValue: u8 {
-            const NONE = 0;
-            const UNDERLINE = 0x01;
-            const OVERLINE = 0x02;
-            const LINE_THROUGH = 0x04;
-            const BLINK = 0x08;
-        % if product == "gecko":
-            /// Only set by presentation attributes
-            ///
-            /// Setting this will mean that text-decorations use the color
-            /// specified by `color` in quirks mode.
-            ///
-            /// For example, this gives <a href=foo><font color="red">text</font></a>
-            /// a red text decoration
-            const COLOR_OVERRIDE = 0x10;
-        % endif
-        }
-    }
-
-    impl ToCss for SpecifiedValue {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            let mut has_any = false;
-
-            macro_rules! write_value {
-                ($line:path => $css:expr) => {
-                    if self.contains($line) {
-                        if has_any {
-                            dest.write_str(" ")?;
-                        }
-                        dest.write_str($css)?;
-                        has_any = true;
-                    }
-                }
-            }
-            write_value!(SpecifiedValue::UNDERLINE => "underline");
-            write_value!(SpecifiedValue::OVERLINE => "overline");
-            write_value!(SpecifiedValue::LINE_THROUGH => "line-through");
-            write_value!(SpecifiedValue::BLINK => "blink");
-            if !has_any {
-                dest.write_str("none")?;
-            }
-
-            Ok(())
-        }
-    }
-    pub mod computed_value {
-        pub type T = super::SpecifiedValue;
-        #[allow(non_upper_case_globals)]
-        pub const none: T = super::SpecifiedValue {
-            bits: 0
-        };
-    }
-    #[inline] pub fn get_initial_value() -> computed_value::T {
-        computed_value::none
-    }
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue::empty()
-    }
-    /// none | [ underline || overline || line-through || blink ]
-    pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-                         -> Result<SpecifiedValue, ParseError<'i>> {
-        let mut result = SpecifiedValue::empty();
-        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
-            return Ok(result)
-        }
-        let mut empty = true;
-
-        loop {
-            let result: Result<_, ParseError> = input.try(|input| {
-                let location = input.current_source_location();
-                match input.expect_ident() {
-                    Ok(ident) => {
-                        (match_ignore_ascii_case! { &ident,
-                            "underline" => if result.contains(SpecifiedValue::UNDERLINE) { Err(()) }
-                                           else { empty = false; result.insert(SpecifiedValue::UNDERLINE); Ok(()) },
-                            "overline" => if result.contains(SpecifiedValue::OVERLINE) { Err(()) }
-                                          else { empty = false; result.insert(SpecifiedValue::OVERLINE); Ok(()) },
-                            "line-through" => if result.contains(SpecifiedValue::LINE_THROUGH) { Err(()) }
-                                              else {
-                                                  empty = false;
-                                                  result.insert(SpecifiedValue::LINE_THROUGH); Ok(())
-                                              },
-                            "blink" => if result.contains(SpecifiedValue::BLINK) { Err(()) }
-                                       else { empty = false; result.insert(SpecifiedValue::BLINK); Ok(()) },
-                            _ => Err(())
-                        }).map_err(|()| {
-                            location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
-                        })
-                    }
-                    Err(e) => return Err(e.into())
-                }
-            });
-            if result.is_err() {
-                break;
-            }
-        }
-
-        if !empty { Ok(result) } else { Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) }
-    }
-
-    % if product == "servo":
-        fn cascade_property_custom(_declaration: &PropertyDeclaration,
-                                   context: &mut computed::Context) {
-            longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context);
-        }
-    % endif
-
-    #[cfg(feature = "gecko")]
-    impl_bitflags_conversions!(SpecifiedValue);
-</%helpers:longhand>
+${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")}
 
 ${helpers.single_keyword("text-decoration-style",
                          "solid double dotted dashed wavy -moz-none",
                          products="gecko",
                          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-style")}
 
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -51,33 +51,16 @@ use style_adjuster::StyleAdjuster;
 pub use self::declaration_block::*;
 
 #[cfg(feature = "gecko")]
 #[macro_export]
 macro_rules! property_name {
     ($s: tt) => { atom!($s) }
 }
 
-#[cfg(feature = "gecko")]
-macro_rules! impl_bitflags_conversions {
-    ($name: ident) => {
-        impl From<u8> for $name {
-            fn from(bits: u8) -> $name {
-                $name::from_bits(bits).expect("bits contain valid flag")
-            }
-        }
-
-        impl From<$name> for u8 {
-            fn from(v: $name) -> u8 {
-                v.bits()
-            }
-        }
-    };
-}
-
 <%!
     from data import Method, Keyword, to_rust_ident, to_camel_case, SYSTEM_FONT_LONGHANDS
     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]}"]
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -42,17 +42,17 @@ pub use self::box_::{AnimationIterationC
 pub use self::color::{Color, ColorPropertyValue, RGBAColor};
 pub use self::effects::{BoxShadow, Filter, SimpleShadow};
 pub use self::flex::FlexBasis;
 pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
 pub use self::rect::LengthOrNumberRect;
 pub use super::{Auto, Either, None_};
-pub use super::specified::BorderStyle;
+pub use super::specified::{BorderStyle, TextDecorationLine};
 pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage};
 pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength};
 pub use self::length::{CSSPixelLength, NonNegativeLength, NonNegativeLengthOrPercentage};
 pub use self::percentage::Percentage;
 pub use self::position::Position;
 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
 pub use self::table::XSpan;
 pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing};
--- a/servo/components/style/values/computed/text.rs
+++ b/servo/components/style/values/computed/text.rs
@@ -8,17 +8,17 @@ use std::fmt;
 use style_traits::ToCss;
 use values::{CSSInteger, CSSFloat};
 use values::animated::ToAnimatedZero;
 use values::computed::{NonNegativeLength, NonNegativeNumber};
 use values::computed::length::{Length, LengthOrPercentage};
 use values::generics::text::InitialLetter as GenericInitialLetter;
 use values::generics::text::LineHeight as GenericLineHeight;
 use values::generics::text::Spacing;
-use values::specified::text::TextOverflowSide;
+use values::specified::text::{TextOverflowSide, TextDecorationLine};
 
 /// A computed value for the `initial-letter` property.
 pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
 
 /// A computed value for the `letter-spacing` property.
 pub type LetterSpacing = Spacing<Length>;
 
 /// A computed value for the `word-spacing` property.
@@ -69,8 +69,35 @@ impl ToCss for TextOverflow {
         } else {
             self.first.to_css(dest)?;
             dest.write_str(" ")?;
             self.second.to_css(dest)?;
         }
         Ok(())
     }
 }
+
+impl ToCss for TextDecorationLine {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        let mut has_any = false;
+
+        macro_rules! write_value {
+            ($line:path => $css:expr) => {
+                if self.contains($line) {
+                    if has_any {
+                        dest.write_str(" ")?;
+                    }
+                    dest.write_str($css)?;
+                    has_any = true;
+                }
+            }
+        }
+        write_value!(TextDecorationLine::UNDERLINE => "underline");
+        write_value!(TextDecorationLine::OVERLINE => "overline");
+        write_value!(TextDecorationLine::LINE_THROUGH => "line-through");
+        write_value!(TextDecorationLine::BLINK => "blink");
+        if !has_any {
+            dest.write_str("none")?;
+        }
+
+        Ok(())
+    }
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -46,17 +46,17 @@ pub use self::length::{LengthOrPercentag
 pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength};
 pub use self::length::{NoCalcLength, ViewportPercentageLength};
 pub use self::length::NonNegativeLengthOrPercentage;
 pub use self::rect::LengthOrNumberRect;
 pub use self::percentage::Percentage;
 pub use self::position::{Position, PositionComponent};
 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind, SVGStrokeDashArray, SVGWidth};
 pub use self::table::XSpan;
-pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextOverflow, WordSpacing};
+pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextDecorationLine, TextOverflow, WordSpacing};
 pub use self::time::Time;
 pub use self::transform::{TimingFunction, Transform, TransformOrigin};
 pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
 
 #[cfg(feature = "gecko")]
 pub mod align;
 pub mod angle;
 pub mod background;
--- a/servo/components/style/values/specified/text.rs
+++ b/servo/components/style/values/specified/text.rs
@@ -1,19 +1,21 @@
 /* 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/. */
 
 //! Specified types for text properties.
 
 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 style_traits::ParseError;
+use style_traits::{ParseError, StyleParseErrorKind};
 use values::computed::{Context, ToComputedValue};
 use values::computed::text::LineHeight as ComputedLineHeight;
 use values::computed::text::TextOverflow as ComputedTextOverflow;
 use values::generics::text::InitialLetter as GenericInitialLetter;
 use values::generics::text::LineHeight as GenericLineHeight;
 use values::generics::text::Spacing;
 use values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number};
 use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength};
@@ -237,8 +239,113 @@ impl ToComputedValue for TextOverflow {
         } else {
             TextOverflow {
                 first: computed.first.clone(),
                 second: Some(computed.second.clone()),
             }
         }
     }
 }
+
+bitflags! {
+    #[derive(MallocSizeOf, ToComputedValue)]
+    /// Specified keyword values for the text-decoration-line property.
+    pub struct TextDecorationLine: u8 {
+        /// No text decoration line is specified
+        const NONE = 0;
+        /// Underline
+        const UNDERLINE = 0x01;
+        /// Overline
+        const OVERLINE = 0x02;
+        /// Line through
+        const LINE_THROUGH = 0x04;
+        /// Blink
+        const BLINK = 0x08;
+        #[cfg(feature = "gecko")]
+        /// Only set by presentation attributes
+        ///
+        /// Setting this will mean that text-decorations use the color
+        /// specified by `color` in quirks mode.
+        ///
+        /// For example, this gives <a href=foo><font color="red">text</font></a>
+        /// a red text decoration
+        const COLOR_OVERRIDE = 0x10;
+    }
+}
+
+#[cfg(feature = "gecko")]
+impl_bitflags_conversions!(TextDecorationLine);
+
+impl TextDecorationLine {
+    #[inline]
+    /// Returns the initial value of text-decoration-line
+    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 {
+    /// none | [ underline || overline || line-through || blink ]
+    fn parse<'i, 't>(
+        _context: &ParserContext,
+        input: &mut Parser<'i, 't>
+    ) -> Result<TextDecorationLine, ParseError<'i>> {
+        let mut result = TextDecorationLine::NONE;
+        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
+            return Ok(result)
+        }
+
+        loop {
+            let result: Result<_, ParseError> = input.try(|input| {
+                try_match_ident_ignore_ascii_case! { input,
+                    "underline" => {
+                        if result.contains(TextDecorationLine::UNDERLINE) {
+                            Err(())
+                        } else {
+                            result.insert(TextDecorationLine::UNDERLINE);
+                            Ok(())
+                        }
+                    }
+                    "overline" => {
+                        if result.contains(TextDecorationLine::OVERLINE) {
+                            Err(())
+                        } else {
+                            result.insert(TextDecorationLine::OVERLINE);
+                            Ok(())
+                        }
+                    }
+                    "line-through" => {
+                        if result.contains(TextDecorationLine::LINE_THROUGH) {
+                            Err(())
+                        } else {
+                            result.insert(TextDecorationLine::LINE_THROUGH);
+                            Ok(())
+                        }
+                    }
+                    "blink" => {
+                        if result.contains(TextDecorationLine::BLINK) {
+                            Err(())
+                        } else {
+                            result.insert(TextDecorationLine::BLINK);
+                            Ok(())
+                        }
+                    }
+                }
+            });
+            if result.is_err() {
+                break;
+            }
+        }
+
+        if !result.is_empty() {
+            Ok(result)
+        } else {
+            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+        }
+    }
+}
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3368,20 +3368,20 @@ pub extern "C" fn Servo_DeclarationBlock
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
     declarations: RawServoDeclarationBlockBorrowed,
 ) {
     use style::properties::PropertyDeclaration;
-    use style::properties::longhands::text_decoration_line;
-
-    let mut decoration = text_decoration_line::computed_value::none;
-    decoration |= text_decoration_line::SpecifiedValue::COLOR_OVERRIDE;
+    use style::values::specified::text::TextDecorationLine;
+
+    let mut decoration = TextDecorationLine::none();
+    decoration |= TextDecorationLine::COLOR_OVERRIDE;
     let decl = PropertyDeclaration::TextDecorationLine(decoration);
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
         decls.push(decl, Importance::Normal, DeclarationSource::CssOm);
     })
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_CSSSupports2(