Move specified color types into specified::color mod. r?manishearth draft
authorXidorn Quan <me@upsuper.org>
Tue, 06 Jun 2017 16:46:43 +1000
changeset 590134 e9c1854ec27b0e0f882d0b18b4037303cfb2b310
parent 590133 bc40336381a70747f37c02ff8de632e8a5aec94b
child 590135 0522bc54293f6499d3f4c0d67b5eb8363d22f36d
push id62604
push userxquan@mozilla.com
push dateWed, 07 Jun 2017 07:07:54 +0000
reviewersmanishearth
milestone55.0a1
Move specified color types into specified::color mod. r?manishearth MozReview-Commit-ID: Ek3PAEp4ImQ
servo/components/style/values/specified/color.rs
servo/components/style/values/specified/mod.rs
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -1,13 +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/. */
 
-//! Non-standard CSS color values
+//! Specified color values.
+
+use cssparser::{self, Parser, Token};
+use itoa;
+use parser::{ParserContext, Parse};
+use std::fmt;
+use std::io::Write;
+use style_traits::ToCss;
+use super::AllowQuirks;
 
 #[cfg(not(feature = "gecko"))] pub use self::servo::Color;
 #[cfg(feature = "gecko")] pub use self::gecko::Color;
 
 #[cfg(not(feature = "gecko"))]
 mod servo {
     pub use cssparser::Color;
     use cssparser::Parser;
@@ -96,8 +104,149 @@ mod gecko {
                 Color::MozHyperlinktext => dest.write_str("-moz-hyperlinktext"),
                 Color::MozActiveHyperlinktext => dest.write_str("-moz-activehyperlinktext"),
                 Color::MozVisitedHyperlinktext => dest.write_str("-moz-visitedhyperlinktext"),
                 Color::InheritFromBodyQuirk => Ok(()),
             }
         }
     }
 }
+
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[allow(missing_docs)]
+pub struct CSSColor {
+    pub parsed: Color,
+    pub authored: Option<Box<str>>,
+}
+
+impl Parse for CSSColor {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        Self::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl CSSColor {
+    /// Parse a color, with quirks.
+    ///
+    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks)
+                        -> Result<Self, ()> {
+        let start_position = input.position();
+        let authored = match input.next() {
+            Ok(Token::Ident(s)) => Some(s.into_owned().into_boxed_str()),
+            _ => None,
+        };
+        input.reset(start_position);
+        if let Ok(parsed) = input.try(|i| Parse::parse(context, i)) {
+            return Ok(CSSColor {
+                parsed: parsed,
+                authored: authored,
+            });
+        }
+        if !allow_quirks.allowed(context.quirks_mode) {
+            return Err(());
+        }
+        let (number, dimension) = match input.next()? {
+            Token::Number(number) => {
+                (number, None)
+            },
+            Token::Dimension(number, dimension) => {
+                (number, Some(dimension))
+            },
+            Token::Ident(ident) => {
+                if ident.len() != 3 && ident.len() != 6 {
+                    return Err(());
+                }
+                return cssparser::Color::parse_hash(ident.as_bytes()).map(|color| {
+                    Self {
+                        parsed: color.into(),
+                        authored: None
+                    }
+                });
+            }
+            _ => {
+                return Err(());
+            },
+        };
+        let value = number.int_value.ok_or(())?;
+        if value < 0 {
+            return Err(());
+        }
+        let length = if value <= 9 {
+            1
+        } else if value <= 99 {
+            2
+        } else if value <= 999 {
+            3
+        } else if value <= 9999 {
+            4
+        } else if value <= 99999 {
+            5
+        } else if value <= 999999 {
+            6
+        } else {
+            return Err(())
+        };
+        let total = length + dimension.as_ref().map_or(0, |d| d.len());
+        if total > 6 {
+            return Err(());
+        }
+        let mut serialization = [b'0'; 6];
+        let space_padding = 6 - total;
+        let mut written = space_padding;
+        written += itoa::write(&mut serialization[written..], value).unwrap();
+        if let Some(dimension) = dimension {
+            written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap();
+        }
+        debug_assert!(written == 6);
+        Ok(CSSColor {
+            parsed: cssparser::Color::parse_hash(&serialization).map(From::from)?,
+            authored: None,
+        })
+    }
+
+    /// Returns false if the color is completely transparent, and
+    /// true otherwise.
+    pub fn is_non_transparent(&self) -> bool {
+        match self.parsed {
+            Color::RGBA(rgba) if rgba.alpha == 0 => false,
+            _ => true,
+        }
+    }
+}
+
+no_viewport_percentage!(CSSColor);
+
+impl ToCss for CSSColor {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match self.authored {
+            Some(ref s) => dest.write_str(s),
+            None => self.parsed.to_css(dest),
+        }
+    }
+}
+
+impl From<Color> for CSSColor {
+    fn from(color: Color) -> Self {
+        CSSColor {
+            parsed: color,
+            authored: None,
+        }
+    }
+}
+
+impl CSSColor {
+    #[inline]
+    /// Returns currentcolor value.
+    pub fn currentcolor() -> CSSColor {
+        Color::CurrentColor.into()
+    }
+
+    #[inline]
+    /// Returns transparent value.
+    pub fn transparent() -> CSSColor {
+        // We should probably set authored to "transparent", but maybe it doesn't matter.
+        Color::RGBA(cssparser::RGBA::transparent()).into()
+    }
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -4,40 +4,38 @@
 
 //! Specified values.
 //!
 //! TODO(emilio): Enhance docs.
 
 use Namespace;
 use context::QuirksMode;
 use cssparser::{self, Parser, Token, serialize_identifier};
-use itoa;
 use parser::{ParserContext, Parse};
 use self::grid::TrackSizeOrRepeat;
 use self::url::SpecifiedUrl;
 use std::ascii::AsciiExt;
 use std::f32;
 use std::fmt;
-use std::io::Write;
 use style_traits::ToCss;
 use style_traits::values::specified::AllowedNumericType;
 use super::{Auto, CSSFloat, CSSInteger, Either, None_};
 use super::computed::{self, Context};
 use super::computed::{Shadow as ComputedShadow, ToComputedValue};
 use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 use super::generics::grid::TrackList as GenericTrackList;
 use values::computed::ComputedValueAsSpecified;
 use values::specified::calc::CalcNode;
 
 #[cfg(feature = "gecko")]
 pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
 pub use self::background::BackgroundSize;
 pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
 pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth};
-pub use self::color::Color;
+pub use self::color::{CSSColor, Color};
 pub use self::rect::LengthOrNumberRect;
 pub use super::generics::grid::GridLine;
 pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use self::image::{GradientItem, GradientKind, Image, ImageRect, ImageLayer};
 pub use self::length::AbsoluteLength;
 pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
 pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
 pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength};
@@ -82,157 +80,16 @@ impl Parse for SpecifiedUrl {
 impl Eq for SpecifiedUrl {}
 
 // TODO(emilio): Maybe consider ComputedUrl to save a word in style structs?
 impl ComputedValueAsSpecified for SpecifiedUrl {}
 
 no_viewport_percentage!(SpecifiedUrl);
 }
 
-#[derive(Clone, PartialEq, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
-pub struct CSSColor {
-    pub parsed: Color,
-    pub authored: Option<Box<str>>,
-}
-
-impl Parse for CSSColor {
-    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_quirky(context, input, AllowQuirks::No)
-    }
-}
-
-impl CSSColor {
-    /// Parse a color, with quirks.
-    ///
-    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
-    pub fn parse_quirky(context: &ParserContext,
-                        input: &mut Parser,
-                        allow_quirks: AllowQuirks)
-                        -> Result<Self, ()> {
-        let start_position = input.position();
-        let authored = match input.next() {
-            Ok(Token::Ident(s)) => Some(s.into_owned().into_boxed_str()),
-            _ => None,
-        };
-        input.reset(start_position);
-        if let Ok(parsed) = input.try(|i| Parse::parse(context, i)) {
-            return Ok(CSSColor {
-                parsed: parsed,
-                authored: authored,
-            });
-        }
-        if !allow_quirks.allowed(context.quirks_mode) {
-            return Err(());
-        }
-        let (number, dimension) = match input.next()? {
-            Token::Number(number) => {
-                (number, None)
-            },
-            Token::Dimension(number, dimension) => {
-                (number, Some(dimension))
-            },
-            Token::Ident(ident) => {
-                if ident.len() != 3 && ident.len() != 6 {
-                    return Err(());
-                }
-                return cssparser::Color::parse_hash(ident.as_bytes()).map(|color| {
-                    Self {
-                        parsed: color.into(),
-                        authored: None
-                    }
-                });
-            }
-            _ => {
-                return Err(());
-            },
-        };
-        let value = number.int_value.ok_or(())?;
-        if value < 0 {
-            return Err(());
-        }
-        let length = if value <= 9 {
-            1
-        } else if value <= 99 {
-            2
-        } else if value <= 999 {
-            3
-        } else if value <= 9999 {
-            4
-        } else if value <= 99999 {
-            5
-        } else if value <= 999999 {
-            6
-        } else {
-            return Err(())
-        };
-        let total = length + dimension.as_ref().map_or(0, |d| d.len());
-        if total > 6 {
-            return Err(());
-        }
-        let mut serialization = [b'0'; 6];
-        let space_padding = 6 - total;
-        let mut written = space_padding;
-        written += itoa::write(&mut serialization[written..], value).unwrap();
-        if let Some(dimension) = dimension {
-            written += (&mut serialization[written..]).write(dimension.as_bytes()).unwrap();
-        }
-        debug_assert!(written == 6);
-        Ok(CSSColor {
-            parsed: cssparser::Color::parse_hash(&serialization).map(From::from)?,
-            authored: None,
-        })
-    }
-
-    /// Returns false if the color is completely transparent, and
-    /// true otherwise.
-    pub fn is_non_transparent(&self) -> bool {
-        match self.parsed {
-            Color::RGBA(rgba) if rgba.alpha == 0 => false,
-            _ => true,
-        }
-    }
-}
-
-no_viewport_percentage!(CSSColor);
-
-impl ToCss for CSSColor {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match self.authored {
-            Some(ref s) => dest.write_str(s),
-            None => self.parsed.to_css(dest),
-        }
-    }
-}
-
-impl From<Color> for CSSColor {
-    fn from(color: Color) -> Self {
-        CSSColor {
-            parsed: color,
-            authored: None,
-        }
-    }
-}
-
-impl CSSColor {
-    #[inline]
-    /// Returns currentcolor value.
-    pub fn currentcolor() -> CSSColor {
-        Color::CurrentColor.into()
-    }
-
-    #[inline]
-    /// Returns transparent value.
-    pub fn transparent() -> CSSColor {
-        // We should probably set authored to "transparent", but maybe it doesn't matter.
-        Color::RGBA(cssparser::RGBA::transparent()).into()
-    }
-}
-
 /// Parse an `<integer>` value, handling `calc()` correctly.
 pub fn parse_integer(context: &ParserContext, input: &mut Parser) -> Result<Integer, ()> {
     match try!(input.next()) {
         Token::Number(ref value) => value.int_value.ok_or(()).map(Integer::new),
         Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
             let result = try!(input.parse_nested_block(|i| {
                 CalcNode::parse_integer(context, i)
             }));