Bug 1434130 part 9 - Use unified list for TextDecorationLine and implement its SpecifiedValueInfo. r?emilio draft
authorXidorn Quan <me@upsuper.org>
Thu, 26 Apr 2018 17:30:00 +1000
changeset 788775 adc038d9c64ae32ca74ecaa46ca5cf0b9d5fdb77
parent 788774 a78f97b583f55fb2373d9629b16883584d93cfd1
child 788776 524796e355b2221343b96a77c7a00abd2eb41af7
push id108088
push userxquan@mozilla.com
push dateFri, 27 Apr 2018 00:40:56 +0000
reviewersemilio
bugs1434130
milestone61.0a1
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)]