servo: Merge #15931 - style: Kill SharedStyleContext::default_computed_values (from emilio:die-defaultvalues-die); r=mbrubeck
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 13 Mar 2017 16:50:26 -0700
changeset 347413 c1880dccfde597ff54f0dea2028f8d56d8231a89
parent 347412 e924204de04084739434958143a0b7e9a78cbd23
child 347414 27faa5825463a71e06c7abd41c0097beae540207
push id31496
push usercbook@mozilla.com
push dateTue, 14 Mar 2017 13:21:57 +0000
treeherdermozilla-central@9a26ed658fdc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbrubeck
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 #15931 - style: Kill SharedStyleContext::default_computed_values (from emilio:die-defaultvalues-die); r=mbrubeck This is on top of https://github.com/servo/servo/pull/15928. Now that cascade() gets a Device ref, we can use the default computed values from there to avoid propagating that state all over the place. Source-Repo: https://github.com/servo/servo Source-Revision: 8c8edb8731dc01d254839d0922590fba72f278c6
servo/components/layout/construct.rs
servo/components/layout_thread/lib.rs
servo/components/script/dom/css.rs
servo/components/script/dom/csssupportsrule.rs
servo/components/script/dom/window.rs
servo/components/script_layout_interface/reporter.rs
servo/components/script_layout_interface/wrapper_traits.rs
servo/components/style/animation.rs
servo/components/style/context.rs
servo/components/style/error_reporting.rs
servo/components/style/gecko/data.rs
servo/components/style/gecko/media_queries.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/keyframes.rs
servo/components/style/matching.rs
servo/components/style/parser.rs
servo/components/style/properties/declaration_block.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/color.mako.rs
servo/components/style/properties/longhand/inherited_text.mako.rs
servo/components/style/properties/longhand/outline.mako.rs
servo/components/style/properties/longhand/text.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/properties/shorthand/serialize.mako.rs
servo/components/style/properties/shorthand/text.mako.rs
servo/components/style/servo/media_queries.rs
servo/components/style/stylesheets.rs
servo/components/style/stylist.rs
servo/components/style/values/computed/image.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/specified/color.rs
servo/components/style/values/specified/mod.rs
servo/components/style/viewport.rs
servo/ports/geckolib/glue.rs
servo/tests/unit/style/media_queries.rs
servo/tests/unit/style/parsing/background.rs
servo/tests/unit/style/parsing/border.rs
servo/tests/unit/style/parsing/column.rs
servo/tests/unit/style/parsing/effects.rs
servo/tests/unit/style/parsing/font.rs
servo/tests/unit/style/parsing/image.rs
servo/tests/unit/style/parsing/inherited_text.rs
servo/tests/unit/style/parsing/mask.rs
servo/tests/unit/style/parsing/mod.rs
servo/tests/unit/style/parsing/outline.rs
servo/tests/unit/style/parsing/ui.rs
servo/tests/unit/style/properties/background.rs
servo/tests/unit/style/properties/serialization.rs
servo/tests/unit/style/rule_tree/bench.rs
servo/tests/unit/style/stylesheets.rs
servo/tests/unit/style/viewport.rs
--- a/servo/components/layout/construct.rs
+++ b/servo/components/layout/construct.rs
@@ -657,18 +657,18 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
                     self.set_flow_construction_result(&kid, ConstructionResult::None)
                 }
             }
 
             let mut style = node.style(self.style_context());
             if node_is_input_or_text_area {
                 style = self.style_context()
                             .stylist
-                            .style_for_anonymous_box(&PseudoElement::ServoInputText, &style,
-                                                     &self.style_context().default_computed_values)
+                            .style_for_anonymous_box(&PseudoElement::ServoInputText,
+                                                     &style)
             }
 
             self.create_fragments_for_node_text_content(&mut initial_fragments, node, &style)
         }
 
         self.build_flow_for_block_starting_with_fragments(flow, node, initial_fragments)
     }
 
@@ -1095,17 +1095,17 @@ impl<'a, ConcreteThreadSafeLayoutNode: T
     fn build_flow_for_table(&mut self, node: &ConcreteThreadSafeLayoutNode, float_value: float::T)
                             -> ConstructionResult {
         let mut legalizer = Legalizer::new();
 
         let table_style = node.style(self.style_context());
         let wrapper_style = self.style_context()
                                 .stylist
                                 .style_for_anonymous_box(&PseudoElement::ServoTableWrapper,
-                                                         &table_style, &self.style_context().default_computed_values);
+                                                         &table_style);
         let wrapper_fragment =
             Fragment::from_opaque_node_and_style(node.opaque(),
                                                  PseudoElementType::Normal,
                                                  wrapper_style,
                                                  node.selected_style(),
                                                  node.restyle_damage(),
                                                  SpecificFragmentInfo::TableWrapper);
         let wrapper_float_kind = FloatKind::from_property(float_value);
@@ -2075,17 +2075,18 @@ impl Legalizer {
                                 pseudos: &[PseudoElement],
                                 specific_fragment_info: SpecificFragmentInfo,
                                 constructor: extern "Rust" fn(Fragment) -> F)
                                 -> FlowRef
                                 where F: Flow {
         let reference_block = reference.as_block();
         let mut new_style = reference_block.fragment.style.clone();
         for pseudo in pseudos {
-            new_style = context.stylist.style_for_anonymous_box(pseudo, &new_style, &context.default_computed_values)
+            new_style = context.stylist.style_for_anonymous_box(pseudo,
+                                                                &new_style)
         }
         let fragment = reference_block.fragment
                                       .create_similar_anonymous_fragment(new_style,
                                                                          specific_fragment_info);
         FlowRef::new(Arc::new(constructor(fragment)))
     }
 }
 
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -105,21 +105,20 @@ use std::process;
 use std::sync::{Arc, Mutex, MutexGuard};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::thread;
 use style::animation::Animation;
 use style::context::{QuirksMode, ReflowGoal, SharedStyleContext, ThreadLocalStyleContextCreationInfo};
 use style::data::StoredRestyleHint;
 use style::dom::{ShowSubtree, ShowSubtreeDataAndPrimaryValues, TElement, TNode};
-use style::error_reporting::{ParseErrorReporter, StdoutErrorReporter};
+use style::error_reporting::StdoutErrorReporter;
 use style::logical_geometry::LogicalPoint;
 use style::media_queries::{Device, MediaType};
 use style::parser::ParserContextExtraData;
-use style::properties::ComputedValues;
 use style::servo::restyle_damage::{REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, REPOSITION, STORE_OVERFLOW};
 use style::stylesheets::{Origin, Stylesheet, UserAgentStylesheets};
 use style::stylist::Stylist;
 use style::thread_state;
 use style::timer::Timer;
 use style::traversal::{DomTraversal, TraversalDriver};
 
 /// Information needed by the layout thread.
@@ -501,25 +500,20 @@ impl LayoutThread {
         let thread_local_style_context_creation_data =
             ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone());
 
         LayoutContext {
             style_context: SharedStyleContext {
                 stylist: rw_data.stylist.clone(),
                 running_animations: self.running_animations.clone(),
                 expired_animations: self.expired_animations.clone(),
-                error_reporter: self.error_reporter.clone(),
+                error_reporter: Box::new(self.error_reporter.clone()),
                 local_context_creation_data: Mutex::new(thread_local_style_context_creation_data),
                 timer: self.timer.clone(),
                 quirks_mode: self.quirks_mode.unwrap(),
-                // FIXME(bz): This isn't really right, but it's no more wrong
-                // than what we used to do.  See
-                // https://github.com/servo/servo/issues/14773 for fixing it
-                // properly.
-                default_computed_values: Arc::new(ComputedValues::initial_values().clone()),
             },
             image_cache_thread: Mutex::new(self.image_cache_thread.clone()),
             font_cache_thread: Mutex::new(self.font_cache_thread.clone()),
             webrender_image_cache: self.webrender_image_cache.clone(),
             pending_images: if request_images { Some(Mutex::new(vec![])) } else { None },
         }
     }
 
@@ -1564,31 +1558,30 @@ fn get_ua_stylesheets() -> Result<UserAg
         Ok(Stylesheet::from_bytes(
             &res,
             ServoUrl::parse(&format!("chrome://resources/{:?}", filename)).unwrap(),
             None,
             None,
             Origin::UserAgent,
             Default::default(),
             None,
-            Box::new(StdoutErrorReporter),
+            &StdoutErrorReporter,
             ParserContextExtraData::default()))
     }
 
     let mut user_or_user_agent_stylesheets = vec!();
     // FIXME: presentational-hints.css should be at author origin with zero specificity.
     //        (Does it make a difference?)
     for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] {
         user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(filename)));
     }
     for &(ref contents, ref url) in &opts::get().user_stylesheets {
         user_or_user_agent_stylesheets.push(Stylesheet::from_bytes(
             &contents, url.clone(), None, None, Origin::User, Default::default(),
-            None, Box::new(StdoutErrorReporter),
-            ParserContextExtraData::default()));
+            None, &StdoutErrorReporter, ParserContextExtraData::default()));
     }
 
     let quirks_mode_stylesheet = try!(parse_ua_stylesheet("quirks-mode.css"));
 
     Ok(UserAgentStylesheets {
         user_or_user_agent_stylesheets: user_or_user_agent_stylesheets,
         quirks_mode_stylesheet: quirks_mode_stylesheet,
     })
--- a/servo/components/script/dom/css.rs
+++ b/servo/components/script/dom/css.rs
@@ -24,25 +24,25 @@ impl CSS {
         serialize_identifier(&ident, &mut escaped).unwrap();
         Ok(DOMString::from(escaped))
     }
 
     /// https://drafts.csswg.org/css-conditional/#dom-css-supports
     pub fn Supports(win: &Window, property: DOMString, value: DOMString) -> bool {
         let decl = Declaration { prop: property.into(), val: value.into() };
         let url = win.Document().url();
-        let context = ParserContext::new_for_cssom(&url);
+        let context = ParserContext::new_for_cssom(&url, win.css_error_reporter());
         decl.eval(&context)
     }
 
     /// https://drafts.csswg.org/css-conditional/#dom-css-supports
     pub fn Supports_(win: &Window, condition: DOMString) -> bool {
         let mut input = Parser::new(&condition);
         let cond = parse_condition_or_declaration(&mut input);
         if let Ok(cond) = cond {
             let url = win.Document().url();
-            let context = ParserContext::new_for_cssom(&url);
+            let context = ParserContext::new_for_cssom(&url, win.css_error_reporter());
             cond.eval(&context)
         } else {
             false
         }
     }
 }
--- a/servo/components/script/dom/csssupportsrule.rs
+++ b/servo/components/script/dom/csssupportsrule.rs
@@ -51,18 +51,20 @@ impl CSSSupportsRule {
         rule.condition.to_css_string().into()
     }
 
     /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
     pub fn set_condition_text(&self, text: DOMString) {
         let mut input = Parser::new(&text);
         let cond = SupportsCondition::parse(&mut input);
         if let Ok(cond) = cond {
-            let url = self.global().as_window().Document().url();
-            let context = ParserContext::new_for_cssom(&url);
+            let global = self.global();
+            let win = global.as_window();
+            let url = win.Document().url();
+            let context = ParserContext::new_for_cssom(&url, win.css_error_reporter());
             let enabled = cond.eval(&context);
             let mut rule = self.supportsrule.write();
             rule.condition = cond;
             rule.enabled = enabled;
         }
     }
 }
 
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -326,18 +326,18 @@ impl Window {
     pub fn bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
         self.bluetooth_thread.clone()
     }
 
     pub fn bluetooth_extra_permission_data(&self) -> &BluetoothExtraPermissionData {
          &self.bluetooth_extra_permission_data
     }
 
-    pub fn css_error_reporter(&self) -> Box<ParseErrorReporter + Send> {
-        self.error_reporter.clone()
+    pub fn css_error_reporter(&self) -> &ParseErrorReporter {
+        &self.error_reporter
     }
 
     /// Sets a new list of scroll offsets.
     ///
     /// This is called when layout gives us new ones and WebRender is in use.
     pub fn set_scroll_offsets(&self, offsets: HashMap<UntrustedNodeAddress, Point2D<f32>>) {
         *self.scroll_offsets.borrow_mut() = offsets
     }
--- a/servo/components/script_layout_interface/reporter.rs
+++ b/servo/components/script_layout_interface/reporter.rs
@@ -6,42 +6,42 @@ use cssparser::{Parser, SourcePosition};
 use ipc_channel::ipc::IpcSender;
 use log;
 use msg::constellation_msg::PipelineId;
 use script_traits::ConstellationControlMsg;
 use servo_url::ServoUrl;
 use std::sync::{Mutex, Arc};
 use style::error_reporting::ParseErrorReporter;
 
-#[derive(HeapSizeOf)]
+#[derive(HeapSizeOf, Clone)]
 pub struct CSSErrorReporter {
     pub pipelineid: PipelineId,
     // Arc+Mutex combo is necessary to make this struct Sync,
     // which is necessary to fulfill the bounds required by the
     // uses of the ParseErrorReporter trait.
     #[ignore_heap_size_of = "Arc is defined in libstd"]
     pub script_chan: Arc<Mutex<IpcSender<ConstellationControlMsg>>>,
 }
 
 impl ParseErrorReporter for CSSErrorReporter {
-     fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str,
-        url: &ServoUrl) {
+     fn report_error(&self,
+                     input: &mut Parser,
+                     position: SourcePosition,
+                     message: &str,
+                     url: &ServoUrl) {
         let location = input.source_location(position);
         if log_enabled!(log::LogLevel::Info) {
-             info!("Url:\t{}\n{}:{} {}", url.as_str(), location.line, location.column, message)
+             info!("Url:\t{}\n{}:{} {}",
+                   url.as_str(),
+                   location.line,
+                   location.column,
+                   message)
         }
 
          //TODO: report a real filename
          let _ = self.script_chan.lock().unwrap().send(
              ConstellationControlMsg::ReportCSSError(self.pipelineid,
                                                      "".to_owned(),
                                                      location.line,
                                                      location.column,
                                                      message.to_owned()));
      }
-
-     fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
-         box CSSErrorReporter {
-             pipelineid: self.pipelineid,
-             script_chan: self.script_chan.clone(),
-         }
-     }
 }
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -402,35 +402,33 @@ pub trait ThreadSafeLayoutElement: Clone
                                 .unwrap()
                                 .borrow()
                                 .styles().pseudos.contains_key(&style_pseudo) {
                             let mut data = self.get_style_data().unwrap().borrow_mut();
                             let new_style =
                                 context.stylist.precomputed_values_for_pseudo(
                                     &style_pseudo,
                                     Some(data.styles().primary.values()),
-                                    &context.default_computed_values,
                                     CascadeFlags::empty());
                             data.styles_mut().pseudos
                                 .insert(style_pseudo.clone(), new_style);
                         }
                     }
                     PseudoElementCascadeType::Lazy => {
                         if !self.get_style_data()
                                 .unwrap()
                                 .borrow()
                                 .styles().pseudos.contains_key(&style_pseudo) {
                             let mut data = self.get_style_data().unwrap().borrow_mut();
                             let new_style =
                                 context.stylist
                                        .lazily_compute_pseudo_element_style(
                                            unsafe { &self.unsafe_get() },
                                            &style_pseudo,
-                                           data.styles().primary.values(),
-                                           &context.default_computed_values);
+                                           data.styles().primary.values());
                             data.styles_mut().pseudos
                                 .insert(style_pseudo.clone(), new_style.unwrap());
                         }
                     }
                 }
 
                 self.get_style_data().unwrap().borrow()
                     .styles().pseudos.get(&style_pseudo)
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -421,24 +421,23 @@ fn compute_style_for_animation_step(cont
             debug_assert!(guard.declarations().iter()
                             .all(|&(_, importance)| importance == Importance::Normal));
 
             let iter = || {
                 guard.declarations().iter().rev().map(|&(ref decl, _importance)| decl)
             };
 
             let computed =
-                properties::apply_declarations(context.viewport_size(),
+                properties::apply_declarations(&context.stylist.device,
                                                /* is_root = */ false,
                                                iter,
                                                previous_style,
                                                previous_style,
-                                               &context.default_computed_values,
                                                /* cascade_info = */ None,
-                                               context.error_reporter.clone(),
+                                               &*context.error_reporter,
                                                /* Metrics provider */ None,
                                                CascadeFlags::empty());
             computed
         }
     }
 }
 
 /// Triggers animations for a given node looking at the animation property
--- a/servo/components/style/context.rs
+++ b/servo/components/style/context.rs
@@ -9,17 +9,16 @@ use animation::Animation;
 use app_units::Au;
 use bloom::StyleBloom;
 use data::ElementData;
 use dom::{OpaqueNode, TNode, TElement, SendElement};
 use error_reporting::ParseErrorReporter;
 use euclid::Size2D;
 use matching::StyleSharingCandidateCache;
 use parking_lot::RwLock;
-use properties::ComputedValues;
 use selector_parser::PseudoElement;
 use selectors::matching::ElementSelectorFlags;
 use servo_config::opts;
 use std::collections::HashMap;
 use std::env;
 use std::fmt;
 use std::ops::Add;
 use std::sync::{Arc, Mutex};
@@ -68,31 +67,27 @@ pub struct SharedStyleContext {
 
     /// The animations that are currently running.
     pub running_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
 
     /// The list of animations that have expired since the last style recalculation.
     pub expired_animations: Arc<RwLock<HashMap<OpaqueNode, Vec<Animation>>>>,
 
     ///The CSS error reporter for all CSS loaded in this layout thread
-    pub error_reporter: Box<ParseErrorReporter + Sync>,
+    pub error_reporter: Box<ParseErrorReporter>,
 
     /// Data needed to create the thread-local style context from the shared one.
     pub local_context_creation_data: Mutex<ThreadLocalStyleContextCreationInfo>,
 
     /// The current timer for transitions and animations. This is needed to test
     /// them.
     pub timer: Timer,
 
     /// The QuirksMode state which the document needs to be rendered with
     pub quirks_mode: QuirksMode,
-
-    /// The default computed values to use for elements with no rules
-    /// applying to them.
-    pub default_computed_values: Arc<ComputedValues>,
 }
 
 impl SharedStyleContext {
     /// Return a suitable viewport size in order to be used for viewport units.
     pub fn viewport_size(&self) -> Size2D<Au> {
         self.stylist.device.au_viewport_size()
     }
 }
--- a/servo/components/style/error_reporting.rs
+++ b/servo/components/style/error_reporting.rs
@@ -6,37 +6,36 @@
 
 #![deny(missing_docs)]
 
 use cssparser::{Parser, SourcePosition};
 use log;
 use servo_url::ServoUrl;
 
 /// A generic trait for an error reporter.
-pub trait ParseErrorReporter {
+pub trait ParseErrorReporter : Sync + Send {
     /// Called the style engine detects an error.
     ///
     /// Returns the current input being parsed, the source position it was
     /// reported from, and a message.
-    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str, url: &ServoUrl);
-    /// Clone this error reporter.
-    ///
-    /// TODO(emilio): I'm pretty sure all the box shenanigans can go away.
-    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync>;
+    fn report_error(&self,
+                    input: &mut Parser,
+                    position: SourcePosition,
+                    message: &str,
+                    url: &ServoUrl);
 }
 
 /// An error reporter that reports the errors to the `info` log channel.
 ///
 /// TODO(emilio): The name of this reporter is a lie, and should be renamed!
 pub struct StdoutErrorReporter;
 impl ParseErrorReporter for StdoutErrorReporter {
-    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str,
-        url: &ServoUrl) {
+    fn report_error(&self,
+                    input: &mut Parser,
+                    position: SourcePosition,
+                    message: &str,
+                    url: &ServoUrl) {
         if log_enabled!(log::LogLevel::Info) {
             let location = input.source_location(position);
             info!("Url:\t{}\n{}:{} {}", url.as_str(), location.line, location.column, message)
         }
     }
-
-    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
-        Box::new(StdoutErrorReporter)
-    }
 }
--- a/servo/components/style/gecko/data.rs
+++ b/servo/components/style/gecko/data.rs
@@ -98,17 +98,17 @@ impl PerDocumentStyleDataImpl {
             let mut stylist = Arc::get_mut(&mut self.stylist).unwrap();
             stylist.update(&self.stylesheets, None, true);
             self.stylesheets_changed = false;
         }
     }
 
     /// Get the default computed values for this document.
     pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
-        self.stylist.device.default_values_arc()
+        self.stylist.device.default_computed_values_arc()
     }
 }
 
 unsafe impl HasFFI for PerDocumentStyleData {
     type FFIType = RawServoStyleSet;
 }
 unsafe impl HasSimpleFFI for PerDocumentStyleData {}
 unsafe impl HasBoxFFI for PerDocumentStyleData {}
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -24,17 +24,17 @@ use values::{CSSFloat, specified};
 use values::computed::{self, ToComputedValue};
 
 /// The `Device` in Gecko wraps a pres context, has a default values computed,
 /// and contains all the viewport rule state.
 pub struct Device {
     /// NB: The pres context lifetime is tied to the styleset, who owns the
     /// stylist, and thus the `Device`, so having a raw pres context pointer
     /// here is fine.
-    pres_context: RawGeckoPresContextOwned,
+    pub pres_context: RawGeckoPresContextOwned,
     default_values: Arc<ComputedValues>,
     viewport_override: Option<ViewportConstraints>,
 }
 
 impl Device {
     /// Trivially constructs a new `Device`.
     pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
         assert!(!pres_context.is_null());
@@ -49,20 +49,26 @@ impl Device {
     /// relevant viewport constraints.
     pub fn account_for_viewport_rule(&mut self,
                                      constraints: &ViewportConstraints) {
         self.viewport_override = Some(constraints.clone());
     }
 
     /// Returns the default computed values as a reference, in order to match
     /// Servo.
-    pub fn default_values(&self) -> &ComputedValues {
+    pub fn default_computed_values(&self) -> &ComputedValues {
         &*self.default_values
     }
 
+    /// Returns the default computed values, but wrapped in an arc for cheap
+    /// cloning.
+    pub fn default_computed_values_arc(&self) -> &Arc<ComputedValues> {
+        &self.default_values
+    }
+
     /// Returns the default computed values as an `Arc`, in order to avoid
     /// clones.
     pub fn default_values_arc(&self) -> &Arc<ComputedValues> {
         &self.default_values
     }
 
     /// Recreates all the temporary state that the `Device` stores.
     ///
@@ -486,29 +492,29 @@ impl Expression {
                         -> bool {
         use self::MediaExpressionValue::*;
         use std::cmp::Ordering;
 
         debug_assert!(self.range == nsMediaExpression_Range::eEqual ||
                       self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
                       "Whoops, wrong range");
 
-        let default_values = device.default_values();
+        let default_values = device.default_computed_values();
 
         // http://dev.w3.org/csswg/mediaqueries3/#units
         // em units are relative to the initial font-size.
         let context = computed::Context {
             is_root_element: false,
-            viewport_size: device.au_viewport_size(),
+            device: device,
             inherited_style: default_values,
             layout_parent_style: default_values,
             // This cloning business is kind of dumb.... It's because Context
             // insists on having an actual ComputedValues inside itself.
             style: default_values.clone(),
-            font_metrics_provider: None
+            font_metrics_provider: None,
         };
 
         let required_value = match self.value {
             Some(ref v) => v,
             None => {
                 // If there's no value, always match unless it's a zero length
                 // or a zero integer or boolean.
                 return match *actual_value {
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -294,17 +294,17 @@ impl<'le> fmt::Debug for GeckoElement<'l
     }
 }
 
 impl<'le> GeckoElement<'le> {
     /// Parse the style attribute of an element.
     pub fn parse_style_attribute(value: &str,
                                  base_url: &ServoUrl,
                                  extra_data: ParserContextExtraData) -> PropertyDeclarationBlock {
-        parse_style_attribute(value, base_url, Box::new(StdoutErrorReporter), extra_data)
+        parse_style_attribute(value, base_url, &StdoutErrorReporter, extra_data)
     }
 
     fn flags(&self) -> u32 {
         self.raw_node()._base._base_1.mFlags
     }
 
     fn raw_node(&self) -> &RawGeckoNode {
         &(self.0)._base._base._base
--- a/servo/components/style/keyframes.rs
+++ b/servo/components/style/keyframes.rs
@@ -121,20 +121,20 @@ impl ToCss for Keyframe {
 
 
 impl Keyframe {
     /// Parse a CSS keyframe.
     pub fn parse(css: &str,
                  parent_stylesheet: &Stylesheet,
                  extra_data: ParserContextExtraData)
                  -> Result<Arc<RwLock<Self>>, ()> {
-        let error_reporter = Box::new(MemoryHoleReporter);
+        let error_reporter = MemoryHoleReporter;
         let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                          &parent_stylesheet.base_url,
-                                                         error_reporter,
+                                                         &error_reporter,
                                                          extra_data);
         let mut input = Parser::new(css);
 
         let mut rule_parser = KeyframeListParser {
             context: &context,
         };
         parse_one_rule(&mut input, &mut rule_parser)
     }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -534,23 +534,22 @@ trait PrivateMatchMethods: TElement {
                     p.is_multicol() ||
                     layout_parent_el.as_ref().unwrap().as_node().can_be_fragmented();
                 unsafe { self.as_node().set_can_be_fragmented(can_be_fragmented); }
             }
         }
 
         // Invoke the cascade algorithm.
         let values =
-            Arc::new(cascade(shared_context.viewport_size(),
+            Arc::new(cascade(&shared_context.stylist.device,
                              rule_node,
                              inherited_values,
                              layout_parent_style,
-                             &shared_context.default_computed_values,
                              Some(&mut cascade_info),
-                             shared_context.error_reporter.clone(),
+                             &*shared_context.error_reporter,
                              cascade_flags));
 
         cascade_info.finish(&self.as_node());
         values
     }
 
     /// Computes values and damage for the primary or pseudo style of an element,
     /// setting them on the ElementData.
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -7,17 +7,17 @@
 #![deny(missing_docs)]
 
 use cssparser::{Parser, SourcePosition, UnicodeRange};
 use error_reporting::ParseErrorReporter;
 #[cfg(feature = "gecko")]
 use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
 use servo_url::ServoUrl;
 use style_traits::OneOrMoreCommaSeparated;
-use stylesheets::{MemoryHoleReporter, Origin};
+use stylesheets::Origin;
 
 /// Extra data that the style backend may need to parse stylesheets.
 #[cfg(not(feature = "gecko"))]
 pub struct ParserContextExtraData;
 
 /// Extra data that the style backend may need to parse stylesheets.
 #[cfg(feature = "gecko")]
 pub struct ParserContextExtraData {
@@ -62,55 +62,60 @@ impl ParserContextExtraData {
 /// The data that the parser needs from outside in order to parse a stylesheet.
 pub struct ParserContext<'a> {
     /// The `Origin` of the stylesheet, whether it's a user, author or
     /// user-agent stylesheet.
     pub stylesheet_origin: Origin,
     /// The base url we're parsing this stylesheet as.
     pub base_url: &'a ServoUrl,
     /// An error reporter to report syntax errors.
-    pub error_reporter: Box<ParseErrorReporter + Send>,
+    pub error_reporter: &'a ParseErrorReporter,
     /// Implementation-dependent extra data.
     pub extra_data: ParserContextExtraData,
 }
 
 impl<'a> ParserContext<'a> {
     /// Create a `ParserContext` with extra data.
     pub fn new_with_extra_data(stylesheet_origin: Origin,
                                base_url: &'a ServoUrl,
-                               error_reporter: Box<ParseErrorReporter + Send>,
+                               error_reporter: &'a ParseErrorReporter,
                                extra_data: ParserContextExtraData)
                                -> ParserContext<'a> {
         ParserContext {
             stylesheet_origin: stylesheet_origin,
             base_url: base_url,
             error_reporter: error_reporter,
             extra_data: extra_data,
         }
     }
 
     /// Create a parser context with the default extra data.
     pub fn new(stylesheet_origin: Origin,
                base_url: &'a ServoUrl,
-               error_reporter: Box<ParseErrorReporter + Send>)
+               error_reporter: &'a ParseErrorReporter)
                -> ParserContext<'a> {
         let extra_data = ParserContextExtraData::default();
         Self::new_with_extra_data(stylesheet_origin, base_url, error_reporter, extra_data)
     }
 
     /// Create a parser context for on-the-fly parsing in CSSOM
-    pub fn new_for_cssom(base_url: &'a ServoUrl) -> ParserContext<'a> {
-        Self::new(Origin::User, base_url, Box::new(MemoryHoleReporter))
+    pub fn new_for_cssom(base_url: &'a ServoUrl,
+                         error_reporter: &'a ParseErrorReporter)
+                         -> ParserContext<'a> {
+        Self::new(Origin::User, base_url, error_reporter)
     }
 }
 
 /// Defaults to a no-op.
 /// Set a `RUST_LOG=style::errors` environment variable
 /// to log CSS parse errors to stderr.
-pub fn log_css_error(input: &mut Parser, position: SourcePosition, message: &str, parsercontext: &ParserContext) {
+pub fn log_css_error(input: &mut Parser,
+                     position: SourcePosition,
+                     message: &str,
+                     parsercontext: &ParserContext) {
     let servo_url = parsercontext.base_url;
     parsercontext.error_reporter.report_error(input, position, message, servo_url);
 }
 
 // XXXManishearth Replace all specified value parse impls with impls of this
 // trait. This will make it easy to write more generic values in the future.
 /// A trait to abstract parsing of a specified value given a `ParserContext` and
 /// CSS input.
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -6,17 +6,16 @@
 
 #![deny(missing_docs)]
 
 use cssparser::{DeclarationListParser, parse_important};
 use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
 use error_reporting::ParseErrorReporter;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
 use servo_url::ServoUrl;
-use std::boxed::Box as StdBox;
 use std::fmt;
 use style_traits::ToCss;
 use stylesheets::Origin;
 use super::*;
 
 /// A declaration [importance][importance].
 ///
 /// [importance]: https://drafts.csswg.org/css-cascade/#importance
@@ -565,35 +564,41 @@ pub fn append_serialization<'a, W, I, N>
 
     write!(dest, ";")
 }
 
 /// A helper to parse the style attribute of an element, in order for this to be
 /// shared between Servo and Gecko.
 pub fn parse_style_attribute(input: &str,
                              base_url: &ServoUrl,
-                             error_reporter: StdBox<ParseErrorReporter + Send>,
+                             error_reporter: &ParseErrorReporter,
                              extra_data: ParserContextExtraData)
                              -> PropertyDeclarationBlock {
-    let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
+    let context = ParserContext::new_with_extra_data(Origin::Author,
+                                                     base_url,
+                                                     error_reporter,
+                                                     extra_data);
     parse_property_declaration_list(&context, &mut Parser::new(input))
 }
 
 /// Parse a given property declaration. Can result in multiple
 /// `PropertyDeclaration`s when expanding a shorthand, for example.
 ///
 /// The vector returned will not have the importance set;
 /// this does not attempt to parse !important at all
 pub fn parse_one_declaration(id: PropertyId,
                              input: &str,
                              base_url: &ServoUrl,
-                             error_reporter: StdBox<ParseErrorReporter + Send>,
+                             error_reporter: &ParseErrorReporter,
                              extra_data: ParserContextExtraData)
                              -> Result<ParsedDeclaration, ()> {
-    let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
+    let context = ParserContext::new_with_extra_data(Origin::Author,
+                                                     base_url,
+                                                     error_reporter,
+                                                     extra_data);
     Parser::new(input).parse_entirely(|parser| {
         ParsedDeclaration::parse(id, &context, parser, false)
             .map_err(|_| ())
     })
 }
 
 /// A struct to parse property declarations.
 struct PropertyDeclarationParser<'a, 'b: 'a> {
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -78,17 +78,17 @@ pub struct ComputedValues {
 
     custom_properties: Option<Arc<ComputedValuesMap>>,
     shareable: bool,
     pub writing_mode: WritingMode,
     pub root_font_size: Au,
 }
 
 impl ComputedValues {
-    pub fn inherit_from(parent: &Arc<Self>, default: &Arc<Self>) -> Arc<Self> {
+    pub fn inherit_from(parent: &Self, default: &Self) -> Arc<Self> {
         Arc::new(ComputedValues {
             custom_properties: parent.custom_properties.clone(),
             shareable: parent.shareable,
             writing_mode: parent.writing_mode,
             root_font_size: parent.root_font_size,
             % for style_struct in data.style_structs:
             % if style_struct.inherited:
             ${style_struct.ident}: parent.${style_struct.ident}.clone(),
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -228,17 +228,17 @@
         ${caller.body()}
         #[allow(unused_variables)]
         pub fn cascade_property(declaration: &PropertyDeclaration,
                                 inherited_style: &ComputedValues,
                                 default_style: &ComputedValues,
                                 context: &mut computed::Context,
                                 cacheable: &mut bool,
                                 cascade_info: &mut Option<<&mut CascadeInfo>,
-                                error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
+                                error_reporter: &ParseErrorReporter) {
             let declared_value = match *declaration {
                 PropertyDeclaration::${property.camel_case}(ref declared_value) => {
                     declared_value
                 }
                 _ => panic!("entered the wrong cascade_property() implementation"),
             };
 
             % if not property.derived_from:
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -80,17 +80,17 @@
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
 
     % if product == "servo":
         fn cascade_property_custom(_declaration: &PropertyDeclaration,
                                    _inherited_style: &ComputedValues,
                                    context: &mut computed::Context,
                                    _cacheable: &mut bool,
-                                   _error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
+                                   _error_reporter: &ParseErrorReporter) {
             longhands::_servo_display_for_hypothetical_box::derive_from_display(context);
             longhands::_servo_text_decorations_in_effect::derive_from_display(context);
             longhands::_servo_under_display_none::derive_from_display(context);
         }
     % endif
 
     ${helpers.gecko_keyword_conversion(Keyword('display', ' '.join(values),
                                                gecko_enum_prefix='StyleDisplay'))}
--- a/servo/components/style/properties/longhand/color.mako.rs
+++ b/servo/components/style/properties/longhand/color.mako.rs
@@ -3,38 +3,34 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("Color", inherited=True) %>
 
 <%helpers:longhand name="color" need_clone="True" animatable="True"
                    spec="https://drafts.csswg.org/css-color/#color">
-    use cssparser::Color as CSSParserColor;
     use cssparser::RGBA;
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
-    use values::specified::{CSSColor, CSSRGBA};
+    use values::specified::{Color, CSSColor, CSSRGBA};
 
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         #[inline]
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
-            match self.0.parsed {
-                CSSParserColor::RGBA(rgba) => rgba,
-                CSSParserColor::CurrentColor => context.inherited_style.get_color().clone_color(),
-            }
+            self.0.parsed.to_computed_value(context)
         }
 
         #[inline]
         fn from_computed_value(computed: &computed_value::T) -> Self {
             SpecifiedValue(CSSColor {
-                parsed: CSSParserColor::RGBA(*computed),
+                parsed: Color::RGBA(*computed),
                 authored: None,
             })
         }
     }
 
     #[derive(Clone, PartialEq, Debug)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     pub struct SpecifiedValue(pub CSSColor);
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -787,17 +787,17 @@
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
             computed_value::T(self.0.iter().map(|value| {
                 computed_value::TextShadow {
                     offset_x: value.offset_x.to_computed_value(context),
                     offset_y: value.offset_y.to_computed_value(context),
                     blur_radius: value.blur_radius.to_computed_value(context),
                     color: value.color
                                 .as_ref()
-                                .map(|color| color.parsed)
+                                .map(|color| color.to_computed_value(context))
                                 .unwrap_or(cssparser::Color::CurrentColor),
                 }
             }).collect())
         }
 
         fn from_computed_value(computed: &computed_value::T) -> Self {
             SpecifiedValue(computed.0.iter().map(|value| {
                 SpecifiedTextShadow {
--- a/servo/components/style/properties/longhand/outline.mako.rs
+++ b/servo/components/style/properties/longhand/outline.mako.rs
@@ -5,17 +5,17 @@
 <%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", "::cssparser::Color::CurrentColor",
+${helpers.predefined_type("outline-color", "CSSColor", "computed::CSSColor::CurrentColor",
                           initial_specified_value="specified::CSSColor::currentcolor()",
                           animatable=True, complex_color=True, need_clone=True,
                           spec="https://drafts.csswg.org/css-ui/#propdef-outline-color")}
 
 <%helpers:longhand name="outline-style" need_clone="True" animatable="False"
                    spec="https://drafts.csswg.org/css-ui/#propdef-outline-style">
 
     use std::fmt;
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -205,28 +205,28 @@
         if !empty { Ok(result) } else { Err(()) }
     }
 
     % if product == "servo":
         fn cascade_property_custom(_declaration: &PropertyDeclaration,
                                    _inherited_style: &ComputedValues,
                                    context: &mut computed::Context,
                                    _cacheable: &mut bool,
-                                   _error_reporter: &mut StdBox<ParseErrorReporter + Send>) {
+                                   _error_reporter: &ParseErrorReporter) {
                 longhands::_servo_text_decorations_in_effect::derive_from_text_decoration(context);
         }
     % endif
 </%helpers:longhand>
 
 ${helpers.single_keyword("text-decoration-style",
                          "solid double dotted dashed wavy -moz-none",
                          products="gecko",
                          animatable=False,
                          spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-style")}
 
 ${helpers.predefined_type(
     "text-decoration-color", "CSSColor",
-    "::cssparser::Color::CurrentColor",
+    "computed::CSSColor::CurrentColor",
     initial_specified_value="specified::CSSColor::currentcolor()",
     complex_color=True,
     products="gecko",
     animatable=True,
     spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration-color")}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -6,33 +6,32 @@
 
 // Please note that valid Rust syntax may be mangled by the Mako parser.
 // For example, Vec<&Foo> will be mangled as Vec&Foo>. To work around these issues, the code
 // can be escaped. In the above example, Vec<<&Foo> or Vec< &Foo> achieves the desired result of Vec<&Foo>.
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 use std::borrow::Cow;
-use std::boxed::Box as StdBox;
 use std::collections::HashSet;
 use std::fmt;
 use std::sync::Arc;
 
 use app_units::Au;
 #[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
 use cssparser::{Parser, TokenSerializationType};
 use error_reporting::ParseErrorReporter;
 #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
-use euclid::size::Size2D;
 use computed_values;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::bindings;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
 #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
 use logical_geometry::WritingMode;
+use media_queries::Device;
 use parser::{Parse, ParserContext, ParserContextExtraData};
 use properties::animated_properties::TransitionProperty;
 #[cfg(feature = "servo")] use servo_config::prefs::PREFS;
 use servo_url::ServoUrl;
 use style_traits::ToCss;
 use stylesheets::Origin;
 #[cfg(feature = "servo")] use values::Either;
 use values::{HasViewportPercentage, computed};
@@ -283,17 +282,17 @@ impl PropertyDeclarationIdSet {
         fn substitute_variables_${property.ident}<F>(
             % if property.boxed:
                 value: &DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>,
             % else:
                 value: &DeclaredValue<longhands::${property.ident}::SpecifiedValue>,
             % endif
             custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
             f: F,
-            error_reporter: &mut StdBox<ParseErrorReporter + Send>)
+            error_reporter: &ParseErrorReporter)
             % if property.boxed:
                 where F: FnOnce(&DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>)
             % else:
                 where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>)
             % endif
         {
             if let DeclaredValue::WithVariables(ref with_variables) = *value {
                 // FIXME(heycam): A ParserContextExtraData should be built from data
@@ -317,33 +316,33 @@ impl PropertyDeclarationIdSet {
         #[inline(never)]
         fn substitute_variables_${property.ident}_slow<F>(
                 css: &String,
                 first_token_type: TokenSerializationType,
                 base_url: &ServoUrl,
                 from_shorthand: Option<ShorthandId>,
                 custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
                 f: F,
-                error_reporter: &mut StdBox<ParseErrorReporter + Send>,
+                error_reporter: &ParseErrorReporter,
                 extra_data: ParserContextExtraData)
                 % if property.boxed:
                     where F: FnOnce(&DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>)
                 % else:
                     where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>)
                 % endif
         {
             f(&
                 ::custom_properties::substitute(css, first_token_type, custom_properties)
                 .and_then(|css| {
                     // As of this writing, only the base URL is used for property values:
                     //
                     // FIXME(pcwalton): Cloning the error reporter is slow! But so are custom
                     // properties, so whatever...
                     let context = ParserContext::new_with_extra_data(
-                        ::stylesheets::Origin::Author, base_url, (*error_reporter).clone(),
+                        ::stylesheets::Origin::Author, base_url, error_reporter,
                         extra_data);
                     Parser::new(&css).parse_entirely(|input| {
                         match from_shorthand {
                             None => {
                                 longhands::${property.ident}::parse_specified(&context, input)
                             }
                             % for shorthand in data.shorthands:
                                 % if property in shorthand.sub_properties:
@@ -1759,17 +1758,17 @@ mod lazy_static_module {
 /// A per-longhand function that performs the CSS cascade for that longhand.
 pub type CascadePropertyFn =
     extern "Rust" fn(declaration: &PropertyDeclaration,
                      inherited_style: &ComputedValues,
                      default_style: &ComputedValues,
                      context: &mut computed::Context,
                      cacheable: &mut bool,
                      cascade_info: &mut Option<<&mut CascadeInfo>,
-                     error_reporter: &mut StdBox<ParseErrorReporter + Send>);
+                     error_reporter: &ParseErrorReporter);
 
 /// A per-longhand array of functions to perform the CSS cascade on each of
 /// them, effectively doing virtual dispatch.
 static CASCADE_PROPERTY: [CascadePropertyFn; ${len(data.longhands)}] = [
     % for property in data.longhands:
         longhands::${property.ident}::cascade_property,
     % endfor
 ];
@@ -1788,40 +1787,48 @@ bitflags! {
         const SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP = 0x04,
     }
 }
 
 /// Performs the CSS cascade, computing new styles for an element from its parent style.
 ///
 /// The arguments are:
 ///
-///   * `viewport_size`: The size of the initial viewport.
+///   * `device`: Used to get the initial viewport and other external state.
 ///
 ///   * `rule_node`: The rule node in the tree that represent the CSS rules that
 ///   matched.
 ///
 ///   * `parent_style`: The parent style, if applicable; if `None`, this is the root node.
 ///
 /// Returns the computed values.
 ///   * `flags`: Various flags.
 ///
-pub fn cascade(viewport_size: Size2D<Au>,
+pub fn cascade(device: &Device,
                rule_node: &StrongRuleNode,
                parent_style: Option<<&ComputedValues>,
                layout_parent_style: Option<<&ComputedValues>,
-               default_style: &ComputedValues,
                cascade_info: Option<<&mut CascadeInfo>,
-               error_reporter: StdBox<ParseErrorReporter + Send>,
+               error_reporter: &ParseErrorReporter,
                flags: CascadeFlags)
                -> ComputedValues {
     debug_assert_eq!(parent_style.is_some(), layout_parent_style.is_some());
     let (is_root_element, inherited_style, layout_parent_style) = match parent_style {
-        Some(parent_style) => (false, parent_style, layout_parent_style.unwrap()),
-        None => (true, &*default_style, &*default_style),
+        Some(parent_style) => {
+            (false,
+             parent_style,
+             layout_parent_style.unwrap())
+        },
+        None => {
+            (true,
+             device.default_computed_values(),
+             device.default_computed_values())
+        }
     };
+
     // Hold locks until after the apply_declarations() call returns.
     // Use filter_map because the root node has no style source.
     let lock_guards = rule_node.self_and_ancestors().filter_map(|node| {
         node.style_source().map(|source| (source.read(), node.importance()))
     }).collect::<Vec<_>>();
     let iter_declarations = || {
         lock_guards.iter().flat_map(|&(ref source, source_importance)| {
             source.declarations().iter()
@@ -1831,44 +1838,43 @@ pub fn cascade(viewport_size: Size2D<Au>
                 if declaration_importance == source_importance {
                     Some(declaration)
                 } else {
                     None
                 }
             })
         })
     };
-    apply_declarations(viewport_size,
+    apply_declarations(device,
                        is_root_element,
                        iter_declarations,
                        inherited_style,
                        layout_parent_style,
-                       default_style,
                        cascade_info,
                        error_reporter,
                        None,
                        flags)
 }
 
 /// NOTE: This function expects the declaration with more priority to appear
 /// first.
-pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
+pub fn apply_declarations<'a, F, I>(device: &Device,
                                     is_root_element: bool,
                                     iter_declarations: F,
                                     inherited_style: &ComputedValues,
                                     layout_parent_style: &ComputedValues,
-                                    default_style: &ComputedValues,
                                     mut cascade_info: Option<<&mut CascadeInfo>,
-                                    mut error_reporter: StdBox<ParseErrorReporter + Send>,
+                                    error_reporter: &ParseErrorReporter,
                                     font_metrics_provider: Option<<&FontMetricsProvider>,
                                     flags: CascadeFlags)
                                     -> ComputedValues
     where F: Fn() -> I,
           I: Iterator<Item = &'a PropertyDeclaration>,
 {
+    let default_style = device.default_computed_values();
     let inherited_custom_properties = inherited_style.custom_properties();
     let mut custom_properties = None;
     let mut seen_custom = HashSet::new();
     for declaration in iter_declarations() {
         if let PropertyDeclaration::Custom(ref name, ref value) = *declaration {
             ::custom_properties::cascade(
                 &mut custom_properties, &inherited_custom_properties,
                 &mut seen_custom, name, value)
@@ -1900,17 +1906,17 @@ pub fn apply_declarations<'a, F, I>(view
                             % for style_struct in data.active_style_structs():
                                 inherited_style.clone_${style_struct.name_lower}(),
                             % endfor
                             )
     };
 
     let mut context = computed::Context {
         is_root_element: is_root_element,
-        viewport_size: viewport_size,
+        device: device,
         inherited_style: inherited_style,
         layout_parent_style: layout_parent_style,
         style: starting_style,
         font_metrics_provider: font_metrics_provider,
     };
 
     // Set computed values, overwriting earlier declarations for the same
     // property.
@@ -1979,17 +1985,17 @@ pub fn apply_declarations<'a, F, I>(view
 
             let discriminant = longhand_id as usize;
             (CASCADE_PROPERTY[discriminant])(declaration,
                                              inherited_style,
                                              default_style,
                                              &mut context,
                                              &mut cacheable,
                                              &mut cascade_info,
-                                             &mut error_reporter);
+                                             error_reporter);
         }
         % if category_to_cascade_now == "early":
             let writing_mode = get_writing_mode(context.style.get_inheritedbox());
             context.style.writing_mode = writing_mode;
         % endif
     % endfor
 
     let mut style = context.style;
--- a/servo/components/style/properties/shorthand/serialize.mako.rs
+++ b/servo/components/style/properties/shorthand/serialize.mako.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/. */
 
-use cssparser::Color;
 use style_traits::ToCss;
-use values::specified::{BorderStyle, CSSColor};
+use values::specified::{BorderStyle, Color, CSSColor};
 use std::fmt;
 
 #[allow(missing_docs)]
 pub fn serialize_four_sides<W, I>(dest: &mut W,
                                   top: &I,
                                   right: &I,
                                   bottom: &I,
                                   left: &I)
--- a/servo/components/style/properties/shorthand/text.mako.rs
+++ b/servo/components/style/properties/shorthand/text.mako.rs
@@ -5,23 +5,22 @@
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <%helpers:shorthand name="text-decoration"
                     sub_properties="text-decoration-line
                     ${' text-decoration-style text-decoration-color' if product == 'gecko' or data.testing else ''}"
                     spec="https://drafts.csswg.org/css-text-decor/#propdef-text-decoration">
 
     % if product == "gecko" or data.testing:
-        use cssparser::Color as CSSParserColor;
+        use values::specified;
         use properties::longhands::{text_decoration_line, text_decoration_style, text_decoration_color};
     % else:
         use properties::longhands::text_decoration_line;
     % endif
 
-
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         % if product == "gecko" or data.testing:
             let (mut line, mut style, mut color, mut any) = (None, None, None, false);
         % else:
             let (mut line, mut any) = (None, false);
         % endif
 
         loop {
@@ -66,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 != CSSParserColor::CurrentColor {
+                if self.text_decoration_color.parsed != specified::Color::CurrentColor {
                     dest.write_str(" ")?;
                     self.text_decoration_color.to_css(dest)?;
                 }
             % endif
 
             Ok(())
         }
     }
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -34,17 +34,20 @@ impl Device {
                -> Device {
         Device {
             media_type: media_type,
             viewport_size: viewport_size,
         }
     }
 
     /// Return the default computed values for this device.
-    pub fn default_values(&self) -> &ComputedValues {
+    pub fn default_computed_values(&self) -> &ComputedValues {
+        // FIXME(bz): This isn't really right, but it's no more wrong
+        // than what we used to do.  See
+        // https://github.com/servo/servo/issues/14773 for fixing it properly.
         ComputedValues::initial_values()
     }
 
     /// Returns the viewport size of the current device in app units, needed,
     /// among other things, to resolve viewport units.
     #[inline]
     pub fn au_viewport_size(&self) -> Size2D<Au> {
         Size2D::new(Au::from_f32_px(self.viewport_size.width),
@@ -123,17 +126,17 @@ impl Expression {
 
     /// Evaluate this expression and return whether it matches the current
     /// device.
     pub fn matches(&self, device: &Device) -> bool {
         let viewport_size = device.au_viewport_size();
         let value = viewport_size.width;
         match self.0 {
             ExpressionKind::Width(ref range) => {
-                match range.to_computed_range(viewport_size, device.default_values()) {
+                match range.to_computed_range(device) {
                     Range::Min(ref width) => { value >= *width },
                     Range::Max(ref width) => { value <= *width },
                     Range::Eq(ref width) => { value == *width },
                 }
             }
         }
     }
 }
@@ -165,25 +168,23 @@ pub enum Range<T> {
     Min(T),
     /// At most the inner value.
     Max(T),
     /// Exactly the inner value.
     Eq(T),
 }
 
 impl Range<specified::Length> {
-    fn to_computed_range(&self,
-                         viewport_size: Size2D<Au>,
-                         default_values: &ComputedValues)
-                         -> Range<Au> {
+    fn to_computed_range(&self, device: &Device) -> Range<Au> {
+        let default_values = device.default_computed_values();
         // http://dev.w3.org/csswg/mediaqueries3/#units
         // em units are relative to the initial font-size.
         let context = computed::Context {
             is_root_element: false,
-            viewport_size: viewport_size,
+            device: device,
             inherited_style: default_values,
             layout_parent_style: default_values,
             // This cloning business is kind of dumb.... It's because Context
             // insists on having an actual ComputedValues inside itself.
             style: default_values.clone(),
             font_metrics_provider: None
         };
 
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -250,19 +250,16 @@ pub struct MemoryHoleReporter;
 impl ParseErrorReporter for MemoryHoleReporter {
     fn report_error(&self,
             _: &mut Parser,
             _: SourcePosition,
             _: &str,
             _: &ServoUrl) {
         // do nothing
     }
-    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
-        Box::new(MemoryHoleReporter)
-    }
 }
 
 #[allow(missing_docs)]
 pub enum SingleRuleParseError {
     Syntax,
     Hierarchy,
 }
 
@@ -336,21 +333,21 @@ impl CssRule {
     // input state is None for a nested rule
     // Returns a parsed CSS rule and the final state of the parser
     #[allow(missing_docs)]
     pub fn parse(css: &str,
                  parent_stylesheet: &Stylesheet,
                  extra_data: ParserContextExtraData,
                  state: Option<State>)
                  -> Result<(Self, State), SingleRuleParseError> {
-        let error_reporter = Box::new(MemoryHoleReporter);
+        let error_reporter = MemoryHoleReporter;
         let mut namespaces = parent_stylesheet.namespaces.write();
         let context = ParserContext::new_with_extra_data(parent_stylesheet.origin,
                                                          &parent_stylesheet.base_url,
-                                                         error_reporter.clone(),
+                                                         &error_reporter,
                                                          extra_data);
         let mut input = Parser::new(css);
 
         // nested rules are in the body state
         let state = state.unwrap_or(State::Body);
         let mut rule_parser = TopLevelRuleParser {
             stylesheet_origin: parent_stylesheet.origin,
             context: context,
@@ -578,17 +575,17 @@ impl Stylesheet {
     /// string to `Stylesheet::from_str`.
     pub fn from_bytes(bytes: &[u8],
                       base_url: ServoUrl,
                       protocol_encoding_label: Option<&str>,
                       environment_encoding: Option<EncodingRef>,
                       origin: Origin,
                       media: MediaList,
                       stylesheet_loader: Option<&StylesheetLoader>,
-                      error_reporter: Box<ParseErrorReporter + Send>,
+                      error_reporter: &ParseErrorReporter,
                       extra_data: ParserContextExtraData)
                       -> Stylesheet {
         let (string, _) = decode_stylesheet_bytes(
             bytes, protocol_encoding_label, environment_encoding);
         Stylesheet::from_str(&string,
                              base_url,
                              origin,
                              media,
@@ -599,32 +596,32 @@ impl Stylesheet {
 
     /// Updates an empty stylesheet with a set of bytes that reached over the
     /// network.
     pub fn update_from_bytes(existing: &Stylesheet,
                              bytes: &[u8],
                              protocol_encoding_label: Option<&str>,
                              environment_encoding: Option<EncodingRef>,
                              stylesheet_loader: Option<&StylesheetLoader>,
-                             error_reporter: Box<ParseErrorReporter + Send>,
+                             error_reporter: &ParseErrorReporter,
                              extra_data: ParserContextExtraData) {
         let (string, _) = decode_stylesheet_bytes(
             bytes, protocol_encoding_label, environment_encoding);
         Self::update_from_str(existing,
                               &string,
                               stylesheet_loader,
                               error_reporter,
                               extra_data)
     }
 
     /// Updates an empty stylesheet from a given string of text.
     pub fn update_from_str(existing: &Stylesheet,
                            css: &str,
                            stylesheet_loader: Option<&StylesheetLoader>,
-                           error_reporter: Box<ParseErrorReporter + Send>,
+                           error_reporter: &ParseErrorReporter,
                            extra_data: ParserContextExtraData) {
         let mut rules = existing.rules.write();
         let mut namespaces = existing.namespaces.write();
 
         assert!(rules.is_empty());
 
         let mut input = Parser::new(css);
         let rule_parser = TopLevelRuleParser {
@@ -663,17 +660,17 @@ impl Stylesheet {
     ///
     /// Effectively creates a new stylesheet and forwards the hard work to
     /// `Stylesheet::update_from_str`.
     pub fn from_str(css: &str,
                     base_url: ServoUrl,
                     origin: Origin,
                     media: MediaList,
                     stylesheet_loader: Option<&StylesheetLoader>,
-                    error_reporter: Box<ParseErrorReporter + Send>,
+                    error_reporter: &ParseErrorReporter,
                     extra_data: ParserContextExtraData) -> Stylesheet {
         let s = Stylesheet {
             origin: origin,
             base_url: base_url,
             namespaces: RwLock::new(Namespaces::default()),
             rules: CssRules::new(vec![]),
             media: Arc::new(RwLock::new(media)),
             dirty_on_viewport_size_change: AtomicBool::new(false),
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -290,17 +290,16 @@ impl Stylist {
     ///
     /// If `inherit_all` is true, then all properties are inherited from the
     /// parent; otherwise, non-inherited properties are reset to their initial
     /// values. The flow constructor uses this flag when constructing anonymous
     /// flows.
     pub fn precomputed_values_for_pseudo(&self,
                                          pseudo: &PseudoElement,
                                          parent: Option<&Arc<ComputedValues>>,
-                                         default: &ComputedValues,
                                          cascade_flags: CascadeFlags)
                                          -> ComputedStyle {
         debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_precomputed());
 
         let rule_node = match self.precomputed_pseudo_element_decls.get(pseudo) {
             Some(declarations) => {
                 // FIXME(emilio): When we've taken rid of the cascade we can just
                 // use into_iter.
@@ -320,33 +319,31 @@ impl Stylist {
         // display for the fieldset is "contents", even though it's not the used
         // value, so we don't need to adjust in a different way anyway.
         //
         // In practice, I don't think any anonymous content can be a direct
         // descendant of a display: contents element where display: contents is
         // the actual used value, and the computed value of it would need
         // blockification.
         let computed =
-            properties::cascade(self.device.au_viewport_size(),
+            properties::cascade(&self.device,
                                 &rule_node,
                                 parent.map(|p| &**p),
                                 parent.map(|p| &**p),
-                                default,
                                 None,
-                                Box::new(StdoutErrorReporter),
+                                &StdoutErrorReporter,
                                 cascade_flags);
         ComputedStyle::new(rule_node, Arc::new(computed))
     }
 
     /// Returns the style for an anonymous box of the given type.
     #[cfg(feature = "servo")]
     pub fn style_for_anonymous_box(&self,
                                    pseudo: &PseudoElement,
-                                   parent_style: &Arc<ComputedValues>,
-                                   default_style: &ComputedValues)
+                                   parent_style: &Arc<ComputedValues>)
                                    -> Arc<ComputedValues> {
         // For most (but not all) pseudo-elements, we inherit all values from the parent.
         let inherit_all = match *pseudo {
             PseudoElement::ServoInputText => false,
             PseudoElement::ServoAnonymousBlock |
             PseudoElement::ServoAnonymousTable |
             PseudoElement::ServoAnonymousTableCell |
             PseudoElement::ServoAnonymousTableRow |
@@ -359,32 +356,31 @@ impl Stylist {
             PseudoElement::DetailsContent => {
                 unreachable!("That pseudo doesn't represent an anonymous box!")
             }
         };
         let mut cascade_flags = CascadeFlags::empty();
         if inherit_all {
             cascade_flags.insert(INHERIT_ALL);
         }
-        self.precomputed_values_for_pseudo(&pseudo, Some(parent_style), default_style, cascade_flags)
+        self.precomputed_values_for_pseudo(&pseudo, Some(parent_style), cascade_flags)
             .values.unwrap()
     }
 
     /// Computes a pseudo-element style lazily during layout.
     ///
     /// This can only be done for a certain set of pseudo-elements, like
     /// :selection.
     ///
     /// Check the documentation on lazy pseudo-elements in
     /// docs/components/style.md
     pub fn lazily_compute_pseudo_element_style<E>(&self,
                                                   element: &E,
                                                   pseudo: &PseudoElement,
-                                                  parent: &Arc<ComputedValues>,
-                                                  default: &Arc<ComputedValues>)
+                                                  parent: &Arc<ComputedValues>)
                                                   -> Option<ComputedStyle>
         where E: TElement +
                  fmt::Debug +
                  PresentationalHintsSynthetizer
     {
         debug_assert!(SelectorImpl::pseudo_element_cascade_type(pseudo).is_lazy());
         if self.pseudos_map.get(pseudo).is_none() {
             return None;
@@ -405,23 +401,22 @@ impl Stylist {
             self.rule_tree.insert_ordered_rules(
                 declarations.into_iter().map(|a| (a.source, a.level)));
 
         // Read the comment on `precomputed_values_for_pseudo` to see why it's
         // difficult to assert that display: contents nodes never arrive here
         // (tl;dr: It doesn't apply for replaced elements and such, but the
         // computed value is still "contents").
         let computed =
-            properties::cascade(self.device.au_viewport_size(),
+            properties::cascade(&self.device,
                                 &rule_node,
                                 Some(&**parent),
                                 Some(&**parent),
-                                default,
                                 None,
-                                Box::new(StdoutErrorReporter),
+                                &StdoutErrorReporter,
                                 CascadeFlags::empty());
 
         // Apply the selector flags. We should be in sequential mode already,
         // so we can directly apply the parent flags.
         if cfg!(feature = "servo") {
             // Servo calls this function from the worker, but only for internal
             // pseudos, so we should never generate selector flags here.
             debug_assert!(flags.is_empty());
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -245,17 +245,17 @@ impl fmt::Debug for ColorStop {
 }
 
 impl ToComputedValue for specified::ColorStop {
     type ComputedValue = ColorStop;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> ColorStop {
         ColorStop {
-            color: self.color.parsed,
+            color: self.color.to_computed_value(context),
             position: match self.position {
                 None => None,
                 Some(ref value) => Some(value.to_computed_value(context)),
             },
         }
     }
     #[inline]
     fn from_computed_value(computed: &ColorStop) -> Self {
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -7,17 +7,16 @@
 use app_units::{Au, AU_PER_PX};
 use ordered_float::NotNaN;
 use std::fmt;
 use style_traits::ToCss;
 use super::{Number, ToComputedValue, Context};
 use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
 use values::specified::length::{FontRelativeLength, ViewportPercentageLength};
 
-pub use cssparser::Color as CSSColor;
 pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
 pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
 
 impl ToComputedValue for specified::NoCalcLength {
     type ComputedValue = Au;
 
     #[inline]
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -2,16 +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/. */
 
 //! Computed values.
 
 use app_units::Au;
 use euclid::size::Size2D;
 use font_metrics::FontMetricsProvider;
+use media_queries::Device;
 use properties::ComputedValues;
 use std::fmt;
 use style_traits::ToCss;
 use super::{CSSFloat, RGBA, specified};
 use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 
 pub use cssparser::Color as CSSColor;
 pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image};
@@ -32,18 +33,18 @@ pub mod length;
 pub mod position;
 
 /// A `Context` is all the data a specified value could ever need to compute
 /// itself and be transformed to a computed value.
 pub struct Context<'a> {
     /// Whether the current element is the root element.
     pub is_root_element: bool,
 
-    /// The current viewport size.
-    pub viewport_size: Size2D<Au>,
+    /// The Device holds the viewport and other external state.
+    pub device: &'a Device,
 
     /// The style we're inheriting from.
     pub inherited_style: &'a ComputedValues,
 
     /// The style of the layout parent node. This will almost always be
     /// `inherited_style`, except when `display: contents` is at play, in which
     /// case it's the style of the last ancestor with a `display` value that
     /// isn't `contents`.
@@ -60,17 +61,17 @@ pub struct Context<'a> {
     /// TODO(emilio): This should be required, see #14079.
     pub font_metrics_provider: Option<&'a FontMetricsProvider>,
 }
 
 impl<'a> Context<'a> {
     /// Whether the current element is the root element.
     pub fn is_root_element(&self) -> bool { self.is_root_element }
     /// The current viewport size.
-    pub fn viewport_size(&self) -> Size2D<Au> { self.viewport_size }
+    pub fn viewport_size(&self) -> Size2D<Au> { self.device.au_viewport_size() }
     /// The style we're inheriting from.
     pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style }
     /// The current style. Note that only "eager" properties should be accessed
     /// from here, see the comment in the member.
     pub fn style(&self) -> &ComputedValues { &self.style }
     /// A mutable reference to the current style.
     pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style }
 }
@@ -108,28 +109,75 @@ impl<T> ToComputedValue for T
     }
 
     #[inline]
     fn from_computed_value(computed: &T) -> Self {
         computed.clone()
     }
 }
 
+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::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),
+        }
+    }
+
+    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 {
         specified::CSSColor {
-            parsed: *computed,
+            parsed: match *computed {
+                CSSColor::RGBA(rgba) => specified::Color::RGBA(rgba),
+                CSSColor::CurrentColor => specified::Color::CurrentColor,
+            },
             authored: None,
         }
     }
 }
 
 #[cfg(feature = "gecko")]
 impl ToComputedValue for specified::JustifyItems {
     type ComputedValue = JustifyItems;
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/specified/color.rs
@@ -0,0 +1,90 @@
+/* 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
+
+#[cfg(not(feature = "gecko"))] pub use self::servo::Color;
+#[cfg(feature = "gecko")] pub use self::gecko::Color;
+
+#[cfg(not(feature = "gecko"))]
+mod servo {
+    pub use cssparser::Color;
+    use cssparser::Parser;
+    use parser::{Parse, ParserContext};
+
+    impl Parse for Color {
+        fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+            Color::parse(input)
+        }
+    }
+}
+
+#[cfg(feature = "gecko")]
+mod gecko {
+    use cssparser::{Color as CSSParserColor, Parser, RGBA};
+    use parser::{Parse, ParserContext};
+    use std::fmt;
+    use style_traits::ToCss;
+    use values::HasViewportPercentage;
+
+    /// 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),
+
+        /// -moz-default-color
+        MozDefaultColor,
+        /// -moz-default-background-color
+        MozDefaultBackgroundColor,
+        /// -moz-hyperlinktext
+        MozHyperlinktext,
+        /// -moz-activehyperlinktext
+        MozActiveHyperlinktext,
+        /// -moz-visitedhyperlinktext
+        MozVisitedHyperlinktext,
+    }
+
+    no_viewport_percentage!(Color);
+
+    impl Parse for Color {
+        fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+            if let Ok(value) = input.try(CSSParserColor::parse) {
+                match value {
+                    CSSParserColor::CurrentColor => Ok(Color::CurrentColor),
+                    CSSParserColor::RGBA(x) => Ok(Color::RGBA(x)),
+                }
+            } 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),
+
+                // 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"),
+            }
+        }
+    }
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -13,60 +13,62 @@ use parser::{ParserContext, Parse};
 use self::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 use self::url::SpecifiedUrl;
 use std::ascii::AsciiExt;
 use std::f32::consts::PI;
 use std::fmt;
 use std::ops::Mul;
 use style_traits::ToCss;
 use super::{Auto, CSSFloat, HasViewportPercentage, Either, None_};
-use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
-use super::computed::Shadow as ComputedShadow;
+use super::computed::{ComputedValueAsSpecified, Context};
+use super::computed::{Shadow as ComputedShadow, ToComputedValue};
 
 #[cfg(feature = "gecko")]
 pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
+pub use self::color::Color;
 pub use self::grid::{GridLine, TrackKeyword};
 pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use self::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use self::image::{SizeKeyword, VerticalDirection};
 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, CalcUnit};
 pub use self::length::{MaxLength, MinLength};
 pub use self::position::{HorizontalPosition, Position, VerticalPosition};
 
 #[cfg(feature = "gecko")]
 pub mod align;
 pub mod basic_shape;
+pub mod color;
 pub mod grid;
 pub mod image;
 pub mod length;
 pub mod position;
 pub mod url;
 
 no_viewport_percentage!(i32);  // For PropertyDeclaration::Order
 
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct CSSColor {
-    pub parsed: cssparser::Color,
+    pub parsed: Color,
     pub authored: Option<Box<str>>,
 }
 
 impl Parse for CSSColor {
-    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> 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);
         Ok(CSSColor {
-            parsed: try!(cssparser::Color::parse(input)),
+            parsed: try!(Parse::parse(context, input)),
             authored: authored,
         })
     }
 }
 
 no_viewport_percentage!(CSSColor);
 
 impl ToCss for CSSColor {
@@ -78,26 +80,26 @@ impl ToCss for CSSColor {
     }
 }
 
 impl CSSColor {
     #[inline]
     /// Returns currentcolor value.
     pub fn currentcolor() -> CSSColor {
         CSSColor {
-            parsed: cssparser::Color::CurrentColor,
+            parsed: Color::CurrentColor,
             authored: None,
         }
     }
 
     #[inline]
     /// Returns transparent value.
     pub fn transparent() -> CSSColor {
         CSSColor {
-            parsed: cssparser::Color::RGBA(cssparser::RGBA::transparent()),
+            parsed: Color::RGBA(cssparser::RGBA::transparent()),
             // This should probably be "transparent", but maybe it doesn't matter.
             authored: None,
         }
     }
 }
 
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -611,17 +613,17 @@ impl ToComputedValue for Shadow {
     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.parsed)
+                        .map(|color| color.to_computed_value(context))
                         .unwrap_or(cssparser::Color::CurrentColor),
             inset: self.inset,
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &ComputedShadow) -> Self {
         Shadow {
--- a/servo/components/style/viewport.rs
+++ b/servo/components/style/viewport.rs
@@ -682,20 +682,20 @@ impl MaybeNew for ViewportConstraints {
         //
         // Note: DEVICE-ADAPT § 5. states that relative length values are
         // resolved against initial values
         let initial_viewport = device.au_viewport_size();
 
         // TODO(emilio): Stop cloning `ComputedValues` around!
         let context = Context {
             is_root_element: false,
-            viewport_size: initial_viewport,
-            inherited_style: device.default_values(),
-            layout_parent_style: device.default_values(),
-            style: device.default_values().clone(),
+            device: device,
+            inherited_style: device.default_computed_values(),
+            layout_parent_style: device.default_computed_values(),
+            style: device.default_computed_values().clone(),
             font_metrics_provider: None, // TODO: Should have!
         };
 
         // DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
         let extend_width;
         let extend_height;
         if let Some(extend_zoom) = max!(initial_zoom, max_zoom) {
             let scale_factor = 1. / extend_zoom;
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -161,22 +161,22 @@ pub extern "C" fn Servo_Shutdown() {
 fn create_shared_context(per_doc_data: &PerDocumentStyleDataImpl) -> SharedStyleContext {
     let local_context_data =
         ThreadLocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone());
 
     SharedStyleContext {
         stylist: per_doc_data.stylist.clone(),
         running_animations: per_doc_data.running_animations.clone(),
         expired_animations: per_doc_data.expired_animations.clone(),
+        // FIXME(emilio): Stop boxing here.
         error_reporter: Box::new(StdoutErrorReporter),
         local_context_creation_data: Mutex::new(local_context_data),
         timer: Timer::new(),
         // FIXME Find the real QuirksMode information for this document
         quirks_mode: QuirksMode::NoQuirks,
-        default_computed_values: per_doc_data.default_computed_values().clone(),
     }
 }
 
 fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
                     unstyled_children_only: bool) {
     // When new content is inserted in a display:none subtree, we will call into
     // servo to try to style it. Detect that here and bail out.
     if let Some(parent) = element.parent_element() {
@@ -332,17 +332,17 @@ pub extern "C" fn Servo_StyleSheet_Empty
     let extra_data = ParserContextExtraData::default();
     let origin = match mode {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
     };
     Arc::new(Stylesheet::from_str(
         "", url, origin, Default::default(), None,
-        Box::new(StdoutErrorReporter), extra_data)
+        &StdoutErrorReporter, extra_data)
     ).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
                                                  stylesheet: *mut ServoStyleSheet,
                                                  data: *const nsACString,
                                                  mode: SheetParsingMode,
@@ -375,17 +375,17 @@ pub extern "C" fn Servo_StyleSheet_FromU
     // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
     let loader: Option<&StyleStylesheetLoader> = match loader {
         None => None,
         Some(ref s) => Some(s),
     };
 
     Arc::new(Stylesheet::from_str(
         input, url, origin, Default::default(), loader,
-        Box::new(StdoutErrorReporter), extra_data)
+        &StdoutErrorReporter, extra_data)
     ).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheetBorrowed,
                                                   loader: *mut Loader,
                                                   gecko_stylesheet: *mut ServoStyleSheet,
                                                   data: *const nsACString,
@@ -411,17 +411,17 @@ pub extern "C" fn Servo_StyleSheet_Clear
         None => None,
         Some(ref s) => Some(s),
     };
 
     let sheet = Stylesheet::as_arc(&stylesheet);
     sheet.rules.write().0.clear();
 
     Stylesheet::update_from_str(&sheet, input, loader,
-                                Box::new(StdoutErrorReporter), extra_data);
+                                &StdoutErrorReporter, extra_data);
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed,
                                                   raw_sheet: RawServoStyleSheetBorrowed,
                                                   flush: bool) {
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let sheet = HasArcFFI::as_arc(&raw_sheet);
@@ -629,17 +629,16 @@ pub extern "C" fn Servo_ComputedValues_G
 
 
     let maybe_parent = ComputedValues::arc_from_borrowed(&parent_style_or_null);
     let mut cascade_flags = CascadeFlags::empty();
     if skip_display_fixup {
         cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
     }
     data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent,
-                                               data.default_computed_values(),
                                                cascade_flags)
         .values.unwrap()
         .into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
                                            pseudo_tag: *mut nsIAtom, is_probe: bool,
@@ -675,18 +674,17 @@ fn get_pseudo_style(element: GeckoElemen
     match SelectorImpl::pseudo_element_cascade_type(&pseudo) {
         PseudoElementCascadeType::Eager => styles.pseudos.get(&pseudo).map(|s| s.values().clone()),
         PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
         PseudoElementCascadeType::Lazy => {
             let d = doc_data.borrow_mut();
             let base = styles.primary.values();
             d.stylist.lazily_compute_pseudo_element_style(&element,
                                                           &pseudo,
-                                                          base,
-                                                          &d.default_computed_values())
+                                                          base)
                      .map(|s| s.values().clone())
         },
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_Inherit(
   raw_data: RawServoStyleSetBorrowed,
@@ -744,19 +742,20 @@ pub extern "C" fn Servo_ParseProperty(pr
         id
     } else {
         return RawServoDeclarationBlockStrong::null()
     };
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     make_context!((base, data) => (base_url, extra_data));
 
+    let reporter = StdoutErrorReporter;
     let context = ParserContext::new_with_extra_data(Origin::Author,
                                                      &base_url,
-                                                     Box::new(StdoutErrorReporter),
+                                                     &reporter,
                                                      extra_data);
 
     match ParsedDeclaration::parse(id, &context, &mut Parser::new(value), false) {
         Ok(parsed) => {
             let mut block = PropertyDeclarationBlock::new();
             parsed.expand(|d| block.push(d, Importance::Normal));
             Arc::new(RwLock::new(block)).into_strong()
         }
@@ -872,17 +871,17 @@ pub extern "C" fn Servo_DeclarationBlock
 
 fn set_property(declarations: RawServoDeclarationBlockBorrowed, property_id: PropertyId,
                 value: *const nsACString, is_important: bool,
                 base: *const nsACString, data: *const structs::GeckoParserExtraData) -> bool {
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     make_context!((base, data) => (base_url, extra_data));
     if let Ok(parsed) = parse_one_declaration(property_id, value, &base_url,
-                                              Box::new(StdoutErrorReporter), extra_data) {
+                                              &StdoutErrorReporter, extra_data) {
         let mut declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations).write();
         let importance = if is_important { Importance::Important } else { Importance::Normal };
         let mut changed = false;
         parsed.expand(|decl| {
             changed |= declarations.set_parsed_declaration(decl, importance);
         });
         changed
     } else {
@@ -1168,19 +1167,18 @@ pub extern "C" fn Servo_DeclarationBlock
     };
     declarations.write().push(prop, Importance::Normal);
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(declarations:
                                                          RawServoDeclarationBlockBorrowed,
                                                          property: nsCSSPropertyID) {
-    use cssparser::Color;
     use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId};
-    use style::values::specified::CSSColor;
+    use style::values::specified::{Color, CSSColor};
 
     let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let cc = CSSColor { parsed: Color::CurrentColor, authored: None };
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => cc,
         BorderRightColor => cc,
@@ -1190,21 +1188,20 @@ pub extern "C" fn Servo_DeclarationBlock
     declarations.write().push(prop, Importance::Normal);
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(declarations:
                                                        RawServoDeclarationBlockBorrowed,
                                                        property: nsCSSPropertyID,
                                                        value: structs::nscolor) {
-    use cssparser::Color;
     use style::gecko::values::convert_nscolor_to_rgba;
     use style::properties::{DeclaredValue, PropertyDeclaration, LonghandId};
     use style::properties::longhands;
-    use style::values::specified::CSSColor;
+    use style::values::specified::{Color, CSSColor};
 
     let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
     let long = get_longhand_from_id!(property);
     let rgba = convert_nscolor_to_rgba(value);
     let color = CSSColor { parsed: Color::RGBA(rgba), authored: None };
 
     let prop = match_wrap_declared! { long,
         BorderTopColor => color,
@@ -1257,27 +1254,28 @@ pub extern "C" fn Servo_CSSSupports2(pro
     } else {
         return false
     };
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     let base_url = &*DUMMY_BASE_URL;
     let extra_data = ParserContextExtraData::default();
 
-    parse_one_declaration(id, &value, &base_url, Box::new(StdoutErrorReporter), extra_data).is_ok()
+    parse_one_declaration(id, &value, &base_url, &StdoutErrorReporter, extra_data).is_ok()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_CSSSupports(cond: *const nsACString) -> bool {
     let condition = unsafe { cond.as_ref().unwrap().as_str_unchecked() };
     let mut input = Parser::new(&condition);
     let cond = parse_condition_or_declaration(&mut input);
     if let Ok(cond) = cond {
         let url = ServoUrl::parse("about:blank").unwrap();
-        let context = ParserContext::new_for_cssom(&url);
+        let reporter = StdoutErrorReporter;
+        let context = ParserContext::new_for_cssom(&url, &reporter);
         cond.eval(&context)
     } else {
         false
     }
 }
 
 /// Only safe to call on the main thread, with exclusive access to the element and
 /// its ancestors.
@@ -1435,21 +1433,21 @@ pub extern "C" fn Servo_GetComputedKeyfr
     use style::properties::LonghandIdSet;
     use style::properties::declaration_block::Importance;
     use style::values::computed::Context;
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
 
     let style = ComputedValues::as_arc(&style);
     let parent_style = parent_style.as_ref().map(|r| &**ComputedValues::as_arc(&r));
 
-    let default_values = data.stylist.device.default_values();
+    let default_values = data.default_computed_values();
 
     let context = Context {
         is_root_element: false,
-        viewport_size: data.stylist.device.au_viewport_size(),
+        device: &data.stylist.device,
         inherited_style: parent_style.unwrap_or(default_values),
         layout_parent_style: parent_style.unwrap_or(default_values),
         style: (**style).clone(),
         font_metrics_provider: None,
     };
 
     for (index, keyframe) in keyframes.iter().enumerate() {
         let ref mut animation_values = computed_keyframes[index];
--- a/servo/tests/unit/style/media_queries.rs
+++ b/servo/tests/unit/style/media_queries.rs
@@ -16,30 +16,26 @@ use style::values::specified;
 use style_traits::ToCss;
 
 pub struct CSSErrorReporterTest;
 
 impl ParseErrorReporter for CSSErrorReporterTest {
     fn report_error(&self, _input: &mut Parser, _position: SourcePosition, _message: &str,
         _url: &ServoUrl) {
     }
-
-     fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
-        Box::new(CSSErrorReporterTest)
-     }
 }
 
 fn test_media_rule<F>(css: &str, callback: F)
     where F: Fn(&MediaList, &str),
 {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let css_str = css.to_owned();
     let stylesheet = Stylesheet::from_str(
         css, url, Origin::Author, Default::default(),
-        None, Box::new(CSSErrorReporterTest),
+        None, &CSSErrorReporterTest,
         ParserContextExtraData::default());
     let mut rule_count = 0;
     media_queries(&stylesheet.rules.read().0, &mut |mq| {
         rule_count += 1;
         callback(mq, css);
     });
     assert!(rule_count > 0, css_str);
 }
@@ -56,17 +52,17 @@ fn media_queries<F>(rules: &[CssRule], f
         })
     }
 }
 
 fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let ss = Stylesheet::from_str(
         css, url, Origin::Author, Default::default(),
-        None, Box::new(CSSErrorReporterTest),
+        None, &CSSErrorReporterTest,
         ParserContextExtraData::default());
     let mut rule_count = 0;
     ss.effective_style_rules(device, |_| rule_count += 1);
     assert!(rule_count == expected_rule_count, css.to_owned());
 }
 
 #[test]
 fn test_mq_empty() {
--- a/servo/tests/unit/style/parsing/background.rs
+++ b/servo/tests/unit/style/parsing/background.rs
@@ -10,17 +10,18 @@ use style::properties::longhands::{backg
 use style::properties::longhands::{background_origin, background_position_x, background_position_y, background_repeat};
 use style::properties::longhands::background_size;
 use style::properties::shorthands::background;
 use style::stylesheets::Origin;
 
 #[test]
 fn background_shorthand_should_parse_all_available_properties_when_specified() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("url(\"http://servo/test.png\") top center / 200px 200px repeat-x fixed padding-box \
         content-box red");
     let result = background::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\")"));
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "center"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "top"));
     assert_eq!(result.background_size, parse_longhand!(background_size, "200px 200px"));
@@ -29,17 +30,18 @@ fn background_shorthand_should_parse_all
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "content-box"));
     assert_eq!(result.background_color, parse_longhand!(background_color, "red"));
 }
 
 #[test]
 fn background_shorthand_should_parse_when_some_fields_set() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("14px 40px repeat-y");
     let result = background::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "14px"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "40px"));
     assert_eq!(result.background_repeat, parse_longhand!(background_repeat, "repeat-y"));
 
     let mut parser = Parser::new("url(\"http://servo/test.png\") repeat blue");
@@ -59,17 +61,18 @@ fn background_shorthand_should_parse_whe
     let result = background::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\")"));
 }
 
 #[test]
 fn background_shorthand_should_parse_comma_separated_declarations() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("url(\"http://servo/test.png\") top left no-repeat, url(\"http://servo/test.png\") \
         center / 100% 100% no-repeat, white");
     let result = background::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\"), \
         url(\"http://servo/test.png\"), none"));
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "left, center, 0%"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "top, center, 0%"));
@@ -80,17 +83,18 @@ fn background_shorthand_should_parse_com
     assert_eq!(result.background_size, parse_longhand!(background_size, "auto auto, 100% 100%, auto auto"));
     assert_eq!(result.background_attachment, parse_longhand!(background_attachment, "scroll, scroll, scroll"));
     assert_eq!(result.background_color, parse_longhand!(background_color, "white"));
 }
 
 #[test]
 fn background_shorthand_should_parse_position_and_size_correctly() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("7px 4px");
     let result = background::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "7px"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "4px"));
 
     let mut parser = Parser::new("7px 4px / 30px 20px");
     let result = background::parse_value(&context, &mut parser).unwrap();
@@ -104,17 +108,18 @@ fn background_shorthand_should_parse_pos
 
     let mut parser = Parser::new("repeat-x / 30px 20px");
     assert!(background::parse_value(&context, &mut parser).is_err());
 }
 
 #[test]
 fn background_shorthand_should_parse_origin_and_clip_correctly() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("padding-box content-box");
     let result = background::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "content-box"));
 
     let mut parser = Parser::new("padding-box padding-box");
     let result = background::parse_value(&context, &mut parser).unwrap();
--- a/servo/tests/unit/style/parsing/border.rs
+++ b/servo/tests/unit/style/parsing/border.rs
@@ -10,120 +10,129 @@ use style::properties::longhands::{borde
 use style::properties::longhands::{border_image_source, border_image_width};
 use style::properties::shorthands::border_image;
 use style::stylesheets::Origin;
 use style_traits::ToCss;
 
 #[test]
 fn border_image_shorthand_should_parse_when_all_properties_specified() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / 20px 40px / 10px \
                                  round stretch");
     let result = border_image::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_width, parse_longhand!(border_image_width, "20px 40px"));
     assert_eq!(result.border_image_outset, parse_longhand!(border_image_outset, "10px"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round stretch"));
 }
 
 #[test]
 fn border_image_shorthand_should_parse_without_width() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / / 10px round stretch");
     let result = border_image::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_outset, parse_longhand!(border_image_outset, "10px"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round stretch"));
     assert_eq!(result.border_image_width, border_image_width::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_shorthand_should_parse_without_outset() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / 20px 40px round");
     let result = border_image::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_width, parse_longhand!(border_image_width, "20px 40px"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round"));
     assert_eq!(result.border_image_outset, border_image_outset::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_shorthand_should_parse_without_width_or_outset() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill round");
     let result = border_image::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round"));
     assert_eq!(result.border_image_width, border_image_width::get_initial_specified_value());
     assert_eq!(result.border_image_outset, border_image_outset::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_shorthand_should_parse_with_just_source() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("linear-gradient(red, blue)");
     let result = border_image::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, border_image_slice::get_initial_specified_value());
     assert_eq!(result.border_image_width, border_image_width::get_initial_specified_value());
     assert_eq!(result.border_image_outset, border_image_outset::get_initial_specified_value());
     assert_eq!(result.border_image_repeat, border_image_repeat::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_outset_should_error_on_negative_length() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("-1em");
     let result = border_image_outset::parse(&context, &mut parser);
     assert_eq!(result, Err(()));
 }
 
 #[test]
 fn border_image_outset_should_error_on_negative_number() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("-15");
     let result = border_image_outset::parse(&context, &mut parser);
     assert_eq!(result, Err(()));
 }
 
 #[test]
 fn border_image_outset_should_return_number_on_plain_zero() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("0");
     let result = border_image_outset::parse(&context, &mut parser);
     assert_eq!(result.unwrap(), parse_longhand!(border_image_outset, "0"));
 }
 
 #[test]
 fn border_image_outset_should_return_length_on_length_zero() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("0em");
     let result = border_image_outset::parse(&context, &mut parser);
     assert_eq!(result.unwrap(), parse_longhand!(border_image_outset, "0em"));
 }
 
 #[test]
 fn test_border_style() {
     use style::values::specified::BorderStyle;
--- a/servo/tests/unit/style/parsing/column.rs
+++ b/servo/tests/unit/style/parsing/column.rs
@@ -14,29 +14,31 @@ fn test_column_width() {
     use style::properties::longhands::column_width;
 
     assert_roundtrip_with_context!(column_width::parse, "auto");
     assert_roundtrip_with_context!(column_width::parse, "6px");
     assert_roundtrip_with_context!(column_width::parse, "2.5em");
     assert_roundtrip_with_context!(column_width::parse, "0.3vw");
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let mut negative = Parser::new("-6px");
     assert!(column_width::parse(&context, &mut negative).is_err());
 }
 
 #[test]
 fn test_column_gap() {
     use style::properties::longhands::column_gap;
 
     assert_roundtrip_with_context!(column_gap::parse, "normal");
     assert_roundtrip_with_context!(column_gap::parse, "6px");
     assert_roundtrip_with_context!(column_gap::parse, "2.5em");
     assert_roundtrip_with_context!(column_gap::parse, "0.3vw");
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let mut negative = Parser::new("-6px");
     assert!(column_gap::parse(&context, &mut negative).is_err());
 }
--- a/servo/tests/unit/style/parsing/effects.rs
+++ b/servo/tests/unit/style/parsing/effects.rs
@@ -33,17 +33,18 @@ fn test_clip() {
     assert_roundtrip_with_context!(clip::parse,
                                    "rect(auto auto auto auto)",
                                    "rect(auto, auto, auto, auto)");
 }
 
 #[test]
 fn test_longhands_parse_origin() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let mut parser = Parser::new("1px some-rubbish");
     let parsed = longhands::parse_origin(&context, &mut parser);
     assert!(parsed.is_ok());
     assert_eq!(parser.is_exhausted(), false);
 
     let mut parser = Parser::new("1px 2px");
     let parsed = longhands::parse_origin(&context, &mut parser);
--- a/servo/tests/unit/style/parsing/font.rs
+++ b/servo/tests/unit/style/parsing/font.rs
@@ -48,17 +48,18 @@ fn font_feature_settings_should_parse_pr
         FeatureTagValue { tag: String::from("efgh"), value: 1 }
     ]);
     assert_eq!(multiple, multiple_computed);
 }
 
 #[test]
 fn font_feature_settings_should_throw_on_bad_input() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let mut empty = Parser::new("");
     assert!(font_feature_settings::parse(&context, &mut empty).is_err());
 
     let mut negative = Parser::new("\"abcd\" -1");
     assert!(font_feature_settings::parse(&context, &mut negative).is_err());
 
     let mut short_tag = Parser::new("\"abc\"");
@@ -98,17 +99,18 @@ fn font_language_override_should_parse_p
     assert_eq!(danish, SpecifiedValue::Override("DAN".to_string()));
 }
 
 #[test]
 fn font_weight_keyword_should_preserve_keyword() {
     use style::properties::longhands::font_weight::SpecifiedValue;
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("normal");
     let result = font_weight::parse(&context, &mut parser);
     assert_eq!(result.unwrap(), SpecifiedValue::Normal);
 
     let mut parser = Parser::new("bold");
     let result = font_weight::parse(&context, &mut parser);
     assert_eq!(result.unwrap(), SpecifiedValue::Bold);
 }
--- a/servo/tests/unit/style/parsing/image.rs
+++ b/servo/tests/unit/style/parsing/image.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use app_units::Au;
 use cssparser::Parser;
-use euclid::size::Size2D;
+use euclid::size::TypedSize2D;
 use media_queries::CSSErrorReporterTest;
 use std::f32::consts::PI;
+use style::media_queries::{Device, MediaType};
 use style::parser::ParserContext;
 use style::properties::ComputedValues;
 use style::stylesheets::Origin;
 use style::values::computed;
 use style::values::computed::{Angle, Context, ToComputedValue};
 use style::values::specified;
 use style::values::specified::image::*;
 use style_traits::ToCss;
@@ -38,21 +38,22 @@ fn test_linear_gradient() {
     assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green, yellow 50%)");
 
     // Parsing without <angle> and <side-or-corner>
     assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)");
 
     // AngleOrCorner::None should become AngleOrCorner::Angle(Angle(PI)) when parsed
     // Note that Angle(PI) is correct for top-to-bottom rendering, whereas Angle(0) would render bottom-to-top.
     // ref: https://developer.mozilla.org/en-US/docs/Web/CSS/angle
-    let container = Size2D::new(Au::default(), Au::default());
+    let viewport_size = TypedSize2D::new(0., 0.);
     let initial_style = ComputedValues::initial_values();
+    let device = Device::new(MediaType::Screen, viewport_size);
     let specified_context = Context {
         is_root_element: true,
-        viewport_size: container,
+        device: &device,
         inherited_style: initial_style,
         layout_parent_style: initial_style,
         style: initial_style.clone(),
         font_metrics_provider: None,
     };
     assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
                computed::AngleOrCorner::Angle(Angle(PI)));
 }
--- a/servo/tests/unit/style/parsing/inherited_text.rs
+++ b/servo/tests/unit/style/parsing/inherited_text.rs
@@ -106,17 +106,18 @@ fn test_text_emphasis_position() {
 fn webkit_text_stroke_shorthand_should_parse_properly() {
     use media_queries::CSSErrorReporterTest;
     use servo_url::ServoUrl;
     use style::properties::longhands::_webkit_text_stroke_color;
     use style::properties::longhands::_webkit_text_stroke_width;
     use style::properties::shorthands::_webkit_text_stroke;
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let mut parser = Parser::new("thin red");
     let result = _webkit_text_stroke::parse_value(&context, &mut parser).unwrap();
     assert_eq!(result._webkit_text_stroke_color, parse_longhand!(_webkit_text_stroke_color, "red"));
     assert_eq!(result._webkit_text_stroke_width, parse_longhand!(_webkit_text_stroke_width, "thin"));
 
     // ensure its no longer sensitive to order
     let mut parser = Parser::new("red thin");
@@ -127,26 +128,28 @@ fn webkit_text_stroke_shorthand_should_p
 
 #[test]
 fn line_height_should_return_number_on_plain_zero() {
     use media_queries::CSSErrorReporterTest;
     use servo_url::ServoUrl;
     use style::properties::longhands::line_height;
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("0");
     let result = line_height::parse(&context, &mut parser);
     assert_eq!(result.unwrap(), parse_longhand!(line_height, "0"));
 }
 
 #[test]
 fn line_height_should_return_length_on_length_zero() {
     use media_queries::CSSErrorReporterTest;
     use servo_url::ServoUrl;
     use style::properties::longhands::line_height;
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("0px");
     let result = line_height::parse(&context, &mut parser);
     assert_eq!(result.unwrap(), parse_longhand!(line_height, "0px"));
 }
--- a/servo/tests/unit/style/parsing/mask.rs
+++ b/servo/tests/unit/style/parsing/mask.rs
@@ -9,17 +9,18 @@ use style::parser::ParserContext;
 use style::properties::longhands::{mask_clip, mask_composite, mask_image, mask_mode};
 use style::properties::longhands::{mask_origin, mask_position_x, mask_position_y, mask_repeat, mask_size};
 use style::properties::shorthands::mask;
 use style::stylesheets::Origin;
 
 #[test]
 fn mask_shorthand_should_parse_all_available_properties_when_specified() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px \
                                  repeat-x padding-box border-box subtract");
     let result = mask::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.mask_image, parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
     assert_eq!(result.mask_mode, parse_longhand!(mask_mode, "luminance"));
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "7px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "4px"));
@@ -28,17 +29,18 @@ fn mask_shorthand_should_parse_all_avail
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "border-box"));
     assert_eq!(result.mask_composite, parse_longhand!(mask_composite, "subtract"));
 }
 
 #[test]
 fn mask_shorthand_should_parse_when_some_fields_set() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("14px 40px repeat-y");
     let result = mask::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "14px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "40px"));
     assert_eq!(result.mask_repeat, parse_longhand!(mask_repeat, "repeat-y"));
 
     let mut parser = Parser::new("url(\"http://servo/test.png\") repeat add");
@@ -57,17 +59,18 @@ fn mask_shorthand_should_parse_when_some
     let result = mask::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.mask_image, parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
 }
 
 #[test]
 fn mask_shorthand_should_parse_position_and_size_correctly() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("7px 4px");
     let result = mask::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "7px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "4px"));
 
     let mut parser = Parser::new("7px 4px / 30px 20px");
     let result = mask::parse_value(&context, &mut parser).unwrap();
@@ -81,17 +84,18 @@ fn mask_shorthand_should_parse_position_
 
     let mut parser = Parser::new("match-source repeat-x / 30px 20px");
     assert!(mask::parse_value(&context, &mut parser).is_err());
 }
 
 #[test]
 fn mask_shorthand_should_parse_origin_and_clip_correctly() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("padding-box content-box");
     let result = mask::parse_value(&context, &mut parser).unwrap();
 
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "content-box"));
 
     let mut parser = Parser::new("padding-box padding-box");
     let result = mask::parse_value(&context, &mut parser).unwrap();
@@ -104,15 +108,16 @@ fn mask_shorthand_should_parse_origin_an
 
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "padding-box"));
 }
 
 #[test]
 fn mask_shorthand_should_parse_mode_everywhere() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new("luminance 7px 4px repeat-x padding-box");
     assert!(mask::parse_value(&context, &mut parser).is_ok());
 
     let mut parser = Parser::new("alpha");
     assert!(mask::parse_value(&context, &mut parser).is_ok());
 }
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -6,30 +6,32 @@
 
 use cssparser::Parser;
 use media_queries::CSSErrorReporterTest;
 use style::parser::ParserContext;
 use style::stylesheets::Origin;
 
 fn parse<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new(s);
     f(&context, &mut parser)
 }
 
 // This is a macro so that the file/line information
 // is preserved in the panic
 macro_rules! assert_roundtrip_with_context {
     ($fun:expr, $string:expr) => {
         assert_roundtrip_with_context!($fun, $string, $string);
     };
     ($fun:expr,$input:expr, $output:expr) => {
         let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+        let reporter = CSSErrorReporterTest;
+        let context = ParserContext::new(Origin::Author, &url, &reporter);
         let mut parser = Parser::new($input);
         let parsed = $fun(&context, &mut parser)
                      .expect(&format!("Failed to parse {}", $input));
         let serialized = ToCss::to_css_string(&parsed);
         assert_eq!(serialized, $output);
 
         let mut parser = Parser::new(&serialized);
         let re_parsed = $fun(&context, &mut parser)
@@ -56,28 +58,30 @@ macro_rules! assert_roundtrip {
         let re_serialized = ToCss::to_css_string(&re_parsed);
         assert_eq!(serialized, re_serialized);
     }
 }
 
 macro_rules! assert_parser_exhausted {
     ($name:ident, $string:expr, $should_exhausted:expr) => {{
         let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+        let reporter = CSSErrorReporterTest;
+        let context = ParserContext::new(Origin::Author, &url, &reporter);
         let mut parser = Parser::new($string);
         let parsed = $name::parse(&context, &mut parser);
         assert_eq!(parsed.is_ok(), true);
         assert_eq!(parser.is_exhausted(), $should_exhausted);
     }}
 }
 
 macro_rules! parse_longhand {
     ($name:ident, $s:expr) => {{
         let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+        let reporter = CSSErrorReporterTest;
+        let context = ParserContext::new(Origin::Author, &url, &reporter);
         $name::parse(&context, &mut Parser::new($s)).unwrap()
     }};
 }
 
 mod animation;
 mod background;
 mod basic_shape;
 mod border;
--- a/servo/tests/unit/style/parsing/outline.rs
+++ b/servo/tests/unit/style/parsing/outline.rs
@@ -23,15 +23,16 @@ fn test_outline_style() {
     assert_roundtrip_with_context!(outline_style::parse, r#"inset"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"outset"#);
 
     {
         // The outline-style property accepts the same values as border-style,
         // except that 'hidden' is not a legal outline style.
 
         let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+        let reporter = CSSErrorReporterTest;
+        let context = ParserContext::new(Origin::Author, &url, &reporter);
         let mut parser = Parser::new(r#"hidden"#);
         let parsed = outline_style::parse(&context, &mut parser);
         assert!(parsed.is_err());
     };
 
 }
--- a/servo/tests/unit/style/parsing/ui.rs
+++ b/servo/tests/unit/style/parsing/ui.rs
@@ -22,17 +22,18 @@ fn test_moz_user_select() {
     assert_roundtrip_with_context!(_moz_user_select::parse, "elements");
     assert_roundtrip_with_context!(_moz_user_select::parse, "toggle");
     assert_roundtrip_with_context!(_moz_user_select::parse, "tri_state");
     assert_roundtrip_with_context!(_moz_user_select::parse, "-moz-all");
     assert_roundtrip_with_context!(_moz_user_select::parse, "-moz-none");
     assert_roundtrip_with_context!(_moz_user_select::parse, "-moz-text");
 
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let mut negative = Parser::new("potato");
     assert!(_moz_user_select::parse(&context, &mut negative).is_err());
 }
 
 #[test]
 fn test_caret_color() {
     use style::properties::longhands::caret_color;
--- a/servo/tests/unit/style/properties/background.rs
+++ b/servo/tests/unit/style/properties/background.rs
@@ -6,14 +6,15 @@ use cssparser::Parser;
 use media_queries::CSSErrorReporterTest;
 use style::parser::ParserContext;
 use style::properties::longhands::background_size;
 use style::stylesheets::Origin;
 
 #[test]
 fn background_size_should_reject_negative_values() {
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     let parse_result = background_size::parse(&context, &mut Parser::new("-40% -40%"));
 
     assert_eq!(parse_result.is_err(), true);
 }
--- a/servo/tests/unit/style/properties/serialization.rs
+++ b/servo/tests/unit/style/properties/serialization.rs
@@ -16,17 +16,18 @@ use style::values::{RGBA, Auto};
 use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length, NoCalcLength};
 use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
 use style::values::specified::url::SpecifiedUrl;
 use style_traits::ToCss;
 use stylesheets::block_from;
 
 fn parse_declaration_block(css_properties: &str) -> PropertyDeclarationBlock {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
     let mut parser = Parser::new(css_properties);
     parse_property_declaration_list(&context, &mut parser)
 }
 
 #[test]
 fn property_declaration_block_should_serialize_correctly() {
     use style::properties::longhands::overflow_x::SpecifiedValue as OverflowXValue;
     use style::properties::longhands::overflow_y::SpecifiedValue as OverflowYContainer;
@@ -958,17 +959,18 @@ mod shorthand_serialization {
             use cssparser::Parser;
             use media_queries::CSSErrorReporterTest;
             use style::parser::ParserContext;
             use style::properties::longhands::transform;
             use style::stylesheets::Origin;
 
             let mut s = String::new();
             let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-            let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+            let reporter = CSSErrorReporterTest;
+            let context = ParserContext::new(Origin::Author, &url, &reporter);
 
             let parsed = transform::parse(&context, &mut Parser::new("none")).unwrap();
             let try_serialize = parsed.to_css(&mut s);
 
             assert_eq!(try_serialize.is_ok(), true);
             assert_eq!(s, "none");
         }
     }
@@ -981,17 +983,18 @@ mod shorthand_serialization {
             use cssparser::Parser;
             use media_queries::CSSErrorReporterTest;
             use style::parser::ParserContext;
             use style::properties::longhands::quotes;
             use style::stylesheets::Origin;
 
             let mut s = String::new();
             let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-            let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+            let reporter = CSSErrorReporterTest;
+            let context = ParserContext::new(Origin::Author, &url, &reporter);
 
             let parsed = quotes::parse(&context, &mut Parser::new("none")).unwrap();
             let try_serialize = parsed.to_css(&mut s);
 
             assert_eq!(try_serialize.is_ok(), true);
             assert_eq!(s, "none");
         }
     }
--- a/servo/tests/unit/style/rule_tree/bench.rs
+++ b/servo/tests/unit/style/rule_tree/bench.rs
@@ -16,20 +16,16 @@ use style::stylesheets::{Origin, Stylesh
 use test::{self, Bencher};
 
 struct ErrorringErrorReporter;
 impl ParseErrorReporter for ErrorringErrorReporter {
     fn report_error(&self, _input: &mut Parser, position: SourcePosition, message: &str,
         url: &ServoUrl) {
         panic!("CSS error: {}\t\n{:?} {}", url.as_str(), position, message);
     }
-
-    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
-        Box::new(ErrorringErrorReporter)
-    }
 }
 
 struct AutoGCRuleTree<'a>(&'a RuleTree);
 
 impl<'a> AutoGCRuleTree<'a> {
     fn new(r: &'a RuleTree) -> Self {
         AutoGCRuleTree(r)
     }
@@ -44,17 +40,17 @@ impl<'a> Drop for AutoGCRuleTree<'a> {
 fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
     let s = Stylesheet::from_str(css,
                                  ServoUrl::parse("http://localhost").unwrap(),
                                  Origin::Author,
                                  MediaList {
                                      media_queries: vec![],
                                  },
                                  None,
-                                 Box::new(ErrorringErrorReporter),
+                                 &ErrorringErrorReporter,
                                  ParserContextExtraData {});
     let rules = s.rules.read();
     rules.0.iter().filter_map(|rule| {
         match *rule {
             CssRule::Style(ref style_rule) => Some(style_rule),
             _ => None,
         }
     }).cloned().map(StyleSource::Style).map(|s| {
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -58,17 +58,17 @@ fn test_parse_stylesheet() {
                 width: 50% !important; /* !important not allowed here */
                 animation-name: 'foo'; /* animation properties not allowed here */
                 animation-play-state: running; /* … except animation-play-state */
             }
         }";
     let url = ServoUrl::parse("about::test").unwrap();
     let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
                                           None,
-                                          Box::new(CSSErrorReporterTest),
+                                          &CSSErrorReporterTest,
                                           ParserContextExtraData::default());
     let mut namespaces = Namespaces::default();
     namespaces.default = Some(ns!(html));
     let expected = Stylesheet {
         origin: Origin::UserAgent,
         media: Default::default(),
         namespaces: RwLock::new(namespaces),
         base_url: url,
@@ -284,61 +284,55 @@ impl CSSInvalidErrorReporterTest {
     pub fn new() -> CSSInvalidErrorReporterTest {
         return CSSInvalidErrorReporterTest{
             errors: Arc::new(Mutex::new(Vec::new()))
         }
     }
 }
 
 impl ParseErrorReporter for CSSInvalidErrorReporterTest {
-    fn report_error(&self, input: &mut CssParser, position: SourcePosition, message: &str,
-        url: &ServoUrl) {
+    fn report_error(&self,
+                    input: &mut CssParser,
+                    position: SourcePosition,
+                    message: &str,
+                    url: &ServoUrl) {
 
         let location = input.source_location(position);
 
-        let errors = self.errors.clone();
-        let mut errors = errors.lock().unwrap();
+        let mut errors = self.errors.lock().unwrap();
 
         errors.push(
             CSSError{
                 url: url.clone(),
                 line: location.line,
                 column: location.column,
                 message: message.to_owned()
             }
         );
     }
-
-    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
-        return Box::new(
-            CSSInvalidErrorReporterTest{
-                errors: self.errors.clone()
-            }
-        );
-    }
 }
 
 
 #[test]
 fn test_report_error_stylesheet() {
     let css = r"
     div {
         background-color: red;
         display: invalid;
         invalid: true;
     }
     ";
     let url = ServoUrl::parse("about::test").unwrap();
-    let error_reporter = Box::new(CSSInvalidErrorReporterTest::new());
+    let error_reporter = CSSInvalidErrorReporterTest::new();
 
     let errors = error_reporter.errors.clone();
 
     Stylesheet::from_str(css, url.clone(), Origin::UserAgent, Default::default(),
                          None,
-                         error_reporter,
+                         &error_reporter,
                          ParserContextExtraData::default());
 
     let mut errors = errors.lock().unwrap();
 
     let error = errors.pop().unwrap();
     assert_eq!("Unsupported property declaration: 'invalid: true;'", error.message);
     assert_eq!(5, error.line);
     assert_eq!(9, error.column);
--- a/servo/tests/unit/style/viewport.rs
+++ b/servo/tests/unit/style/viewport.rs
@@ -2,17 +2,16 @@
  * 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::Parser;
 use euclid::size::TypedSize2D;
 use media_queries::CSSErrorReporterTest;
 use servo_config::prefs::{PREFS, PrefValue};
 use servo_url::ServoUrl;
-use style::error_reporting::ParseErrorReporter;
 use style::media_queries::{Device, MediaType};
 use style::parser::{ParserContext, ParserContextExtraData};
 use style::stylesheets::{Stylesheet, Origin};
 use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
 use style::values::specified::NoCalcLength::{self, ViewportPercentage};
 use style::values::specified::ViewportPercentageLength::Vw;
 use style::viewport::*;
 use style_traits::PinchZoomFactor;
@@ -21,29 +20,29 @@ use style_traits::viewport::*;
 macro_rules! stylesheet {
     ($css:expr, $origin:ident, $error_reporter:expr) => {
         Box::new(Stylesheet::from_str(
             $css,
             ServoUrl::parse("http://localhost").unwrap(),
             Origin::$origin,
             Default::default(),
             None,
-            $error_reporter,
+            &$error_reporter,
             ParserContextExtraData::default()
         ))
     }
 }
 
 fn test_viewport_rule<F>(css: &str,
                          device: &Device,
                          callback: F)
     where F: Fn(&Vec<ViewportDescriptorDeclaration>, &str)
 {
     PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
-    let stylesheet = stylesheet!(css, Author, Box::new(CSSErrorReporterTest));
+    let stylesheet = stylesheet!(css, Author, CSSErrorReporterTest);
     let mut rule_count = 0;
     stylesheet.effective_viewport_rules(&device, |rule| {
         rule_count += 1;
         callback(&rule.declarations, css);
     });
     assert!(rule_count > 0);
 }
 
@@ -248,43 +247,44 @@ fn cascading_within_viewport_rule() {
 }
 
 #[test]
 fn multiple_stylesheets_cascading() {
     PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true));
     let device = Device::new(MediaType::Screen, TypedSize2D::new(800., 600.));
     let error_reporter = CSSErrorReporterTest;
     let stylesheets = vec![
-        stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", UserAgent, error_reporter.clone()),
-        stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", User, error_reporter.clone()),
-        stylesheet!("@viewport { min-width: 300px; }", Author, error_reporter.clone())];
+        stylesheet!("@viewport { min-width: 100px; min-height: 100px; zoom: 1; }", UserAgent, error_reporter),
+        stylesheet!("@viewport { min-width: 200px; min-height: 200px; }", User, error_reporter),
+        stylesheet!("@viewport { min-width: 300px; }", Author, error_reporter)];
 
     let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish();
     assert_decl_len!(declarations == 3);
     assert_decl_eq!(&declarations[0], UserAgent, Zoom: Zoom::Number(1.));
     assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px));
     assert_decl_eq!(&declarations[2], Author, MinWidth: viewport_length!(300., px));
 
     let stylesheets = vec![
-        stylesheet!("@viewport { min-width: 100px !important; }", UserAgent, error_reporter.clone()),
+        stylesheet!("@viewport { min-width: 100px !important; }", UserAgent, error_reporter),
         stylesheet!("@viewport { min-width: 200px !important; min-height: 200px !important; }",
-        User, error_reporter.clone()),
+        User, error_reporter),
         stylesheet!("@viewport { min-width: 300px !important; min-height: 300px !important; zoom: 3 !important; }",
-        Author, error_reporter.clone())];
+        Author, error_reporter)];
     let declarations = Cascade::from_stylesheets(&stylesheets, &device).finish();
     assert_decl_len!(declarations == 3);
     assert_decl_eq!(&declarations[0], UserAgent, MinWidth: viewport_length!(100., px), !important);
     assert_decl_eq!(&declarations[1], User, MinHeight: viewport_length!(200., px), !important);
     assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
 }
 
 #[test]
 fn constrain_viewport() {
     let url = ServoUrl::parse("http://localhost").unwrap();
-    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter);
 
     macro_rules! from_css {
         ($css:expr) => {
             &ViewportRule::parse(&mut Parser::new($css), &context).unwrap()
         }
     }
 
     let initial_viewport = TypedSize2D::new(800., 600.);