Merge CSSColor into Color. r?manishearth draft
authorXidorn Quan <me@upsuper.org>
Tue, 06 Jun 2017 22:35:14 +1000
changeset 590139 899a1a8b3feec08c40a9727b00e424143e042af4
parent 590138 0869b6408b7d7d1d2a6deffbbd3dae169a0552d2
child 590140 7e533d521ab811e5a6c61ad0c1a315bc625af030
push id62604
push userxquan@mozilla.com
push dateWed, 07 Jun 2017 07:07:54 +0000
reviewersmanishearth
milestone55.0a1
Merge CSSColor into Color. r?manishearth MozReview-Commit-ID: DqGY4VRvIZs
servo/components/script/dom/element.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/background.mako.rs
servo/components/style/properties/longhand/border.mako.rs
servo/components/style/properties/longhand/color.mako.rs
servo/components/style/properties/longhand/column.mako.rs
servo/components/style/properties/longhand/inherited_text.mako.rs
servo/components/style/properties/longhand/outline.mako.rs
servo/components/style/properties/longhand/text.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/properties/shorthand/background.mako.rs
servo/components/style/properties/shorthand/border.mako.rs
servo/components/style/properties/shorthand/outline.mako.rs
servo/components/style/properties/shorthand/serialize.mako.rs
servo/components/style/properties/shorthand/text.mako.rs
servo/components/style/rule_tree/mod.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/specified/color.rs
servo/components/style/values/specified/image.rs
servo/components/style/values/specified/mod.rs
servo/ports/geckolib/glue.rs
servo/tests/unit/style/parsing/ui.rs
servo/tests/unit/style/properties/serialization.rs
servo/tests/unit/style/stylesheets.rs
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -106,17 +106,17 @@ use style::restyle_hints::RestyleHint;
 use style::rule_tree::CascadeLevel;
 use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
 use style::shared_lock::{SharedRwLock, Locked};
 use style::sink::Push;
 use style::stylearc::Arc;
 use style::stylist::ApplicableDeclarationBlock;
 use style::thread_state;
 use style::values::{CSSFloat, Either};
-use style::values::specified::{self, CSSColor, Color};
+use style::values::specified::{self, Color};
 use stylesheet_loader::StylesheetOwner;
 
 // TODO: Update focus state when the top-level browsing context gains or loses system focus,
 // and when the element enters or leaves a browsing context container.
 // https://html.spec.whatwg.org/multipage/#selector-focus
 
 #[dom_struct]
 pub struct Element {
@@ -409,18 +409,18 @@ impl LayoutElementHelpers for LayoutJS<E
             this.get_background_color()
         } else {
             None
         };
 
         if let Some(color) = bgcolor {
             hints.push(from_declaration(
                 shared_lock,
-                PropertyDeclaration::BackgroundColor(
-                    CSSColor { parsed: Color::RGBA(color), authored: None })));
+                PropertyDeclaration::BackgroundColor(Color::rgba(color))
+            ));
         }
 
         let background = if let Some(this) = self.downcast::<HTMLBodyElement>() {
             this.get_background()
         } else {
             None
         };
 
@@ -444,20 +444,17 @@ impl LayoutElementHelpers for LayoutJS<E
         } else {
             None
         };
 
         if let Some(color) = color {
             hints.push(from_declaration(
                 shared_lock,
                 PropertyDeclaration::Color(
-                    longhands::color::SpecifiedValue(CSSColor {
-                        parsed: Color::RGBA(color),
-                        authored: None,
-                    })
+                    longhands::color::SpecifiedValue(Color::rgba(color))
                 )
             ));
         }
 
         let font_family = if let Some(this) = self.downcast::<HTMLFontElement>() {
             this.get_face()
         } else {
             None
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -6,17 +6,16 @@
 
 <%!
     from data import to_rust_ident, to_camel_case
     from data import Keyword
 %>
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 use app_units::Au;
-use cssparser::Color;
 use custom_properties::ComputedValuesMap;
 use gecko_bindings::bindings;
 % for style_struct in data.style_structs:
 use gecko_bindings::structs::${style_struct.gecko_ffi_name};
 use gecko_bindings::bindings::Gecko_Construct_Default_${style_struct.gecko_ffi_name};
 use gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ffi_name};
 use gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name};
 % endfor
@@ -312,45 +311,32 @@ def set_gecko_property(ffi_name, expr):
         }
     }
 </%def>
 
 <%def name="impl_color_setter(ident, gecko_ffi_name, complex_color=True)">
     #[allow(unreachable_code)]
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
-        % if complex_color:
-            let result = v.into();
-        % else:
-            let result = match color {
-                Color::RGBA(rgba) => convert_rgba_to_nscolor(&rgba),
-                // FIXME handle currentcolor
-                Color::CurrentColor => 0,
-            };
-        % endif
-        ${set_gecko_property(gecko_ffi_name, "result")}
+        ${set_gecko_property(gecko_ffi_name, "v.into()")}
     }
 </%def>
 
 <%def name="impl_color_copy(ident, gecko_ffi_name, complex_color=True)">
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         let color = ${get_gecko_property(gecko_ffi_name, self_param = "other")};
         ${set_gecko_property(gecko_ffi_name, "color")};
     }
 </%def>
 
 <%def name="impl_color_clone(ident, gecko_ffi_name, complex_color=True)">
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
-        % if complex_color:
-            ${get_gecko_property(gecko_ffi_name)}.into()
-        % else:
-            Color::RGBA(convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)}))
-        % endif
+        ${get_gecko_property(gecko_ffi_name)}.into()
     }
 </%def>
 
 <%def name="impl_keyword(ident, gecko_ffi_name, keyword, need_clone, cast_type='u8', **kwargs)">
 <%call expr="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type, **kwargs)"></%call>
 <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
 %if need_clone:
 <%call expr="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type)"></%call>
@@ -714,17 +700,17 @@ impl Debug for ${style_struct.gecko_stru
         "LengthOrPercentageOrNone": impl_style_coord,
         "LengthOrNone": impl_style_coord,
         "LengthOrNormal": impl_style_coord,
         "MaxLength": impl_style_coord,
         "MozLength": impl_style_coord,
         "Number": impl_simple,
         "Integer": impl_simple,
         "Opacity": impl_simple,
-        "CSSColor": impl_color,
+        "Color": impl_color,
         "RGBAColor": impl_rgba_color,
         "SVGPaint": impl_svg_paint,
         "UrlOrNone": impl_css_url,
     }
 
     def longhand_method(longhand):
         args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name,
                     need_clone=longhand.need_clone)
@@ -735,18 +721,16 @@ impl Debug for ${style_struct.gecko_stru
             args.update(name=longhand.name)
         elif longhand.keyword:
             method = impl_keyword
             args.update(keyword=longhand.keyword)
             if "font" in longhand.ident:
                 args.update(cast_type=longhand.cast_type)
         else:
             method = predefined_types[longhand.predefined_type]
-            if longhand.predefined_type in ["CSSColor"]:
-                args.update(complex_color=longhand.complex_color)
 
         method(**args)
 
     picked_longhands, stub_longhands = [], []
     for x in longhands:
         if (x.keyword or x.predefined_type in predefined_types or x.logical) and x.name not in force_stub:
             picked_longhands.append(x)
         else:
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Background", inherited=False) %>
 
-${helpers.predefined_type("background-color", "CSSColor",
+${helpers.predefined_type("background-color", "Color",
     "::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
     initial_specified_value="SpecifiedValue::transparent()",
     spec="https://drafts.csswg.org/css-backgrounds/#background-color",
     animation_value_type="IntermediateColor",
     complex_color=True,
     ignored_when_colors_disabled=True,
     allow_quirks=True)}
 
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -11,17 +11,17 @@
 <%
     def maybe_logical_spec(side, kind):
         if side[1]: # if it is logical
             return "https://drafts.csswg.org/css-logical-props/#propdef-border-%s-%s" % (side[0], kind)
         else:
             return "https://drafts.csswg.org/css-backgrounds/#border-%s-%s" % (side[0], kind)
 %>
 % for side in ALL_SIDES:
-    ${helpers.predefined_type("border-%s-color" % side[0], "CSSColor",
+    ${helpers.predefined_type("border-%s-color" % side[0], "Color",
                               "::cssparser::Color::CurrentColor",
                               alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
                               spec=maybe_logical_spec(side, "color"),
                               animation_value_type="IntermediateColor",
                               logical=side[1],
                               allow_quirks=not side[1],
                               ignored_when_colors_disabled=True)}
 
--- a/servo/components/style/properties/longhand/color.mako.rs
+++ b/servo/components/style/properties/longhand/color.mako.rs
@@ -7,48 +7,52 @@
 <% data.new_style_struct("Color", inherited=True) %>
 
 <% from data import to_rust_ident %>
 
 <%helpers:longhand name="color" need_clone="True"
                    animation_value_type="IntermediateRGBA"
                    ignored_when_colors_disabled="True"
                    spec="https://drafts.csswg.org/css-color/#color">
-    use cssparser::RGBA;
-    use values::specified::{AllowQuirks, Color, CSSColor};
+    use cssparser::{Color as CSSParserColor, RGBA};
+    use values::specified::{AllowQuirks, Color};
 
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
-            self.0.parsed.to_computed_value(context)
+            match self.0.to_computed_value(context) {
+                CSSParserColor::RGBA(rgba) => rgba,
+                CSSParserColor::CurrentColor =>
+                    context.inherited_style.get_color().clone_color(),
+            }
         }
 
         #[inline]
         fn from_computed_value(computed: &computed_value::T) -> Self {
-            SpecifiedValue(Color::RGBA(*computed).into())
+            SpecifiedValue(Color::rgba(*computed).into())
         }
     }
 
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     #[derive(Clone, Debug, PartialEq, ToCss)]
-    pub struct SpecifiedValue(pub CSSColor);
+    pub struct SpecifiedValue(pub Color);
     no_viewport_percentage!(SpecifiedValue);
 
     pub mod computed_value {
         use cssparser;
         pub type T = cssparser::RGBA;
     }
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         RGBA::new(0, 0, 0, 255) // black
     }
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        CSSColor::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue)
+        Color::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue)
     }
 
     // FIXME(#15973): Add servo support for system colors
     % if product == "gecko":
         <%
             # These are actually parsed. See nsCSSProps::kColorKTable
             system_colors = """activeborder activecaption appworkspace background buttonface
                                buttonhighlight buttonshadow buttontext captiontext graytext highlight
--- a/servo/components/style/properties/longhand/column.mako.rs
+++ b/servo/components/style/properties/longhand/column.mako.rs
@@ -46,19 +46,19 @@
                           initial_specified_value="specified::BorderSideWidth::Medium",
                           computed_type="::app_units::Au",
                           products="gecko",
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
                           animation_value_type="ComputedValue",
                           extra_prefixes="moz")}
 
 // https://drafts.csswg.org/css-multicol-1/#crc
-${helpers.predefined_type("column-rule-color", "CSSColor",
+${helpers.predefined_type("column-rule-color", "Color",
                           "::cssparser::Color::CurrentColor",
-                          initial_specified_value="specified::CSSColor::currentcolor()",
+                          initial_specified_value="specified::Color::currentcolor()",
                           products="gecko", animation_value_type="IntermediateColor", extra_prefixes="moz",
                           complex_color=True, need_clone=True,
                           ignored_when_colors_disabled=True,
                           spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-color")}
 
 ${helpers.single_keyword("column-span", "none all",
                          products="gecko", animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-multicol/#propdef-column-span")}
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -680,19 +680,19 @@
                     HorizontalWritingModeValue::Under
                 };
                 SpecifiedValue(horiz, vert)
             }
         }
     % endif
 </%helpers:longhand>
 
-${helpers.predefined_type("text-emphasis-color", "CSSColor",
+${helpers.predefined_type("text-emphasis-color", "Color",
                           "::cssparser::Color::CurrentColor",
-                          initial_specified_value="specified::CSSColor::currentcolor()",
+                          initial_specified_value="specified::Color::currentcolor()",
                           products="gecko", animation_value_type="IntermediateColor",
                           complex_color=True, need_clone=True,
                           ignored_when_colors_disabled=True,
                           spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")}
 
 
 ${helpers.predefined_type(
     "-moz-tab-size", "LengthOrNumber",
@@ -700,27 +700,27 @@
     "parse_non_negative",
     products="gecko", animation_value_type="none",
     spec="https://drafts.csswg.org/css-text-3/#tab-size-property")}
 
 
 // CSS Compatibility
 // https://compat.spec.whatwg.org
 ${helpers.predefined_type(
-    "-webkit-text-fill-color", "CSSColor",
+    "-webkit-text-fill-color", "Color",
     "CSSParserColor::CurrentColor",
     products="gecko", animation_value_type="IntermediateColor",
     complex_color=True, need_clone=True,
     ignored_when_colors_disabled=True,
     spec="https://compat.spec.whatwg.org/#the-webkit-text-fill-color")}
 
 ${helpers.predefined_type(
-    "-webkit-text-stroke-color", "CSSColor",
+    "-webkit-text-stroke-color", "Color",
     "CSSParserColor::CurrentColor",
-    initial_specified_value="specified::CSSColor::currentcolor()",
+    initial_specified_value="specified::Color::currentcolor()",
     products="gecko", animation_value_type="IntermediateColor",
     complex_color=True, need_clone=True,
     ignored_when_colors_disabled=True,
     spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
 
 ${helpers.predefined_type("-webkit-text-stroke-width",
                           "BorderSideWidth",
                           "Au::from_px(0)",
--- a/servo/components/style/properties/longhand/outline.mako.rs
+++ b/servo/components/style/properties/longhand/outline.mako.rs
@@ -5,18 +5,18 @@
 <%namespace name="helpers" file="/helpers.mako.rs" />
 <% from data import Method %>
 
 <% data.new_style_struct("Outline",
                          inherited=False,
                          additional_methods=[Method("outline_has_nonzero_width", "bool")]) %>
 
 // TODO(pcwalton): `invert`
-${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::CurrentColor",
-                          initial_specified_value="specified::CSSColor::currentcolor()",
+${helpers.predefined_type("outline-color", "Color", "computed::Color::CurrentColor",
+                          initial_specified_value="specified::Color::currentcolor()",
                           animation_value_type="IntermediateColor", complex_color=True, need_clone=True,
                           ignored_when_colors_disabled=True,
                           spec="https://drafts.csswg.org/css-ui/#propdef-outline-color")}
 
 <%helpers:longhand name="outline-style" need_clone="True" animation_value_type="none"
                    spec="https://drafts.csswg.org/css-ui/#propdef-outline-style">
     use values::specified::BorderStyle;
 
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -273,19 +273,19 @@
 
 ${helpers.single_keyword("text-decoration-style",
                          "solid double dotted dashed wavy -moz-none",
                          products="gecko",
                          animation_value_type="discrete",
                          spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style")}
 
 ${helpers.predefined_type(
-    "text-decoration-color", "CSSColor",
-    "computed::CSSColor::CurrentColor",
-    initial_specified_value="specified::CSSColor::currentcolor()",
+    "text-decoration-color", "Color",
+    "computed::Color::CurrentColor",
+    initial_specified_value="specified::Color::currentcolor()",
     complex_color=True,
     products="gecko",
     animation_value_type="IntermediateColor",
     ignored_when_colors_disabled=True,
     spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-color")}
 
 <%helpers:longhand name="initial-letter"
                    animation_value_type="none"
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2635,17 +2635,17 @@ pub fn apply_declarations<'a, F, I>(devi
         cached_system_font: None,
         in_media_query: false,
         quirks_mode: quirks_mode,
     };
 
     let ignore_colors = !device.use_document_colors();
     let default_background_color_decl = if ignore_colors {
         let color = device.default_background_color();
-        Some(PropertyDeclaration::BackgroundColor(Color::RGBA(color).into()))
+        Some(PropertyDeclaration::BackgroundColor(Color::rgba(color)))
     } else {
         None
     };
 
     // Set computed values, overwriting earlier declarations for the same
     // property.
     //
     // NB: The cacheable boolean is not used right now, but will be once we
--- a/servo/components/style/properties/shorthand/background.mako.rs
+++ b/servo/components/style/properties/shorthand/background.mako.rs
@@ -10,17 +10,17 @@
                                     background-attachment background-image background-size background-origin
                                     background-clip"
                     spec="https://drafts.csswg.org/css-backgrounds/#the-background">
     use properties::longhands::{background_position_x, background_position_y, background_repeat};
     use properties::longhands::{background_attachment, background_image, background_size, background_origin};
     use properties::longhands::background_clip;
     use properties::longhands::background_clip::single_value::computed_value::T as Clip;
     use properties::longhands::background_origin::single_value::computed_value::T as Origin;
-    use values::specified::{CSSColor, Position, PositionComponent};
+    use values::specified::{Color, Position, PositionComponent};
     use parser::Parse;
 
     impl From<background_origin::single_value::SpecifiedValue> for background_clip::single_value::SpecifiedValue {
         fn from(origin: background_origin::single_value::SpecifiedValue) ->
             background_clip::single_value::SpecifiedValue {
             match origin {
                 background_origin::single_value::SpecifiedValue::content_box =>
                     background_clip::single_value::SpecifiedValue::content_box,
@@ -45,17 +45,17 @@
                 return Err(());
             }
 
             % for name in "image position repeat size attachment origin clip".split():
                 let mut ${name} = None;
             % endfor
             loop {
                 if background_color.is_none() {
-                    if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+                    if let Ok(value) = input.try(|i| Color::parse(context, i)) {
                         background_color = Some(value);
                         continue
                     }
                 }
                 if position.is_none() {
                     if let Ok(value) = input.try(|input| Position::parse(context, input)) {
                         position = Some(value);
 
@@ -107,17 +107,17 @@
                 % endfor
                 Ok(())
             } else {
                 Err(())
             }
         }));
 
         Ok(expanded! {
-             background_color: background_color.unwrap_or(CSSColor::transparent()),
+             background_color: background_color.unwrap_or(Color::transparent()),
              background_image: background_image,
              background_position_x: background_position_x,
              background_position_y: background_position_y,
              background_repeat: background_repeat,
              background_attachment: background_attachment,
              background_size: background_size,
              background_origin: background_origin,
              background_clip: background_clip,
--- a/servo/components/style/properties/shorthand/border.mako.rs
+++ b/servo/components/style/properties/shorthand/border.mako.rs
@@ -1,16 +1,16 @@
 /* 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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 <% from data import to_rust_ident, ALL_SIDES, PHYSICAL_SIDES, maybe_moz_logical_alias %>
 
-${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse",
+${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Color::parse",
                                spec="https://drafts.csswg.org/css-backgrounds/#border-color",
                                allow_quirks=True)}
 
 ${helpers.four_sides_shorthand("border-style", "border-%s-style",
                                "specified::BorderStyle::parse",
                                spec="https://drafts.csswg.org/css-backgrounds/#border-style")}
 
 <%helpers:shorthand name="border-width" sub_properties="${
@@ -39,28 +39,28 @@
             % endfor
             Rect::new(top, right, bottom, left).to_css(dest)
         }
     }
 </%helpers:shorthand>
 
 
 pub fn parse_border(context: &ParserContext, input: &mut Parser)
-                 -> Result<(specified::CSSColor,
+                 -> Result<(specified::Color,
                             specified::BorderStyle,
                             specified::BorderSideWidth), ()> {
-    use values::specified::{CSSColor, BorderStyle, BorderSideWidth};
+    use values::specified::{Color, BorderStyle, BorderSideWidth};
     let _unused = context;
     let mut color = None;
     let mut style = None;
     let mut width = None;
     let mut any = false;
     loop {
         if color.is_none() {
-            if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+            if let Ok(value) = input.try(|i| Color::parse(context, i)) {
                 color = Some(value);
                 any = true;
                 continue
             }
         }
         if style.is_none() {
             if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
                 style = Some(value);
@@ -73,17 +73,17 @@ pub fn parse_border(context: &ParserCont
                 width = Some(value);
                 any = true;
                 continue
             }
         }
         break
     }
     if any {
-        Ok((color.unwrap_or_else(|| CSSColor::currentcolor()),
+        Ok((color.unwrap_or_else(|| Color::currentcolor()),
             style.unwrap_or(BorderStyle::none),
             width.unwrap_or(BorderSideWidth::Medium)))
     } else {
         Err(())
     }
 }
 
 % for side, logical in ALL_SIDES:
--- a/servo/components/style/properties/shorthand/outline.mako.rs
+++ b/servo/components/style/properties/shorthand/outline.mako.rs
@@ -13,17 +13,17 @@
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let _unused = context;
         let mut color = None;
         let mut style = None;
         let mut width = None;
         let mut any = false;
         loop {
             if color.is_none() {
-                if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
+                if let Ok(value) = input.try(|i| specified::Color::parse(context, i)) {
                     color = Some(value);
                     any = true;
                     continue
                 }
             }
             if style.is_none() {
                 if let Ok(value) = input.try(|input| outline_style::parse(context, input)) {
                     style = Some(value);
--- a/servo/components/style/properties/shorthand/serialize.mako.rs
+++ b/servo/components/style/properties/shorthand/serialize.mako.rs
@@ -1,22 +1,22 @@
 /* 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/. */
 
 use style_traits::ToCss;
-use values::specified::{BorderStyle, Color, CSSColor};
+use values::specified::{BorderStyle, Color};
 use std::fmt;
 
 fn serialize_directional_border<W, I,>(dest: &mut W,
                                        width: &I,
                                        style: &BorderStyle,
-                                       color: &CSSColor)
+                                       color: &Color)
     -> fmt::Result where W: fmt::Write, I: ToCss {
     width.to_css(dest)?;
     dest.write_str(" ")?;
     style.to_css(dest)?;
-    if color.parsed != Color::CurrentColor {
+    if *color != Color::CurrentColor {
         dest.write_str(" ")?;
         color.to_css(dest)?;
     }
     Ok(())
 }
--- a/servo/components/style/properties/shorthand/text.mako.rs
+++ b/servo/components/style/properties/shorthand/text.mako.rs
@@ -65,17 +65,17 @@
             self.text_decoration_line.to_css(dest)?;
 
             % if product == "gecko" or data.testing:
                 if self.text_decoration_style != &text_decoration_style::SpecifiedValue::solid {
                     dest.write_str(" ")?;
                     self.text_decoration_style.to_css(dest)?;
                 }
 
-                if self.text_decoration_color.parsed != specified::Color::CurrentColor {
+                if *self.text_decoration_color != specified::Color::CurrentColor {
                     dest.write_str(" ")?;
                     self.text_decoration_color.to_css(dest)?;
                 }
             % endif
 
             Ok(())
         }
     }
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -909,17 +909,16 @@ impl StrongRuleNode {
     pub fn has_author_specified_rules<E>(&self,
                                          mut element: E,
                                          guards: &StylesheetGuards,
                                          rule_type_mask: u32,
                                          author_colors_allowed: bool)
         -> bool
         where E: ::dom::TElement
     {
-        use cssparser::RGBA;
         use gecko_bindings::structs::{NS_AUTHOR_SPECIFIED_BACKGROUND, NS_AUTHOR_SPECIFIED_BORDER};
         use gecko_bindings::structs::{NS_AUTHOR_SPECIFIED_PADDING, NS_AUTHOR_SPECIFIED_TEXT_SHADOW};
         use properties::{CSSWideKeyword, LonghandId, LonghandIdSet};
         use properties::{PropertyDeclaration, PropertyDeclarationId};
         use std::borrow::Cow;
         use values::specified::Color;
 
         // Reset properties:
@@ -1080,17 +1079,17 @@ impl StrongRuleNode {
                     CascadeLevel::Animations |
                     CascadeLevel::AuthorImportant |
                     CascadeLevel::StyleAttributeImportant |
                     CascadeLevel::Transitions => {
                         for (id, declaration) in longhands {
                             if properties.contains(id) {
                                 if !author_colors_allowed {
                                     if let PropertyDeclaration::BackgroundColor(ref color) = *declaration {
-                                        return color.parsed == Color::RGBA(RGBA::transparent())
+                                        return *color == Color::transparent()
                                     }
                                 }
                                 return true
                             }
                         }
                     }
                 }
             }
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -18,17 +18,17 @@ use std::f32::consts::PI;
 use std::fmt;
 use style_traits::ToCss;
 use super::{CSSFloat, CSSInteger, RGBA};
 use super::generics::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 use super::generics::grid::TrackList as GenericTrackList;
 use super::specified;
 
 pub use app_units::Au;
-pub use cssparser::Color as CSSColor;
+pub use cssparser::Color;
 pub use self::background::BackgroundSize;
 pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
 pub use self::border::{BorderRadius, BorderCornerRadius};
 pub use self::color::RGBAColor;
 pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
 pub use self::rect::LengthOrNumberRect;
 pub use super::{Auto, Either, None_};
 #[cfg(feature = "gecko")]
@@ -392,17 +392,17 @@ impl ComputedValueAsSpecified for specif
 #[derive(Debug, PartialEq, Clone, Copy)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct Shadow {
     pub offset_x: Au,
     pub offset_y: Au,
     pub blur_radius: Au,
     pub spread_radius: Au,
-    pub color: CSSColor,
+    pub color: Color,
     pub inset: bool,
 }
 
 impl ToCss for Shadow {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         if self.inset {
             dest.write_str("inset ")?;
         }
@@ -574,9 +574,9 @@ impl ClipRectOrAuto {
         match *self {
             Either::Second(_) => true,
             _ => false
         }
     }
 }
 
 /// <color> | auto
-pub type ColorOrAuto = Either<CSSColor, Auto>;
+pub type ColorOrAuto = Either<Color, Auto>;
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -1,33 +1,40 @@
 /* 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 color values.
 
-use cssparser::{self, Color as CSSParserColor, Parser, RGBA, Token};
+use cssparser::{Color as CSSParserColor, Parser, RGBA, Token};
+#[cfg(feature = "gecko")]
+use gecko_bindings::structs::nscolor;
 use itoa;
 use parser::{ParserContext, Parse};
 #[cfg(feature = "gecko")]
 use properties::longhands::color::SystemColor;
 use std::fmt;
 use std::io::Write;
 use style_traits::ToCss;
 use super::AllowQuirks;
 use values::computed::{Context, ToComputedValue};
 
 /// Specified color value
-#[derive(Clone, Copy, PartialEq, Debug)]
+#[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum Color {
     /// The 'currentColor' keyword
     CurrentColor,
     /// A specific RGBA color
-    RGBA(RGBA),
+    Numeric {
+        /// Parsed RGBA color
+        parsed: RGBA,
+        /// Authored representation
+        authored: Option<Box<str>>,
+    },
 
     /// A system color
     #[cfg(feature = "gecko")]
     System(SystemColor),
     /// A special color keyword value used in Gecko
     #[cfg(feature = "gecko")]
     Special(gecko::SpecialColorKeyword),
     /// Quirksmode-only rule for inheriting color from the body
@@ -45,29 +52,35 @@ mod gecko {
         "-moz-default-color" => MozDefaultColor,
         "-moz-default-background-color" => MozDefaultBackgroundColor,
         "-moz-hyperlinktext" => MozHyperlinktext,
         "-moz-activehyperlinktext" => MozActiveHyperlinktext,
         "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
     }
 }
 
-impl From<CSSParserColor> for Color {
-    fn from(value: CSSParserColor) -> Self {
-        match value {
-            CSSParserColor::CurrentColor => Color::CurrentColor,
-            CSSParserColor::RGBA(x) => Color::RGBA(x),
-        }
-    }
-}
-
 impl Parse for Color {
     fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        // Currently we only store authored value for color keywords,
+        // because all browsers serialize those values as keywords for
+        // specified value.
+        let start_position = input.position();
+        let authored = match input.next() {
+            Ok(Token::Ident(s)) => Some(s.to_lowercase().into_boxed_str()),
+            _ => None,
+        };
+        input.reset(start_position);
         if let Ok(value) = input.try(CSSParserColor::parse) {
-            Ok(value.into())
+            Ok(match value {
+                CSSParserColor::CurrentColor => Color::CurrentColor,
+                CSSParserColor::RGBA(rgba) => Color::Numeric {
+                    parsed: rgba,
+                    authored: authored,
+                },
+            })
         } else {
             #[cfg(feature = "gecko")] {
                 if let Ok(system) = input.try(SystemColor::parse) {
                     Ok(Color::System(system))
                 } else {
                     gecko::SpecialColorKeyword::parse(input).map(Color::Special)
                 }
             }
@@ -77,81 +90,97 @@ impl Parse for Color {
         }
     }
 }
 
 impl ToCss for Color {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         match *self {
             Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
-            Color::RGBA(rgba) => rgba.to_css(dest),
+            Color::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
+            Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
             #[cfg(feature = "gecko")]
             Color::System(system) => system.to_css(dest),
             #[cfg(feature = "gecko")]
             Color::Special(special) => special.to_css(dest),
             #[cfg(feature = "gecko")]
             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>>,
+/// A wrapper of cssparser::Color::parse_hash.
+///
+/// That function should never return CurrentColor, so it makes no sense
+/// to handle a cssparser::Color here. This should really be done in
+/// cssparser directly rather than here.
+fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
+    CSSParserColor::parse_hash(value).map(|color| {
+        match color {
+            CSSParserColor::RGBA(rgba) => rgba,
+            CSSParserColor::CurrentColor =>
+                unreachable!("parse_hash should never return currentcolor"),
+        }
+    })
 }
 
-impl Parse for CSSColor {
-    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_quirky(context, input, AllowQuirks::No)
+impl Color {
+    /// Returns currentcolor value.
+    #[inline]
+    pub fn currentcolor() -> Color {
+        Color::CurrentColor
     }
-}
+
+    /// Returns transparent value.
+    #[inline]
+    pub fn transparent() -> Color {
+        // We should probably set authored to "transparent", but maybe it doesn't matter.
+        Color::rgba(RGBA::transparent())
+    }
 
-impl CSSColor {
+    /// Returns a numeric RGBA color value.
+    #[inline]
+    pub fn rgba(rgba: RGBA) -> Self {
+        Color::Numeric {
+            parsed: rgba,
+            authored: None,
+        }
+    }
+
     /// 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(());
-        }
+        input.try(|i| Self::parse(context, i)).or_else(|_| {
+            if !allow_quirks.allowed(context.quirks_mode) {
+                return Err(());
+            }
+            Color::parse_quirky_color(input).map(|rgba| Color::rgba(rgba))
+        })
+    }
+
+    /// Parse a <quirky-color> value.
+    ///
+    /// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
+    fn parse_quirky_color(input: &mut Parser) -> Result<RGBA, ()> {
         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 parse_hash_color(ident.as_bytes());
             }
             _ => {
                 return Err(());
             },
         };
         let value = number.int_value.ok_or(())?;
         if value < 0 {
             return Err(());
@@ -178,152 +207,98 @@ impl CSSColor {
         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,
-        })
+        parse_hash_color(&serialization)
     }
 
     /// 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,
+        match *self {
+            Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
             _ => 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()
-    }
+#[cfg(feature = "gecko")]
+fn to_rgba(color: nscolor) -> CSSParserColor {
+    use gecko::values::convert_nscolor_to_rgba;
+    CSSParserColor::RGBA(convert_nscolor_to_rgba(color))
 }
 
 impl ToComputedValue for Color {
-    type ComputedValue = RGBA;
+    type ComputedValue = CSSParserColor;
 
-    fn to_computed_value(&self, context: &Context) -> RGBA {
-        #[cfg(feature = "gecko")]
-        use gecko::values::convert_nscolor_to_rgba as to_rgba;
+    fn to_computed_value(&self, _context: &Context) -> CSSParserColor {
         match *self {
-            Color::RGBA(rgba) => rgba,
-            Color::CurrentColor => context.inherited_style.get_color().clone_color(),
+            Color::CurrentColor => CSSParserColor::CurrentColor,
+            Color::Numeric { ref parsed, .. } => CSSParserColor::RGBA(*parsed),
             #[cfg(feature = "gecko")]
-            Color::System(system) => to_rgba(system.to_computed_value(context)),
+            Color::System(system) => to_rgba(system.to_computed_value(_context)),
             #[cfg(feature = "gecko")]
             Color::Special(special) => {
                 use self::gecko::SpecialColorKeyword as Keyword;
-                let pres_context = unsafe { &*context.device.pres_context };
+                let pres_context = unsafe { &*_context.device.pres_context };
                 to_rgba(match special {
                     Keyword::MozDefaultColor => pres_context.mDefaultColor,
                     Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
                     Keyword::MozHyperlinktext => pres_context.mLinkColor,
                     Keyword::MozActiveHyperlinktext => pres_context.mActiveLinkColor,
                     Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
                 })
             }
             #[cfg(feature = "gecko")]
             Color::InheritFromBodyQuirk => {
                 use dom::TElement;
                 use gecko::wrapper::GeckoElement;
                 use gecko_bindings::bindings::Gecko_GetBody;
-                let pres_context = unsafe { &*context.device.pres_context };
+                let pres_context = unsafe { &*_context.device.pres_context };
                 let body = unsafe {
                     Gecko_GetBody(pres_context)
                 };
                 if let Some(body) = body {
                     let wrap = GeckoElement(body);
                     let borrow = wrap.borrow_data();
-                    borrow.as_ref().unwrap()
-                          .styles().primary.values()
-                          .get_color()
-                          .clone_color()
+                    CSSParserColor::RGBA(borrow.as_ref().unwrap()
+                                               .styles().primary.values()
+                                               .get_color()
+                                               .clone_color())
                 } else {
                     to_rgba(pres_context.mDefaultColor)
                 }
             },
         }
     }
 
-    fn from_computed_value(computed: &RGBA) -> Self {
-        Color::RGBA(*computed)
-    }
-}
-
-impl ToComputedValue for CSSColor {
-    type ComputedValue = CSSParserColor;
-
-    #[inline]
-    fn to_computed_value(&self, _context: &Context) -> CSSParserColor {
-        match self.parsed {
-            Color::RGBA(rgba) => CSSParserColor::RGBA(rgba),
-            Color::CurrentColor => CSSParserColor::CurrentColor,
-            // Resolve non-standard -moz keywords to RGBA:
-            #[cfg(feature = "gecko")]
-            non_standard => CSSParserColor::RGBA(non_standard.to_computed_value(_context)),
+    fn from_computed_value(computed: &CSSParserColor) -> Self {
+        match *computed {
+            CSSParserColor::RGBA(rgba) => Color::rgba(rgba),
+            CSSParserColor::CurrentColor => Color::currentcolor(),
         }
     }
-
-    #[inline]
-    fn from_computed_value(computed: &CSSParserColor) -> Self {
-        (match *computed {
-            CSSParserColor::RGBA(rgba) => Color::RGBA(rgba),
-            CSSParserColor::CurrentColor => Color::CurrentColor,
-        }).into()
-    }
 }
 
 /// Specified color value, but resolved to just RGBA for computed value
 /// with value from color property at the same context.
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct RGBAColor(pub CSSColor);
+pub struct RGBAColor(pub Color);
 
 no_viewport_percentage!(RGBAColor);
 
 impl Parse for RGBAColor {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        CSSColor::parse(context, input).map(RGBAColor)
+        Color::parse(context, input).map(RGBAColor)
     }
 }
 
 impl ToCss for RGBAColor {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         self.0.to_css(dest)
     }
 }
@@ -334,29 +309,17 @@ impl ToComputedValue for RGBAColor {
     fn to_computed_value(&self, context: &Context) -> RGBA {
         match self.0.to_computed_value(context) {
             CSSParserColor::RGBA(rgba) => rgba,
             CSSParserColor::CurrentColor => context.style.get_color().clone_color(),
         }
     }
 
     fn from_computed_value(computed: &RGBA) -> Self {
-        RGBAColor(CSSColor {
-            parsed: Color::RGBA(*computed),
-            authored: None,
-        })
+        RGBAColor(Color::rgba(*computed))
     }
 }
 
 impl From<Color> for RGBAColor {
     fn from(color: Color) -> RGBAColor {
-        RGBAColor(CSSColor {
-            parsed: color,
-            authored: None,
-        })
-    }
-}
-
-impl From<CSSColor> for RGBAColor {
-    fn from(color: CSSColor) -> RGBAColor {
         RGBAColor(color)
     }
 }
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -18,17 +18,17 @@ use std::fmt;
 use style_traits::ToCss;
 use values::{Either, None_};
 use values::generics::image::{Circle, CompatMode, Ellipse, ColorStop as GenericColorStop};
 use values::generics::image::{EndingShape as GenericEndingShape, Gradient as GenericGradient};
 use values::generics::image::{GradientItem as GenericGradientItem, GradientKind as GenericGradientKind};
 use values::generics::image::{Image as GenericImage, ImageRect as GenericImageRect};
 use values::generics::image::{LineDirection as GenericsLineDirection, ShapeExtent};
 use values::generics::position::Position as GenericPosition;
-use values::specified::{Angle, CSSColor, Color, Length, LengthOrPercentage};
+use values::specified::{Angle, Color, Length, LengthOrPercentage};
 use values::specified::{Number, NumberOrPercentage, Percentage, RGBAColor};
 use values::specified::position::{Position, PositionComponent, Side, X, Y};
 use values::specified::url::SpecifiedUrl;
 
 /// A specified image layer.
 pub type ImageLayer = Either<None_, Image>;
 
 /// Specified values for an image according to CSS-IMAGES.
@@ -374,18 +374,18 @@ impl Gradient {
                             };
                             i.expect_comma()?;
                             p
                         },
                         "from" => 0.,
                         "to" => 1.,
                         _ => return Err(()),
                     };
-                    let color = CSSColor::parse(context, i)?;
-                    if color.parsed == Color::CurrentColor {
+                    let color = Color::parse(context, i)?;
+                    if color == Color::CurrentColor {
                         return Err(());
                     }
                     Ok((color.into(), p))
                 })?;
                 if reverse_stops {
                     p = 1. - p;
                 }
                 Ok(GenericGradientItem::ColorStop(GenericColorStop {
@@ -393,21 +393,21 @@ impl Gradient {
                     position: Some(LengthOrPercentage::Percentage(Percentage(p))),
                 }))
             })
         }).unwrap_or(vec![]);
 
         if items.is_empty() {
             items = vec![
                 GenericGradientItem::ColorStop(GenericColorStop {
-                    color: CSSColor::transparent().into(),
+                    color: Color::transparent().into(),
                     position: Some(Percentage(0.).into()),
                 }),
                 GenericGradientItem::ColorStop(GenericColorStop {
-                    color: CSSColor::transparent().into(),
+                    color: Color::transparent().into(),
                     position: Some(Percentage(1.).into()),
                 }),
             ];
         } else if items.len() == 1 {
             let first = items[0].clone();
             items.push(first);
         } else {
             items.sort_by(|a, b| {
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -25,17 +25,17 @@ use super::generics::grid::TrackList as 
 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::{CSSColor, Color, RGBAColor};
+pub use self::color::{Color, RGBAColor};
 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};
@@ -671,17 +671,17 @@ pub type TrackListOrNone = Either<TrackL
 #[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct Shadow {
     pub offset_x: Length,
     pub offset_y: Length,
     pub blur_radius: Length,
     pub spread_radius: Length,
-    pub color: Option<CSSColor>,
+    pub color: Option<Color>,
     pub inset: bool,
 }
 
 impl ToComputedValue for Shadow {
     type ComputedValue = ComputedShadow;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
@@ -761,17 +761,17 @@ impl Shadow {
                             }
                         }
                     }
                     lengths_parsed = true;
                     continue
                 }
             }
             if color.is_none() {
-                if let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+                if let Ok(value) = input.try(|i| Color::parse(context, i)) {
                     color = Some(value);
                     continue
                 }
             }
             break
         }
 
         // Lengths must be specified.
@@ -987,17 +987,17 @@ impl ClipRectOrAuto {
             Ok(Either::First(v))
         } else {
             Auto::parse(context, input).map(Either::Second)
         }
     }
 }
 
 /// <color> | auto
-pub type ColorOrAuto = Either<CSSColor, Auto>;
+pub type ColorOrAuto = Either<Color, Auto>;
 
 /// Whether quirks are allowed in this context.
 #[derive(Clone, Copy, PartialEq)]
 pub enum AllowQuirks {
     /// Quirks are allowed.
     Yes,
     /// Quirks are not allowed.
     No,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -2168,20 +2168,20 @@ pub extern "C" fn Servo_DeclarationBlock
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
                                                          RawServoDeclarationBlockBorrowed,
                                                          property: nsCSSPropertyID) {
     use style::properties::{PropertyDeclaration, LonghandId};
-    use style::values::specified::{Color, CSSColor};
+    use style::values::specified::Color;
 
     let long = get_longhand_from_id!(property);
-    let cc = CSSColor { parsed: Color::CurrentColor, authored: None };
+    let cc = Color::currentcolor();
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => cc,
         BorderRightColor => cc,
         BorderBottomColor => cc,
         BorderLeftColor => cc,
     };
     write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
@@ -2192,21 +2192,21 @@ pub extern "C" fn Servo_DeclarationBlock
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
                                                        RawServoDeclarationBlockBorrowed,
                                                        property: nsCSSPropertyID,
                                                        value: structs::nscolor) {
     use style::gecko::values::convert_nscolor_to_rgba;
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands;
-    use style::values::specified::{Color, CSSColor};
+    use style::values::specified::Color;
 
     let long = get_longhand_from_id!(property);
     let rgba = convert_nscolor_to_rgba(value);
-    let color = CSSColor { parsed: Color::RGBA(rgba), authored: None };
+    let color = Color::rgba(rgba);
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => color,
         BorderRightColor => color,
         BorderBottomColor => color,
         BorderLeftColor => color,
         Color => longhands::color::SpecifiedValue(color),
         BackgroundColor => color,
--- a/servo/tests/unit/style/parsing/ui.rs
+++ b/servo/tests/unit/style/parsing/ui.rs
@@ -1,16 +1,16 @@
 /* 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/. */
 
 use cssparser::RGBA;
 use parsing::parse;
 use style::values::{Auto, Either};
-use style::values::specified::{CSSColor, Color};
+use style::values::specified::Color;
 use style_traits::ToCss;
 
 #[test]
 fn test_moz_user_select() {
     use style::properties::longhands::_moz_user_select;
 
     assert_roundtrip_with_context!(_moz_user_select::parse, "auto");
     assert_roundtrip_with_context!(_moz_user_select::parse, "text");
@@ -28,21 +28,21 @@ fn test_moz_user_select() {
 
 #[test]
 fn test_caret_color() {
     use style::properties::longhands::caret_color;
 
     let auto = parse_longhand!(caret_color, "auto");
     assert_eq!(auto, Either::Second(Auto));
 
-    let blue_color = CSSColor {
-        parsed: Color::RGBA(RGBA {
+    let blue_color = Color::Numeric {
+        parsed: RGBA {
             red: 0,
             green: 0,
             blue: 255,
             alpha: 255,
-        }),
+        },
         authored: Some(String::from("blue").into_boxed_str()),
     };
 
     let color = parse_longhand!(caret_color, "blue");
     assert_eq!(color, Either::First(blue_color));
 }
--- a/servo/tests/unit/style/properties/serialization.rs
+++ b/servo/tests/unit/style/properties/serialization.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use properties::parse;
 use style::computed_values::display::T::inline_block;
 use style::properties::{PropertyDeclaration, Importance, PropertyId};
 use style::properties::parse_property_declaration_list;
 use style::values::{RGBA, Auto};
 use style::values::CustomIdent;
-use style::values::specified::{BorderStyle, BorderSideWidth, CSSColor, Color};
+use style::values::specified::{BorderStyle, BorderSideWidth, Color};
 use style::values::specified::{Length, LengthOrPercentage};
 use style::values::specified::{LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
 use style::values::specified::{NoCalcLength, PositionComponent};
 use style::values::specified::position::Y;
 use style::values::specified::url::SpecifiedUrl;
 use style_traits::ToCss;
 use stylesheets::block_from;
 
@@ -105,36 +105,33 @@ mod shorthand_serialization {
         use super::*;
 
         #[test]
         fn text_decoration_should_show_all_properties_when_set() {
             let mut properties = Vec::new();
 
             let line = TextDecorationLine::OVERLINE;
             let style = TextDecorationStyle::dotted;
-            let color = CSSColor {
-                parsed: Color::RGBA(RGBA::new(128, 0, 128, 255)),
-                authored: None
-            };
+            let color = Color::rgba(RGBA::new(128, 0, 128, 255));
 
             properties.push(PropertyDeclaration::TextDecorationLine(line));
             properties.push(PropertyDeclaration::TextDecorationStyle(style));
             properties.push(PropertyDeclaration::TextDecorationColor(color));
 
             let serialization = shorthand_properties_to_string(properties);
             assert_eq!(serialization, "text-decoration: overline dotted rgb(128, 0, 128);");
         }
 
         #[test]
         fn text_decoration_should_not_serialize_initial_style_value() {
             let mut properties = Vec::new();
 
             let line = TextDecorationLine::UNDERLINE;
             let style = TextDecorationStyle::solid;
-            let color = CSSColor::currentcolor();
+            let color = Color::currentcolor();
 
             properties.push(PropertyDeclaration::TextDecorationLine(line));
             properties.push(PropertyDeclaration::TextDecorationStyle(style));
             properties.push(PropertyDeclaration::TextDecorationColor(color));
 
             let serialization = shorthand_properties_to_string(properties);
             assert_eq!(serialization, "text-decoration: underline;");
         }
@@ -224,20 +221,17 @@ mod shorthand_serialization {
           let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
           let px_10 = BorderSideWidth::Length(Length::from_px(10f32));
 
           properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
           properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
           properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
           properties.push(PropertyDeclaration::BorderLeftWidth(px_10.clone()));
 
-          let blue = CSSColor {
-              parsed: Color::RGBA(RGBA::new(0, 0, 255, 255)),
-              authored: None
-          };
+          let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
 
           properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
           properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
           properties.push(PropertyDeclaration::BorderBottomColor(blue.clone()));
           properties.push(PropertyDeclaration::BorderLeftColor(blue.clone()));
 
           let serialization = shorthand_properties_to_string(properties);
           assert_eq!(serialization,
@@ -257,20 +251,17 @@ mod shorthand_serialization {
 
           let px_30 = BorderSideWidth::Length(Length::from_px(30f32));
 
           properties.push(PropertyDeclaration::BorderTopWidth(px_30.clone()));
           properties.push(PropertyDeclaration::BorderRightWidth(px_30.clone()));
           properties.push(PropertyDeclaration::BorderBottomWidth(px_30.clone()));
           properties.push(PropertyDeclaration::BorderLeftWidth(px_30.clone()));
 
-          let blue = CSSColor {
-              parsed: Color::RGBA(RGBA::new(0, 0, 255, 255)),
-              authored: None
-          };
+          let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
 
           properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
           properties.push(PropertyDeclaration::BorderRightColor(blue.clone()));
           properties.push(PropertyDeclaration::BorderBottomColor(blue.clone()));
           properties.push(PropertyDeclaration::BorderLeftColor(blue.clone()));
 
           let serialization = shorthand_properties_to_string(properties);
           assert_eq!(serialization, "border-style: solid; border-width: 30px; border-color: rgb(0, 0, 255);");
@@ -327,25 +318,18 @@ mod shorthand_serialization {
             let serialization = shorthand_properties_to_string(properties);
             assert_eq!(serialization, "border-width: thin medium thick 15px;");
         }
 
         #[test]
         fn border_color_should_serialize_correctly() {
             let mut properties = Vec::new();
 
-            let red = CSSColor {
-                parsed: Color::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
-
-            let blue = CSSColor {
-                parsed: Color::RGBA(RGBA::new(0, 0, 255, 255)),
-                authored: None
-            };
+            let red = Color::rgba(RGBA::new(255, 0, 0, 255));
+            let blue = Color::rgba(RGBA::new(0, 0, 255, 255));
 
             properties.push(PropertyDeclaration::BorderTopColor(blue.clone()));
             properties.push(PropertyDeclaration::BorderRightColor(red.clone()));
             properties.push(PropertyDeclaration::BorderBottomColor(blue));
             properties.push(PropertyDeclaration::BorderLeftColor(red));
 
             let serialization = shorthand_properties_to_string(properties);
 
@@ -400,33 +384,30 @@ mod shorthand_serialization {
         // but afterwards, we only need to to one test per "directional border shorthand"
 
         #[test]
         fn directional_border_should_show_all_properties_when_values_are_set() {
             let mut properties = Vec::new();
 
             let width = BorderSideWidth::Length(Length::from_px(4f32));
             let style = BorderStyle::solid;
-            let color = CSSColor {
-                parsed: Color::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
+            let color = Color::rgba(RGBA::new(255, 0, 0, 255));
 
             properties.push(PropertyDeclaration::BorderTopWidth(width));
             properties.push(PropertyDeclaration::BorderTopStyle(style));
             properties.push(PropertyDeclaration::BorderTopColor(color));
 
             let serialization = shorthand_properties_to_string(properties);
             assert_eq!(serialization, "border-top: 4px solid rgb(255, 0, 0);");
         }
 
-        fn get_border_property_values() -> (BorderSideWidth, BorderStyle, CSSColor) {
+        fn get_border_property_values() -> (BorderSideWidth, BorderStyle, Color) {
             (BorderSideWidth::Length(Length::from_px(4f32)),
              BorderStyle::solid,
-             CSSColor::currentcolor())
+             Color::currentcolor())
         }
 
         #[test]
         fn border_top_should_serialize_correctly() {
             let mut properties = Vec::new();
             let (width, style, color) = get_border_property_values();
             properties.push(PropertyDeclaration::BorderTopWidth(width));
             properties.push(PropertyDeclaration::BorderTopStyle(style));
@@ -527,39 +508,33 @@ mod shorthand_serialization {
         use super::*;
 
         #[test]
         fn outline_should_show_all_properties_when_set() {
             let mut properties = Vec::new();
 
             let width = BorderSideWidth::Length(Length::from_px(4f32));
             let style = Either::Second(BorderStyle::solid);
-            let color = CSSColor {
-                parsed: Color::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
+            let color = Color::rgba(RGBA::new(255, 0, 0, 255));
 
             properties.push(PropertyDeclaration::OutlineWidth(width));
             properties.push(PropertyDeclaration::OutlineStyle(style));
             properties.push(PropertyDeclaration::OutlineColor(color));
 
             let serialization = shorthand_properties_to_string(properties);
             assert_eq!(serialization, "outline: 4px solid rgb(255, 0, 0);");
         }
 
         #[test]
         fn outline_should_serialize_correctly_when_style_is_auto() {
             let mut properties = Vec::new();
 
             let width = BorderSideWidth::Length(Length::from_px(4f32));
             let style = Either::First(Auto);
-            let color = CSSColor {
-                parsed: Color::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
+            let color = Color::rgba(RGBA::new(255, 0, 0, 255));
             properties.push(PropertyDeclaration::OutlineWidth(width));
             properties.push(PropertyDeclaration::OutlineStyle(style));
             properties.push(PropertyDeclaration::OutlineColor(color));
 
             let serialization = shorthand_properties_to_string(properties);
             assert_eq!(serialization, "outline: 4px auto rgb(255, 0, 0);");
         }
     }
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -21,17 +21,17 @@ use style::properties::{CSSWideKeyword, 
 use style::properties::longhands;
 use style::properties::longhands::animation_play_state;
 use style::shared_lock::SharedRwLock;
 use style::stylearc::Arc;
 use style::stylesheets::{Origin, Namespaces};
 use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule};
 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframePercentage};
 use style::values::{KeyframesName, CustomIdent};
-use style::values::specified::{Color, LengthOrPercentageOrAuto, Percentage, PositionComponent};
+use style::values::specified::{LengthOrPercentageOrAuto, Percentage, PositionComponent};
 
 pub fn block_from<I>(iterable: I) -> PropertyDeclarationBlock
 where I: IntoIterator<Item=(PropertyDeclaration, Importance)> {
     let mut block = PropertyDeclarationBlock::new();
     for (d, i) in iterable {
         block.push(d, i)
     }
     block
@@ -153,19 +153,19 @@ fn test_parse_stylesheet() {
                         Component::ID(Atom::from("d1")),
                         Component::Combinator(Combinator::Child),
                         Component::DefaultNamespace(NsAtom::from("http://www.w3.org/1999/xhtml")),
                         Component::Class(Atom::from("ok"))
                     ), (1 << 20) + (1 << 10) + (0 << 0))
                 )),
                 block: Arc::new(stylesheet.shared_lock.wrap(block_from(vec![
                     (PropertyDeclaration::BackgroundColor(
-                        longhands::background_color::SpecifiedValue {
+                        longhands::background_color::SpecifiedValue::Numeric {
                             authored: Some("blue".to_owned().into_boxed_str()),
-                            parsed: Color::RGBA(cssparser::RGBA::new(0, 0, 255, 255)),
+                            parsed: cssparser::RGBA::new(0, 0, 255, 255),
                         }
                      ),
                      Importance::Normal),
                     (PropertyDeclaration::BackgroundPositionX(
                         longhands::background_position_x::SpecifiedValue(
                         vec![PositionComponent::zero()])),
                      Importance::Normal),
                     (PropertyDeclaration::BackgroundPositionY(