servo: Merge #14373 - Use the ParserContext along with the Parser (from Wafflespeanut:parse); r=emilio
authorRavi Shankar <wafflespeanut@gmail.com>
Sat, 26 Nov 2016 19:20:10 -0800
changeset 340230 84d3efcfbb34ec2dbd9013f9f689b1aa0d016527
parent 340229 b29078f132699af836917ea09ea3eae9fdc93415
child 340231 17458270d9693d168c6b14bdfccbe34886c93948
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
servo: Merge #14373 - Use the ParserContext along with the Parser (from Wafflespeanut:parse); r=emilio <!-- Please describe your changes on the following line: --> This changes the `parse` function's signature to include `ParserContext`, so that we don't introduce another trait just for the sake of the context. Instead, we can safely ignore the context whenever we don't need it. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors <!-- Either: --> - [x] These changes do not require tests because it's a refactor <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> r? @SimonSapin or @emilio or @Manishearth Source-Repo: https://github.com/servo/servo Source-Revision: 4755cb7586ab4a89f35bbccf8b57c85ed2f428e7
servo/components/style/custom_properties.rs
servo/components/style/parser.rs
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/longhand/background.mako.rs
servo/components/style/properties/longhand/border.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/color.mako.rs
servo/components/style/properties/longhand/column.mako.rs
servo/components/style/properties/longhand/effects.mako.rs
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/properties/longhand/inherited_svg.mako.rs
servo/components/style/properties/longhand/inherited_text.mako.rs
servo/components/style/properties/longhand/list.mako.rs
servo/components/style/properties/longhand/outline.mako.rs
servo/components/style/properties/longhand/padding.mako.rs
servo/components/style/properties/longhand/pointing.mako.rs
servo/components/style/properties/longhand/position.mako.rs
servo/components/style/properties/longhand/text.mako.rs
servo/components/style/properties/longhand/xul.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/properties/shorthand/border.mako.rs
servo/components/style/properties/shorthand/box.mako.rs
servo/components/style/properties/shorthand/outline.mako.rs
servo/components/style/properties/shorthand/position.mako.rs
servo/components/style/values/mod.rs
servo/components/style/values/specified/basic_shape.rs
servo/components/style/values/specified/image.rs
servo/components/style/values/specified/length.rs
servo/components/style/values/specified/mod.rs
servo/components/style/values/specified/position.rs
servo/tests/unit/style/parsing/basic_shape.rs
servo/tests/unit/style/parsing/mod.rs
servo/tests/unit/style/parsing/position.rs
servo/tests/unit/style/parsing/selectors.rs
--- a/servo/components/style/custom_properties.rs
+++ b/servo/components/style/custom_properties.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Support for [custom properties for cascading variables][custom].
 //!
 //! [custom]: https://drafts.csswg.org/css-variables/
 
 use Atom;
 use cssparser::{Delimiter, Parser, SourcePosition, Token, TokenSerializationType};
-use parser::Parse;
+use parser::{Parse, ParserContext};
 use properties::DeclaredValue;
 use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
 use std::fmt;
 use std::sync::Arc;
 use style_traits::ToCss;
 
@@ -108,17 +108,17 @@ impl ComputedValue {
     }
 
     fn push_variable(&mut self, variable: &ComputedValue) {
         self.push(&variable.css, variable.first_token_type, variable.last_token_type)
     }
 }
 
 impl Parse for SpecifiedValue {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         let mut references = Some(HashSet::new());
         let (first, css, last) = try!(parse_self_contained_declaration_value(input, &mut references));
         Ok(SpecifiedValue {
             css: css.into_owned(),
             first_token_type: first,
             last_token_type: last,
             references: references.unwrap(),
         })
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -64,13 +64,11 @@ impl<'a> ParserContext<'a> {
 /// 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) {
     parsercontext.error_reporter.report_error(input, position, message);
 }
 
 // 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.
-// There may need to be two traits -- one for parsing with context, and one
-// for parsing without
 pub trait Parse {
-    fn parse(input: &mut Parser) -> Result<Self, ()> where Self: Sized;
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> where Self: Sized;
 }
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -11,17 +11,17 @@
             pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                                -> Result<DeclaredValue<SpecifiedValue>, ()> {
                 parse(context, input).map(DeclaredValue::Value)
             }
         % endif
     </%call>
 </%def>
 
-<%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=False, **kwargs)">
+<%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=True, **kwargs)">
     <%call expr="longhand(name, predefined_type=type, **kwargs)">
         #[allow(unused_imports)]
         use app_units::Au;
         use cssparser::{Color as CSSParserColor, RGBA};
         pub use values::specified::${type} as SpecifiedValue;
         pub mod computed_value {
             pub use values::computed::${type} as T;
         }
@@ -278,17 +278,17 @@
                 % endif
             % else:
                 // Do not allow stylesheets to set derived properties.
             % endif
         }
         % if not property.derived_from:
             pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                                -> Result<DeclaredValue<SpecifiedValue>, ()> {
-                match input.try(CSSWideKeyword::parse) {
+                match input.try(|i| CSSWideKeyword::parse(context, i)) {
                     Ok(CSSWideKeyword::InheritKeyword) => Ok(DeclaredValue::Inherit),
                     Ok(CSSWideKeyword::InitialKeyword) => Ok(DeclaredValue::Initial),
                     Ok(CSSWideKeyword::UnsetKeyword) => Ok(DeclaredValue::${
                         "Inherit" if data.current_style_struct.inherited else "Initial"}),
                     Err(()) => {
                         input.look_for_var_functions();
                         let start = input.position();
                         let specified = parse_specified(context, input);
@@ -510,27 +510,33 @@
             }
         }
 
         ${caller.body()}
     }
     % endif
 </%def>
 
-<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function)">
+<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, needs_context=True)">
     <%self:shorthand name="${name}" sub_properties="${
             ' '.join(sub_property_pattern % side
                      for side in ['top', 'right', 'bottom', 'left'])}">
         #[allow(unused_imports)]
         use parser::Parse;
         use super::parse_four_sides;
         use values::specified;
 
-        pub fn parse_value(_: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
-            let (top, right, bottom, left) = try!(parse_four_sides(input, ${parser_function}));
+        pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
+            let (top, right, bottom, left) =
+            % if needs_context:
+                try!(parse_four_sides(input, |i| ${parser_function}(context, i)));
+            % else:
+                try!(parse_four_sides(input, ${parser_function}));
+                let _unused = context;
+            % endif
             Ok(Longhands {
                 % for side in ["top", "right", "bottom", "left"]:
                     ${to_rust_ident(sub_property_pattern % side)}: Some(${side}),
                 % endfor
             })
         }
 
         impl<'a> LonghandsToSerialize<'a> {
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -115,19 +115,19 @@
             Position {
                 horiz_keyword: None,
                 horiz_position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
                 vert_keyword: None,
                 vert_position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
             }
         }
 
-        pub fn parse(_context: &ParserContext, input: &mut Parser)
+        pub fn parse(context: &ParserContext, input: &mut Parser)
                      -> Result<SpecifiedValue, ()> {
-            Ok(try!(Position::parse(input)))
+            Ok(try!(Position::parse(context, input)))
         }
 </%helpers:vector_longhand>
 
 ${helpers.single_keyword("background-repeat",
                          "repeat repeat-x repeat-y space round no-repeat",
                          vector=True,
                          animatable=False)}
 
@@ -297,45 +297,45 @@
     #[inline]
     pub fn get_initial_specified_value() -> SpecifiedValue {
         SpecifiedValue::Explicit(ExplicitSize {
             width: specified::LengthOrPercentageOrAuto::Auto,
             height: specified::LengthOrPercentageOrAuto::Auto,
         })
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         let width;
         if let Ok(value) = input.try(|input| {
             match input.next() {
                 Err(_) => Err(()),
                 Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("cover") => {
                     Ok(SpecifiedValue::Cover)
                 }
                 Ok(Token::Ident(ref ident)) if ident.eq_ignore_ascii_case("contain") => {
                     Ok(SpecifiedValue::Contain)
                 }
                 Ok(_) => Err(()),
             }
         }) {
             return Ok(value)
         } else {
-            width = try!(specified::LengthOrPercentageOrAuto::parse(input))
+            width = try!(specified::LengthOrPercentageOrAuto::parse(context, input))
         }
 
         let height;
         if let Ok(value) = input.try(|input| {
             match input.next() {
                 Err(_) => Ok(specified::LengthOrPercentageOrAuto::Auto),
                 Ok(_) => Err(()),
             }
         }) {
             height = value
         } else {
-            height = try!(specified::LengthOrPercentageOrAuto::parse(input));
+            height = try!(specified::LengthOrPercentageOrAuto::parse(context, input));
         }
 
         Ok(SpecifiedValue::Explicit(ExplicitSize {
             width: width,
             height: height,
         }))
     }
 </%helpers:vector_longhand>
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -13,33 +13,34 @@
     ${helpers.predefined_type("border-%s-color" % side[0], "CSSColor",
                               "::cssparser::Color::CurrentColor",
                               animatable=True, logical = side[1])}
 % endfor
 
 % for side in ALL_SIDES:
     ${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
                               "specified::BorderStyle::none",
-                              need_clone=True, animatable=False, logical = side[1])}
+                              needs_context=False, need_clone=True,
+                              animatable=False, logical = side[1])}
 % endfor
 
 % for side in ALL_SIDES:
     <%helpers:longhand name="border-${side[0]}-width" animatable="True" logical="${side[1]}">
         use app_units::Au;
         use std::fmt;
         use style_traits::ToCss;
         use values::HasViewportPercentage;
         use values::specified::BorderWidth;
 
         pub type SpecifiedValue = BorderWidth;
 
         #[inline]
-        pub fn parse(_context: &ParserContext, input: &mut Parser)
+        pub fn parse(context: &ParserContext, input: &mut Parser)
                      -> Result<SpecifiedValue, ()> {
-            BorderWidth::parse(input)
+            BorderWidth::parse(context, input)
         }
 
         pub mod computed_value {
             use app_units::Au;
             pub type T = Au;
         }
         #[inline] pub fn get_initial_value() -> computed_value::T {
             Au::from_px(3)  // medium
@@ -498,34 +499,34 @@
             SpecifiedValue(vec![ToComputedValue::from_computed_value(&computed.0),
                                 ToComputedValue::from_computed_value(&computed.1),
                                 ToComputedValue::from_computed_value(&computed.2),
                                 ToComputedValue::from_computed_value(&computed.3)])
         }
     }
 
     impl Parse for SingleSpecifiedValue {
-        fn parse(input: &mut Parser) -> Result<Self, ()> {
+        fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
             if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
                 return Ok(SingleSpecifiedValue::Auto);
             }
 
-            if let Ok(len) = input.try(|input| LengthOrPercentage::parse(input)) {
+            if let Ok(len) = input.try(|input| LengthOrPercentage::parse(context, input)) {
                 return Ok(SingleSpecifiedValue::LengthOrPercentage(len));
             }
 
             let num = try!(Number::parse_non_negative(input));
             Ok(SingleSpecifiedValue::Number(num))
         }
     }
 
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         let mut values = vec![];
         for _ in 0..4 {
-            let value = input.try(|input| SingleSpecifiedValue::parse(input));
+            let value = input.try(|input| SingleSpecifiedValue::parse(context, input));
             match value {
                 Ok(val) => values.push(val),
                 Err(_) => break,
             }
         }
 
         if values.len() > 0 {
             Ok(SpecifiedValue(values))
@@ -704,32 +705,32 @@
                               ToComputedValue::from_computed_value(&computed.corners[2]),
                               ToComputedValue::from_computed_value(&computed.corners[3])],
                 fill: computed.fill,
             }
         }
     }
 
     impl Parse for PercentageOrNumber {
-        fn parse(input: &mut Parser) -> Result<Self, ()> {
-            if let Ok(per) = input.try(|input| Percentage::parse(input)) {
+        fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+            if let Ok(per) = input.try(|input| Percentage::parse(context, input)) {
                 return Ok(PercentageOrNumber::Percentage(per));
             }
 
             let num = try!(Number::parse_non_negative(input));
             Ok(PercentageOrNumber::Number(num))
         }
     }
 
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         let mut fill = input.try(|input| input.expect_ident_matching("fill")).is_ok();
 
         let mut values = vec![];
         for _ in 0..4 {
-            let value = input.try(|input| PercentageOrNumber::parse(input));
+            let value = input.try(|input| PercentageOrNumber::parse(context, input));
             match value {
                 Ok(val) => values.push(val),
                 Err(_) => break,
             }
         }
 
         if fill == false {
             fill = input.try(|input| input.expect_ident_matching("fill")).is_ok();
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -178,18 +178,18 @@
                   SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"),
               % endfor
               SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest),
           }
       }
   }
   /// baseline | sub | super | top | text-top | middle | bottom | text-bottom
   /// | <percentage> | <length>
-  pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-      input.try(specified::LengthOrPercentage::parse)
+  pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+      input.try(|i| specified::LengthOrPercentage::parse(context, i))
       .map(SpecifiedValue::LengthOrPercentage)
       .or_else(|()| {
           match_ignore_ascii_case! { try!(input.expect_ident()),
               % for keyword in vertical_align_keywords:
                   "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
               % endfor
               _ => Err(())
           }
@@ -354,18 +354,18 @@
         Time(0.0)
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(vec![get_initial_single_value()])
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
-        Ok(SpecifiedValue(try!(input.parse_comma_separated(Time::parse))))
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+        Ok(SpecifiedValue(try!(input.parse_comma_separated(|i| Time::parse(context, i)))))
     }
 </%helpers:longhand>
 
 // TODO(pcwalton): Lots more timing functions.
 // TODO(pcwalton): Multiple transitions.
 <%helpers:longhand name="transition-timing-function"
                    need_index="True"
                    animatable="False">
@@ -411,33 +411,33 @@
 
     static STEP_START: TransitionTimingFunction =
         TransitionTimingFunction::Steps(1, StartEnd::Start);
     static STEP_END: TransitionTimingFunction =
         TransitionTimingFunction::Steps(1, StartEnd::End);
 
     pub mod computed_value {
         use euclid::point::Point2D;
-        use parser::Parse;
+        use parser::{Parse, ParserContext};
         use std::fmt;
         use style_traits::ToCss;
         use values::specified;
         use values::computed::ComputedValueAsSpecified;
 
         pub use self::TransitionTimingFunction as SingleComputedValue;
 
         #[derive(Copy, Clone, Debug, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub enum TransitionTimingFunction {
             CubicBezier(Point2D<f32>, Point2D<f32>),
             Steps(u32, StartEnd),
         }
 
         impl Parse for TransitionTimingFunction {
-            fn parse(input: &mut ::cssparser::Parser) -> Result<Self, ()> {
+            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> {
                 if let Ok(function_name) = input.try(|input| input.expect_function()) {
                     return match_ignore_ascii_case! { function_name,
                         "cubic-bezier" => {
                             let (mut p1x, mut p1y, mut p2x, mut p2y) = (0.0, 0.0, 0.0, 0.0);
                             try!(input.parse_nested_block(|input| {
                                 p1x = try!(specified::parse_number(input));
                                 try!(input.expect_comma());
                                 p1y = try!(specified::parse_number(input));
@@ -554,18 +554,20 @@
         ease()
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(vec![get_initial_single_value()])
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
-        Ok(SpecifiedValue(try!(input.parse_comma_separated(TransitionTimingFunction::parse))))
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+        Ok(SpecifiedValue(try!(input.parse_comma_separated(|i| {
+            TransitionTimingFunction::parse(context, i)
+        }))))
     }
 </%helpers:longhand>
 
 <%helpers:longhand name="transition-property"
                    need_index="True"
                    animatable="False">
 
     use values::computed::ComputedValueAsSpecified;
@@ -601,17 +603,17 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(Vec::new())
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         Ok(SpecifiedValue(try!(input.parse_comma_separated(SingleSpecifiedValue::parse))))
     }
 
     use values::NoViewportPercentage;
     impl NoViewportPercentage for SpecifiedValue {}
 
     impl ComputedValueAsSpecified for SpecifiedValue { }
 </%helpers:longhand>
@@ -628,17 +630,17 @@
                    need_index="True"
                    animatable="False",
                    allowed_in_keyframe_block="False">
     use values::computed::ComputedValueAsSpecified;
     use values::NoViewportPercentage;
 
     pub mod computed_value {
         use Atom;
-        use parser::Parse;
+        use parser::{Parse, ParserContext};
         use std::fmt;
         use std::ops::Deref;
         use style_traits::ToCss;
 
         #[derive(Clone, Debug, Hash, Eq, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub struct AnimationName(pub Atom);
 
@@ -646,17 +648,17 @@
             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 self.0.fmt(f)
             }
         }
 
         pub use self::AnimationName as SingleComputedValue;
 
         impl Parse for AnimationName {
-            fn parse(input: &mut ::cssparser::Parser) -> Result<Self, ()> {
+            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> {
                 use cssparser::Token;
                 Ok(match input.next() {
                     Ok(Token::Ident(ref value)) if value != "none" => AnimationName(Atom::from(&**value)),
                     Ok(Token::QuotedString(value)) => AnimationName(Atom::from(&*value)),
                     _ => return Err(()),
                 })
             }
         }
@@ -687,19 +689,19 @@
     impl NoViewportPercentage for SpecifiedValue {}
     pub use self::computed_value::SingleComputedValue as SingleSpecifiedValue;
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(vec![])
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         use std::borrow::Cow;
-        Ok(SpecifiedValue(try!(input.parse_comma_separated(SingleSpecifiedValue::parse))))
+        Ok(SpecifiedValue(try!(input.parse_comma_separated(|i| SingleSpecifiedValue::parse(context, i)))))
     }
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
 </%helpers:longhand>
 
 <%helpers:longhand name="animation-duration"
                    need_index="True"
                    animatable="False",
@@ -723,31 +725,31 @@
 <%helpers:longhand name="animation-iteration-count"
                    need_index="True"
                    animatable="False",
                    allowed_in_keyframe_block="False">
     use values::computed::ComputedValueAsSpecified;
     use values::NoViewportPercentage;
 
     pub mod computed_value {
-        use parser::Parse;
+        use parser::{Parse, ParserContext};
         use std::fmt;
         use style_traits::ToCss;
 
         pub use self::AnimationIterationCount as SingleComputedValue;
 
         #[derive(Debug, Clone, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub enum AnimationIterationCount {
             Number(u32),
             Infinite,
         }
 
         impl Parse for AnimationIterationCount {
-            fn parse(input: &mut ::cssparser::Parser) -> Result<Self, ()> {
+            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<Self, ()> {
                 if input.try(|input| input.expect_ident_matching("infinite")).is_ok() {
                     return Ok(AnimationIterationCount::Infinite)
                 }
 
                 let number = try!(input.expect_integer());
                 if number < 0 {
                     return Err(());
                 }
@@ -791,18 +793,20 @@
     impl NoViewportPercentage for SpecifiedValue {}
 
     #[inline]
     pub fn get_initial_single_value() -> AnimationIterationCount {
         AnimationIterationCount::Number(1)
     }
 
     #[inline]
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        Ok(SpecifiedValue(try!(input.parse_comma_separated(AnimationIterationCount::parse))))
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+        Ok(SpecifiedValue(try!(input.parse_comma_separated(|i| {
+            AnimationIterationCount::parse(context, i)
+        }))))
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(vec![get_initial_single_value()])
     }
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
@@ -992,41 +996,42 @@
 
         #[derive(Clone, Debug, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub struct T(pub Option<Vec<ComputedOperation>>);
     }
 
     pub use self::computed_value::ComputedMatrix as SpecifiedMatrix;
 
-    fn parse_two_lengths_or_percentages(input: &mut Parser)
+    fn parse_two_lengths_or_percentages(context: &ParserContext, input: &mut Parser)
                                         -> Result<(specified::LengthOrPercentage,
                                                    specified::LengthOrPercentage),()> {
-        let first = try!(specified::LengthOrPercentage::parse(input));
+        let first = try!(specified::LengthOrPercentage::parse(context, input));
         let second = input.try(|input| {
             try!(input.expect_comma());
-            specified::LengthOrPercentage::parse(input)
+            specified::LengthOrPercentage::parse(context, input)
         }).unwrap_or(specified::LengthOrPercentage::zero());
         Ok((first, second))
     }
 
     fn parse_two_floats(input: &mut Parser) -> Result<(CSSFloat,CSSFloat),()> {
         let first = try!(specified::parse_number(input));
         let second = input.try(|input| {
             try!(input.expect_comma());
             specified::parse_number(input)
         }).unwrap_or(first);
         Ok((first, second))
     }
 
-    fn parse_two_angles(input: &mut Parser) -> Result<(specified::Angle, specified::Angle),()> {
-        let first = try!(specified::Angle::parse(input));
+    fn parse_two_angles(context: &ParserContext, input: &mut Parser)
+                       -> Result<(specified::Angle, specified::Angle),()> {
+        let first = try!(specified::Angle::parse(context, input));
         let second = input.try(|input| {
             try!(input.expect_comma());
-            specified::Angle::parse(input)
+            specified::Angle::parse(context, input)
         }).unwrap_or(specified::Angle(0.0));
         Ok((first, second))
     }
 
     #[derive(Copy, Clone, Debug, PartialEq)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     enum TranslateKind {
         Translate,
@@ -1155,17 +1160,17 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(None)
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(SpecifiedValue(Vec::new()))
         }
 
         let mut result = Vec::new();
         loop {
             let name = match input.expect_function() {
                 Ok(name) => name,
@@ -1206,64 +1211,64 @@
                                     m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11],
                                     m41: values[12], m42: values[13], m43: values[14], m44: values[15]
                                 }));
                         Ok(())
                     }))
                 },
                 "translate" => {
                     try!(input.parse_nested_block(|input| {
-                        let (tx, ty) = try!(parse_two_lengths_or_percentages(input));
+                        let (tx, ty) = try!(parse_two_lengths_or_percentages(context, input));
                         result.push(SpecifiedOperation::Translate(TranslateKind::Translate,
                                                                   tx,
                                                                   ty,
                                                                   specified::Length::Absolute(Au(0))));
                         Ok(())
                     }))
                 },
                 "translatex" => {
                     try!(input.parse_nested_block(|input| {
-                        let tx = try!(specified::LengthOrPercentage::parse(input));
+                        let tx = try!(specified::LengthOrPercentage::parse(context, input));
                         result.push(SpecifiedOperation::Translate(
                             TranslateKind::TranslateX,
                             tx,
                             specified::LengthOrPercentage::zero(),
                             specified::Length::Absolute(Au(0))));
                         Ok(())
                     }))
                 },
                 "translatey" => {
                     try!(input.parse_nested_block(|input| {
-                        let ty = try!(specified::LengthOrPercentage::parse(input));
+                        let ty = try!(specified::LengthOrPercentage::parse(context, input));
                         result.push(SpecifiedOperation::Translate(
                             TranslateKind::TranslateY,
                             specified::LengthOrPercentage::zero(),
                             ty,
                             specified::Length::Absolute(Au(0))));
                         Ok(())
                     }))
                 },
                 "translatez" => {
                     try!(input.parse_nested_block(|input| {
-                        let tz = try!(specified::Length::parse(input));
+                        let tz = try!(specified::Length::parse(context, input));
                         result.push(SpecifiedOperation::Translate(
                             TranslateKind::TranslateZ,
                             specified::LengthOrPercentage::zero(),
                             specified::LengthOrPercentage::zero(),
                             tz));
                         Ok(())
                     }))
                 },
                 "translate3d" => {
                     try!(input.parse_nested_block(|input| {
-                        let tx = try!(specified::LengthOrPercentage::parse(input));
+                        let tx = try!(specified::LengthOrPercentage::parse(context, input));
                         try!(input.expect_comma());
-                        let ty = try!(specified::LengthOrPercentage::parse(input));
+                        let ty = try!(specified::LengthOrPercentage::parse(context, input));
                         try!(input.expect_comma());
-                        let tz = try!(specified::Length::parse(input));
+                        let tz = try!(specified::Length::parse(context, input));
                         result.push(SpecifiedOperation::Translate(
                             TranslateKind::Translate3D,
                             tx,
                             ty,
                             tz));
                         Ok(())
                     }))
 
@@ -1304,80 +1309,80 @@
                         try!(input.expect_comma());
                         let sz = try!(specified::parse_number(input));
                         result.push(SpecifiedOperation::Scale(sx, sy, sz));
                         Ok(())
                     }))
                 },
                 "rotate" => {
                     try!(input.parse_nested_block(|input| {
-                        let theta = try!(specified::Angle::parse(input));
+                        let theta = try!(specified::Angle::parse(context,input));
                         result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta));
                         Ok(())
                     }))
                 },
                 "rotatex" => {
                     try!(input.parse_nested_block(|input| {
-                        let theta = try!(specified::Angle::parse(input));
+                        let theta = try!(specified::Angle::parse(context,input));
                         result.push(SpecifiedOperation::Rotate(1.0, 0.0, 0.0, theta));
                         Ok(())
                     }))
                 },
                 "rotatey" => {
                     try!(input.parse_nested_block(|input| {
-                        let theta = try!(specified::Angle::parse(input));
+                        let theta = try!(specified::Angle::parse(context,input));
                         result.push(SpecifiedOperation::Rotate(0.0, 1.0, 0.0, theta));
                         Ok(())
                     }))
                 },
                 "rotatez" => {
                     try!(input.parse_nested_block(|input| {
-                        let theta = try!(specified::Angle::parse(input));
+                        let theta = try!(specified::Angle::parse(context,input));
                         result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta));
                         Ok(())
                     }))
                 },
                 "rotate3d" => {
                     try!(input.parse_nested_block(|input| {
                         let ax = try!(specified::parse_number(input));
                         try!(input.expect_comma());
                         let ay = try!(specified::parse_number(input));
                         try!(input.expect_comma());
                         let az = try!(specified::parse_number(input));
                         try!(input.expect_comma());
-                        let theta = try!(specified::Angle::parse(input));
+                        let theta = try!(specified::Angle::parse(context,input));
                         // TODO(gw): Check the axis can be normalized!!
                         result.push(SpecifiedOperation::Rotate(ax, ay, az, theta));
                         Ok(())
                     }))
                 },
                 "skew" => {
                     try!(input.parse_nested_block(|input| {
-                        let (theta_x, theta_y) = try!(parse_two_angles(input));
+                        let (theta_x, theta_y) = try!(parse_two_angles(context, input));
                         result.push(SpecifiedOperation::Skew(theta_x, theta_y));
                         Ok(())
                     }))
                 },
                 "skewx" => {
                     try!(input.parse_nested_block(|input| {
-                        let theta_x = try!(specified::Angle::parse(input));
+                        let theta_x = try!(specified::Angle::parse(context,input));
                         result.push(SpecifiedOperation::Skew(theta_x, specified::Angle(0.0)));
                         Ok(())
                     }))
                 },
                 "skewy" => {
                     try!(input.parse_nested_block(|input| {
-                        let theta_y = try!(specified::Angle::parse(input));
+                        let theta_y = try!(specified::Angle::parse(context,input));
                         result.push(SpecifiedOperation::Skew(specified::Angle(0.0), theta_y));
                         Ok(())
                     }))
                 },
                 "perspective" => {
                     try!(input.parse_nested_block(|input| {
-                        let d = try!(specified::Length::parse(input));
+                        let d = try!(specified::Length::parse(context, input));
                         result.push(SpecifiedOperation::Perspective(d));
                         Ok(())
                     }))
                 },
                 _ => return Err(())
             }
         }
 
@@ -1542,12 +1547,11 @@
                          """,
                          gecko_ffi_name="mAppearance",
                          gecko_constant_prefix="NS_THEME",
                          products="gecko",
                          animatable=False)}
 
 // Non-standard: https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-binding
 ${helpers.predefined_type("-moz-binding", "UrlOrNone", "computed_value::T::None",
-                          needs_context=True,
                           products="gecko",
                           animatable="False",
                           disable_when_testing="True")}
--- a/servo/components/style/properties/longhand/color.mako.rs
+++ b/servo/components/style/properties/longhand/color.mako.rs
@@ -32,19 +32,19 @@
     pub mod computed_value {
         use cssparser;
         pub type T = cssparser::RGBA;
     }
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         RGBA { red: 0., green: 0., blue: 0., alpha: 1. }  /* black */
     }
-    pub fn parse_specified(_context: &ParserContext, input: &mut Parser)
+    pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                            -> Result<DeclaredValue<SpecifiedValue>, ()> {
-        let value = try!(CSSColor::parse(input));
+        let value = try!(CSSColor::parse(context, input));
         let rgba = match value.parsed {
             CSSParserColor::RGBA(rgba) => rgba,
             CSSParserColor::CurrentColor => return Ok(DeclaredValue::Inherit)
         };
         Ok(DeclaredValue::Value(CSSRGBA {
             parsed: rgba,
             authored: value.authored,
         }))
--- a/servo/components/style/properties/longhand/column.mako.rs
+++ b/servo/components/style/properties/longhand/column.mako.rs
@@ -268,18 +268,18 @@
 
     pub type SpecifiedValue = BorderWidth;
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         Au::from_px(3) // medium
     }
 
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        BorderWidth::parse(input)
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+        BorderWidth::parse(context, input)
     }
 </%helpers:longhand>
 
 // https://drafts.csswg.org/css-multicol-1/#crc
 ${helpers.predefined_type("-moz-column-rule-color", "CSSColor",
                           "::cssparser::Color::CurrentColor",
                           products="gecko", gecko_ffi_name="mColumnRuleColor",
                           animatable=True, complex_color=True, need_clone=True)}
--- a/servo/components/style/properties/longhand/effects.mako.rs
+++ b/servo/components/style/properties/longhand/effects.mako.rs
@@ -120,36 +120,36 @@
                 blur_radius: ToComputedValue::from_computed_value(&computed.blur_radius),
                 spread_radius: ToComputedValue::from_computed_value(&computed.spread_radius),
                 color: Some(ToComputedValue::from_computed_value(&computed.color)),
                 inset: computed.inset,
             }
         }
     }
 
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         use app_units::Au;
         let mut lengths = [specified::Length::Absolute(Au(0)); 4];
         let mut lengths_parsed = false;
         let mut color = None;
         let mut inset = false;
 
         loop {
             if !inset {
                 if input.try(|input| input.expect_ident_matching("inset")).is_ok() {
                     inset = true;
                     continue
                 }
             }
             if !lengths_parsed {
-                if let Ok(value) = input.try(specified::Length::parse) {
+                if let Ok(value) = input.try(|i| specified::Length::parse(context, i)) {
                     lengths[0] = value;
                     let mut length_parsed_count = 1;
                     while length_parsed_count < 4 {
-                        if let Ok(value) = input.try(specified::Length::parse) {
+                        if let Ok(value) = input.try(|i| specified::Length::parse(context, i)) {
                             lengths[length_parsed_count] = value
                         } else {
                             break
                         }
                         length_parsed_count += 1;
                     }
 
                     // The first two lengths must be specified.
@@ -157,17 +157,17 @@
                         return Err(())
                     }
 
                     lengths_parsed = true;
                     continue
                 }
             }
             if color.is_none() {
-                if let Ok(value) = input.try(specified::CSSColor::parse) {
+                if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                     color = Some(value);
                     continue
                 }
             }
             break
         }
 
         // Lengths must be specified.
@@ -347,52 +347,52 @@
                 top: ToComputedValue::from_computed_value(&value.top),
                 right: value.right.map(|right| ToComputedValue::from_computed_value(&right)),
                 bottom: value.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)),
                 left: ToComputedValue::from_computed_value(&value.left),
             }))
         }
     }
 
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         use app_units::Au;
         use std::ascii::AsciiExt;
         use values::specified::Length;
 
-        fn parse_argument(input: &mut Parser) -> Result<Option<Length>, ()> {
+        fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> {
             if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
                 Ok(None)
             } else {
-                Length::parse(input).map(Some)
+                Length::parse(context, input).map(Some)
             }
         }
 
         if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
             return Ok(SpecifiedValue(None))
         }
         if !try!(input.expect_function()).eq_ignore_ascii_case("rect") {
             return Err(())
         }
 
         input.parse_nested_block(|input| {
-            let top = try!(parse_argument(input));
+            let top = try!(parse_argument(context, input));
             let right;
             let bottom;
             let left;
 
             if input.try(|input| input.expect_comma()).is_ok() {
-                right = try!(parse_argument(input));
+                right = try!(parse_argument(context, input));
                 try!(input.expect_comma());
-                bottom = try!(parse_argument(input));
+                bottom = try!(parse_argument(context, input));
                 try!(input.expect_comma());
-                left = try!(parse_argument(input));
+                left = try!(parse_argument(context, input));
             } else {
-                right = try!(parse_argument(input));
-                bottom = try!(parse_argument(input));
-                left = try!(parse_argument(input));
+                right = try!(parse_argument(context, input));
+                bottom = try!(parse_argument(context, input));
+                left = try!(parse_argument(context, input));
             }
             Ok(SpecifiedValue(Some(SpecifiedClipRect {
                 top: top.unwrap_or(Length::Absolute(Au(0))),
                 right: right,
                 bottom: bottom,
                 left: left.unwrap_or(Length::Absolute(Au(0))),
             })))
         })
@@ -622,36 +622,36 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T::new(Vec::new())
     }
 
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         let mut filters = Vec::new();
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(SpecifiedValue(filters))
         }
         loop {
             if let Ok(function_name) = input.try(|input| input.expect_function()) {
                 filters.push(try!(input.parse_nested_block(|input| {
                     match_ignore_ascii_case! { function_name,
                         "blur" => specified::Length::parse_non_negative(input).map(SpecifiedFilter::Blur),
                         "brightness" => parse_factor(input).map(SpecifiedFilter::Brightness),
                         "contrast" => parse_factor(input).map(SpecifiedFilter::Contrast),
                         "grayscale" => parse_factor(input).map(SpecifiedFilter::Grayscale),
-                        "hue-rotate" => Angle::parse(input).map(SpecifiedFilter::HueRotate),
+                        "hue-rotate" => Angle::parse(context, input).map(SpecifiedFilter::HueRotate),
                         "invert" => parse_factor(input).map(SpecifiedFilter::Invert),
                         "opacity" => parse_factor(input).map(SpecifiedFilter::Opacity),
                         "saturate" => parse_factor(input).map(SpecifiedFilter::Saturate),
                         "sepia" => parse_factor(input).map(SpecifiedFilter::Sepia),
                         % if product == "gecko":
-                        "drop-shadow" => parse_drop_shadow(input),
+                        "drop-shadow" => parse_drop_shadow(context, input),
                         % endif
                         _ => Err(())
                     }
                 })));
             } else if filters.is_empty() {
                 return Err(())
             } else {
                 return Ok(SpecifiedValue(filters))
@@ -664,21 +664,22 @@
         match input.next() {
             Ok(Token::Number(value)) => Ok(value.value),
             Ok(Token::Percentage(value)) => Ok(value.unit_value),
             _ => Err(())
         }
     }
 
     % if product == "gecko":
-    fn parse_drop_shadow(input: &mut Parser) -> Result<SpecifiedFilter, ()> {
-        let offset_x = try!(specified::Length::parse(input));
-        let offset_y = try!(specified::Length::parse(input));
-        let blur_radius = input.try(specified::Length::parse).unwrap_or(specified::Length::from_px(0.0));
-        let color = input.try(specified::CSSColor::parse).ok();
+    fn parse_drop_shadow(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedFilter, ()> {
+        let offset_x = try!(specified::Length::parse(context, input));
+        let offset_y = try!(specified::Length::parse(context, input));
+        let blur_radius = input.try(|i| specified::Length::parse(context, i))
+                               .unwrap_or(specified::Length::from_px(0.0));
+        let color = input.try(|i| specified::CSSColor::parse(context, i)).ok();
         Ok(SpecifiedFilter::DropShadow(offset_x, offset_y, blur_radius, color))
     }
     % endif
 
     impl ToComputedValue for SpecifiedValue {
         type ComputedValue = computed_value::T;
 
         fn to_computed_value(&self, context: &Context) -> computed_value::T {
@@ -740,17 +741,17 @@
 </%helpers:longhand>
 
 pub struct OriginParseResult {
     pub horizontal: Option<specified::LengthOrPercentage>,
     pub vertical: Option<specified::LengthOrPercentage>,
     pub depth: Option<specified::Length>
 }
 
-pub fn parse_origin(_: &ParserContext, input: &mut Parser) -> Result<OriginParseResult,()> {
+pub fn parse_origin(context: &ParserContext, input: &mut Parser) -> Result<OriginParseResult,()> {
     use values::specified::{LengthOrPercentage, Percentage};
     let (mut horizontal, mut vertical, mut depth) = (None, None, None);
     loop {
         if let Err(_) = input.try(|input| {
             let token = try!(input.expect_ident());
             match_ignore_ascii_case! {
                 token,
                 "left" => {
@@ -789,17 +790,17 @@ pub fn parse_origin(_: &ParserContext, i
                     } else {
                         return Err(())
                     }
                 },
                 _ => return Err(())
             }
             Ok(())
         }) {
-            match LengthOrPercentage::parse(input) {
+            match LengthOrPercentage::parse(context, input) {
                 Ok(value) => {
                     if horizontal.is_none() {
                         horizontal = Some(value);
                     } else if vertical.is_none() {
                         vertical = Some(value);
                     } else if let LengthOrPercentage::Length(length) = value {
                         depth = Some(length);
                     } else {
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -505,17 +505,17 @@
     use values::computed::ComputedValueAsSpecified;
     pub use self::computed_value::T as SpecifiedValue;
 
     impl ComputedValueAsSpecified for SpecifiedValue {}
     impl NoViewportPercentage for SpecifiedValue {}
 
     pub mod computed_value {
         use cssparser::Parser;
-        use parser::Parse;
+        use parser::{Parse, ParserContext};
         use std::fmt;
         use style_traits::ToCss;
 
         #[derive(Debug, Clone, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub enum T {
             Normal,
             Tag(Vec<FeatureTagValue>)
@@ -555,17 +555,17 @@
                     x => write!(dest, "\"{}\" {}", self.tag, x)
                 }
             }
         }
 
         impl Parse for FeatureTagValue {
             /// https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings
             /// <string> [ on | off | <integer> ]
-            fn parse(input: &mut Parser) -> Result<Self, ()> {
+            fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
                 let tag = try!(input.expect_string());
 
                 // allowed strings of length 4 containing chars: <U+20, U+7E>
                 if tag.len() != 4 ||
                    tag.chars().any(|c| c < ' ' || c > '~')
                 {
                     return Err(())
                 }
@@ -592,21 +592,21 @@
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T::Normal
     }
 
     /// normal | <feature-tag-value>#
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
             Ok(computed_value::T::Normal)
         } else {
-            input.parse_comma_separated(computed_value::FeatureTagValue::parse)
+            input.parse_comma_separated(|i| computed_value::FeatureTagValue::parse(context, i))
                  .map(computed_value::T::Tag)
         }
     }
 </%helpers:longhand>
 
 // https://www.w3.org/TR/css-fonts-3/#propdef-font-language-override
 <%helpers:longhand name="font-language-override" products="none" animatable="False">
     use values::NoViewportPercentage;
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -45,16 +45,17 @@
 ${helpers.single_keyword("stroke-linecap", "butt round square",
                          products="gecko", animatable=False)}
 
 ${helpers.single_keyword("stroke-linejoin", "miter round bevel",
                          products="gecko", animatable=False)}
 
 ${helpers.predefined_type("stroke-miterlimit", "Number", "4.0",
                           "parse_at_least_one", products="gecko",
+                          needs_context=False,
                           animatable=False)}
 
 ${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
                           products="gecko", animatable=False)}
 
 // Section 14 - Clipping, Masking and Compositing
 ${helpers.single_keyword("clip-rule", "nonzero evenodd",
                          products="gecko",
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -195,18 +195,17 @@
             _moz_right("-moz-right") => 8,
             match_parent("match-parent") => 9,
             % endif
         }
     }
     #[inline] pub fn get_initial_value() -> computed_value::T {
         computed_value::T::start
     }
-    pub fn parse(_context: &ParserContext, input: &mut Parser)
-                 -> Result<SpecifiedValue, ()> {
+    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         computed_value::T::parse(input)
     }
 </%helpers:longhand>
 
 // FIXME: This prop should be animatable.
 <%helpers:longhand name="letter-spacing" animatable="False">
     use std::fmt;
     use style_traits::ToCss;
@@ -640,37 +639,37 @@
         }
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T(Vec::new())
     }
 
-    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             Ok(SpecifiedValue(Vec::new()))
         } else {
-            input.parse_comma_separated(parse_one_text_shadow).map(SpecifiedValue)
+            input.parse_comma_separated(|i| parse_one_text_shadow(context, i)).map(SpecifiedValue)
         }
     }
 
-    fn parse_one_text_shadow(input: &mut Parser) -> Result<SpecifiedTextShadow,()> {
+    fn parse_one_text_shadow(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedTextShadow,()> {
         use app_units::Au;
         let mut lengths = [specified::Length::Absolute(Au(0)); 3];
         let mut lengths_parsed = false;
         let mut color = None;
 
         loop {
             if !lengths_parsed {
-                if let Ok(value) = input.try(specified::Length::parse) {
+                if let Ok(value) = input.try(|i| specified::Length::parse(context, i)) {
                     lengths[0] = value;
                     let mut length_parsed_count = 1;
                     while length_parsed_count < 3 {
-                        if let Ok(value) = input.try(specified::Length::parse) {
+                        if let Ok(value) = input.try(|i| specified::Length::parse(context, i)) {
                             lengths[length_parsed_count] = value
                         } else {
                             break
                         }
                         length_parsed_count += 1;
                     }
 
                     // The first two lengths must be specified.
@@ -678,17 +677,17 @@
                         return Err(())
                     }
 
                     lengths_parsed = true;
                     continue
                 }
             }
             if color.is_none() {
-                if let Ok(value) = input.try(specified::CSSColor::parse) {
+                if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                     color = Some(value);
                     continue
                 }
             }
             break
         }
 
         // Lengths must be specified.
@@ -1019,19 +1018,18 @@
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
     use values::specified::BorderWidth;
 
     pub type SpecifiedValue = BorderWidth;
 
     #[inline]
-    pub fn parse(_context: &ParserContext, input: &mut Parser)
-                 -> Result<SpecifiedValue, ()> {
-        BorderWidth::parse(input)
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+        BorderWidth::parse(context, input)
     }
 
     pub mod computed_value {
         use app_units::Au;
         pub type T = Au;
     }
     #[inline] pub fn get_initial_value() -> computed_value::T {
         Au::from_px(0)
--- a/servo/components/style/properties/longhand/list.mako.rs
+++ b/servo/components/style/properties/longhand/list.mako.rs
@@ -22,17 +22,16 @@
                            gujarati gurmukhi kannada khmer lao malayalam mongolian
                            myanmar oriya persian telugu thai tibetan cjk-earthly-branch
                            cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana
                            katakana-iroha""",
     gecko_constant_prefix="NS_STYLE_LIST_STYLE",
     animatable=False)}
 
 ${helpers.predefined_type("list-style-image", "UrlOrNone", "computed_value::T::None",
-                          needs_context=True,
                           animatable="False")}
 
 <%helpers:longhand name="quotes" animatable="False">
     use cssparser::Token;
     use std::borrow::Cow;
     use std::fmt;
     use style_traits::ToCss;
     use values::computed::ComputedValueAsSpecified;
--- a/servo/components/style/properties/longhand/outline.mako.rs
+++ b/servo/components/style/properties/longhand/outline.mako.rs
@@ -14,17 +14,17 @@
                           animatable=True, complex_color=True, need_clone=True)}
 
 <%helpers:longhand name="outline-style" need_clone="True" animatable="False">
     pub use values::specified::BorderStyle as SpecifiedValue;
     pub fn get_initial_value() -> SpecifiedValue { SpecifiedValue::none }
     pub mod computed_value {
         pub use values::specified::BorderStyle as T;
     }
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         match SpecifiedValue::parse(input) {
             Ok(SpecifiedValue::hidden) => Err(()),
             result => result
         }
     }
 </%helpers:longhand>
 
 <%helpers:longhand name="outline-width" animatable="True">
--- a/servo/components/style/properties/longhand/padding.mako.rs
+++ b/servo/components/style/properties/longhand/padding.mako.rs
@@ -5,11 +5,12 @@
 <%namespace name="helpers" file="/helpers.mako.rs" />
 <% from data import ALL_SIDES %>
 <% data.new_style_struct("Padding", inherited=False) %>
 
 % for side in ALL_SIDES:
     ${helpers.predefined_type("padding-%s" % side[0], "LengthOrPercentage",
                                "computed::LengthOrPercentage::Length(Au(0))",
                                "parse_non_negative",
+                               needs_context=False,
                                animatable=True,
                                logical = side[1])}
 % endfor
--- a/servo/components/style/properties/longhand/pointing.mako.rs
+++ b/servo/components/style/properties/longhand/pointing.mako.rs
@@ -91,17 +91,17 @@
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T {
             images: vec![],
             keyword: computed_value::Keyword::AutoCursor
         }
     }
 
     impl Parse for computed_value::Keyword {
-        fn parse(input: &mut Parser) -> Result<computed_value::Keyword, ()> {
+        fn parse(_context: &ParserContext, input: &mut Parser) -> Result<computed_value::Keyword, ()> {
             use std::ascii::AsciiExt;
             use style_traits::cursor::Cursor;
             let ident = try!(input.expect_ident());
             if ident.eq_ignore_ascii_case("auto") {
                 Ok(computed_value::Keyword::AutoCursor)
             } else {
                 Cursor::from_css_keyword(&ident).map(computed_value::Keyword::SpecifiedCursor)
             }
@@ -115,35 +115,35 @@
             hotspot: match input.try(|input| input.expect_number()) {
                 Ok(number) => Some((number, try!(input.expect_number()))),
                 Err(()) => None,
             },
         })
     }
 
     #[cfg(not(feature = "gecko"))]
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        computed_value::Keyword::parse(input)
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+        computed_value::Keyword::parse(context, input)
     }
 
     /// cursor: [<url> [<number> <number>]?]# [auto | default | ...]
     #[cfg(feature = "gecko")]
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         let mut images = vec![];
         loop {
             match input.try(|input| parse_image(context, input)) {
                 Ok(image) => images.push(image),
                 Err(()) => break,
             }
             try!(input.expect_comma());
         }
 
         Ok(computed_value::T {
             images: images,
-            keyword: try!(computed_value::Keyword::parse(input)),
+            keyword: try!(computed_value::Keyword::parse(context, input)),
         })
     }
 </%helpers:longhand>
 
 // NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
 // is nonstandard, slated for CSS4-UI.
 // TODO(pcwalton): SVG-only values.
 ${helpers.single_keyword("pointer-events", "auto none", animatable=False)}
--- a/servo/components/style/properties/longhand/position.mako.rs
+++ b/servo/components/style/properties/longhand/position.mako.rs
@@ -90,20 +90,22 @@
 ${helpers.single_keyword("align-content", "stretch flex-start flex-end center space-between space-around",
                          gecko_constant_prefix="NS_STYLE_ALIGN",
                          products="servo",
                          animatable=False)}
 
 // Flex item properties
 ${helpers.predefined_type("flex-grow", "Number",
                           "0.0", "parse_non_negative",
+                          needs_context=False,
                           animatable=True)}
 
 ${helpers.predefined_type("flex-shrink", "Number",
                           "1.0", "parse_non_negative",
+                          needs_context=False,
                           animatable=True)}
 
 ${helpers.single_keyword("align-self", "auto stretch flex-start flex-end center baseline",
                          need_clone=True,
                          gecko_constant_prefix="NS_STYLE_ALIGN",
                          animatable=False)}
 
 // https://drafts.csswg.org/css-flexbox/#propdef-order
@@ -135,30 +137,33 @@
                           animatable=False)}
 
 % for (size, logical) in ALL_SIZES:
     // width, height, block-size, inline-size
     ${helpers.predefined_type("%s" % size,
                               "LengthOrPercentageOrAuto",
                               "computed::LengthOrPercentageOrAuto::Auto",
                               "parse_non_negative",
+                              needs_context=False,
                               animatable=True, logical = logical)}
 
     // min-width, min-height, min-block-size, min-inline-size
     ${helpers.predefined_type("min-%s" % size,
                               "LengthOrPercentage",
                               "computed::LengthOrPercentage::Length(Au(0))",
                               "parse_non_negative",
+                              needs_context=False,
                               animatable=True, logical = logical)}
 
     // max-width, max-height, max-block-size, max-inline-size
     ${helpers.predefined_type("max-%s" % size,
                               "LengthOrPercentageOrNone",
                               "computed::LengthOrPercentageOrNone::None",
                               "parse_non_negative",
+                              needs_context=False,
                               animatable=True, logical = logical)}
 % endfor
 
 ${helpers.single_keyword("box-sizing",
                          "content-box border-box",
                          animatable=False)}
 
 // CSS Image Values and Replaced Content Module Level 3
--- a/servo/components/style/properties/longhand/text.mako.rs
+++ b/servo/components/style/properties/longhand/text.mako.rs
@@ -42,26 +42,26 @@
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         SpecifiedValue {
             first: Side::Clip,
             second: None
         }
     }
-    pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        let first = try!(Side::parse(input));
-        let second = Side::parse(input).ok();
+    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+        let first = try!(Side::parse(context, input));
+        let second = Side::parse(context, input).ok();
         Ok(SpecifiedValue {
             first: first,
             second: second,
         })
     }
     impl Parse for Side {
-        fn parse(input: &mut Parser) -> Result<Side, ()> {
+        fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Side, ()> {
             if let Ok(ident) = input.try(|input| input.expect_ident()) {
                 match_ignore_ascii_case! { ident,
                     "clip" => Ok(Side::Clip),
                     "ellipsis" => Ok(Side::Ellipsis),
                     _ => Err(())
                 }
             } else {
                 Ok(Side::String(try!(input.expect_string()).into_owned()))
--- a/servo/components/style/properties/longhand/xul.mako.rs
+++ b/servo/components/style/properties/longhand/xul.mako.rs
@@ -10,9 +10,10 @@
 
 ${helpers.single_keyword("-moz-box-align", "stretch start center baseline end",
                          products="gecko", gecko_ffi_name="mBoxAlign",
                          gecko_enum_prefix="StyleBoxAlign",
                          animatable=False)}
 
 ${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative",
                           products="gecko", gecko_ffi_name="mBoxFlex",
+                          needs_context=False,
                           animatable=False)}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -79,42 +79,43 @@ pub mod longhands {
 }
 
 pub mod shorthands {
     use cssparser::Parser;
     use parser::{Parse, ParserContext};
     use values::specified;
 
     pub fn parse_four_sides<F, T>(input: &mut Parser, parse_one: F) -> Result<(T, T, T, T), ()>
-    where F: Fn(&mut Parser) -> Result<T, ()>, F: Copy, T: Clone {
+        where F: Fn(&mut Parser) -> Result<T, ()>, T: Clone
+    {
         // zero or more than four values is invalid.
         // one value sets them all
         // two values set (top, bottom) and (left, right)
         // three values set top, (left, right) and bottom
         // four values set them in order
         let top = try!(parse_one(input));
         let right;
         let bottom;
         let left;
-        match input.try(parse_one) {
+        match input.try(|i| parse_one(i)) {
             Err(()) => {
                 right = top.clone();
                 bottom = top.clone();
                 left = top.clone();
             }
             Ok(value) => {
                 right = value;
-                match input.try(parse_one) {
+                match input.try(|i| parse_one(i)) {
                     Err(()) => {
                         bottom = top.clone();
                         left = right.clone();
                     }
                     Ok(value) => {
                         bottom = value;
-                        match input.try(parse_one) {
+                        match input.try(|i| parse_one(i)) {
                             Err(()) => {
                                 left = right.clone();
                             }
                             Ok(value) => {
                                 left = value;
                             }
                         }
 
@@ -360,17 +361,17 @@ fn remove_one<T, F: FnMut(&T) -> bool>(v
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum CSSWideKeyword {
     InitialKeyword,
     InheritKeyword,
     UnsetKeyword,
 }
 
 impl Parse for CSSWideKeyword {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match_ignore_ascii_case! { try!(input.expect_ident()),
             "initial" => Ok(CSSWideKeyword::InitialKeyword),
             "inherit" => Ok(CSSWideKeyword::InheritKeyword),
             "unset" => Ok(CSSWideKeyword::UnsetKeyword),
             _ => Err(())
         }
     }
 }
@@ -748,21 +749,21 @@ impl PropertyDeclaration {
     /// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
     /// > except those defined in this specification,
     /// > but does accept the `animation-play-state` property and interprets it specially.
     pub fn parse(name: &str, context: &ParserContext, input: &mut Parser,
                  result_list: &mut Vec<PropertyDeclaration>,
                  in_keyframe_block: bool)
                  -> PropertyDeclarationParseResult {
         if let Ok(name) = ::custom_properties::parse_name(name) {
-            let value = match input.try(CSSWideKeyword::parse) {
+            let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
                 Ok(CSSWideKeyword::UnsetKeyword) |  // Custom properties are alawys inherited
                 Ok(CSSWideKeyword::InheritKeyword) => DeclaredValue::Inherit,
                 Ok(CSSWideKeyword::InitialKeyword) => DeclaredValue::Initial,
-                Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
+                Err(()) => match ::custom_properties::SpecifiedValue::parse(context, input) {
                     Ok(value) => DeclaredValue::Value(value),
                     Err(()) => return PropertyDeclarationParseResult::InvalidValue,
                 }
             };
             result_list.push(PropertyDeclaration::Custom(Atom::from(name), value));
             return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
         }
         match_ignore_ascii_case! { name,
@@ -810,17 +811,17 @@ impl PropertyDeclaration {
                         }
                     % endif
                     % if shorthand.experimental and product == "servo":
                         if !::util::prefs::PREFS.get("${shorthand.experimental}")
                             .as_boolean().unwrap_or(false) {
                             return PropertyDeclarationParseResult::ExperimentalProperty
                         }
                     % endif
-                    match input.try(CSSWideKeyword::parse) {
+                    match input.try(|i| CSSWideKeyword::parse(context, i)) {
                         Ok(CSSWideKeyword::InheritKeyword) => {
                             % for sub_property in shorthand.sub_properties:
                                 result_list.push(
                                     PropertyDeclaration::${sub_property.camel_case}(
                                         DeclaredValue::Inherit));
                             % endfor
                             PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
                         },
--- a/servo/components/style/properties/shorthand/border.mako.rs
+++ b/servo/components/style/properties/shorthand/border.mako.rs
@@ -1,27 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 <%namespace name="helpers" file="/helpers.mako.rs" />
 <% from data import to_rust_ident, ALL_SIDES %>
 
 ${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::CSSColor::parse")}
+
 ${helpers.four_sides_shorthand("border-style", "border-%s-style",
-                       "specified::BorderStyle::parse")}
+                               "specified::BorderStyle::parse",
+                               needs_context=False)}
+
 <%helpers:shorthand name="border-width" sub_properties="${
         ' '.join('border-%s-width' % side
                  for side in ['top', 'right', 'bottom', 'left'])}">
     use super::parse_four_sides;
+    use parser::Parse;
     use values::specified;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
-        let _unused = context;
-        let (top, right, bottom, left) = try!(parse_four_sides(input, specified::BorderWidth::parse));
+        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
         Ok(Longhands {
             % for side in ["top", "right", "bottom", "left"]:
                 ${to_rust_ident('border-%s-width' % side)}: Some(${side}),
             % endfor
         })
     }
 
     impl<'a> LonghandsToSerialize<'a>  {
@@ -53,31 +56,31 @@ pub fn parse_border(context: &ParserCont
     use values::specified;
     let _unused = context;
     let mut color = None;
     let mut style = None;
     let mut width = None;
     let mut any = false;
     loop {
         if color.is_none() {
-            if let Ok(value) = input.try(specified::CSSColor::parse) {
+            if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                 color = Some(value);
                 any = true;
                 continue
             }
         }
         if style.is_none() {
             if let Ok(value) = input.try(specified::BorderStyle::parse) {
                 style = Some(value);
                 any = true;
                 continue
             }
         }
         if width.is_none() {
-            if let Ok(value) = input.try(specified::BorderWidth::parse) {
+            if let Ok(value) = input.try(|i| specified::BorderWidth::parse(context, i)) {
                 width = Some(value);
                 any = true;
                 continue
             }
         }
         break
     }
     if any { Ok((color, style, width)) } else { Err(()) }
@@ -147,19 +150,17 @@ pub fn parse_border(context: &ParserCont
 <%helpers:shorthand name="border-radius" sub_properties="${' '.join(
     'border-%s-radius' % (corner)
      for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
 )}">
     use values::specified::basic_shape::BorderRadius;
     use parser::Parse;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
-        let _ignored = context;
-
-        let radii = try!(BorderRadius::parse(input));
+        let radii = try!(BorderRadius::parse(context, input));
         Ok(Longhands {
             border_top_left_radius: Some(radii.top_left),
             border_top_right_radius: Some(radii.top_right),
             border_bottom_right_radius: Some(radii.bottom_right),
             border_bottom_left_radius: Some(radii.bottom_left),
         })
     }
 
--- a/servo/components/style/properties/shorthand/box.mako.rs
+++ b/servo/components/style/properties/shorthand/box.mako.rs
@@ -53,43 +53,53 @@
 macro_rules! try_parse_one {
     ($input: expr, $var: ident, $prop_module: ident) => {
         if $var.is_none() {
             if let Ok(value) = $input.try($prop_module::computed_value::SingleComputedValue::parse) {
                 $var = Some(value);
                 continue;
             }
         }
-    }
+    };
+    ($context: expr, $input: expr, $var: ident, $prop_module: ident) => {
+        if $var.is_none() {
+            if let Ok(value) = $input.try(|i| {
+                $prop_module::computed_value::SingleComputedValue::parse($context, i)
+            }) {
+                $var = Some(value);
+                continue;
+            }
+        }
+    };
 }
 
 <%helpers:shorthand name="transition"
                     sub_properties="transition-property transition-duration
                                     transition-timing-function
                                     transition-delay">
     use parser::Parse;
     use properties::longhands::{transition_delay, transition_duration, transition_property};
     use properties::longhands::{transition_timing_function};
 
-    pub fn parse_value(_: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
+    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         struct SingleTransition {
             transition_property: transition_property::SingleSpecifiedValue,
             transition_duration: transition_duration::SingleSpecifiedValue,
             transition_timing_function: transition_timing_function::SingleSpecifiedValue,
             transition_delay: transition_delay::SingleSpecifiedValue,
         }
 
-        fn parse_one_transition(input: &mut Parser) -> Result<SingleTransition,()> {
+        fn parse_one_transition(context: &ParserContext, input: &mut Parser) -> Result<SingleTransition,()> {
             let (mut property, mut duration) = (None, None);
             let (mut timing_function, mut delay) = (None, None);
             loop {
                 try_parse_one!(input, property, transition_property);
-                try_parse_one!(input, duration, transition_duration);
-                try_parse_one!(input, timing_function, transition_timing_function);
-                try_parse_one!(input, delay, transition_delay);
+                try_parse_one!(context, input, duration, transition_duration);
+                try_parse_one!(context, input, timing_function, transition_timing_function);
+                try_parse_one!(context, input, delay, transition_delay);
 
                 break
             }
 
             if let Some(property) = property {
                 Ok(SingleTransition {
                     transition_property: property,
                     transition_duration:
@@ -108,17 +118,17 @@ macro_rules! try_parse_one {
             return Ok(Longhands {
                 transition_property: None,
                 transition_duration: None,
                 transition_timing_function: None,
                 transition_delay: None,
             })
         }
 
-        let results = try!(input.parse_comma_separated(parse_one_transition));
+        let results = try!(input.parse_comma_separated(|i| parse_one_transition(context, i)));
         let (mut properties, mut durations) = (Vec::new(), Vec::new());
         let (mut timing_functions, mut delays) = (Vec::new(), Vec::new());
         for result in results {
             properties.push(result.transition_property);
             durations.push(result.transition_duration);
             timing_functions.push(result.transition_timing_function);
             delays.push(result.transition_delay);
         }
@@ -154,52 +164,52 @@ macro_rules! try_parse_one {
                                     animation-iteration-count animation-direction
                                     animation-fill-mode animation-play-state"
                     allowed_in_keyframe_block="False">
     use parser::Parse;
     use properties::longhands::{animation_name, animation_duration, animation_timing_function};
     use properties::longhands::{animation_delay, animation_iteration_count, animation_direction};
     use properties::longhands::{animation_fill_mode, animation_play_state};
 
-    pub fn parse_value(_: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
+    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         struct SingleAnimation {
             animation_name: animation_name::SingleSpecifiedValue,
             animation_duration: animation_duration::SingleSpecifiedValue,
             animation_timing_function: animation_timing_function::SingleSpecifiedValue,
             animation_delay: animation_delay::SingleSpecifiedValue,
             animation_iteration_count: animation_iteration_count::SingleSpecifiedValue,
             animation_direction: animation_direction::SingleSpecifiedValue,
             animation_fill_mode: animation_fill_mode::SingleSpecifiedValue,
             animation_play_state: animation_play_state::SingleSpecifiedValue,
         }
 
-        fn parse_one_animation(input: &mut Parser) -> Result<SingleAnimation,()> {
+        fn parse_one_animation(context: &ParserContext, input: &mut Parser) -> Result<SingleAnimation,()> {
             let mut duration = None;
             let mut timing_function = None;
             let mut delay = None;
             let mut iteration_count = None;
             let mut direction = None;
             let mut fill_mode = None;
             let mut play_state = None;
             let mut name = None;
 
             // NB: Name must be the last one here so that keywords valid for other
             // longhands are not interpreted as names.
             //
             // Also, duration must be before delay, see
             // https://drafts.csswg.org/css-animations/#typedef-single-animation
             loop {
-                try_parse_one!(input, duration, animation_duration);
-                try_parse_one!(input, timing_function, animation_timing_function);
-                try_parse_one!(input, delay, animation_delay);
-                try_parse_one!(input, iteration_count, animation_iteration_count);
+                try_parse_one!(context, input, duration, animation_duration);
+                try_parse_one!(context, input, timing_function, animation_timing_function);
+                try_parse_one!(context, input, delay, animation_delay);
+                try_parse_one!(context, input, iteration_count, animation_iteration_count);
                 try_parse_one!(input, direction, animation_direction);
                 try_parse_one!(input, fill_mode, animation_fill_mode);
                 try_parse_one!(input, play_state, animation_play_state);
-                try_parse_one!(input, name, animation_name);
+                try_parse_one!(context, input, name, animation_name);
 
                 break
             }
 
             if let Some(name) = name {
                 Ok(SingleAnimation {
                     animation_name: name,
                     animation_duration:
@@ -230,17 +240,17 @@ macro_rules! try_parse_one {
                 animation_delay: None,
                 animation_iteration_count: None,
                 animation_direction: None,
                 animation_fill_mode: None,
                 animation_play_state: None,
             })
         }
 
-        let results = try!(input.parse_comma_separated(parse_one_animation));
+        let results = try!(input.parse_comma_separated(|i| parse_one_animation(context, i)));
 
         let mut names = vec![];
         let mut durations = vec![];
         let mut timing_functions = vec![];
         let mut delays = vec![];
         let mut iteration_counts = vec![];
         let mut directions = vec![];
         let mut fill_modes = vec![];
--- a/servo/components/style/properties/shorthand/outline.mako.rs
+++ b/servo/components/style/properties/shorthand/outline.mako.rs
@@ -12,17 +12,17 @@
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let _unused = context;
         let mut color = None;
         let mut style = None;
         let mut width = None;
         let mut any = false;
         loop {
             if color.is_none() {
-                if let Ok(value) = input.try(specified::CSSColor::parse) {
+                if let Ok(value) = input.try(|i| specified::CSSColor::parse(context, i)) {
                     color = Some(value);
                     any = true;
                     continue
                 }
             }
             if style.is_none() {
                 if let Ok(value) = input.try(specified::BorderStyle::parse) {
                     style = Some(value);
--- a/servo/components/style/properties/shorthand/position.mako.rs
+++ b/servo/components/style/properties/shorthand/position.mako.rs
@@ -62,17 +62,17 @@
 
     pub fn parse_flexibility(input: &mut Parser)
                              -> Result<(Number, Option<Number>),()> {
         let grow = try!(Number::parse_non_negative(input));
         let shrink = input.try(Number::parse_non_negative).ok();
         Ok((grow, shrink))
     }
 
-    pub fn parse_value(_: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
+    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let mut grow = None;
         let mut shrink = None;
         let mut basis = None;
 
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(Longhands {
                 flex_grow: Some(Number(0.0)),
                 flex_shrink: Some(Number(0.0)),
@@ -83,17 +83,17 @@
             if grow.is_none() {
                 if let Ok((flex_grow, flex_shrink)) = input.try(parse_flexibility) {
                     grow = Some(flex_grow);
                     shrink = flex_shrink;
                     continue
                 }
             }
             if basis.is_none() {
-                if let Ok(value) = input.try(LengthOrPercentageOrAutoOrContent::parse) {
+                if let Ok(value) = input.try(|i| LengthOrPercentageOrAutoOrContent::parse(context, i)) {
                     basis = Some(value);
                     continue
                 }
             }
             break
         }
 
         if grow.is_none() && basis.is_none() {
--- a/servo/components/style/values/mod.rs
+++ b/servo/components/style/values/mod.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Common [values][values] used in CSS.
 //!
 //! [values]: https://drafts.csswg.org/css-values/
 
 pub use cssparser::{RGBA, Parser};
-use parser::Parse;
+use parser::{Parse, ParserContext};
 use std::fmt::{self, Debug};
 use style_traits::ToCss;
 
 macro_rules! define_numbered_css_keyword_enum {
     ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => {
         define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+);
     };
     ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => {
@@ -78,17 +78,17 @@ macro_rules! define_keyword_type {
 
         impl fmt::Debug for $name {
             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 write!(f, $css)
             }
         }
 
         impl Parse for $name {
-            fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
+            fn parse(_context: &ParserContext, input: &mut ::cssparser::Parser) -> Result<$name, ()> {
                 input.expect_ident_matching($css).map(|_| $name)
             }
         }
 
         impl ComputedValueAsSpecified for $name {}
         impl NoViewportPercentage for $name {}
     };
 }
@@ -127,21 +127,21 @@ impl<A: HasViewportPercentage, B: HasVie
         match *self {
             Either::First(ref v) => v.has_viewport_percentage(),
             Either::Second(ref v) => v.has_viewport_percentage(),
         }
     }
 }
 
 impl<A: Parse, B: Parse> Parse for Either<A, B> {
-    fn parse(input: &mut Parser) -> Result<Either<A, B>, ()> {
-        if let Ok(v) = input.try(|i| A::parse(i)) {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Either<A, B>, ()> {
+        if let Ok(v) = input.try(|i| A::parse(context, i)) {
             Ok(Either::First(v))
         } else {
-            B::parse(input).map(Either::Second)
+            B::parse(context, input).map(Either::Second)
         }
     }
 }
 
 use self::computed::{Context, ToComputedValue};
 
 impl<A: ToComputedValue, B: ToComputedValue> ToComputedValue for Either<A, B> {
     type ComputedValue = Either<A::ComputedValue, B::ComputedValue>;
--- a/servo/components/style/values/specified/basic_shape.rs
+++ b/servo/components/style/values/specified/basic_shape.rs
@@ -56,29 +56,30 @@ impl<T: ToCss> ToCss for ShapeSource<T> 
 
 impl<T: Parse + PartialEq + Copy> ShapeSource<T> {
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) {
             Ok(ShapeSource::None)
         } else if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
             Ok(ShapeSource::Url(url))
         } else {
-            fn parse_component<U: Parse>(input: &mut Parser, component: &mut Option<U>) -> bool {
+            fn parse_component<U: Parse>(context: &ParserContext, input: &mut Parser,
+                                         component: &mut Option<U>) -> bool {
                 if component.is_some() {
                     return false; // already parsed this component
                 }
-                *component = input.try(U::parse).ok();
+                *component = input.try(|i| U::parse(context, i)).ok();
                 component.is_some()
             }
 
             let mut shape = None;
             let mut reference = None;
             loop {
-                if !parse_component(input, &mut shape) &&
-                   !parse_component(input, &mut reference) {
+                if !parse_component(context, input, &mut shape) &&
+                   !parse_component(context, input, &mut reference) {
                     break;
                 }
             }
             match (shape, reference) {
                 (Some(shape), _) => Ok(ShapeSource::Shape(shape, reference)),
                 (None, Some(reference)) => Ok(ShapeSource::Box(reference)),
                 (None, None) => Err(()),
             }
@@ -131,33 +132,33 @@ impl<T: ToComputedValue> ToComputedValue
 pub enum BasicShape {
     Inset(InsetRect),
     Circle(Circle),
     Ellipse(Ellipse),
     Polygon(Polygon),
 }
 
 impl Parse for BasicShape {
-    fn parse(input: &mut Parser) -> Result<BasicShape, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<BasicShape, ()> {
         match_ignore_ascii_case! { try!(input.expect_function()),
             "inset" => {
                 Ok(BasicShape::Inset(
-                   try!(input.parse_nested_block(InsetRect::parse_function_arguments))))
+                   try!(input.parse_nested_block(|i| InsetRect::parse_function_arguments(context, i)))))
             },
             "circle" => {
                 Ok(BasicShape::Circle(
-                   try!(input.parse_nested_block(Circle::parse_function_arguments))))
+                   try!(input.parse_nested_block(|i| Circle::parse_function_arguments(context, i)))))
             },
             "ellipse" => {
                 Ok(BasicShape::Ellipse(
-                   try!(input.parse_nested_block(Ellipse::parse_function_arguments))))
+                   try!(input.parse_nested_block(|i| Ellipse::parse_function_arguments(context, i)))))
             },
             "polygon" => {
                 Ok(BasicShape::Polygon(
-                   try!(input.parse_nested_block(Polygon::parse_function_arguments))))
+                   try!(input.parse_nested_block(|i| Polygon::parse_function_arguments(context, i)))))
             },
             _ => Err(())
         }
     }
 }
 
 impl ToCss for BasicShape {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
@@ -208,39 +209,39 @@ pub struct InsetRect {
     pub top: LengthOrPercentage,
     pub right: LengthOrPercentage,
     pub bottom: LengthOrPercentage,
     pub left: LengthOrPercentage,
     pub round: Option<BorderRadius>,
 }
 
 impl InsetRect {
-    pub fn parse_function_arguments(input: &mut Parser) -> Result<InsetRect, ()> {
-        let (t, r, b, l) = try!(parse_four_sides(input, LengthOrPercentage::parse));
+    pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<InsetRect, ()> {
+        let (t, r, b, l) = try!(parse_four_sides(input, |i| LengthOrPercentage::parse(context, i)));
         let mut rect = InsetRect {
             top: t,
             right: r,
             bottom: b,
             left: l,
             round: None,
         };
         if let Ok(_) = input.try(|input| input.expect_ident_matching("round")) {
-            rect.round = Some(try!(BorderRadius::parse(input)));
+            rect.round = Some(try!(BorderRadius::parse(context, input)));
         }
         Ok(rect)
     }
 }
 
 impl Parse for InsetRect {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match_ignore_ascii_case! { try!(input.expect_function()),
-                                   "inset" => {
-                                       Ok(try!(input.parse_nested_block(InsetRect::parse_function_arguments)))
-                                   },
-                                   _ => Err(())
+           "inset" => {
+               Ok(try!(input.parse_nested_block(|i| InsetRect::parse_function_arguments(context, i))))
+           },
+           _ => Err(())
         }
     }
 }
 
 impl ToCss for InsetRect {
     // XXXManishearth again, we should try to reduce the number of values printed here
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         try!(dest.write_str("inset("));
@@ -372,20 +373,20 @@ fn serialize_basicshape_position<W>(posi
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 /// https://drafts.csswg.org/css-shapes/#funcdef-circle
 pub struct Circle {
     pub radius: ShapeRadius,
     pub position: Position,
 }
 
 impl Circle {
-    pub fn parse_function_arguments(input: &mut Parser) -> Result<Circle, ()> {
-        let radius = input.try(ShapeRadius::parse).ok().unwrap_or_else(Default::default);
+    pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Circle, ()> {
+        let radius = input.try(|i| ShapeRadius::parse(context, i)).ok().unwrap_or_else(Default::default);
         let position = if let Ok(_) = input.try(|input| input.expect_ident_matching("at")) {
-            try!(Position::parse(input))
+            try!(Position::parse(context, input))
         } else {
             // Defaults to origin
             Position {
                 horiz_keyword: Some(Keyword::Center),
                 horiz_position: None,
                 vert_keyword: Some(Keyword::Center),
                 vert_position: None,
             }
@@ -393,22 +394,22 @@ impl Circle {
         Ok(Circle {
             radius: radius,
             position: position,
         })
     }
 }
 
 impl Parse for Circle {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match_ignore_ascii_case! { try!(input.expect_function()),
-                                   "circle" => {
-                                       Ok(try!(input.parse_nested_block(Circle::parse_function_arguments)))
-                                   },
-                                   _ => Err(())
+           "circle" => {
+               Ok(try!(input.parse_nested_block(|i| Circle::parse_function_arguments(context, i))))
+           },
+           _ => Err(())
         }
     }
 }
 
 impl ToCss for Circle {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         try!(dest.write_str("circle("));
         if ShapeRadius::ClosestSide != self.radius {
@@ -447,22 +448,22 @@ impl ToComputedValue for Circle {
 pub struct Ellipse {
     pub semiaxis_x: ShapeRadius,
     pub semiaxis_y: ShapeRadius,
     pub position: Position,
 }
 
 
 impl Ellipse {
-    pub fn parse_function_arguments(input: &mut Parser) -> Result<Ellipse, ()> {
+    pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Ellipse, ()> {
         let (a, b) = input.try(|input| -> Result<_, ()> {
-            Ok((try!(ShapeRadius::parse(input)), try!(ShapeRadius::parse(input))))
+            Ok((try!(ShapeRadius::parse(context, input)), try!(ShapeRadius::parse(context, input))))
         }).ok().unwrap_or_default();
         let position = if let Ok(_) = input.try(|input| input.expect_ident_matching("at")) {
-            try!(Position::parse(input))
+            try!(Position::parse(context, input))
         } else {
             // Defaults to origin
             Position {
                 horiz_keyword: Some(Keyword::Center),
                 horiz_position: None,
                 vert_keyword: Some(Keyword::Center),
                 vert_position: None,
             }
@@ -471,22 +472,22 @@ impl Ellipse {
             semiaxis_x: a,
             semiaxis_y: b,
             position: position,
         })
     }
 }
 
 impl Parse for Ellipse {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match_ignore_ascii_case! { try!(input.expect_function()),
-                                   "ellipse" => {
-                                       Ok(try!(input.parse_nested_block(Ellipse::parse_function_arguments)))
-                                   },
-                                   _ => Err(())
+           "ellipse" => {
+               Ok(try!(input.parse_nested_block(|i| Ellipse::parse_function_arguments(context, i))))
+           },
+           _ => Err(())
         }
     }
 }
 
 impl ToCss for Ellipse {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         try!(dest.write_str("ellipse("));
         if (self.semiaxis_x, self.semiaxis_y) != Default::default() {
@@ -528,41 +529,41 @@ impl ToComputedValue for Ellipse {
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 /// https://drafts.csswg.org/css-shapes/#funcdef-polygon
 pub struct Polygon {
     pub fill: FillRule,
     pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
 }
 
 impl Polygon {
-    pub fn parse_function_arguments(input: &mut Parser) -> Result<Polygon, ()> {
+    pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Polygon, ()> {
         let fill = input.try(|input| {
-            let fill = FillRule::parse(input);
+            let fill = FillRule::parse(context, input);
             // only eat the comma if there is something before it
             try!(input.expect_comma());
             fill
         }).ok().unwrap_or_else(Default::default);
         let buf = try!(input.parse_comma_separated(|input| {
-            Ok((try!(LengthOrPercentage::parse(input)),
-                try!(LengthOrPercentage::parse(input))))
+            Ok((try!(LengthOrPercentage::parse(context, input)),
+                try!(LengthOrPercentage::parse(context, input))))
         }));
         Ok(Polygon {
             fill: fill,
             coordinates: buf,
         })
     }
 }
 
 impl Parse for Polygon {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match_ignore_ascii_case! { try!(input.expect_function()),
-                                   "polygon" => {
-                                       Ok(try!(input.parse_nested_block(Polygon::parse_function_arguments)))
-                                   },
-                                   _ => Err(())
+           "polygon" => {
+               Ok(try!(input.parse_nested_block(|i| Polygon::parse_function_arguments(context, i))))
+           },
+           _ => Err(())
         }
     }
 }
 
 impl ToCss for Polygon {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         try!(dest.write_str("polygon("));
         let mut need_space = false;
@@ -624,19 +625,18 @@ pub enum ShapeRadius {
 
 impl Default for ShapeRadius {
     fn default() -> Self {
         ShapeRadius::ClosestSide
     }
 }
 
 impl Parse for ShapeRadius {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
-        input.try(LengthOrPercentage::parse).map(ShapeRadius::Length)
-                                            .or_else(|_| {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        input.try(|i| LengthOrPercentage::parse(context, i)).map(ShapeRadius::Length).or_else(|_| {
             match_ignore_ascii_case! { try!(input.expect_ident()),
                 "closest-side" => Ok(ShapeRadius::ClosestSide),
                 "farthest-side" => Ok(ShapeRadius::FarthestSide),
                 _ => Err(())
             }
         })
     }
 }
@@ -711,49 +711,49 @@ impl ToCss for BorderRadius {
                                  &self.top_right.0.height,
                                  &self.bottom_right.0.height,
                                  &self.bottom_left.0.height)
         }
     }
 }
 
 impl Parse for BorderRadius {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
-        let widths = try!(parse_one_set_of_border_values(input));
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        let widths = try!(parse_one_set_of_border_values(context, input));
         let heights = if input.try(|input| input.expect_delim('/')).is_ok() {
-            try!(parse_one_set_of_border_values(input))
+            try!(parse_one_set_of_border_values(context, input))
         } else {
             widths.clone()
         };
         Ok(BorderRadius {
             top_left: BorderRadiusSize::new(widths[0], heights[0]),
             top_right: BorderRadiusSize::new(widths[1], heights[1]),
             bottom_right: BorderRadiusSize::new(widths[2], heights[2]),
             bottom_left: BorderRadiusSize::new(widths[3], heights[3]),
         })
     }
 }
 
-fn parse_one_set_of_border_values(mut input: &mut Parser)
+fn parse_one_set_of_border_values(context: &ParserContext, mut input: &mut Parser)
                                  -> Result<[LengthOrPercentage; 4], ()> {
-    let a = try!(LengthOrPercentage::parse(input));
+    let a = try!(LengthOrPercentage::parse(context, input));
 
-    let b = if let Ok(b) = input.try(LengthOrPercentage::parse) {
+    let b = if let Ok(b) = input.try(|i| LengthOrPercentage::parse(context, i)) {
         b
     } else {
         return Ok([a, a, a, a])
     };
 
-    let c = if let Ok(c) = input.try(LengthOrPercentage::parse) {
+    let c = if let Ok(c) = input.try(|i| LengthOrPercentage::parse(context, i)) {
         c
     } else {
         return Ok([a, b, a, b])
     };
 
-    if let Ok(d) = input.try(LengthOrPercentage::parse) {
+    if let Ok(d) = input.try(|i| LengthOrPercentage::parse(context, i)) {
         Ok([a, b, c, d])
     } else {
         Ok([a, b, c, b])
     }
 }
 
 
 impl ToComputedValue for BorderRadius {
@@ -789,17 +789,17 @@ pub enum FillRule {
     // basic-shapes spec says that these are the only two values, however
     // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
     // says that it can also be `inherit`
 }
 
 impl ComputedValueAsSpecified for FillRule {}
 
 impl Parse for FillRule {
-    fn parse(input: &mut Parser) -> Result<FillRule, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<FillRule, ()> {
         match_ignore_ascii_case! { try!(input.expect_ident()),
             "nonzero" => Ok(FillRule::NonZero),
             "evenodd" => Ok(FillRule::EvenOdd),
             _ => Err(())
         }
     }
 }
 
@@ -824,18 +824,18 @@ impl ToCss for FillRule {
 pub enum GeometryBox {
     Fill,
     Stroke,
     View,
     ShapeBox(ShapeBox),
 }
 
 impl Parse for GeometryBox {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
-        if let Ok(shape_box) = input.try(ShapeBox::parse) {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if let Ok(shape_box) = input.try(|i| ShapeBox::parse(context, i)) {
             Ok(GeometryBox::ShapeBox(shape_box))
         } else {
             match_ignore_ascii_case! { try!(input.expect_ident()),
                 "fill-box" => Ok(GeometryBox::Fill),
                 "stroke-box" => Ok(GeometryBox::Stroke),
                 "view-box" => Ok(GeometryBox::View),
                 _ => Err(())
             }
@@ -863,17 +863,17 @@ pub enum ShapeBox {
     Margin,
     // https://drafts.csswg.org/css-backgrounds-3/#box
     Border,
     Padding,
     Content,
 }
 
 impl Parse for ShapeBox {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match_ignore_ascii_case! { try!(input.expect_ident()),
             "margin-box" => Ok(ShapeBox::Margin),
             "border-box" => Ok(ShapeBox::Border),
             "padding-box" => Ok(ShapeBox::Padding),
             "content-box" => Ok(ShapeBox::Content),
             _ => Err(())
         }
     }
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -37,17 +37,17 @@ impl ToCss for Image {
 }
 
 impl Image {
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
         if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
             return Ok(Image::Url(url));
         }
 
-        Ok(Image::Gradient(try!(Gradient::parse_function(input))))
+        Ok(Image::Gradient(try!(Gradient::parse_function(context, input))))
     }
 
     /// Creates an already specified image value from an already resolved URL
     /// for insertion in the cascade.
     pub fn for_cascade(url: Option<ServoUrl>, extra_data: UrlExtraData) -> Self {
         Image::Url(SpecifiedUrl::for_cascade(url, extra_data))
     }
 }
@@ -87,49 +87,49 @@ impl ToCss for Gradient {
             try!(stop.to_css(dest));
         }
         dest.write_str(")")
     }
 }
 
 impl Gradient {
     /// Parses a gradient from the given arguments.
-    pub fn parse_function(input: &mut Parser) -> Result<Gradient, ()> {
+    pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Gradient, ()> {
         let mut repeating = false;
         let (gradient_kind, stops) = match_ignore_ascii_case! { try!(input.expect_function()),
             "linear-gradient" => {
                 try!(input.parse_nested_block(|input| {
-                        let kind = try!(GradientKind::parse_linear(input));
-                        let stops = try!(input.parse_comma_separated(ColorStop::parse));
+                        let kind = try!(GradientKind::parse_linear(context, input));
+                        let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i)));
                         Ok((kind, stops))
                     })
                 )
             },
             "repeating-linear-gradient" => {
                 repeating = true;
                 try!(input.parse_nested_block(|input| {
-                        let kind = try!(GradientKind::parse_linear(input));
-                        let stops = try!(input.parse_comma_separated(ColorStop::parse));
+                        let kind = try!(GradientKind::parse_linear(context, input));
+                        let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i)));
                         Ok((kind, stops))
                     })
                 )
             },
             "radial-gradient" => {
                 try!(input.parse_nested_block(|input| {
-                        let kind = try!(GradientKind::parse_radial(input));
-                        let stops = try!(input.parse_comma_separated(ColorStop::parse));
+                        let kind = try!(GradientKind::parse_radial(context, input));
+                        let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i)));
                         Ok((kind, stops))
                     })
                 )
             },
             "repeating-radial-gradient" => {
                 repeating = true;
                 try!(input.parse_nested_block(|input| {
-                        let kind = try!(GradientKind::parse_radial(input));
-                        let stops = try!(input.parse_comma_separated(ColorStop::parse));
+                        let kind = try!(GradientKind::parse_radial(context, input));
+                        let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i)));
                         Ok((kind, stops))
                     })
                 )
             },
             _ => { return Err(()); }
         };
 
         Ok(Gradient {
@@ -146,85 +146,88 @@ impl Gradient {
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum GradientKind {
     Linear(AngleOrCorner),
     Radial(EndingShape, Position),
 }
 
 impl GradientKind {
     /// Parses a linear gradient kind from the given arguments.
-    pub fn parse_linear(input: &mut Parser) -> Result<GradientKind, ()> {
-        let angle_or_corner = try!(AngleOrCorner::parse(input));
+    pub fn parse_linear(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> {
+        let angle_or_corner = try!(AngleOrCorner::parse(context, input));
         Ok(GradientKind::Linear(angle_or_corner))
     }
 
     /// Parses a radial gradient from the given arguments.
-    pub fn parse_radial(input: &mut Parser) -> Result<GradientKind, ()> {
+    pub fn parse_radial(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> {
         let mut needs_comma = true;
 
         // Ending shape and position can be in various order. Checks all probabilities.
-        let (shape, position) = if let Ok(position) = input.try(parse_position) {
+        let (shape, position) = if let Ok(position) = input.try(|i| parse_position(context, i)) {
             // Handle just <position>
             (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), position)
-        } else if let Ok((first, second)) = input.try(parse_two_length) {
+        } else if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) {
             // Handle <LengthOrPercentage> <LengthOrPercentage> <shape>? <position>?
             let _ = input.try(|input| input.expect_ident_matching("ellipse"));
             (EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(first, second)),
-             input.try(parse_position).unwrap_or(Position::center()))
-        } else if let Ok(length) = input.try(Length::parse) {
+             input.try(|i| parse_position(context, i)).unwrap_or(Position::center()))
+        } else if let Ok(length) = input.try(|i| Length::parse(context, i)) {
             // Handle <Length> <circle>? <position>?
             let _ = input.try(|input| input.expect_ident_matching("circle"));
             (EndingShape::Circle(LengthOrKeyword::Length(length)),
-             input.try(parse_position).unwrap_or(Position::center()))
+             input.try(|i| parse_position(context, i)).unwrap_or(Position::center()))
         } else if let Ok(keyword) = input.try(SizeKeyword::parse) {
             // Handle <keyword> <shape-keyword>? <position>?
             let shape = if input.try(|input| input.expect_ident_matching("circle")).is_ok() {
                 EndingShape::Circle(LengthOrKeyword::Keyword(keyword))
             } else {
                 let _ = input.try(|input| input.expect_ident_matching("ellipse"));
                 EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(keyword))
             };
-            (shape, input.try(parse_position).unwrap_or(Position::center()))
+            (shape, input.try(|i| parse_position(context, i)).unwrap_or(Position::center()))
         } else {
             // Handle <shape-keyword> <length>? <position>?
             if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() {
                 // Handle <ellipse> <LengthOrPercentageOrKeyword>? <position>?
-                let length = input.try(LengthOrPercentageOrKeyword::parse)
+                let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i))
                                   .unwrap_or(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner));
-                (EndingShape::Ellipse(length), input.try(parse_position).unwrap_or(Position::center()))
+                (EndingShape::Ellipse(length),
+                 input.try(|i| parse_position(context, i)).unwrap_or(Position::center()))
             } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() {
                 // Handle <ellipse> <LengthOrKeyword>? <position>?
-                let length = input.try(LengthOrKeyword::parse)
+                let length = input.try(|i| LengthOrKeyword::parse(context, i))
                                   .unwrap_or(LengthOrKeyword::Keyword(SizeKeyword::FarthestCorner));
-                (EndingShape::Circle(length), input.try(parse_position).unwrap_or(Position::center()))
+                (EndingShape::Circle(length), input.try(|i| parse_position(context, i))
+                                                   .unwrap_or(Position::center()))
             } else {
                 // If there is no shape keyword, it should set to default.
                 needs_comma = false;
                 (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)),
-                 input.try(parse_position).unwrap_or(Position::center()))
+                 input.try(|i| parse_position(context, i)).unwrap_or(Position::center()))
             }
         };
 
         if needs_comma {
             try!(input.expect_comma());
         }
 
         Ok(GradientKind::Radial(shape, position))
     }
 }
 
-fn parse_two_length(input: &mut Parser) -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
-    let first = try!(LengthOrPercentage::parse(input));
-    let second = try!(LengthOrPercentage::parse(input));
+fn parse_two_length(context: &ParserContext, input: &mut Parser)
+                    -> Result<(LengthOrPercentage, LengthOrPercentage), ()> {
+    let first = try!(LengthOrPercentage::parse(context, input));
+    let second = try!(LengthOrPercentage::parse(context, input));
     Ok((first, second))
 }
 
-fn parse_position(input: &mut Parser) -> Result<Position, ()> {
+fn parse_position(context: &ParserContext, input: &mut Parser) -> Result<Position, ()> {
     try!(input.expect_ident_matching("at"));
-    input.try(Position::parse)
+    input.try(|i| Position::parse(context, i))
 }
 
 /// Specified values for an angle or a corner in a linear gradient.
 #[derive(Clone, PartialEq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum AngleOrCorner {
     Angle(Angle),
     Corner(HorizontalDirection, VerticalDirection),
@@ -241,17 +244,17 @@ impl ToCss for AngleOrCorner {
                 try!(vertical.to_css(dest));
                 Ok(())
             }
         }
     }
 }
 
 impl Parse for AngleOrCorner {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         if input.try(|input| input.expect_ident_matching("to")).is_ok() {
             let (horizontal, vertical) =
             if let Ok(value) = input.try(HorizontalDirection::parse) {
                 (Some(value), input.try(VerticalDirection::parse).ok())
             } else {
                 let value = try!(VerticalDirection::parse(input));
                 (input.try(HorizontalDirection::parse).ok(), Some(value))
             };
@@ -269,17 +272,17 @@ impl Parse for AngleOrCorner {
                 (Some(HorizontalDirection::Left), None) => {
                     Ok(AngleOrCorner::Angle(Angle(PI * 1.5)))
                 },
                 (Some(horizontal), Some(vertical)) => {
                     Ok(AngleOrCorner::Corner(horizontal, vertical))
                 }
                 (None, None) => unreachable!(),
             }
-        } else if let Ok(angle) = input.try(Angle::parse) {
+        } else if let Ok(angle) = input.try(|i| Angle::parse(context, i)) {
             try!(input.expect_comma());
             Ok(AngleOrCorner::Angle(angle))
         } else {
             Ok(AngleOrCorner::Angle(Angle(PI)))
         }
     }
 }
 
@@ -308,20 +311,20 @@ impl ToCss for ColorStop {
         Ok(())
     }
 }
 
 define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right);
 define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom);
 
 impl Parse for ColorStop {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         Ok(ColorStop {
-            color: try!(CSSColor::parse(input)),
-            position: input.try(LengthOrPercentage::parse).ok(),
+            color: try!(CSSColor::parse(context, input)),
+            position: input.try(|i| LengthOrPercentage::parse(context, i)).ok(),
         })
     }
 }
 
 /// Determines whether the gradient's ending shape is a circle or an ellipse.
 /// If <shape> is omitted, the ending shape defaults to a circle
 /// if the <size> is a single <length>, and to an ellipse otherwise.
 /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
@@ -352,21 +355,21 @@ impl ToCss for EndingShape {
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum LengthOrKeyword {
     Length(Length),
     Keyword(SizeKeyword),
 }
 
 impl Parse for LengthOrKeyword {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         if let Ok(keyword) = input.try(SizeKeyword::parse) {
             Ok(LengthOrKeyword::Keyword(keyword))
         } else {
-            Ok(LengthOrKeyword::Length(try!(Length::parse(input))))
+            Ok(LengthOrKeyword::Length(try!(Length::parse(context, input))))
         }
     }
 }
 
 impl ToCss for LengthOrKeyword {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         match *self {
             LengthOrKeyword::Length(ref length) => length.to_css(dest),
@@ -380,22 +383,23 @@ impl ToCss for LengthOrKeyword {
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum LengthOrPercentageOrKeyword {
     LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
     Keyword(SizeKeyword),
 }
 
 
 impl Parse for LengthOrPercentageOrKeyword {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         if let Ok(keyword) = input.try(SizeKeyword::parse) {
             Ok(LengthOrPercentageOrKeyword::Keyword(keyword))
         } else {
-            Ok(LengthOrPercentageOrKeyword::LengthOrPercentage(try!(LengthOrPercentage::parse(input)),
-                                                               try!(LengthOrPercentage::parse(input))))
+            Ok(LengthOrPercentageOrKeyword::LengthOrPercentage(
+                try!(LengthOrPercentage::parse(context, input)),
+                try!(LengthOrPercentage::parse(context, input))))
         }
     }
 }
 
 impl ToCss for LengthOrPercentageOrKeyword {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         match *self {
             LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => {
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.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, Token};
 use euclid::size::Size2D;
 use font_metrics::FontMetrics;
-use parser::Parse;
+use parser::{Parse, ParserContext};
 use std::ascii::AsciiExt;
 use std::cmp;
 use std::fmt;
 use std::ops::Mul;
 use style_traits::ToCss;
 use style_traits::values::specified::AllowedNumericType;
 use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time};
 use values::{CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_};
@@ -333,17 +333,17 @@ impl Length {
     }
     #[inline]
     pub fn from_px(px_value: CSSFloat) -> Length {
         Length::Absolute(Au((px_value * AU_PER_PX) as i32))
     }
 }
 
 impl Parse for Length {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         Length::parse_internal(input, AllowedNumericType::All)
     }
 }
 
 impl<T> Either<Length, T> {
     #[inline]
     pub fn parse_non_negative_length(input: &mut Parser) -> Result<Either<Length, T>, ()> {
         Length::parse_internal(input, AllowedNumericType::NonNegative).map(Either::First)
@@ -748,17 +748,17 @@ pub struct Percentage(pub CSSFloat); // 
 impl ToCss for Percentage {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         write!(dest, "{}%", self.0 * 100.)
     }
 }
 
 impl Parse for Percentage {
     #[inline]
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         let context = AllowedNumericType::All;
         match try!(input.next()) {
             Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
                 Ok(Percentage(value.unit_value)),
             _ => Err(())
         }
     }
 }
@@ -816,17 +816,17 @@ impl LengthOrPercentage {
     #[inline]
     pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
         LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative)
     }
 }
 
 impl Parse for LengthOrPercentage {
     #[inline]
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         LengthOrPercentage::parse_internal(input, AllowedNumericType::All)
     }
 }
 
 #[derive(Clone, PartialEq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum LengthOrPercentageOrAuto {
     Length(Length),
@@ -879,17 +879,17 @@ impl LengthOrPercentageOrAuto {
     #[inline]
     pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
         LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::NonNegative)
     }
 }
 
 impl Parse for LengthOrPercentageOrAuto {
     #[inline]
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::All)
     }
 }
 
 #[derive(Clone, PartialEq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum LengthOrPercentageOrNone {
     Length(Length),
@@ -941,17 +941,17 @@ impl LengthOrPercentageOrNone {
     #[inline]
     pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
         LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::NonNegative)
     }
 }
 
 impl Parse for LengthOrPercentageOrNone {
     #[inline]
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::All)
     }
 }
 
 pub type LengthOrNone = Either<Length, None_>;
 
 #[derive(Clone, PartialEq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -981,17 +981,17 @@ impl ToCss for LengthOrPercentageOrAutoO
             LengthOrPercentageOrAutoOrContent::Auto => dest.write_str("auto"),
             LengthOrPercentageOrAutoOrContent::Content => dest.write_str("content"),
             LengthOrPercentageOrAutoOrContent::Calc(calc) => calc.to_css(dest),
         }
     }
 }
 
 impl Parse for LengthOrPercentageOrAutoOrContent {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         let context = AllowedNumericType::NonNegative;
         match try!(input.next()) {
             Token::Dimension(ref value, ref unit) if context.is_ok(value.value) =>
                 Length::parse_dimension(value.value, unit).map(LengthOrPercentageOrAutoOrContent::Length),
             Token::Percentage(ref value) if context.is_ok(value.unit_value) =>
                 Ok(LengthOrPercentageOrAutoOrContent::Percentage(Percentage(value.unit_value))),
             Token::Number(ref value) if value.value == 0. =>
                 Ok(LengthOrPercentageOrAutoOrContent::Length(Length::Absolute(Au(0)))),
@@ -1007,15 +1007,15 @@ impl Parse for LengthOrPercentageOrAutoO
         }
     }
 }
 
 pub type LengthOrNumber = Either<Length, Number>;
 
 impl LengthOrNumber {
     pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
-        if let Ok(v) = input.try(|i| Length::parse_non_negative(i)) {
+        if let Ok(v) = input.try(Length::parse_non_negative) {
             Ok(Either::First(v))
         } else {
             Number::parse_non_negative(input).map(Either::Second)
         }
     }
 }
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -33,17 +33,17 @@ impl NoViewportPercentage for i32 {}  //
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct CSSColor {
     pub parsed: cssparser::Color,
     pub authored: Option<String>,
 }
 
 impl Parse for CSSColor {
-    fn parse(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()),
             _ => None,
         };
         input.reset(start_position);
         Ok(CSSColor {
             parsed: try!(cssparser::Color::parse(input)),
@@ -192,17 +192,17 @@ impl BorderRadiusSize {
 
     pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize {
         BorderRadiusSize(Size2D::new(radius, radius))
     }
 }
 
 impl Parse for BorderRadiusSize {
     #[inline]
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         let first = try!(LengthOrPercentage::parse_non_negative(input));
         let second = input.try(LengthOrPercentage::parse_non_negative).unwrap_or(first);
         Ok(BorderRadiusSize(Size2D::new(first, second)))
     }
 }
 
 impl ToCss for BorderRadiusSize {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
@@ -236,17 +236,17 @@ impl Angle {
 }
 
 const RAD_PER_DEG: CSSFloat = PI / 180.0;
 const RAD_PER_GRAD: CSSFloat = PI / 200.0;
 const RAD_PER_TURN: CSSFloat = PI * 2.0;
 
 impl Parse for Angle {
     /// Parses an angle according to CSS-VALUES ยง 6.1.
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match try!(input.next()) {
             Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit),
             Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)),
             Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
                 input.parse_nested_block(CalcLengthOrPercentage::parse_angle)
             },
             _ => Err(())
         }
@@ -260,18 +260,18 @@ impl Angle {
             "grad" => Ok(Angle(value * RAD_PER_GRAD)),
             "turn" => Ok(Angle(value * RAD_PER_TURN)),
             "rad" => Ok(Angle(value)),
              _ => Err(())
         }
     }
 }
 
-pub fn parse_border_radius(input: &mut Parser) -> Result<BorderRadiusSize, ()> {
-    input.try(BorderRadiusSize::parse).or_else(|()| {
+pub fn parse_border_radius(context: &ParserContext, input: &mut Parser) -> Result<BorderRadiusSize, ()> {
+    input.try(|i| BorderRadiusSize::parse(context, i)).or_else(|()| {
             match_ignore_ascii_case! { try!(input.expect_ident()),
                 "thin" => Ok(BorderRadiusSize::circle(
                                  LengthOrPercentage::Length(Length::from_px(1.)))),
                 "medium" => Ok(BorderRadiusSize::circle(
                                    LengthOrPercentage::Length(Length::from_px(3.)))),
                 "thick" => Ok(BorderRadiusSize::circle(
                                   LengthOrPercentage::Length(Length::from_px(5.)))),
                 _ => Err(())
@@ -294,34 +294,36 @@ pub fn parse_border_width(input: &mut Pa
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum BorderWidth {
     Thin,
     Medium,
     Thick,
     Width(Length),
 }
 
-impl BorderWidth {
-    pub fn from_length(length: Length) -> Self {
-        BorderWidth::Width(length)
-    }
-
-    pub fn parse(input: &mut Parser) -> Result<BorderWidth, ()> {
+impl Parse for BorderWidth {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<BorderWidth, ()> {
         match input.try(Length::parse_non_negative) {
             Ok(length) => Ok(BorderWidth::Width(length)),
             Err(_) => match_ignore_ascii_case! { try!(input.expect_ident()),
                "thin" => Ok(BorderWidth::Thin),
                "medium" => Ok(BorderWidth::Medium),
                "thick" => Ok(BorderWidth::Thick),
                _ => Err(())
             }
         }
     }
 }
 
+impl BorderWidth {
+    pub fn from_length(length: Length) -> Self {
+        BorderWidth::Width(length)
+    }
+}
+
 impl ToCss for BorderWidth {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         match *self {
             BorderWidth::Thin => dest.write_str("thin"),
             BorderWidth::Medium => dest.write_str("medium"),
             BorderWidth::Thick => dest.write_str("thick"),
             BorderWidth::Width(length) => length.to_css(dest)
         }
@@ -404,17 +406,17 @@ impl Time {
             Err(())
         }
     }
 }
 
 impl ComputedValueAsSpecified for Time {}
 
 impl Parse for Time {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         match input.next() {
             Ok(Token::Dimension(ref value, ref unit)) => {
                 Time::parse_dimension(value.value, &unit)
             }
             Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => {
                 input.parse_nested_block(CalcLengthOrPercentage::parse_time)
             }
             _ => Err(())
@@ -430,17 +432,17 @@ impl ToCss for Time {
 
 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct Number(pub CSSFloat);
 
 impl NoViewportPercentage for Number {}
 
 impl Parse for Number {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         parse_number(input).map(Number)
     }
 }
 
 impl Number {
     fn parse_with_minimum(input: &mut Parser, min: CSSFloat) -> Result<Number, ()> {
         match parse_number(input) {
             Ok(value) if value < min => Err(()),
@@ -477,17 +479,17 @@ impl ToCss for Number {
 
 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct Opacity(pub CSSFloat);
 
 impl NoViewportPercentage for Opacity {}
 
 impl Parse for Opacity {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
+    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         parse_number(input).map(Opacity)
     }
 }
 
 impl ToComputedValue for Opacity {
     type ComputedValue = CSSFloat;
 
     #[inline]
--- a/servo/components/style/values/specified/position.rs
+++ b/servo/components/style/values/specified/position.rs
@@ -4,17 +4,17 @@
 
 //! CSS handling for the specified value of
 //! [`position`][position]s
 //!
 //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
 
 use app_units::Au;
 use cssparser::{Parser, Token};
-use parser::Parse;
+use parser::{Parse, ParserContext};
 use std::fmt;
 use style_traits::ToCss;
 use values::HasViewportPercentage;
 use values::computed::{CalcLengthOrPercentage, Context};
 use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue};
 use values::computed::position as computed_position;
 use values::specified::{LengthOrPercentage, Percentage};
 
@@ -176,24 +176,24 @@ impl Position {
             horiz_position: None,
             vert_keyword: Some(Keyword::Center),
             vert_position: None,
         }
     }
 }
 
 impl Parse for Position {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
-        let first = try!(PositionComponent::parse(input));
-        let second = input.try(PositionComponent::parse)
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        let first = try!(PositionComponent::parse(context, input));
+        let second = input.try(|i| PositionComponent::parse(context, i))
             .unwrap_or(PositionComponent::Keyword(Keyword::Center));
 
         // Try to parse third and fourth values
-        if let Ok(third) = input.try(PositionComponent::parse) {
-            if let Ok(fourth) = input.try(PositionComponent::parse) {
+        if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) {
+            if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) {
                 // Handle 4 value background position
                 Position::new(Some(second), Some(fourth), Some(first), Some(third))
             } else {
                 // Handle 3 value background position there are several options:
                 if let PositionCategory::LengthOrPercentage = category(first) {
                     // "length keyword length"
                     Position::new(Some(first), Some(third), None, Some(second))
                 } else {
@@ -370,18 +370,18 @@ impl PositionComponent {
         match self {
             PositionComponent::Length(value) => value,
             PositionComponent::Keyword(keyword) => keyword.to_length_or_percentage(),
         }
     }
 }
 
 impl Parse for PositionComponent {
-    fn parse(input: &mut Parser) -> Result<Self, ()> {
-        input.try(LengthOrPercentage::parse)
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        input.try(|i| LengthOrPercentage::parse(context, i))
             .map(PositionComponent::Length)
             .or_else(|()| {
                 match try!(input.next()) {
                     Token::Ident(value) => {
                         match_ignore_ascii_case! { value,
                                                    "center" => Ok(PositionComponent::Keyword(Keyword::Center)),
                                                    "left" => Ok(PositionComponent::Keyword(Keyword::Left)),
                                                    "right" => Ok(PositionComponent::Keyword(Keyword::Right)),
--- a/servo/tests/unit/style/parsing/basic_shape.rs
+++ b/servo/tests/unit/style/parsing/basic_shape.rs
@@ -1,23 +1,26 @@
 /* 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::Parser;
+use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::Parse;
+use style::parser::{Parse, ParserContext};
+use style::stylesheets::Origin;
 use style::values::specified::basic_shape::*;
 use style_traits::ToCss;
 
 // Ensure that basic-shape sub-functions parse as both basic shapes
 // and their individual components
 macro_rules! assert_roundtrip_basicshape {
     ($fun:expr, $input:expr, $output:expr) => {
-        assert_roundtrip!($fun, $input, $output);
-        assert_roundtrip!(BasicShape::parse, $input, $output);
+        assert_roundtrip_with_context!($fun, $input, $output);
+        assert_roundtrip_with_context!(BasicShape::parse, $input, $output);
     }
 }
 
 macro_rules! assert_border_radius_values {
     ($input:expr; $tlw:expr, $trw:expr, $brw:expr, $blw:expr ;
                   $tlh:expr, $trh:expr, $brh:expr, $blh:expr) => {
         let input = parse(BorderRadius::parse, $input)
                           .expect(&format!("Failed parsing {} as border radius",
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -1,63 +1,49 @@
 /* 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/. */
 
 //! Tests for parsing and serialization of values/properties
 
 use cssparser::Parser;
+use media_queries::CSSErrorReporterTest;
+use style::parser::ParserContext;
+use style::stylesheets::Origin;
 
-fn parse<T, F: Fn(&mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
+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 mut parser = Parser::new(s);
-    f(&mut parser)
+    f(&context, &mut parser)
 }
 
-
 // This is a macro so that the file/line information
 // is preserved in the panic
-macro_rules! assert_roundtrip {
-    ($fun:expr, $string:expr) => {
-        assert_roundtrip!($fun, $string, $string);
-    };
-    ($fun:expr, $input:expr, $output:expr) => {
-        let parsed = $crate::parsing::parse($fun, $input)
-                        .expect(&format!("Failed to parse {}", $input));
-        let serialized = ToCss::to_css_string(&parsed);
-        assert_eq!(serialized, $output);
-
-        let re_parsed = $crate::parsing::parse($fun, &serialized)
-                        .expect(&format!("Failed to parse serialization {}", $input));
-        let re_serialized = ToCss::to_css_string(&re_parsed);
-        assert_eq!(serialized, re_serialized);
-    }
-}
-
 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 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)
-                        .expect(&format!("Failed to parse {}", $input));
+                        .expect(&format!("Failed to parse serialization {}", $input));
         let re_serialized = ToCss::to_css_string(&re_parsed);
         assert_eq!(serialized, re_serialized);
     }
 }
 
-
 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));
         $name::parse(&context, &mut Parser::new($s)).unwrap()
     }};
 }
 
--- a/servo/tests/unit/style/parsing/position.rs
+++ b/servo/tests/unit/style/parsing/position.rs
@@ -1,54 +1,57 @@
 /* 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::Parser;
+use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::Parse;
+use style::parser::{Parse, ParserContext};
+use style::stylesheets::Origin;
 use style::values::specified::position::*;
 use style_traits::ToCss;
 
 #[test]
 fn test_position() {
     // Serialization is not actually specced
     // though these are the values expected by basic-shape
     // https://github.com/w3c/csswg-drafts/issues/368
-    assert_roundtrip!(Position::parse, "center", "center center");
-    assert_roundtrip!(Position::parse, "top left", "left top");
-    assert_roundtrip!(Position::parse, "left top", "left top");
-    assert_roundtrip!(Position::parse, "top right", "right top");
-    assert_roundtrip!(Position::parse, "right top", "right top");
-    assert_roundtrip!(Position::parse, "bottom left", "left bottom");
-    assert_roundtrip!(Position::parse, "left bottom", "left bottom");
-    assert_roundtrip!(Position::parse, "left center", "left center");
-    assert_roundtrip!(Position::parse, "right center", "right center");
-    assert_roundtrip!(Position::parse, "center top", "center top");
-    assert_roundtrip!(Position::parse, "center bottom", "center bottom");
-    assert_roundtrip!(Position::parse, "center 10px", "center 10px");
-    assert_roundtrip!(Position::parse, "center 10%", "center 10%");
-    assert_roundtrip!(Position::parse, "right 10%", "right 10%");
+    assert_roundtrip_with_context!(Position::parse, "center", "center center");
+    assert_roundtrip_with_context!(Position::parse, "top left", "left top");
+    assert_roundtrip_with_context!(Position::parse, "left top", "left top");
+    assert_roundtrip_with_context!(Position::parse, "top right", "right top");
+    assert_roundtrip_with_context!(Position::parse, "right top", "right top");
+    assert_roundtrip_with_context!(Position::parse, "bottom left", "left bottom");
+    assert_roundtrip_with_context!(Position::parse, "left bottom", "left bottom");
+    assert_roundtrip_with_context!(Position::parse, "left center", "left center");
+    assert_roundtrip_with_context!(Position::parse, "right center", "right center");
+    assert_roundtrip_with_context!(Position::parse, "center top", "center top");
+    assert_roundtrip_with_context!(Position::parse, "center bottom", "center bottom");
+    assert_roundtrip_with_context!(Position::parse, "center 10px", "center 10px");
+    assert_roundtrip_with_context!(Position::parse, "center 10%", "center 10%");
+    assert_roundtrip_with_context!(Position::parse, "right 10%", "right 10%");
 
     // Only keywords can be reordered
     assert!(parse(Position::parse, "top 40%").is_err());
     assert!(parse(Position::parse, "40% left").is_err());
 
     // 3 and 4 value serialization
-    assert_roundtrip!(Position::parse, "left 10px top 15px", "left 10px top 15px");
-    assert_roundtrip!(Position::parse, "top 15px left 10px", "left 10px top 15px");
-    assert_roundtrip!(Position::parse, "left 10% top 15px", "left 10% top 15px");
-    assert_roundtrip!(Position::parse, "top 15px left 10%", "left 10% top 15px");
-    assert_roundtrip!(Position::parse, "left top 15px", "left top 15px");
-    assert_roundtrip!(Position::parse, "top 15px left", "left top 15px");
-    assert_roundtrip!(Position::parse, "left 10px top", "left 10px top");
-    assert_roundtrip!(Position::parse, "top left 10px", "left 10px top");
-    assert_roundtrip!(Position::parse, "right 10px bottom", "right 10px bottom");
-    assert_roundtrip!(Position::parse, "bottom right 10px", "right 10px bottom");
-    assert_roundtrip!(Position::parse, "center right 10px", "right 10px center");
-    assert_roundtrip!(Position::parse, "center bottom 10px", "center bottom 10px");
+    assert_roundtrip_with_context!(Position::parse, "left 10px top 15px", "left 10px top 15px");
+    assert_roundtrip_with_context!(Position::parse, "top 15px left 10px", "left 10px top 15px");
+    assert_roundtrip_with_context!(Position::parse, "left 10% top 15px", "left 10% top 15px");
+    assert_roundtrip_with_context!(Position::parse, "top 15px left 10%", "left 10% top 15px");
+    assert_roundtrip_with_context!(Position::parse, "left top 15px", "left top 15px");
+    assert_roundtrip_with_context!(Position::parse, "top 15px left", "left top 15px");
+    assert_roundtrip_with_context!(Position::parse, "left 10px top", "left 10px top");
+    assert_roundtrip_with_context!(Position::parse, "top left 10px", "left 10px top");
+    assert_roundtrip_with_context!(Position::parse, "right 10px bottom", "right 10px bottom");
+    assert_roundtrip_with_context!(Position::parse, "bottom right 10px", "right 10px bottom");
+    assert_roundtrip_with_context!(Position::parse, "center right 10px", "right 10px center");
+    assert_roundtrip_with_context!(Position::parse, "center bottom 10px", "center bottom 10px");
 
     // Only horizontal and vertical keywords can have positions
     assert!(parse(Position::parse, "center 10px left 15px").is_err());
     assert!(parse(Position::parse, "center 10px 15px").is_err());
     assert!(parse(Position::parse, "center 10px bottom").is_err());
 
     // "Horizontal Horizontal" or "Vertical Vertical" positions cause error
     assert!(parse(Position::parse, "left right").is_err());
--- a/servo/tests/unit/style/parsing/selectors.rs
+++ b/servo/tests/unit/style/parsing/selectors.rs
@@ -1,26 +1,28 @@
 /* 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::{Parser, ToCss};
+use media_queries::CSSErrorReporterTest;
 use selectors::parser::SelectorList;
+use style::parser::ParserContext;
 use style::selector_parser::{SelectorImpl, SelectorParser};
 use style::stylesheets::{Origin, Namespaces};
 
-fn parse(input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
+fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
     let mut ns = Namespaces::default();
     ns.prefixes.insert("svg".into(), ns!(svg));
     let parser = SelectorParser {
         stylesheet_origin: Origin::UserAgent,
         namespaces: &ns,
     };
     SelectorList::parse(&parser, input)
 }
 
 #[test]
 fn test_selectors() {
-    assert_roundtrip!(parse, "div");
-    assert_roundtrip!(parse, "svg|circle");
-    assert_roundtrip!(parse, "p:before", "p::before");
-    assert_roundtrip!(parse, "[border = \"0\"]:-servo-nonzero-border ~ ::-servo-details-summary");
+    assert_roundtrip_with_context!(parse, "div");
+    assert_roundtrip_with_context!(parse, "svg|circle");
+    assert_roundtrip_with_context!(parse, "p:before", "p::before");
+    assert_roundtrip_with_context!(parse, "[border = \"0\"]:-servo-nonzero-border ~ ::-servo-details-summary");
 }