Bug 1434130 part 9 - Use unified list for TextDecorationLine and implement its SpecifiedValueInfo. r?emilio
MozReview-Commit-ID: 2sCnK1AecFk
--- 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)]