servo: Merge #17219 - Support interpolation between currentcolor and numeric color (from upsuper:currentcolor); r=Manishearth,birtles
authorXidorn Quan <me@upsuper.org>
Wed, 07 Jun 2017 21:03:52 -0700
changeset 362956 b1628969b8330e235e62664d966b38fa560fbb23
parent 362955 66124e23e8d8637de199d3ede303ec3cb9672f55
child 362957 e1880a72e41e5718754a6321e87b5923348908c0
push id91212
push usercbook@mozilla.com
push dateThu, 08 Jun 2017 13:18:08 +0000
treeherdermozilla-inbound@280dedc5b8c8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth, birtles
bugs1345709
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #17219 - Support interpolation between currentcolor and numeric color (from upsuper:currentcolor); r=Manishearth,birtles This is the Servo side change of [bug 1345709](https://bugzilla.mozilla.org/show_bug.cgi?id=1345709). Source-Repo: https://github.com/servo/servo Source-Revision: 24e944ad94816e607e833e34095c4f8b8136df4c
servo/Cargo.lock
servo/components/layout/Cargo.toml
servo/components/layout/display_list_builder.rs
servo/components/layout/lib.rs
servo/components/layout/table_cell.rs
servo/components/layout/table_row.rs
servo/components/script/dom/element.rs
servo/components/style/gecko/conversions.rs
servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
servo/components/style/gecko_bindings/sugar/style_complex_color.rs
servo/components/style/properties/data.py
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.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/svg.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/color.rs
servo/components/style/values/computed/image.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/components/style/values/specified/mod.rs.rej
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/Cargo.lock
+++ b/servo/Cargo.lock
@@ -1414,17 +1414,16 @@ source = "registry+https://github.com/ru
 [[package]]
 name = "layout"
 version = "0.0.1"
 dependencies = [
  "app_units 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "canvas_traits 0.0.1",
- "cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gfx 0.0.1",
  "gfx_traits 0.0.1",
  "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "html5ever 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/servo/components/layout/Cargo.toml
+++ b/servo/components/layout/Cargo.toml
@@ -9,17 +9,16 @@ publish = false
 name = "layout"
 path = "lib.rs"
 
 [dependencies]
 app_units = "0.4.1"
 atomic_refcell = "0.1"
 bitflags = "0.7"
 canvas_traits = {path = "../canvas_traits"}
-cssparser = "0.13.7"
 euclid = "0.13"
 fnv = "1.0"
 gfx = {path = "../gfx"}
 gfx_traits = {path = "../gfx_traits"}
 heapsize = "0.4"
 html5ever = "0.17"
 ipc-channel = "0.7"
 libc = "0.2"
--- a/servo/components/layout/display_list_builder.rs
+++ b/servo/components/layout/display_list_builder.rs
@@ -417,27 +417,25 @@ pub trait FragmentDisplayListBuilding {
                                                        clip: &ClippingRegion,
                                                        paint_worklet: &PaintWorklet,
                                                        index: usize);
 
     fn convert_linear_gradient(&self,
                                bounds: &Rect<Au>,
                                stops: &[GradientItem],
                                direction: &LineDirection,
-                               repeating: bool,
-                               style: &ServoComputedValues)
+                               repeating: bool)
                                -> display_list::Gradient;
 
     fn convert_radial_gradient(&self,
                                bounds: &Rect<Au>,
                                stops: &[GradientItem],
                                shape: &EndingShape,
                                center: &Position,
-                               repeating: bool,
-                               style: &ServoComputedValues)
+                               repeating: bool)
                                -> display_list::RadialGradient;
 
     /// Adds the display items necessary to paint the background linear gradient of this fragment
     /// to the appropriate section of the display list.
     fn build_display_list_for_background_gradient(&self,
                                                   state: &mut DisplayListBuildState,
                                                   display_list_section: DisplayListSection,
                                                   absolute_bounds: &Rect<Au>,
@@ -629,18 +627,17 @@ fn build_border_radius_for_inner_rect(ou
     radii.top_right.height = cmp::max(Au(0), radii.top_right.height - border_widths.top);
 
     radii.bottom_left.height = cmp::max(Au(0), radii.bottom_left.height - border_widths.bottom);
     radii.bottom_right.height = cmp::max(Au(0), radii.bottom_right.height - border_widths.bottom);
     radii
 }
 
 fn convert_gradient_stops(gradient_items: &[GradientItem],
-                          total_length: Au,
-                          style: &ServoComputedValues) -> Vec<GradientStop> {
+                          total_length: Au) -> Vec<GradientStop> {
     // Determine the position of each stop per CSS-IMAGES ยง 3.4.
 
     // Only keep the color stops, discard the color interpolation hints.
     let mut stop_items = gradient_items.iter().filter_map(|item| {
         match *item {
             GenericGradientItem::ColorStop(ref stop) => Some(*stop),
             _ => None,
         }
@@ -717,17 +714,17 @@ fn convert_gradient_stops(gradient_items
             }
             Some(position) => {
                 stop_run = None;
                 position_to_offset(position, total_length)
             }
         };
         stops.push(GradientStop {
             offset: offset,
-            color: style.resolve_color(stop.color).to_gfx_color()
+            color: stop.color.to_gfx_color()
         })
     }
     stops
 }
 
 #[inline]
 /// Duplicate the first and last stops if necessary.
 ///
@@ -1187,18 +1184,17 @@ impl FragmentDisplayListBuilding for Fra
                                                     WebRenderImageInfo::from_image(&image),
                                                     index);
     }
 
     fn convert_linear_gradient(&self,
                                bounds: &Rect<Au>,
                                stops: &[GradientItem],
                                direction: &LineDirection,
-                               repeating: bool,
-                               style: &ServoComputedValues)
+                               repeating: bool)
                                -> display_list::Gradient {
         let angle = match *direction {
             LineDirection::Angle(angle) => angle.radians(),
             LineDirection::Corner(horizontal, vertical) => {
                 // This the angle for one of the diagonals of the box. Our angle
                 // will either be this one, this one + PI, or one of the other
                 // two perpendicular angles.
                 let atan = (bounds.size.height.to_f32_px() /
@@ -1229,17 +1225,17 @@ impl FragmentDisplayListBuilding for Fra
         // of the distance between the starting point and the ending point.
         let delta = Point2D::new(Au::from_f32_px(dir.x * inv_dir_length * line_length / 2.0),
                                  Au::from_f32_px(dir.y * inv_dir_length * line_length / 2.0));
 
         // This is the length of the gradient line.
         let length = Au::from_f32_px(
             (delta.x.to_f32_px() * 2.0).hypot(delta.y.to_f32_px() * 2.0));
 
-        let mut stops = convert_gradient_stops(stops, length, style);
+        let mut stops = convert_gradient_stops(stops, length);
 
         // Only clamped gradients need to be fixed because in repeating gradients
         // there is no "first" or "last" stop because they repeat infinitly in
         // both directions, so the rendering is always correct.
         if !repeating {
             fix_gradient_stops(&mut stops);
         }
 
@@ -1253,18 +1249,17 @@ impl FragmentDisplayListBuilding for Fra
         }
     }
 
     fn convert_radial_gradient(&self,
                                bounds: &Rect<Au>,
                                stops: &[GradientItem],
                                shape: &EndingShape,
                                center: &Position,
-                               repeating: bool,
-                               style: &ServoComputedValues)
+                               repeating: bool)
                                -> display_list::RadialGradient {
         let center = Point2D::new(center.horizontal.to_used_value(bounds.size.width),
                                   center.vertical.to_used_value(bounds.size.height));
         let radius = match *shape {
             GenericEndingShape::Circle(Circle::Radius(length)) => {
                 Size2D::new(length, length)
             },
             GenericEndingShape::Circle(Circle::Extent(extent)) => {
@@ -1273,17 +1268,17 @@ impl FragmentDisplayListBuilding for Fra
             GenericEndingShape::Ellipse(Ellipse::Radii(x, y)) => {
                 Size2D::new(x.to_used_value(bounds.size.width), y.to_used_value(bounds.size.height))
             },
             GenericEndingShape::Ellipse(Ellipse::Extent(extent)) => {
                 convert_ellipse_size_keyword(extent, &bounds.size, &center)
             },
         };
 
-        let mut stops = convert_gradient_stops(stops, radius.width, style);
+        let mut stops = convert_gradient_stops(stops, radius.width);
         // Repeating gradients have no last stops that can be ignored. So
         // fixup is not necessary but may actually break the gradient.
         if !repeating {
             fix_gradient_stops(&mut stops);
         }
 
         display_list::RadialGradient {
             center: center,
@@ -1317,30 +1312,28 @@ impl FragmentDisplayListBuilding for Fra
                                                   style.get_cursor(Cursor::Default),
                                                   display_list_section);
 
         let display_item = match gradient.kind {
             GradientKind::Linear(ref angle_or_corner) => {
                 let gradient = self.convert_linear_gradient(&bounds,
                                                             &gradient.items[..],
                                                             angle_or_corner,
-                                                            gradient.repeating,
-                                                            style);
+                                                            gradient.repeating);
                 DisplayItem::Gradient(box GradientDisplayItem {
                     base: base,
                     gradient: gradient,
                 })
             }
             GradientKind::Radial(ref shape, ref center) => {
                 let gradient = self.convert_radial_gradient(&bounds,
                                                             &gradient.items[..],
                                                             shape,
                                                             center,
-                                                            gradient.repeating,
-                                                            style);
+                                                            gradient.repeating);
                 DisplayItem::RadialGradient(box RadialGradientDisplayItem {
                     base: base,
                     gradient: gradient,
                 })
             }
         };
         state.add_display_item(display_item);
     }
@@ -1454,18 +1447,17 @@ impl FragmentDisplayListBuilding for Fra
                 }));
             }
             Either::Second(Image::Gradient(ref gradient)) => {
                 match gradient.kind {
                     GradientKind::Linear(angle_or_corner) => {
                         let grad = self.convert_linear_gradient(&bounds,
                                                                 &gradient.items[..],
                                                                 &angle_or_corner,
-                                                                gradient.repeating,
-                                                                style);
+                                                                gradient.repeating);
 
                         state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
                             base: base,
                             border_widths: border.to_physical(style.writing_mode),
                             details: BorderDetails::Gradient(display_list::GradientBorder {
                                 gradient: grad,
 
                                 // TODO(gw): Support border-image-outset
@@ -1473,18 +1465,17 @@ impl FragmentDisplayListBuilding for Fra
                             }),
                         }));
                     }
                     GradientKind::Radial(ref shape, ref center) => {
                         let grad = self.convert_radial_gradient(&bounds,
                                                                 &gradient.items[..],
                                                                 shape,
                                                                 center,
-                                                                gradient.repeating,
-                                                                style);
+                                                                gradient.repeating);
                         state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
                             base: base,
                             border_widths: border.to_physical(style.writing_mode),
                             details: BorderDetails::RadialGradient(
                                 display_list::RadialGradientBorder {
                                     gradient: grad,
 
                                     // TODO(gw): Support border-image-outset
--- a/servo/components/layout/lib.rs
+++ b/servo/components/layout/lib.rs
@@ -11,17 +11,16 @@
 #![feature(step_by)]
 
 extern crate app_units;
 extern crate atomic_refcell;
 #[macro_use]
 extern crate bitflags;
 extern crate canvas_traits;
 extern crate core;
-extern crate cssparser;
 extern crate euclid;
 extern crate fnv;
 extern crate gfx;
 extern crate gfx_traits;
 extern crate heapsize;
 #[macro_use] extern crate html5ever;
 extern crate ipc_channel;
 extern crate libc;
--- a/servo/components/layout/table_cell.rs
+++ b/servo/components/layout/table_cell.rs
@@ -4,29 +4,29 @@
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
 use context::LayoutContext;
-use cssparser::Color;
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
 use flow::{self, Flow, FlowClass, IS_ABSOLUTELY_POSITIONED, OpaqueFlow};
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use model::MaybeAuto;
 use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;
 use std::fmt;
 use style::computed_values::{border_collapse, border_top_style, vertical_align};
 use style::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
 use style::properties::ServoComputedValues;
+use style::values::computed::Color;
 use table::InternalTable;
 use table_row::{CollapsedBorder, CollapsedBorderProvenance};
 
 /// A table formatting context.
 #[derive(Serialize)]
 pub struct TableCellFlow {
     /// Data common to all block flows.
     pub block_flow: BlockFlow,
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -4,34 +4,33 @@
 
 //! CSS table formatting contexts.
 
 #![deny(unsafe_code)]
 
 use app_units::Au;
 use block::{BlockFlow, ISizeAndMarginsComputer};
 use context::LayoutContext;
-use cssparser::{Color, RGBA};
 use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode, DisplayListBuildState};
 use euclid::Point2D;
 use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
 use flow_list::MutFlowListIterator;
 use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
 use gfx_traits::print_tree::PrintTree;
 use layout_debug;
 use model::MaybeAuto;
 use serde::{Serialize, Serializer};
 use std::cmp::max;
 use std::fmt;
 use std::iter::{Enumerate, IntoIterator, Peekable};
 use style::computed_values::{border_collapse, border_spacing, border_top_style};
 use style::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
 use style::properties::ServoComputedValues;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW};
-use style::values::computed::LengthOrPercentageOrAuto;
+use style::values::computed::{Color, LengthOrPercentageOrAuto};
 use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, VecExt};
 use table_cell::{CollapsedBordersForCell, TableCellFlow};
 
 /// A single row of a table.
 pub struct TableRowFlow {
     /// Fields common to all block flows.
     pub block_flow: BlockFlow,
 
@@ -601,17 +600,17 @@ pub enum CollapsedBorderProvenance {
 }
 
 impl CollapsedBorder {
     /// Creates a collapsible border style for no border.
     pub fn new() -> CollapsedBorder {
         CollapsedBorder {
             style: border_top_style::T::none,
             width: Au(0),
-            color: Color::RGBA(RGBA::transparent()),
+            color: Color::transparent(),
             provenance: CollapsedBorderProvenance::FromTable,
         }
     }
 
     /// Creates a collapsed border from the block-start border described in the given CSS style
     /// object.
     fn top(css_style: &ServoComputedValues, provenance: CollapsedBorderProvenance)
            -> CollapsedBorder {
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -1,15 +1,14 @@
 /* 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/. */
 
 //! Element nodes.
 
-use cssparser::Color;
 use devtools_traits::AttrInfo;
 use dom::activation::Activatable;
 use dom::attr::{Attr, AttrHelpersForLayout};
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
 use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
 use dom::bindings::codegen::Bindings::ElementBinding;
 use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
@@ -108,17 +107,17 @@ use style::rule_tree::CascadeLevel;
 use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
 use style::selector_parser::extended_filtering;
 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};
+use style::values::specified;
 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 {
@@ -417,18 +416,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.into())
+            ));
         }
 
         let background = if let Some(this) = self.downcast::<HTMLBodyElement>() {
             this.get_background()
         } else {
             None
         };
 
@@ -452,20 +451,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.into())
                 )
             ));
         }
 
         let font_family = if let Some(this) = self.downcast::<HTMLFontElement>() {
             this.get_face()
         } else {
             None
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -178,17 +178,16 @@ impl nsStyleImage {
                 unsafe {
                     Gecko_SetImageElement(self, element.as_ptr());
                 }
             }
         }
     }
 
     fn set_gradient(&mut self, gradient: Gradient) {
-        use cssparser::Color as CSSColor;
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
         use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
         use gecko_bindings::structs::nsStyleCoord;
         use values::computed::image::LineDirection;
         use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
         use values::specified::position::{X, Y};
@@ -316,29 +315,17 @@ impl nsStyleImage {
 
             let mut gecko_stop = unsafe {
                 &mut (*gecko_gradient).mStops[index]
             };
             let mut coord = nsStyleCoord::null();
 
             match *item {
                 GradientItem::ColorStop(ref stop) => {
-                    gecko_stop.mColor = match stop.color {
-                        CSSColor::CurrentColor => {
-                            // TODO(emilio): gecko just stores an nscolor,
-                            // and it doesn't seem to support currentColor
-                            // as value in a gradient.
-                            //
-                            // Double-check it and either remove
-                            // currentColor for servo or see how gecko
-                            // handles this.
-                            0
-                        },
-                        CSSColor::RGBA(ref rgba) => convert_rgba_to_nscolor(rgba),
-                    };
+                    gecko_stop.mColor = convert_rgba_to_nscolor(&stop.color);
                     gecko_stop.mIsInterpolationHint = false;
                     coord.set(stop.position);
                 },
                 GradientItem::InterpolationHint(hint) => {
                     gecko_stop.mIsInterpolationHint = true;
                     coord.set(Some(hint));
                 }
             }
--- a/servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
@@ -1,43 +1,42 @@
 /* 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/. */
 
 //! Rust helpers for Gecko's `nsCSSShadowItem`.
 
 use app_units::Au;
-use cssparser::Color;
 use gecko::values::{convert_rgba_to_nscolor, convert_nscolor_to_rgba};
 use gecko_bindings::structs::nsCSSShadowItem;
-use values::computed::Shadow;
+use values::computed::{Color, Shadow};
 
 impl nsCSSShadowItem {
     /// Set this item to the given shadow value.
     pub fn set_from_shadow(&mut self, other: Shadow) {
         self.mXOffset = other.offset_x.0;
         self.mYOffset = other.offset_y.0;
         self.mRadius = other.blur_radius.0;
         self.mSpread = other.spread_radius.0;
         self.mInset = other.inset;
-        self.mColor = match other.color {
-            Color::RGBA(rgba) => {
-                self.mHasColor = true;
-                convert_rgba_to_nscolor(&rgba)
-            },
+        if other.color.is_currentcolor() {
             // TODO handle currentColor
             // https://bugzilla.mozilla.org/show_bug.cgi?id=760345
-            Color::CurrentColor => 0,
+            self.mHasColor = false;
+            self.mColor = 0;
+        } else {
+            self.mHasColor = true;
+            self.mColor = convert_rgba_to_nscolor(&other.color.color);
         }
     }
 
     /// Generate shadow value from this shadow item.
     pub fn to_shadow(&self) -> Shadow {
         Shadow {
             offset_x: Au(self.mXOffset),
             offset_y: Au(self.mYOffset),
             blur_radius: Au(self.mRadius),
             spread_radius: Au(self.mSpread),
             inset: self.mInset,
-            color: Color::RGBA(convert_nscolor_to_rgba(self.mColor)),
+            color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
         }
     }
 }
--- a/servo/components/style/gecko_bindings/sugar/style_complex_color.rs
+++ b/servo/components/style/gecko_bindings/sugar/style_complex_color.rs
@@ -1,18 +1,18 @@
 /* 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/. */
 
 //! Rust helpers to interact with Gecko's StyleComplexColor.
 
-use cssparser;
 use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
 use gecko_bindings::structs::{nscolor, StyleComplexColor};
-use values;
+use values::{Auto, Either};
+use values::computed::Color as ComputedColor;
 
 impl From<nscolor> for StyleComplexColor {
     fn from(other: nscolor) -> Self {
         StyleComplexColor {
             mColor: other,
             mForegroundRatio: 0,
             mIsAuto: false,
         }
@@ -34,45 +34,46 @@ impl StyleComplexColor {
         StyleComplexColor {
             mColor: 0,
             mForegroundRatio: 255,
             mIsAuto: true,
         }
     }
 }
 
-impl From<cssparser::Color> for StyleComplexColor {
-    fn from(other: cssparser::Color) -> Self {
-        use cssparser::Color;
-
-        match other {
-            Color::RGBA(rgba) => convert_rgba_to_nscolor(&rgba).into(),
-            Color::CurrentColor => StyleComplexColor::current_color(),
+impl From<ComputedColor> for StyleComplexColor {
+    fn from(other: ComputedColor) -> Self {
+        StyleComplexColor {
+            mColor: convert_rgba_to_nscolor(&other.color).into(),
+            mForegroundRatio: other.foreground_ratio,
+            mIsAuto: false,
         }
     }
 }
 
-impl From<StyleComplexColor> for values::computed::ColorOrAuto {
-    fn from(color: StyleComplexColor) -> Self {
-        use values::{Auto, Either};
-
-        if color.mIsAuto {
-            return Either::Second(Auto);
+impl From<StyleComplexColor> for ComputedColor {
+    fn from(other: StyleComplexColor) -> Self {
+        debug_assert!(!other.mIsAuto);
+        ComputedColor {
+            color: convert_nscolor_to_rgba(other.mColor),
+            foreground_ratio: other.mForegroundRatio,
         }
-
-        Either::First(color.into())
     }
 }
 
-impl From<StyleComplexColor> for cssparser::Color {
-    fn from(other: StyleComplexColor) -> Self {
-        use cssparser::Color;
-
-        if other.mForegroundRatio == 0 {
-            Color::RGBA(convert_nscolor_to_rgba(other.mColor))
-        } else if other.mForegroundRatio == 255 {
-            Color::CurrentColor
-        } else {
-            // FIXME #13546 handle interpolation values
-            Color::CurrentColor
+impl From<Either<ComputedColor, Auto>> for StyleComplexColor {
+    fn from(other: Either<ComputedColor, Auto>) -> Self {
+        match other {
+            Either::First(color) => color.into(),
+            Either::Second(_auto) => StyleComplexColor::auto(),
         }
     }
 }
+
+impl From<StyleComplexColor> for Either<ComputedColor, Auto> {
+    fn from(other: StyleComplexColor) -> Self {
+        if !other.mIsAuto {
+            Either::First(other.into())
+        } else {
+            Either::Second(Auto)
+        }
+    }
+}
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -143,17 +143,17 @@ def arg_to_bool(arg):
     assert arg in ["True", "False"]
     return arg == "True"
 
 
 class Longhand(object):
     def __init__(self, style_struct, name, spec=None, animation_value_type=None, derived_from=None, keyword=None,
                  predefined_type=None, custom_cascade=False, experimental=False, internal=False,
                  need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False,
-                 allowed_in_keyframe_block=True, complex_color=False, cast_type='u8',
+                 allowed_in_keyframe_block=True, cast_type='u8',
                  has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False,
                  flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False,
                  vector=False):
         self.name = name
         if not spec:
             raise TypeError("Spec should be specified for %s" % name)
         self.spec = spec
         self.keyword = keyword
@@ -164,17 +164,16 @@ class Longhand(object):
         self.experimental = ("layout.%s.enabled" % name) if experimental else None
         self.custom_cascade = custom_cascade
         self.internal = internal
         self.need_index = need_index
         self.has_uncacheable_values = has_uncacheable_values
         self.gecko_ffi_name = gecko_ffi_name or "m" + self.camel_case
         self.depend_on_viewport_size = depend_on_viewport_size
         self.derived_from = (derived_from or "").split()
-        self.complex_color = complex_color
         self.cast_type = cast_type
         self.logical = arg_to_bool(logical)
         self.alias = alias.split() if alias else []
         self.extra_prefixes = extra_prefixes.split() if extra_prefixes else []
         self.boxed = arg_to_bool(boxed)
         self.flags = flags.split() if flags else []
         self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule)
         self.allow_quirks = allow_quirks
--- 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
@@ -38,17 +37,17 @@ use gecko_bindings::bindings::Gecko_NewC
 use gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
 use gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
 use gecko_bindings::bindings::Gecko_SetListStyleImageNone;
 use gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
 use gecko_bindings::bindings::Gecko_SetNullImageValue;
 use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
 use gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
 use gecko_bindings::bindings::RawGeckoPresContextBorrowed;
-use gecko_bindings::structs::{self, StyleComplexColor};
+use gecko_bindings::structs;
 use gecko_bindings::structs::nsCSSPropertyID;
 use gecko_bindings::structs::nsStyleVariables;
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
 use gecko_bindings::sugar::ownership::HasArcFFI;
 use gecko::values::convert_nscolor_to_rgba;
 use gecko::values::convert_rgba_to_nscolor;
 use gecko::values::GeckoStyleCoordConvertible;
 use gecko::values::round_border_to_device_pixels;
@@ -311,57 +310,36 @@ def set_gecko_property(ffi_name, expr):
             % endfor
             % if keyword.gecko_inexhaustive:
             x => panic!("Found unexpected value in style struct for ${ident} property: {:?}", x),
             % endif
         }
     }
 </%def>
 
-/// Convert a Servo color into an nscolor; with currentColor as 0
-///
-/// Call sites will need to be updated after https://bugzilla.mozilla.org/show_bug.cgi?id=760345
-fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
-    match color {
-        Color::RGBA(rgba) => {
-            convert_rgba_to_nscolor(&rgba)
-        },
-        Color::CurrentColor => 0,
-    }
-}
-
-<%def name="impl_color_setter(ident, gecko_ffi_name, complex_color=True)">
+<%def name="impl_color_setter(ident, gecko_ffi_name)">
     #[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 = color_to_nscolor_zero_currentcolor(v);
-        % 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)">
+<%def name="impl_color_copy(ident, gecko_ffi_name)">
     #[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)">
+<%def name="impl_color_clone(ident, gecko_ffi_name)">
     #[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>
@@ -403,25 +381,39 @@ fn color_to_nscolor_zero_currentcolor(co
             longhands::${ident}::computed_value::T {
                 horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(),
                 vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(),
             }
         }
     % endif
 </%def>
 
-<%def name="impl_color(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
-<%call expr="impl_color_setter(ident, gecko_ffi_name, complex_color)"></%call>
-<%call expr="impl_color_copy(ident, gecko_ffi_name, complex_color)"></%call>
+<%def name="impl_color(ident, gecko_ffi_name, need_clone=False)">
+<%call expr="impl_color_setter(ident, gecko_ffi_name)"></%call>
+<%call expr="impl_color_copy(ident, gecko_ffi_name)"></%call>
 % if need_clone:
-    <%call expr="impl_color_clone(ident, gecko_ffi_name, complex_color)"></%call>
+    <%call expr="impl_color_clone(ident, gecko_ffi_name)"></%call>
 % endif
 </%def>
 
-<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
+<%def name="impl_rgba_color(ident, gecko_ffi_name, need_clone=False)">
+    #[allow(non_snake_case)]
+    pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
+        ${set_gecko_property(gecko_ffi_name, "convert_rgba_to_nscolor(&v)")}
+    }
+    <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
+    % if need_clone:
+        #[allow(non_snake_case)]
+        pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
+            convert_nscolor_to_rgba(${get_gecko_property(gecko_ffi_name)})
+        }
+    % endif
+</%def>
+
+<%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, mut v: longhands::${ident}::computed_value::T) {
         use values::generics::SVGPaintKind;
         use self::structs::nsStyleSVGPaintType;
         use self::structs::nsStyleSVGFallbackType;
 
         let ref mut paint = ${get_gecko_property(gecko_ffi_name)};
         unsafe {
@@ -439,24 +431,24 @@ fn color_to_nscolor_zero_currentcolor(co
             SVGPaintKind::PaintServer(url) => {
                 unsafe {
                     bindings::Gecko_nsStyleSVGPaint_SetURLValue(paint, url.for_ffi());
                 }
             }
             SVGPaintKind::Color(color) => {
                 paint.mType = nsStyleSVGPaintType::eStyleSVGPaintType_Color;
                 unsafe {
-                    *paint.mPaint.mColor.as_mut() = color_to_nscolor_zero_currentcolor(color);
+                    *paint.mPaint.mColor.as_mut() = convert_rgba_to_nscolor(&color);
                 }
             }
         }
 
         if let Some(fallback) = fallback {
             paint.mFallbackType = nsStyleSVGFallbackType::eStyleSVGFallbackType_Color;
-            paint.mFallbackColor = color_to_nscolor_zero_currentcolor(fallback);
+            paint.mFallbackColor = convert_rgba_to_nscolor(&fallback);
         }
     }
 
     #[allow(non_snake_case)]
     pub fn copy_${ident}_from(&mut self, other: &Self) {
         unsafe {
             bindings::Gecko_nsStyleSVGPaint_CopyFrom(
                 &mut ${get_gecko_property(gecko_ffi_name)},
@@ -467,30 +459,30 @@ fn color_to_nscolor_zero_currentcolor(co
 
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
         use values::generics::{SVGPaint, SVGPaintKind};
         use self::structs::nsStyleSVGPaintType;
         use self::structs::nsStyleSVGFallbackType;
         let ref paint = ${get_gecko_property(gecko_ffi_name)};
         let fallback = if let nsStyleSVGFallbackType::eStyleSVGFallbackType_Color = paint.mFallbackType {
-            Some(Color::RGBA(convert_nscolor_to_rgba(paint.mFallbackColor)))
+            Some(convert_nscolor_to_rgba(paint.mFallbackColor))
         } else {
             None
         };
         let kind = match paint.mType {
             nsStyleSVGPaintType::eStyleSVGPaintType_None => SVGPaintKind::None,
             nsStyleSVGPaintType::eStyleSVGPaintType_ContextFill => SVGPaintKind::ContextFill,
             nsStyleSVGPaintType::eStyleSVGPaintType_ContextStroke => SVGPaintKind::ContextStroke,
             nsStyleSVGPaintType::eStyleSVGPaintType_Server => {
                 // FIXME (bug 1353966) this should animate
                 SVGPaintKind::None
             }
             nsStyleSVGPaintType::eStyleSVGPaintType_Color => {
-                unsafe { SVGPaintKind::Color(Color::RGBA(convert_nscolor_to_rgba(*paint.mPaint.mColor.as_ref()))) }
+                unsafe { SVGPaintKind::Color(convert_nscolor_to_rgba(*paint.mPaint.mColor.as_ref())) }
             }
         };
         SVGPaint {
             kind: kind,
             fallback: fallback,
         }
     }
 </%def>
@@ -711,17 +703,18 @@ 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)
 
@@ -731,18 +724,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:
@@ -943,17 +934,17 @@ fn static_assert() {
             },
             Some(ref colors) => {
                 unsafe {
                     bindings::Gecko_EnsureMozBorderColors(&mut self.gecko);
                     bindings::Gecko_ClearMozBorderColors(&mut self.gecko,
                                                          structs::Side::eSide${to_camel_case(side.ident)});
                 }
                 for color in colors {
-                    let c = color_to_nscolor_zero_currentcolor(*color);
+                    let c = convert_rgba_to_nscolor(color);
                     unsafe {
                         bindings::Gecko_AppendMozBorderColors(&mut self.gecko,
                                                               structs::Side::eSide${to_camel_case(side.ident)},
                                                               c);
                     }
                 }
             }
         }
@@ -4263,35 +4254,17 @@ clip-path
 
     pub fn copy_cursor_from(&mut self, other: &Self) {
         self.gecko.mCursor = other.gecko.mCursor;
         unsafe {
             Gecko_CopyCursorArrayFrom(&mut self.gecko, &other.gecko);
         }
     }
 
-    pub fn set_caret_color(&mut self, v: longhands::caret_color::computed_value::T){
-        use values::Either;
-
-        match v {
-            Either::First(color) => {
-                self.gecko.mCaretColor = StyleComplexColor::from(color);
-            }
-            Either::Second(_auto) => {
-                self.gecko.mCaretColor = StyleComplexColor::auto();
-            }
-        }
-    }
-
-    pub fn copy_caret_color_from(&mut self, other: &Self){
-        self.gecko.mCaretColor = other.gecko.mCaretColor;
-    }
-
-    <%call expr="impl_color_clone('caret_color', 'mCaretColor')"></%call>
-
+    <%call expr="impl_color('caret_color', 'mCaretColor', need_clone=True)"></%call>
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Column"
                   skip_longhands="column-count column-rule-width">
 
     #[allow(unused_unsafe)]
     pub fn set_column_count(&mut self, v: longhands::column_count::computed_value::T) {
         use gecko_bindings::structs::{NS_STYLE_COLUMN_COUNT_AUTO, nsStyleColumn_kMaxColumnCount};
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -2,17 +2,17 @@
  * 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 SYSTEM_FONT_LONGHANDS %>
 
 use app_units::Au;
-use cssparser::{Color as CSSParserColor, Parser, RGBA, serialize_identifier};
+use cssparser::{Parser, RGBA, serialize_identifier};
 use euclid::{Point2D, Size2D};
 #[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::RawGeckoGfxMatrix4x4;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
 #[cfg(feature = "gecko")] use gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
 #[cfg(feature = "gecko")] use gecko_string_cache::Atom;
 use properties::{CSSWideKeyword, PropertyDeclaration};
 use properties::longhands;
@@ -33,17 +33,17 @@ use std::cmp;
 #[cfg(feature = "gecko")] use std::collections::HashMap;
 use std::fmt;
 use style_traits::ToCss;
 use super::ComputedValues;
 use values::CSSFloat;
 use values::{Auto, Either};
 use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
 use values::computed::{BorderCornerRadius, ClipRect};
-use values::computed::{CalcLengthOrPercentage, Context, ComputedValueAsSpecified};
+use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
 use values::computed::{LengthOrPercentage, MaxLength, MozLength, Shadow, ToComputedValue};
 use values::generics::{SVGPaint, SVGPaintKind};
 use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
 use values::generics::position as generic_position;
 
 
 /// A given transition property, that is either `All`, or an animatable
 /// property.
@@ -2716,121 +2716,173 @@ impl Animatable for IntermediateRGBA {
                                .fold(0.0f64, |n, (&a, &b)| {
                                    let diff = (a - b) as f64;
                                    n + diff * diff
                                });
         Ok(diff)
     }
 }
 
-impl From<Either<CSSParserColor, Auto>> for Either<IntermediateColor, Auto> {
-    fn from(from: Either<CSSParserColor, Auto>) -> Either<IntermediateColor, Auto> {
+impl From<Either<Color, Auto>> for Either<IntermediateColor, Auto> {
+    fn from(from: Either<Color, Auto>) -> Either<IntermediateColor, Auto> {
         match from {
-            Either::First(from) =>
-                match from {
-                    CSSParserColor::RGBA(color) =>
-                        Either::First(IntermediateColor::IntermediateRGBA(
-                            IntermediateRGBA::new(color.red_f32(),
-                                                  color.green_f32(),
-                                                  color.blue_f32(),
-                                                  color.alpha_f32()))),
-                    CSSParserColor::CurrentColor =>
-                        Either::First(IntermediateColor::CurrentColor),
-                },
+            Either::First(from) => Either::First(from.into()),
             Either::Second(Auto) => Either::Second(Auto),
         }
     }
 }
 
-impl From<Either<IntermediateColor, Auto>> for Either<CSSParserColor, Auto> {
-    fn from(from: Either<IntermediateColor, Auto>) -> Either<CSSParserColor, Auto> {
+impl From<Either<IntermediateColor, Auto>> for Either<Color, Auto> {
+    fn from(from: Either<IntermediateColor, Auto>) -> Either<Color, Auto> {
         match from {
-            Either::First(from) =>
-                match from {
-                    IntermediateColor::IntermediateRGBA(color) =>
-                        Either::First(CSSParserColor::RGBA(RGBA::from_floats(color.red,
-                                                                             color.green,
-                                                                             color.blue,
-                                                                             color.alpha))),
-                    IntermediateColor::CurrentColor =>
-                        Either::First(CSSParserColor::CurrentColor),
-                },
+            Either::First(from) => Either::First(from.into()),
             Either::Second(Auto) => Either::Second(Auto),
         }
     }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
-pub enum IntermediateColor {
-    CurrentColor,
-    IntermediateRGBA(IntermediateRGBA),
+pub struct IntermediateColor {
+    color: IntermediateRGBA,
+    foreground_ratio: f32,
+}
+
+impl IntermediateColor {
+    fn currentcolor() -> Self {
+        IntermediateColor {
+            color: IntermediateRGBA::transparent(),
+            foreground_ratio: 1.,
+        }
+    }
+
+    fn transparent() -> Self {
+        IntermediateColor {
+            color: IntermediateRGBA::transparent(),
+            foreground_ratio: 0.,
+        }
+    }
+
+    fn is_currentcolor(&self) -> bool {
+        self.foreground_ratio >= 1.
+    }
+
+    fn is_numeric(&self) -> bool {
+        self.foreground_ratio <= 0.
+    }
+
+    fn effective_intermediate_rgba(&self) -> IntermediateRGBA {
+        IntermediateRGBA {
+            alpha: self.color.alpha * (1. - self.foreground_ratio),
+            .. self.color
+        }
+    }
 }
 
 impl Animatable for IntermediateColor {
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
-        match (*self, *other) {
-            (IntermediateColor::IntermediateRGBA(ref this),
-             IntermediateColor::IntermediateRGBA(ref other)) => {
-                this.add_weighted(other, self_portion, other_portion)
-                    .map(IntermediateColor::IntermediateRGBA)
+        // Common cases are interpolating between two numeric colors,
+        // two currentcolors, and a numeric color and a currentcolor.
+        //
+        // Note: this algorithm assumes self_portion + other_portion
+        // equals to one, so it may be broken for additive operation.
+        // To properly support additive color interpolation, we would
+        // need two ratio fields in computed color types.
+        if self.foreground_ratio == other.foreground_ratio {
+            if self.is_currentcolor() {
+                Ok(IntermediateColor::currentcolor())
+            } else {
+                Ok(IntermediateColor {
+                    color: self.color.add_weighted(&other.color, self_portion, other_portion)?,
+                    foreground_ratio: self.foreground_ratio,
+                })
             }
-            // FIXME: Bug 1345709: Implement currentColor animations.
-            _ => Err(()),
+        } else if self.is_currentcolor() && other.is_numeric() {
+            Ok(IntermediateColor {
+                color: other.color,
+                foreground_ratio: self_portion as f32,
+            })
+        } else if self.is_numeric() && other.is_currentcolor() {
+            Ok(IntermediateColor {
+                color: self.color,
+                foreground_ratio: other_portion as f32,
+            })
+        } else {
+            // For interpolating between two complex colors, we need to
+            // generate colors with effective alpha value.
+            let self_color = self.effective_intermediate_rgba();
+            let other_color = other.effective_intermediate_rgba();
+            let color = self_color.add_weighted(&other_color, self_portion, other_portion)?;
+            // Then we compute the final foreground ratio, and derive
+            // the final alpha value from the effective alpha value.
+            let foreground_ratio = self.foreground_ratio
+                .add_weighted(&other.foreground_ratio, self_portion, other_portion)?;
+            let alpha = color.alpha / (1. - foreground_ratio);
+            Ok(IntermediateColor {
+                color: IntermediateRGBA {
+                    alpha: alpha,
+                    .. color
+                },
+                foreground_ratio: foreground_ratio,
+            })
         }
     }
 
     #[inline]
     fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
         self.compute_squared_distance(other).map(|sq| sq.sqrt())
     }
 
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
-        match (*self, *other) {
-            (IntermediateColor::IntermediateRGBA(ref this), IntermediateColor::IntermediateRGBA(ref other)) => {
-                this.compute_squared_distance(other)
-            },
-            _ => Ok(0.0),
+        // All comments in add_weighted also applies here.
+        if self.foreground_ratio == other.foreground_ratio {
+            if self.is_currentcolor() {
+                Ok(0.)
+            } else {
+                self.color.compute_squared_distance(&other.color)
+            }
+        } else if self.is_currentcolor() && other.is_numeric() {
+            Ok(IntermediateRGBA::transparent().compute_squared_distance(&other.color)? + 1.)
+        } else if self.is_numeric() && other.is_currentcolor() {
+            Ok(self.color.compute_squared_distance(&IntermediateRGBA::transparent())? + 1.)
+        } else {
+            let self_color = self.effective_intermediate_rgba();
+            let other_color = other.effective_intermediate_rgba();
+            let dist = self_color.compute_squared_distance(&other_color)?;
+            let ratio_diff = (self.foreground_ratio - other.foreground_ratio) as f64;
+            Ok(dist + ratio_diff * ratio_diff)
         }
     }
 }
 
-impl From<CSSParserColor> for IntermediateColor {
-    fn from(color: CSSParserColor) -> IntermediateColor {
-        match color {
-            CSSParserColor::RGBA(color) =>
-                IntermediateColor::IntermediateRGBA(IntermediateRGBA::new(color.red_f32(),
-                                                                          color.green_f32(),
-                                                                          color.blue_f32(),
-                                                                          color.alpha_f32())),
-            CSSParserColor::CurrentColor => IntermediateColor::CurrentColor,
+impl From<Color> for IntermediateColor {
+    fn from(color: Color) -> IntermediateColor {
+        IntermediateColor {
+            color: color.color.into(),
+            foreground_ratio: color.foreground_ratio as f32 * (1. / 255.),
         }
     }
 }
 
-impl From<IntermediateColor> for CSSParserColor {
-    fn from(color: IntermediateColor) -> CSSParserColor {
-        match color {
-            IntermediateColor::IntermediateRGBA(color) =>
-                CSSParserColor::RGBA(RGBA::from_floats(color.red,
-                                                       color.green,
-                                                       color.blue,
-                                                       color.alpha)),
-            IntermediateColor::CurrentColor => CSSParserColor::CurrentColor,
+impl From<IntermediateColor> for Color {
+    fn from(color: IntermediateColor) -> Color {
+        Color {
+            color: color.color.into(),
+            foreground_ratio: (color.foreground_ratio * 255.).round() as u8,
         }
     }
 }
 
 /// Animatable SVGPaint
-pub type IntermediateSVGPaint = SVGPaint<IntermediateColor>;
+pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
 /// Animatable SVGPaintKind
-pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateColor>;
+pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateRGBA>;
 
 impl From<::values::computed::SVGPaint> for IntermediateSVGPaint {
     fn from(paint: ::values::computed::SVGPaint) -> IntermediateSVGPaint {
         paint.convert(|color| (*color).into())
     }
 }
 
 impl From<IntermediateSVGPaint> for ::values::computed::SVGPaint {
@@ -3019,17 +3071,17 @@ impl Animatable for IntermediateShadowLi
     #[inline]
     fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
         // The inset value must change
         let mut zero = IntermediateShadow {
             offset_x: Au(0),
             offset_y: Au(0),
             blur_radius: Au(0),
             spread_radius: Au(0),
-            color: IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent()),
+            color: IntermediateColor::transparent(),
             inset: false,
         };
 
         let max_len = cmp::max(self.0.len(), other.0.len());
 
         let mut result = if max_len > 1 {
             SmallVec::from_vec(Vec::with_capacity(max_len))
         } else {
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -1,22 +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/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Background", inherited=False) %>
 
-${helpers.predefined_type("background-color", "CSSColor",
-    "::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
+${helpers.predefined_type("background-color", "Color",
+    "computed_value::T::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)}
 
 ${helpers.predefined_type("background-image", "ImageLayer",
     initial_value="Either::First(None_)",
     initial_specified_value="Either::First(None_)",
     spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
     vector="True",
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -11,18 +11,18 @@
 <%
     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",
-                              "::cssparser::Color::CurrentColor",
+    ${helpers.predefined_type("border-%s-color" % side[0], "Color",
+                              "computed_value::T::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)}
 
     ${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
@@ -61,31 +61,31 @@
 /// These non-spec properties are just for Gecko (Stylo) internal use.
 % for side in PHYSICAL_SIDES:
     <%helpers:longhand name="-moz-border-${side}-colors" animation_value_type="none"
                        spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-border-*-colors)"
                        products="gecko"
                        ignored_when_colors_disabled="True">
         use std::fmt;
         use style_traits::ToCss;
-        use values::specified::CSSColor;
+        use values::specified::RGBAColor;
         no_viewport_percentage!(SpecifiedValue);
 
         pub mod computed_value {
-            use values::computed::CSSColor;
+            use cssparser::RGBA;
             #[derive(Debug, Clone, PartialEq)]
             #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-            pub struct T(pub Option<Vec<CSSColor>>);
+            pub struct T(pub Option<Vec<RGBA>>);
         }
 
         #[derive(Debug, Clone, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub enum SpecifiedValue {
             None,
-            Colors(Vec<CSSColor>),
+            Colors(Vec<RGBAColor>),
         }
 
         impl ToCss for computed_value::T {
             fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                 match self.0 {
                     None => return dest.write_str("none"),
                     Some(ref vec) => {
                         let mut first = true;
@@ -163,17 +163,17 @@
         #[inline]
         pub fn parse(context: &ParserContext, input: &mut Parser)
                      -> Result<SpecifiedValue, ()> {
             if input.try(|input| input.expect_ident_matching("none")).is_ok() {
                 return Ok(SpecifiedValue::None)
             }
 
             let mut result = Vec::new();
-            while let Ok(value) = input.try(|i| CSSColor::parse(context, i)) {
+            while let Ok(value) = input.try(|i| RGBAColor::parse(context, i)) {
                 result.push(value);
             }
 
             if !result.is_empty() {
                 Ok(SpecifiedValue::Colors(result))
             } else {
                 Err(())
             }
--- a/servo/components/style/properties/longhand/color.mako.rs
+++ b/servo/components/style/properties/longhand/color.mako.rs
@@ -8,47 +8,48 @@
 
 <% 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 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)
+            self.0.to_computed_value(context)
+                .to_rgba(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,22 +46,21 @@
                           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",
-                          "::cssparser::Color::CurrentColor",
-                          initial_specified_value="specified::CSSColor::currentcolor()",
+${helpers.predefined_type("column-rule-color", "Color",
+                          "computed_value::T::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,
+                          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")}
 
 ${helpers.single_keyword("column-rule-style",
                          "none hidden dotted dashed solid double groove ridge inset outset",
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -680,50 +680,47 @@
                     HorizontalWritingModeValue::Under
                 };
                 SpecifiedValue(horiz, vert)
             }
         }
     % endif
 </%helpers:longhand>
 
-${helpers.predefined_type("text-emphasis-color", "CSSColor",
-                          "::cssparser::Color::CurrentColor",
-                          initial_specified_value="specified::CSSColor::currentcolor()",
+${helpers.predefined_type("text-emphasis-color", "Color",
+                          "computed_value::T::currentcolor()",
+                          initial_specified_value="specified::Color::currentcolor()",
                           products="gecko", animation_value_type="IntermediateColor",
-                          complex_color=True, need_clone=True,
-                          ignored_when_colors_disabled=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",
     "::values::Either::Second(8.0)",
     "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",
-    "CSSParserColor::CurrentColor",
+    "-webkit-text-fill-color", "Color",
+    "computed_value::T::currentcolor()",
     products="gecko", animation_value_type="IntermediateColor",
-    complex_color=True, need_clone=True,
-    ignored_when_colors_disabled=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",
-    "CSSParserColor::CurrentColor",
-    initial_specified_value="specified::CSSColor::currentcolor()",
+    "-webkit-text-stroke-color", "Color",
+    "computed_value::T::currentcolor()",
+    initial_specified_value="specified::Color::currentcolor()",
     products="gecko", animation_value_type="IntermediateColor",
-    complex_color=True, need_clone=True,
-    ignored_when_colors_disabled=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)",
                           initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
                           computed_type="::app_units::Au",
                           products="gecko",
--- a/servo/components/style/properties/longhand/outline.mako.rs
+++ b/servo/components/style/properties/longhand/outline.mako.rs
@@ -5,19 +5,19 @@
 <%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()",
-                          animation_value_type="IntermediateColor", complex_color=True, need_clone=True,
+${helpers.predefined_type("outline-color", "Color", "computed_value::T::currentcolor()",
+                          initial_specified_value="specified::Color::currentcolor()",
+                          animation_value_type="IntermediateColor", 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;
 
     pub type SpecifiedValue = Either<Auto, BorderStyle>;
--- a/servo/components/style/properties/longhand/svg.mako.rs
+++ b/servo/components/style/properties/longhand/svg.mako.rs
@@ -15,43 +15,43 @@
 
 ${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
                          products="gecko", animation_value_type="discrete",
                          spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty")}
 
 // Section 13 - Gradients and Patterns
 
 ${helpers.predefined_type(
-    "stop-color", "CSSColor",
-    "CSSParserColor::RGBA(RGBA::new(0, 0, 0, 255))",
+    "stop-color", "RGBAColor",
+    "RGBA::new(0, 0, 0, 255)",
     products="gecko",
     animation_value_type="none",
     spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty")}
 
 ${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
                           products="gecko",
                           animation_value_type="none",
                           spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity")}
 
 // Section 15 - Filter Effects
 
 ${helpers.predefined_type(
-    "flood-color", "CSSColor",
-    "CSSParserColor::RGBA(RGBA::new(0, 0, 0, 255))",
+    "flood-color", "RGBAColor",
+    "RGBA::new(0, 0, 0, 255)",
     products="gecko",
     animation_value_type="none",
     spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty")}
 
 ${helpers.predefined_type("flood-opacity", "Opacity",
                           "1.0", products="gecko", animation_value_type="none",
                           spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")}
 
 ${helpers.predefined_type(
-    "lighting-color", "CSSColor",
-    "CSSParserColor::RGBA(RGBA::new(255, 255, 255, 255))",
+    "lighting-color", "RGBAColor",
+    "RGBA::new(255, 255, 255, 255)",
     products="gecko",
     animation_value_type="none",
     spec="https://www.w3.org/TR/SVG/filters.html#LightingColorProperty")}
 
 // CSS Masking Module Level 1
 // https://drafts.fxtf.org/css-masking
 ${helpers.single_keyword("mask-type", "luminance alpha",
                          products="gecko", animation_value_type="discrete",
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -273,20 +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()",
-    complex_color=True,
+    "text-decoration-color", "Color",
+    "computed_value::T::currentcolor()",
+    initial_specified_value="specified::Color::currentcolor()",
     products="gecko",
     animation_value_type="IntermediateColor",
     ignored_when_colors_disabled=True,
     spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-color")}
 
 ${helpers.predefined_type(
     "initial-letter",
     "InitialLetter",
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -13,17 +13,17 @@
 use std::borrow::Cow;
 use std::collections::HashSet;
 use std::fmt;
 use std::mem;
 use std::ops::Deref;
 use stylearc::{Arc, UniqueArc};
 
 use app_units::Au;
-#[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
+#[cfg(feature = "servo")] use cssparser::RGBA;
 use cssparser::{Parser, TokenSerializationType, serialize_identifier};
 use error_reporting::ParseErrorReporter;
 #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
 use computed_values;
 use context::QuirksMode;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::bindings;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
@@ -35,17 +35,16 @@ use properties::animated_properties::Tra
 #[cfg(feature = "gecko")] use properties::longhands::system_font::SystemFont;
 #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
 use shared_lock::StylesheetGuards;
 use style_traits::{HasViewportPercentage, ToCss};
 use stylesheets::{CssRuleType, MallocSizeOf, MallocSizeOfFn, Origin, UrlExtraData};
 #[cfg(feature = "servo")] use values::Either;
 use values::generics::text::LineHeight;
 use values::computed;
-use values::specified::Color;
 use cascade_info::CascadeInfo;
 use rule_tree::{CascadeLevel, StrongRuleNode};
 use style_adjuster::StyleAdjuster;
 #[cfg(feature = "servo")] use values::specified::BorderStyle;
 
 pub use self::declaration_block::*;
 
 #[cfg(feature = "gecko")]
@@ -1933,21 +1932,18 @@ impl ComputedValues {
     /// Resolves the currentColor keyword.
     ///
     /// Any color value from computed values (except for the 'color' property
     /// itself) should go through this method.
     ///
     /// Usage example:
     /// let top_color = style.resolve_color(style.Border.border_top_color);
     #[inline]
-    pub fn resolve_color(&self, color: CSSParserColor) -> RGBA {
-        match color {
-            CSSParserColor::RGBA(rgba) => rgba,
-            CSSParserColor::CurrentColor => self.get_color().color,
-        }
+    pub fn resolve_color(&self, color: computed::Color) -> RGBA {
+        color.to_rgba(self.get_color().color)
     }
 
     /// Get the logical computed inline size.
     #[inline]
     pub fn content_inline_size(&self) -> computed::LengthOrPercentageOrAuto {
         let position_style = self.get_position();
         if self.writing_mode.is_vertical() {
             position_style.height
@@ -2621,17 +2617,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.into()))
     } 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
@@ -907,17 +907,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:
@@ -1078,17 +1077,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
                             }
                         }
                     }
                 }
             }
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/computed/color.rs
@@ -0,0 +1,144 @@
+/* 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/. */
+
+//! Computed color values.
+
+use cssparser::{Color as CSSParserColor, RGBA};
+use std::fmt;
+use style_traits::ToCss;
+
+/// This struct represents a combined color from a numeric color and
+/// the current foreground color (currentcolor keyword).
+/// Conceptually, the formula is "color * (1 - p) + currentcolor * p"
+/// where p is foreground_ratio.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct Color {
+    /// RGBA color.
+    pub color: RGBA,
+    /// The ratio of currentcolor in complex color.
+    pub foreground_ratio: u8,
+}
+
+fn blend_color_component(bg: u8, fg: u8, fg_alpha: u8) -> u8 {
+    let bg_ratio = (u8::max_value() - fg_alpha) as u32;
+    let fg_ratio = fg_alpha as u32;
+    let color = bg as u32 * bg_ratio + fg as u32 * fg_ratio;
+    // Rounding divide the number by 255
+    ((color + 127) / 255) as u8
+}
+
+impl Color {
+    /// Returns a numeric color representing the given RGBA value.
+    pub fn rgba(rgba: RGBA) -> Color {
+        Color {
+            color: rgba,
+            foreground_ratio: 0,
+        }
+    }
+
+    /// Returns a complex color value representing transparent.
+    pub fn transparent() -> Color {
+        Color::rgba(RGBA::transparent())
+    }
+
+    /// Returns a complex color value representing currentcolor.
+    pub fn currentcolor() -> Color {
+        Color {
+            color: RGBA::transparent(),
+            foreground_ratio: u8::max_value(),
+        }
+    }
+
+    /// Whether it is a numeric color (no currentcolor component).
+    pub fn is_numeric(&self) -> bool {
+        self.foreground_ratio == 0
+    }
+
+    /// Whether it is a currentcolor value (no numeric color component).
+    pub fn is_currentcolor(&self) -> bool {
+        self.foreground_ratio == u8::max_value()
+    }
+
+    /// Combine this complex color with the given foreground color into
+    /// a numeric RGBA color. It currently uses linear blending.
+    pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
+        // Common cases that the complex color is either pure numeric
+        // color or pure currentcolor.
+        if self.is_numeric() {
+            return self.color;
+        }
+        if self.is_currentcolor() {
+            return fg_color.clone();
+        }
+        // Common case that alpha channel is equal (usually both are opaque).
+        let fg_ratio = self.foreground_ratio;
+        if self.color.alpha == fg_color.alpha {
+            let r = blend_color_component(self.color.red, fg_color.red, fg_ratio);
+            let g = blend_color_component(self.color.green, fg_color.green, fg_ratio);
+            let b = blend_color_component(self.color.blue, fg_color.blue, fg_ratio);
+            return RGBA::new(r, g, b, fg_color.alpha);
+        }
+
+        // For the more complicated case that the alpha value differs,
+        // we use the following formula to compute the components:
+        // alpha = self_alpha * (1 - fg_ratio) + fg_alpha * fg_ratio
+        // color = (self_color * self_alpha * (1 - fg_ratio) +
+        //          fg_color * fg_alpha * fg_ratio) / alpha
+
+        let p1 = (1. / 255.) * (255 - fg_ratio) as f32;
+        let a1 = self.color.alpha_f32();
+        let r1 = a1 * self.color.red_f32();
+        let g1 = a1 * self.color.green_f32();
+        let b1 = a1 * self.color.blue_f32();
+
+        let p2 = 1. - p1;
+        let a2 = fg_color.alpha_f32();
+        let r2 = a2 * fg_color.red_f32();
+        let g2 = a2 * fg_color.green_f32();
+        let b2 = a2 * fg_color.blue_f32();
+
+        let a = p1 * a1 + p2 * a2;
+        if a == 0.0 {
+            return RGBA::transparent();
+        }
+
+        let inverse_a = 1. / a;
+        let r = (p1 * r1 + p2 * r2) * inverse_a;
+        let g = (p1 * g1 + p2 * g2) * inverse_a;
+        let b = (p1 * b1 + p2 * b2) * inverse_a;
+        return RGBA::from_floats(r, g, b, a);
+    }
+}
+
+impl PartialEq for Color {
+    fn eq(&self, other: &Color) -> bool {
+        self.foreground_ratio == other.foreground_ratio &&
+            (self.is_currentcolor() || self.color == other.color)
+    }
+}
+
+impl From<RGBA> for Color {
+    fn from(color: RGBA) -> Color {
+        Color {
+            color: color,
+            foreground_ratio: 0,
+        }
+    }
+}
+
+impl ToCss for Color {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        if self.is_numeric() {
+            self.color.to_css(dest)
+        } else if self.is_currentcolor() {
+            CSSParserColor::CurrentColor.to_css(dest)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+/// Computed value type for the specified RGBAColor.
+pub type RGBAColor = RGBA;
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -2,17 +2,17 @@
  * 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/. */
 
 //! CSS handling for the computed value of
 //! [`image`][image]s
 //!
 //! [image]: https://drafts.csswg.org/css-images/#image-values
 
-use cssparser::Color as CSSColor;
+use cssparser::RGBA;
 use std::f32::consts::PI;
 use std::fmt;
 use style_traits::ToCss;
 use values::{Either, None_};
 use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
 use values::computed::position::Position;
 use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingShape as GenericEndingShape};
 use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
@@ -30,17 +30,17 @@ pub type Image = GenericImage<Gradient, 
 
 /// Computed values for a CSS gradient.
 /// https://drafts.csswg.org/css-images/#gradients
 pub type Gradient = GenericGradient<
     LineDirection,
     Length,
     LengthOrPercentage,
     Position,
-    CSSColor,
+    RGBA,
 >;
 
 /// A computed gradient kind.
 pub type GradientKind = GenericGradientKind<
     LineDirection,
     Length,
     LengthOrPercentage,
     Position,
@@ -55,20 +55,20 @@ pub enum LineDirection {
     /// A corner.
     Corner(X, Y),
 }
 
 /// A computed radial gradient ending shape.
 pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
 
 /// A computed gradient item.
-pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;
+pub type GradientItem = GenericGradientItem<RGBA, LengthOrPercentage>;
 
 /// A computed color stop.
-pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;
+pub type ColorStop = GenericColorStop<RGBA, LengthOrPercentage>;
 
 /// Computed values for ImageRect.
 pub type ImageRect = GenericImageRect<NumberOrPercentage>;
 
 impl GenericLineDirection for LineDirection {
     fn points_downwards(&self) -> bool {
         match *self {
             LineDirection::Angle(angle) => angle.radians() == PI,
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -18,21 +18,21 @@ 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 properties::animated_properties::TransitionProperty;
 pub use self::background::BackgroundSize;
 pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
 pub use self::border::{BorderRadius, BorderCornerRadius};
+pub use self::color::{Color, RGBAColor};
 pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
 pub use self::rect::LengthOrNumberRect;
 pub use super::{Auto, Either, None_};
 #[cfg(feature = "gecko")]
 pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
 pub use super::specified::{BorderStyle, Percentage, UrlOrNone};
@@ -43,16 +43,17 @@ pub use self::length::{LengthOrPercentag
 pub use self::length::{MaxLength, MozLength};
 pub use self::position::Position;
 pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
 pub use self::transform::{TimingFunction, TransformOrigin};
 
 pub mod background;
 pub mod basic_shape;
 pub mod border;
+pub mod color;
 pub mod image;
 #[cfg(feature = "gecko")]
 pub mod gecko;
 pub mod length;
 pub mod position;
 pub mod rect;
 pub mod text;
 pub mod transform;
@@ -355,96 +356,16 @@ impl Time {
 impl ToCss for Time {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
         where W: fmt::Write,
     {
         write!(dest, "{}s", self.seconds())
     }
 }
 
-impl ToComputedValue for specified::Color {
-    type ComputedValue = RGBA;
-
-    #[cfg(not(feature = "gecko"))]
-    fn to_computed_value(&self, context: &Context) -> RGBA {
-        match *self {
-            specified::Color::RGBA(rgba) => rgba,
-            specified::Color::CurrentColor => context.inherited_style.get_color().clone_color(),
-        }
-    }
-
-    #[cfg(feature = "gecko")]
-    fn to_computed_value(&self, context: &Context) -> RGBA {
-        use gecko::values::convert_nscolor_to_rgba as to_rgba;
-        // It's safe to access the nsPresContext immutably during style computation.
-        let pres_context = unsafe { &*context.device.pres_context };
-        match *self {
-            specified::Color::RGBA(rgba) => rgba,
-            specified::Color::System(system) => to_rgba(system.to_computed_value(context)),
-            specified::Color::CurrentColor => context.inherited_style.get_color().clone_color(),
-            specified::Color::MozDefaultColor => to_rgba(pres_context.mDefaultColor),
-            specified::Color::MozDefaultBackgroundColor => to_rgba(pres_context.mBackgroundColor),
-            specified::Color::MozHyperlinktext => to_rgba(pres_context.mLinkColor),
-            specified::Color::MozActiveHyperlinktext => to_rgba(pres_context.mActiveLinkColor),
-            specified::Color::MozVisitedHyperlinktext => to_rgba(pres_context.mVisitedLinkColor),
-            specified::Color::InheritFromBodyQuirk => {
-                use dom::TElement;
-                use gecko::wrapper::GeckoElement;
-                use gecko_bindings::bindings::Gecko_GetBody;
-                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()
-                } else {
-                    to_rgba(pres_context.mDefaultColor)
-                }
-            },
-        }
-    }
-
-    fn from_computed_value(computed: &RGBA) -> Self {
-        specified::Color::RGBA(*computed)
-    }
-}
-
-impl ToComputedValue for specified::CSSColor {
-    type ComputedValue = CSSColor;
-
-    #[cfg(not(feature = "gecko"))]
-    #[inline]
-    fn to_computed_value(&self, _context: &Context) -> CSSColor {
-        self.parsed
-    }
-
-    #[cfg(feature = "gecko")]
-    #[inline]
-    fn to_computed_value(&self, context: &Context) -> CSSColor {
-        match self.parsed {
-            specified::Color::RGBA(rgba) => CSSColor::RGBA(rgba),
-            specified::Color::CurrentColor => CSSColor::CurrentColor,
-            // Resolve non-standard -moz keywords to RGBA:
-            non_standard => CSSColor::RGBA(non_standard.to_computed_value(context)),
-        }
-    }
-
-    #[inline]
-    fn from_computed_value(computed: &CSSColor) -> Self {
-        (match *computed {
-            CSSColor::RGBA(rgba) => specified::Color::RGBA(rgba),
-            CSSColor::CurrentColor => specified::Color::CurrentColor,
-        }).into()
-    }
-}
-
 #[cfg(feature = "gecko")]
 impl ToComputedValue for specified::JustifyItems {
     type ComputedValue = JustifyItems;
 
     // https://drafts.csswg.org/css-align/#valdef-justify-items-auto
     fn to_computed_value(&self, context: &Context) -> JustifyItems {
         use values::specified::align;
         // If the inherited value of `justify-items` includes the `legacy` keyword, `auto` computes
@@ -475,17 +396,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 ")?;
         }
@@ -554,35 +475,35 @@ impl IntegerOrAuto {
         match *self {
             Either::First(n) => n,
             Either::Second(Auto) => auto_value,
         }
     }
 }
 
 /// Computed SVG Paint value
-pub type SVGPaint = ::values::generics::SVGPaint<CSSColor>;
+pub type SVGPaint = ::values::generics::SVGPaint<RGBA>;
 /// Computed SVG Paint Kind value
-pub type SVGPaintKind = ::values::generics::SVGPaintKind<CSSColor>;
+pub type SVGPaintKind = ::values::generics::SVGPaintKind<RGBA>;
 
 impl Default for SVGPaint {
     fn default() -> Self {
         SVGPaint {
             kind: ::values::generics::SVGPaintKind::None,
             fallback: None,
         }
     }
 }
 
 impl SVGPaint {
     /// Opaque black color
     pub fn black() -> Self {
         let rgba = RGBA::from_floats(0., 0., 0., 1.);
         SVGPaint {
-            kind: ::values::generics::SVGPaintKind::Color(CSSColor::RGBA(rgba)),
+            kind: ::values::generics::SVGPaintKind::Color(rgba),
             fallback: None,
         }
     }
 }
 
 /// <length> | <percentage> | <number>
 pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
 
@@ -657,9 +578,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,103 +1,337 @@
 /* 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::{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::{Color as ComputedColor, Context, ToComputedValue};
+
+/// Specified color value
+#[derive(Clone, PartialEq, Debug)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum Color {
+    /// The 'currentColor' keyword
+    CurrentColor,
+    /// A specific RGBA color
+    Numeric {
+        /// Parsed RGBA color
+        parsed: RGBA,
+        /// Authored representation
+        authored: Option<Box<str>>,
+    },
+    /// A complex color value from computed value
+    Complex(ComputedColor),
+
+    /// 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
+    #[cfg(feature = "gecko")]
+    InheritFromBodyQuirk,
+}
+
+no_viewport_percentage!(Color);
+
+#[cfg(feature = "gecko")]
+mod gecko {
+    use style_traits::ToCss;
+
+    define_css_keyword_enum! { SpecialColorKeyword:
+        "-moz-default-color" => MozDefaultColor,
+        "-moz-default-background-color" => MozDefaultBackgroundColor,
+        "-moz-hyperlinktext" => MozHyperlinktext,
+        "-moz-activehyperlinktext" => MozActiveHyperlinktext,
+        "-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
+    }
+}
 
-#[cfg(not(feature = "gecko"))] pub use self::servo::Color;
-#[cfg(feature = "gecko")] pub use self::gecko::Color;
+impl From<RGBA> for Color {
+    fn from(value: RGBA) -> Self {
+        Color::rgba(value)
+    }
+}
+
+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(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)
+                }
+            }
+            #[cfg(not(feature = "gecko"))] {
+                Err(())
+            }
+        }
+    }
+}
+
+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::Numeric { authored: Some(ref authored), .. } => dest.write_str(authored),
+            Color::Numeric { parsed: ref rgba, .. } => rgba.to_css(dest),
+            Color::Complex(_) => Ok(()),
+            #[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(()),
+        }
+    }
+}
 
-#[cfg(not(feature = "gecko"))]
-mod servo {
-    pub use cssparser::Color;
-    use cssparser::Parser;
-    use parser::{Parse, ParserContext};
+/// 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 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())
+    }
+
+    /// 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, ()> {
+        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))
+        })
+    }
 
-    impl Parse for Color {
-        fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-            Color::parse(input)
+    /// 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 parse_hash_color(ident.as_bytes());
+            }
+            _ => {
+                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);
+        parse_hash_color(&serialization)
+    }
+
+    /// Returns false if the color is completely transparent, and
+    /// true otherwise.
+    pub fn is_non_transparent(&self) -> bool {
+        match *self {
+            Color::Numeric { ref parsed, .. } => parsed.alpha != 0,
+            _ => true,
         }
     }
 }
 
 #[cfg(feature = "gecko")]
-mod gecko {
-    use cssparser::{Color as CSSParserColor, Parser, RGBA};
-    use parser::{Parse, ParserContext};
-    use properties::longhands::color::SystemColor;
-    use std::fmt;
-    use style_traits::ToCss;
+fn convert_nscolor_to_computedcolor(color: nscolor) -> ComputedColor {
+    use gecko::values::convert_nscolor_to_rgba;
+    ComputedColor::rgba(convert_nscolor_to_rgba(color))
+}
+
+impl ToComputedValue for Color {
+    type ComputedValue = ComputedColor;
 
-    /// Color value including non-standard -moz prefixed values.
-    #[derive(Clone, Copy, PartialEq, Debug)]
-    pub enum Color {
-        /// The 'currentColor' keyword
-        CurrentColor,
-        /// A specific RGBA color
-        RGBA(RGBA),
-        /// A system color
-        System(SystemColor),
-        /// -moz-default-color
-        MozDefaultColor,
-        /// -moz-default-background-color
-        MozDefaultBackgroundColor,
-        /// -moz-hyperlinktext
-        MozHyperlinktext,
-        /// -moz-activehyperlinktext
-        MozActiveHyperlinktext,
-        /// -moz-visitedhyperlinktext
-        MozVisitedHyperlinktext,
-        /// Quirksmode-only rule for inheriting color from the body
-        InheritFromBodyQuirk,
-    }
-
-    no_viewport_percentage!(Color);
-
-    impl From<CSSParserColor> for Color {
-        fn from(value: CSSParserColor) -> Self {
-            match value {
-                CSSParserColor::CurrentColor => Color::CurrentColor,
-                CSSParserColor::RGBA(x) => Color::RGBA(x),
+    fn to_computed_value(&self, _context: &Context) -> ComputedColor {
+        match *self {
+            Color::CurrentColor => ComputedColor::currentcolor(),
+            Color::Numeric { ref parsed, .. } => ComputedColor::rgba(*parsed),
+            Color::Complex(ref complex) => *complex,
+            #[cfg(feature = "gecko")]
+            Color::System(system) =>
+                convert_nscolor_to_computedcolor(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 };
+                convert_nscolor_to_computedcolor(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 body = unsafe {
+                    Gecko_GetBody(pres_context)
+                };
+                if let Some(body) = body {
+                    let wrap = GeckoElement(body);
+                    let borrow = wrap.borrow_data();
+                    ComputedColor::rgba(borrow.as_ref().unwrap()
+                                              .styles().primary.values()
+                                              .get_color()
+                                              .clone_color())
+                } else {
+                    convert_nscolor_to_computedcolor(pres_context.mDefaultColor)
+                }
+            },
         }
     }
 
-    impl Parse for Color {
-        fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-            if let Ok(value) = input.try(CSSParserColor::parse) {
-                Ok(value.into())
-            } else if let Ok(system) = input.try(SystemColor::parse) {
-                Ok(Color::System(system))
-            } else {
-                let ident = input.expect_ident()?;
-                match_ignore_ascii_case! { &ident,
-                    "-moz-default-color" => Ok(Color::MozDefaultColor),
-                    "-moz-default-background-color" => Ok(Color::MozDefaultBackgroundColor),
-                    "-moz-hyperlinktext" => Ok(Color::MozHyperlinktext),
-                    "-moz-activehyperlinktext" => Ok(Color::MozActiveHyperlinktext),
-                    "-moz-visitedhyperlinktext" => Ok(Color::MozVisitedHyperlinktext),
-                    _ => Err(())
-                }
-            }
-        }
-    }
-
-    impl ToCss for Color {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            match *self {
-                // Standard values:
-                Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
-                Color::RGBA(rgba) => rgba.to_css(dest),
-                Color::System(system) => system.to_css(dest),
-
-                // Non-standard values:
-                Color::MozDefaultColor => dest.write_str("-moz-default-color"),
-                Color::MozDefaultBackgroundColor => dest.write_str("-moz-default-background-color"),
-                Color::MozHyperlinktext => dest.write_str("-moz-hyperlinktext"),
-                Color::MozActiveHyperlinktext => dest.write_str("-moz-activehyperlinktext"),
-                Color::MozVisitedHyperlinktext => dest.write_str("-moz-visitedhyperlinktext"),
-                Color::InheritFromBodyQuirk => Ok(()),
-            }
+    fn from_computed_value(computed: &ComputedColor) -> Self {
+        if computed.is_numeric() {
+            Color::rgba(computed.color)
+        } else if computed.is_currentcolor() {
+            Color::currentcolor()
+        } else {
+            Color::Complex(*computed)
         }
     }
 }
+
+/// 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 Color);
+
+no_viewport_percentage!(RGBAColor);
+
+impl Parse for RGBAColor {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        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)
+    }
+}
+
+impl ToComputedValue for RGBAColor {
+    type ComputedValue = RGBA;
+
+    fn to_computed_value(&self, context: &Context) -> RGBA {
+        self.0.to_computed_value(context)
+            .to_rgba(context.style.get_color().clone_color())
+    }
+
+    fn from_computed_value(computed: &RGBA) -> Self {
+        RGBAColor(Color::rgba(*computed))
+    }
+}
+
+impl From<Color> for RGBAColor {
+    fn from(color: Color) -> RGBAColor {
+        RGBAColor(color)
+    }
+}
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -19,18 +19,18 @@ 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::image::PaintWorklet;
 use values::generics::position::Position as GenericPosition;
-use values::specified::{Angle, CSSColor, Color, Length, LengthOrPercentage};
-use values::specified::{Number, NumberOrPercentage, Percentage};
+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.
 /// https://drafts.csswg.org/css-images/#image-values
@@ -38,17 +38,17 @@ pub type Image = GenericImage<Gradient, 
 
 /// Specified values for a CSS gradient.
 /// https://drafts.csswg.org/css-images/#gradients
 pub type Gradient = GenericGradient<
     LineDirection,
     Length,
     LengthOrPercentage,
     Position,
-    CSSColor,
+    RGBAColor,
 >;
 
 /// A specified gradient kind.
 pub type GradientKind = GenericGradientKind<
     LineDirection,
     Length,
     LengthOrPercentage,
     Position,
@@ -67,20 +67,20 @@ pub enum LineDirection {
     /// A direction towards a corner of a box.
     Corner(X, Y),
 }
 
 /// A specified ending shape.
 pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
 
 /// A specified gradient item.
-pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;
+pub type GradientItem = GenericGradientItem<RGBAColor, LengthOrPercentage>;
 
 /// A computed color stop.
-pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;
+pub type ColorStop = GenericColorStop<RGBAColor, LengthOrPercentage>;
 
 /// Specified values for `moz-image-rect`
 /// -moz-image-rect(<uri>, top, right, bottom, left);
 pub type ImageRect = GenericImageRect<NumberOrPercentage>;
 
 impl Parse for Image {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
         #[cfg(feature = "gecko")]
@@ -381,40 +381,40 @@ 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, p))
+                    Ok((color.into(), p))
                 })?;
                 if reverse_stops {
                     p = 1. - p;
                 }
                 Ok(GenericGradientItem::ColorStop(GenericColorStop {
                     color: color,
                     position: Some(LengthOrPercentage::Percentage(Percentage(p))),
                 }))
             })
         }).unwrap_or(vec![]);
 
         if items.is_empty() {
             items = vec![
                 GenericGradientItem::ColorStop(GenericColorStop {
-                    color: CSSColor::transparent(),
+                    color: Color::transparent().into(),
                     position: Some(Percentage(0.).into()),
                 }),
                 GenericGradientItem::ColorStop(GenericColorStop {
-                    color: CSSColor::transparent(),
+                    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| {
@@ -669,17 +669,17 @@ impl GradientItem {
         }
         Ok(items)
     }
 }
 
 impl Parse for ColorStop {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         Ok(ColorStop {
-            color: try!(CSSColor::parse(context, input)),
+            color: try!(RGBAColor::parse(context, input)),
             position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
         })
     }
 }
 
 impl Parse for PaintWorklet {
     fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         input.expect_function_matching("paint")?;
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -3,42 +3,40 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Specified values.
 //!
 //! TODO(emilio): Enhance docs.
 
 use Namespace;
 use context::QuirksMode;
-use cssparser::{self, Parser, Token, serialize_identifier};
-use itoa;
+use cssparser::{Parser, Token, serialize_identifier};
 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;
 
 pub use properties::animated_properties::TransitionProperty;
 #[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::{Color, RGBAColor};
 pub use self::rect::LengthOrNumberRect;
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
 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};
@@ -87,176 +85,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()
-    }
-}
-
-#[derive(Clone, PartialEq, Debug)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[allow(missing_docs)]
-pub struct CSSRGBA {
-    pub parsed: cssparser::RGBA,
-    pub authored: Option<Box<str>>,
-}
-
-no_viewport_percentage!(CSSRGBA);
-
-impl ToCss for CSSRGBA {
-    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),
-        }
-    }
-}
-
 /// 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)
             }));
@@ -838,34 +676,32 @@ 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 {
         ComputedShadow {
             offset_x: self.offset_x.to_computed_value(context),
             offset_y: self.offset_y.to_computed_value(context),
             blur_radius: self.blur_radius.to_computed_value(context),
             spread_radius: self.spread_radius.to_computed_value(context),
-            color: self.color
-                        .as_ref()
-                        .map(|color| color.to_computed_value(context))
-                        .unwrap_or(cssparser::Color::CurrentColor),
+            color: self.color.as_ref().unwrap_or(&Color::CurrentColor)
+                             .to_computed_value(context),
             inset: self.inset,
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &ComputedShadow) -> Self {
         Shadow {
             offset_x: ToComputedValue::from_computed_value(&computed.offset_x),
@@ -928,17 +764,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.
@@ -956,20 +792,20 @@ impl Shadow {
             inset: inset,
         })
     }
 }
 
 no_viewport_percentage!(SVGPaint);
 
 /// Specified SVG Paint value
-pub type SVGPaint = ::values::generics::SVGPaint<CSSColor>;
+pub type SVGPaint = ::values::generics::SVGPaint<RGBAColor>;
 
 /// Specified SVG Paint Kind value
-pub type SVGPaintKind = ::values::generics::SVGPaintKind<CSSColor>;
+pub type SVGPaintKind = ::values::generics::SVGPaintKind<RGBAColor>;
 
 impl ToComputedValue for SVGPaint {
     type ComputedValue = super::computed::SVGPaint;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         super::computed::SVGPaint {
             kind: self.kind.to_computed_value(context),
@@ -986,22 +822,17 @@ impl ToComputedValue for SVGPaint {
     }
 }
 
 impl ToComputedValue for SVGPaintKind {
     type ComputedValue = super::computed::SVGPaintKind;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
-        self.convert(|color| {
-            match color.parsed {
-                Color::CurrentColor => cssparser::Color::RGBA(context.style().get_color().clone_color()),
-                _ => color.to_computed_value(context),
-            }
-        })
+        self.convert(|color| color.to_computed_value(context))
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         computed.convert(ToComputedValue::from_computed_value)
     }
 }
 
@@ -1159,17 +990,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,
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/specified/mod.rs.rej
@@ -0,0 +1,44 @@
+--- components/style/values/specified/mod.rs
++++ 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};
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -2211,20 +2211,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| {
@@ -2235,21 +2235,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::{Color, RGBA};
+use cssparser::RGBA;
 use parsing::parse;
 use style::values::{Auto, Either};
-use style::values::specified::CSSColor;
+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
@@ -1,20 +1,20 @@
 /* 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 properties::parse;
 use style::computed_values::display::T::inline_block;
 use style::properties::{PropertyDeclaration, Importance, PropertyId};
-use style::properties::longhands::outline_color::computed_value::T as ComputedColor;
 use style::properties::parse_property_declaration_list;
 use style::values::{RGBA, Auto};
 use style::values::CustomIdent;
-use style::values::specified::{BorderStyle, BorderSideWidth, CSSColor, Length, LengthOrPercentage};
+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;
 
 #[test]
@@ -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: ComputedColor::RGBA(RGBA::new(128, 0, 128, 255)),
-                authored: None
-            };
+            let color = RGBA::new(128, 0, 128, 255).into();
 
             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: ComputedColor::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: ComputedColor::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: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
-
-            let blue = CSSColor {
-                parsed: ComputedColor::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: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
+            let color = RGBA::new(255, 0, 0, 255).into();
 
             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: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
+            let color = RGBA::new(255, 0, 0, 255).into();
 
             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: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
-                authored: None
-            };
+            let color = RGBA::new(255, 0, 0, 255).into();
             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
@@ -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: cssparser::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(