Bug 1434130 part 9 - Use unified list for TextDecorationLine and implement its SpecifiedValueInfo. r=emilio
authorXidorn Quan <me@upsuper.org>
Sun, 29 Apr 2018 09:03:31 +1000
changeset 416181 e615f3f0029a0b7b5d169b9dbf7ea61cc86ccfd6
parent 416180 1fc2da3cfe61153253ff19a6362cd89057f82a92
child 416182 83df94ad2416a8f603acdbdc9fccdfccea90ffba
push id33918
push usernerli@mozilla.com
push dateSun, 29 Apr 2018 09:47:13 +0000
treeherdermozilla-central@afbec7f03bd8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1434130
milestone61.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
Bug 1434130 part 9 - Use unified list for TextDecorationLine and implement its SpecifiedValueInfo. r=emilio MozReview-Commit-ID: 2sCnK1AecFk
servo/components/style/values/computed/text.rs
servo/components/style/values/specified/text.rs
--- a/servo/components/style/values/computed/text.rs
+++ b/servo/components/style/values/computed/text.rs
@@ -10,18 +10,17 @@ use std::fmt::{self, Write};
 use style_traits::{CssWriter, ToCss};
 use values::{CSSFloat, CSSInteger};
 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::MozTabSize as GenericMozTabSize;
 use values::generics::text::Spacing;
-use values::specified::text::{TextDecorationLine, TextEmphasisFillMode};
-use values::specified::text::{TextEmphasisShapeKeyword, TextOverflowSide};
+use values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide};
 
 pub use values::specified::TextAlignKeyword as TextAlign;
 pub use values::specified::TextEmphasisPosition;
 
 /// A computed value for the `initial-letter` property.
 pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
 
 /// A computed value for the `letter-spacing` property.
@@ -74,46 +73,16 @@ impl ToCss for TextOverflow {
             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 CssWriter<W>) -> fmt::Result
-    where
-        W: 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 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)]
--- a/servo/components/style/values/specified/text.rs
+++ b/servo/components/style/values/specified/text.rs
@@ -4,17 +4,19 @@
 
 //! Specified types for text properties.
 
 use cssparser::{Parser, Token};
 use parser::{Parse, ParserContext};
 use properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode;
 use selectors::parser::SelectorParseErrorKind;
 use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
+use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
+use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
+use style_traits::values::SequenceWriter;
 use unicode_segmentation::UnicodeSegmentation;
 use values::computed::{Context, ToComputedValue};
 use values::computed::text::LineHeight as ComputedLineHeight;
 use values::computed::text::TextEmphasisKeywordValue as ComputedTextEmphasisKeywordValue;
 use values::computed::text::TextEmphasisStyle as ComputedTextEmphasisStyle;
 use values::computed::text::TextOverflow as ComputedTextOverflow;
 use values::generics::text::InitialLetter as GenericInitialLetter;
 use values::generics::text::LineHeight as GenericLineHeight;
@@ -246,119 +248,138 @@ impl ToComputedValue for TextOverflow {
             TextOverflow {
                 first: computed.first.clone(),
                 second: Some(computed.second.clone()),
             }
         }
     }
 }
 
-bitflags! {
-    #[derive(MallocSizeOf, SpecifiedValueInfo, 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;
+macro_rules! impl_text_decoration_line {
+    {
+        $(
+            $(#[$($meta:tt)+])*
+            $ident:ident / $css:expr => $value:expr,
+        )+
+    } => {
+        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;
+                $(
+                    $(#[$($meta)+])*
+                    const $ident = $value;
+                )+
+                #[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;
+            }
+        }
+
+        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 = input.try(|input| {
+                        let ident = input.expect_ident().map_err(|_| ())?;
+                        match_ignore_ascii_case! { ident,
+                            $(
+                                $css => {
+                                    if result.contains(TextDecorationLine::$ident) {
+                                        Err(())
+                                    } else {
+                                        result.insert(TextDecorationLine::$ident);
+                                        Ok(())
+                                    }
+                                }
+                            )+
+                            _ => Err(()),
+                        }
+                    });
+                    if result.is_err() {
+                        break;
+                    }
+                }
+
+                if !result.is_empty() {
+                    Ok(result)
+                } else {
+                    Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+                }
+            }
+        }
+
+        impl ToCss for TextDecorationLine {
+            fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+            where
+                W: Write,
+            {
+                if self.is_empty() {
+                    return dest.write_str("none");
+                }
+
+                let mut writer = SequenceWriter::new(dest, " ");
+                $(
+                    if self.contains(TextDecorationLine::$ident) {
+                        writer.raw_item($css)?;
+                    }
+                )+
+                Ok(())
+            }
+        }
+
+        impl SpecifiedValueInfo for TextDecorationLine {
+            fn collect_completion_keywords(f: KeywordsCollectFn) {
+                f(&["none", $($css,)+]);
+            }
+        }
     }
 }
 
+impl_text_decoration_line! {
+    /// Underline
+    UNDERLINE / "underline" => 1 << 0,
+    /// Overline
+    OVERLINE / "overline" => 1 << 1,
+    /// Line through
+    LINE_THROUGH / "line-through" => 1 << 2,
+    /// Blink
+    BLINK / "blink" => 1 << 3,
+}
+
 #[cfg(feature = "gecko")]
 impl_bitflags_conversions!(TextDecorationLine);
 
 impl TextDecorationLine {
     #[inline]
     /// Returns the initial value of text-decoration-line
     pub fn none() -> Self {
         TextDecorationLine::NONE
     }
 }
 
-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 = input.try(|input| {
-                let ident = input.expect_ident().map_err(|_| ())?;
-                match_ignore_ascii_case! { ident,
-                    "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(())
-                        }
-                    }
-                    _ => Err(()),
-                }
-            });
-            if result.is_err() {
-                break;
-            }
-        }
-
-        if !result.is_empty() {
-            Ok(result)
-        } else {
-            Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
-        }
-    }
-}
-
 macro_rules! define_text_align_keyword {
     ($(
         $(#[$($meta:tt)+])*
         $name: ident => $discriminant: expr,
     )+) => {
         /// Specified value of text-align keyword value.
         #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq,
                  SpecifiedValueInfo, ToComputedValue, ToCss)]