servo: Merge #16609 - Implement unitless length quirk (from nox:quirks); r=Manishearth,emilio
authorAnthony Ramine <n.oxyde@gmail.com>
Thu, 27 Apr 2017 22:32:24 -0500
changeset 355513 bb059c15dd418217004416baccc77a8c55d32729
parent 355512 4573433fcf30cd55ad93a81e7cf76b92f31109cb
child 355514 cc0825d18ef89c6f90515bca6fbcd4418095342f
push id89678
push usercbook@mozilla.com
push dateFri, 28 Apr 2017 08:45:40 +0000
treeherdermozilla-inbound@a77813ea2be4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth, emilio
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #16609 - Implement unitless length quirk (from nox:quirks); r=Manishearth,emilio The Gecko side doesn't propagate its quirks mode yet. Source-Repo: https://github.com/servo/servo Source-Revision: d8bcc0db1aad26e007b7e2bdeda3cea4953c0db0
servo/components/layout_thread/lib.rs
servo/components/script/dom/css.rs
servo/components/script/dom/cssmediarule.rs
servo/components/script/dom/cssstyledeclaration.rs
servo/components/script/dom/csssupportsrule.rs
servo/components/script/dom/document.rs
servo/components/script/dom/element.rs
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmetaelement.rs
servo/components/script/dom/htmlstyleelement.rs
servo/components/script/dom/medialist.rs
servo/components/script/dom/mediaquerylist.rs
servo/components/script/dom/window.rs
servo/components/script/stylesheet_loader.rs
servo/components/script_layout_interface/message.rs
servo/components/style/animation.rs
servo/components/style/encoding_support.rs
servo/components/style/gecko/media_queries.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/keyframes.rs
servo/components/style/matching.rs
servo/components/style/media_queries.rs
servo/components/style/parser.rs
servo/components/style/properties/data.py
servo/components/style/properties/declaration_block.rs
servo/components/style/properties/helpers.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/properties/longhand/border.mako.rs
servo/components/style/properties/longhand/box.mako.rs
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/properties/longhand/inherited_table.mako.rs
servo/components/style/properties/longhand/inherited_text.mako.rs
servo/components/style/properties/longhand/margin.mako.rs
servo/components/style/properties/longhand/padding.mako.rs
servo/components/style/properties/longhand/position.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/properties/shorthand/background.mako.rs
servo/components/style/properties/shorthand/border.mako.rs
servo/components/style/properties/shorthand/margin.mako.rs
servo/components/style/properties/shorthand/padding.mako.rs
servo/components/style/servo/media_queries.rs
servo/components/style/stylesheets.rs
servo/components/style/stylist.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/specified/length.rs
servo/components/style/values/specified/mod.rs
servo/components/style/values/specified/position.rs
servo/components/style/viewport.rs
servo/ports/geckolib/glue.rs
servo/tests/unit/style/media_queries.rs
servo/tests/unit/style/parsing/image.rs
servo/tests/unit/style/parsing/length.rs
servo/tests/unit/style/parsing/mod.rs
servo/tests/unit/style/properties/mod.rs
servo/tests/unit/style/rule_tree/bench.rs
servo/tests/unit/style/stylesheets.rs
servo/tests/unit/style/viewport.rs
--- a/servo/components/layout_thread/lib.rs
+++ b/servo/components/layout_thread/lib.rs
@@ -596,17 +596,17 @@ impl LayoutThread {
     fn handle_request_helper<'a, 'b>(&mut self,
                                      request: Msg,
                                      possibly_locked_rw_data: &mut RwData<'a, 'b>)
                                      -> bool {
         match request {
             Msg::AddStylesheet(style_info) => {
                 self.handle_add_stylesheet(style_info, possibly_locked_rw_data)
             }
-            Msg::SetQuirksMode => self.handle_set_quirks_mode(possibly_locked_rw_data),
+            Msg::SetQuirksMode(mode) => self.handle_set_quirks_mode(possibly_locked_rw_data, mode),
             Msg::GetRPC(response_chan) => {
                 response_chan.send(box LayoutRPCImpl(self.rw_data.clone()) as
                                    Box<LayoutRPC + Send>).unwrap();
             },
             Msg::Reflow(data) => {
                 profile(time::ProfilerCategory::LayoutPerform,
                         self.profiler_metadata(),
                         self.time_profiler_chan.clone(),
@@ -767,19 +767,21 @@ impl LayoutThread {
                                        tick_animations: bool) {
         self.timer.increment(how_many_ms as f64 / 1000.0);
         if tick_animations {
             self.tick_all_animations(possibly_locked_rw_data);
         }
     }
 
     /// Sets quirks mode for the document, causing the quirks mode stylesheet to be used.
-    fn handle_set_quirks_mode<'a, 'b>(&self, possibly_locked_rw_data: &mut RwData<'a, 'b>) {
+    fn handle_set_quirks_mode<'a, 'b>(&self,
+                                      possibly_locked_rw_data: &mut RwData<'a, 'b>,
+                                      quirks_mode: QuirksMode) {
         let mut rw_data = possibly_locked_rw_data.lock();
-        Arc::get_mut(&mut rw_data.stylist).unwrap().set_quirks_mode(true);
+        Arc::get_mut(&mut rw_data.stylist).unwrap().set_quirks_mode(quirks_mode);
         possibly_locked_rw_data.block(rw_data);
     }
 
     fn try_get_layout_root<N: LayoutNode>(&self, node: N) -> Option<FlowRef> {
         let mut data = match node.mutate_layout_data() {
             Some(x) => x,
             None => return None,
         };
@@ -1582,30 +1584,31 @@ fn get_ua_stylesheets() -> Result<UserAg
             &res,
             ServoUrl::parse(&format!("chrome://resources/{:?}", filename)).unwrap(),
             None,
             None,
             Origin::UserAgent,
             MediaList::empty(),
             shared_lock.clone(),
             None,
-            &NullReporter))
+            &NullReporter,
+            QuirksMode::NoQuirks))
     }
 
     let shared_lock = SharedRwLock::new();
     let mut user_or_user_agent_stylesheets = vec!();
     // FIXME: presentational-hints.css should be at author origin with zero specificity.
     //        (Does it make a difference?)
     for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] {
         user_or_user_agent_stylesheets.push(try!(parse_ua_stylesheet(&shared_lock, filename)));
     }
     for &(ref contents, ref url) in &opts::get().user_stylesheets {
         user_or_user_agent_stylesheets.push(Stylesheet::from_bytes(
             &contents, url.clone(), None, None, Origin::User, MediaList::empty(),
-            shared_lock.clone(), None, &RustLogReporter));
+            shared_lock.clone(), None, &RustLogReporter, QuirksMode::NoQuirks));
     }
 
     let quirks_mode_stylesheet = try!(parse_ua_stylesheet(&shared_lock, "quirks-mode.css"));
 
     Ok(UserAgentStylesheets {
         shared_lock: shared_lock,
         user_or_user_agent_stylesheets: user_or_user_agent_stylesheets,
         quirks_mode_stylesheet: quirks_mode_stylesheet,
--- a/servo/components/script/dom/css.rs
+++ b/servo/components/script/dom/css.rs
@@ -4,16 +4,17 @@
 
 use cssparser::{Parser, serialize_identifier};
 use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
 use dom::bindings::error::Fallible;
 use dom::bindings::reflector::Reflector;
 use dom::bindings::str::DOMString;
 use dom::window::Window;
 use dom_struct::dom_struct;
+use style::context::QuirksMode;
 use style::parser::{LengthParsingMode, ParserContext};
 use style::stylesheets::CssRuleType;
 use style::supports::{Declaration, parse_condition_or_declaration};
 
 #[dom_struct]
 pub struct CSS {
     reflector_: Reflector,
 }
@@ -26,26 +27,28 @@ impl CSS {
         Ok(DOMString::from(escaped))
     }
 
     /// https://drafts.csswg.org/css-conditional/#dom-css-supports
     pub fn Supports(win: &Window, property: DOMString, value: DOMString) -> bool {
         let decl = Declaration { prop: property.into(), val: value.into() };
         let url = win.Document().url();
         let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Supports),
-                                                   LengthParsingMode::Default);
+                                                   LengthParsingMode::Default,
+                                                   QuirksMode::NoQuirks);
         decl.eval(&context)
     }
 
     /// https://drafts.csswg.org/css-conditional/#dom-css-supports
     pub fn Supports_(win: &Window, condition: DOMString) -> bool {
         let mut input = Parser::new(&condition);
         let cond = parse_condition_or_declaration(&mut input);
         if let Ok(cond) = cond {
             let url = win.Document().url();
             let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Supports),
-                                                       LengthParsingMode::Default);
+                                                       LengthParsingMode::Default,
+                                                       QuirksMode::NoQuirks);
             cond.eval(&context)
         } else {
             false
         }
     }
 }
--- a/servo/components/script/dom/cssmediarule.rs
+++ b/servo/components/script/dom/cssmediarule.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::Parser;
 use dom::bindings::codegen::Bindings::CSSMediaRuleBinding;
 use dom::bindings::codegen::Bindings::CSSMediaRuleBinding::CSSMediaRuleMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
 use dom::bindings::js::{MutNullableJS, Root};
 use dom::bindings::reflector::{DomObject, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssconditionrule::CSSConditionRule;
 use dom::cssrule::SpecificCSSRule;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::medialist::MediaList;
 use dom::window::Window;
@@ -67,18 +68,20 @@ impl CSSMediaRule {
     }
 
     /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface
     pub fn set_condition_text(&self, text: DOMString) {
         let mut input = Parser::new(&text);
         let global = self.global();
         let win = global.as_window();
         let url = win.get_url();
+        let quirks_mode = win.Document().quirks_mode();
         let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Media),
-                                                   LengthParsingMode::Default);
+                                                   LengthParsingMode::Default,
+                                                   quirks_mode);
         let new_medialist = parse_media_query_list(&context, &mut input);
         let mut guard = self.cssconditionrule.shared_lock().write();
 
         // Clone an Arc because we can’t borrow `guard` twice at the same time.
 
         // FIXME(SimonSapin): allow access to multiple objects with one write guard?
         // Would need a set of usize pointer addresses or something,
         // the same object is not accessed more than once.
--- a/servo/components/script/dom/cssstyledeclaration.rs
+++ b/servo/components/script/dom/cssstyledeclaration.rs
@@ -251,19 +251,22 @@ impl CSSStyleDeclaration {
                 _ => {
                     *changed = false;
                     return Ok(());
                 }
             };
 
             // Step 6
             let window = self.owner.window();
+            let quirks_mode = window.Document().quirks_mode();
             let result =
                 parse_one_declaration(id, &value, &self.owner.base_url(),
-                                      window.css_error_reporter(), LengthParsingMode::Default);
+                                      window.css_error_reporter(),
+                                      LengthParsingMode::Default,
+                                      quirks_mode);
 
             // Step 7
             let parsed = match result {
                 Ok(parsed) => parsed,
                 Err(_) => {
                     *changed = false;
                     return Ok(());
                 }
@@ -429,21 +432,23 @@ impl CSSStyleDeclarationMethods for CSSS
     fn SetCssText(&self, value: DOMString) -> ErrorResult {
         let window = self.owner.window();
 
         // Step 1
         if self.readonly {
             return Err(Error::NoModificationAllowed);
         }
 
+        let quirks_mode = window.Document().quirks_mode();
         self.owner.mutate_associated_block(|mut pdb, mut _changed| {
             // Step 3
             *pdb = parse_style_attribute(&value,
                                          &self.owner.base_url(),
-                                         window.css_error_reporter());
+                                         window.css_error_reporter(),
+                                         quirks_mode);
         });
 
         Ok(())
     }
 
     // https://drafts.csswg.org/cssom/#dom-cssstyledeclaration-_camel_cased_attribute
     css_properties_accessors!(css_properties);
 }
--- a/servo/components/script/dom/csssupportsrule.rs
+++ b/servo/components/script/dom/csssupportsrule.rs
@@ -56,18 +56,20 @@ impl CSSSupportsRule {
     /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
     pub fn set_condition_text(&self, text: DOMString) {
         let mut input = Parser::new(&text);
         let cond = SupportsCondition::parse(&mut input);
         if let Ok(cond) = cond {
             let global = self.global();
             let win = global.as_window();
             let url = win.Document().url();
+            let quirks_mode = win.Document().quirks_mode();
             let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Supports),
-                                                       LengthParsingMode::Default);
+                                                       LengthParsingMode::Default,
+                                                       quirks_mode);
             let enabled = cond.eval(&context);
             let mut guard = self.cssconditionrule.shared_lock().write();
             let rule = self.supportsrule.write_with(&mut guard);
             rule.condition = cond;
             rule.enabled = enabled;
         }
     }
 }
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -537,17 +537,17 @@ impl Document {
     pub fn quirks_mode(&self) -> QuirksMode {
         self.quirks_mode.get()
     }
 
     pub fn set_quirks_mode(&self, mode: QuirksMode) {
         self.quirks_mode.set(mode);
 
         if mode == QuirksMode::Quirks {
-            self.window.layout_chan().send(Msg::SetQuirksMode).unwrap();
+            self.window.layout_chan().send(Msg::SetQuirksMode(mode)).unwrap();
         }
     }
 
     pub fn encoding(&self) -> EncodingRef {
         self.encoding.get()
     }
 
     pub fn set_encoding(&self, encoding: EncodingRef) {
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -2191,17 +2191,18 @@ impl VirtualMethods for Element {
                             let mut value = AttrValue::String(serialization);
                             attr.swap_value(&mut value);
                             block
                         } else {
                             let win = window_from_node(self);
                             Arc::new(doc.style_shared_lock().wrap(parse_style_attribute(
                                 &attr.value(),
                                 &doc.base_url(),
-                                win.css_error_reporter())))
+                                win.css_error_reporter(),
+                                doc.quirks_mode())))
                         };
 
                         Some(block)
                     }
                     AttributeMutation::Removed => {
                         None
                     }
                 };
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -277,17 +277,18 @@ impl HTMLLinkElement {
             Some(ref value) => &***value,
             None => "",
         };
 
         let mut css_parser = CssParser::new(&mq_str);
         let win = document.window();
         let doc_url = document.url();
         let context = CssParserContext::new_for_cssom(&doc_url, win.css_error_reporter(), Some(CssRuleType::Media),
-                                                      LengthParsingMode::Default);
+                                                      LengthParsingMode::Default,
+                                                      document.quirks_mode());
         let media = parse_media_query_list(&context, &mut css_parser);
 
         let im_attribute = element.get_attribute(&ns!(), &local_name!("integrity"));
         let integrity_val = im_attribute.r().map(|a| a.value());
         let integrity_metadata = match integrity_val {
             Some(ref value) => &***value,
             None => "",
         };
--- a/servo/components/script/dom/htmlmetaelement.rs
+++ b/servo/components/script/dom/htmlmetaelement.rs
@@ -108,16 +108,17 @@ impl HTMLMetaElement {
                         shared_lock: shared_lock.clone(),
                         url_data: window_from_node(self).get_url(),
                         namespaces: Default::default(),
                         media: Arc::new(shared_lock.wrap(MediaList::empty())),
                         // Viewport constraints are always recomputed on resize; they don't need to
                         // force all styles to be recomputed.
                         dirty_on_viewport_size_change: AtomicBool::new(false),
                         disabled: AtomicBool::new(false),
+                        quirks_mode: document.quirks_mode(),
                     }));
                     let doc = document_from_node(self);
                     doc.invalidate_stylesheets();
                 }
             }
         }
     }
 
--- a/servo/components/script/dom/htmlstyleelement.rs
+++ b/servo/components/script/dom/htmlstyleelement.rs
@@ -71,48 +71,50 @@ impl HTMLStyleElement {
     }
 
     pub fn parse_own_css(&self) {
         let node = self.upcast::<Node>();
         let element = self.upcast::<Element>();
         assert!(node.is_in_doc());
 
         let win = window_from_node(node);
+        let doc = document_from_node(self);
 
         let mq_attribute = element.get_attribute(&ns!(), &local_name!("media"));
         let mq_str = match mq_attribute {
             Some(a) => String::from(&**a.value()),
             None => String::new(),
         };
 
         let data = node.GetTextContent().expect("Element.textContent must be a string");
         let url = win.get_url();
         let context = CssParserContext::new_for_cssom(&url,
                                                       win.css_error_reporter(),
                                                       Some(CssRuleType::Media),
-                                                      LengthParsingMode::Default);
+                                                      LengthParsingMode::Default,
+                                                      doc.quirks_mode());
         let shared_lock = node.owner_doc().style_shared_lock().clone();
         let mq = Arc::new(shared_lock.wrap(
                     parse_media_query_list(&context, &mut CssParser::new(&mq_str))));
         let loader = StylesheetLoader::for_element(self.upcast());
         let sheet = Stylesheet::from_str(&data, win.get_url(), Origin::Author, mq,
                                          shared_lock, Some(&loader),
                                          win.css_error_reporter(),
+                                         doc.quirks_mode(),
                                          self.line_number);
 
         let sheet = Arc::new(sheet);
 
         // No subresource loads were triggered, just fire the load event now.
         if self.pending_loads.get() == 0 {
             self.upcast::<EventTarget>().fire_event(atom!("load"));
         }
 
         win.layout_chan().send(Msg::AddStylesheet(sheet.clone())).unwrap();
         *self.stylesheet.borrow_mut() = Some(sheet);
-        let doc = document_from_node(self);
         doc.invalidate_stylesheets();
     }
 
     pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
         self.stylesheet.borrow().clone()
     }
 
     pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
--- a/servo/components/script/dom/medialist.rs
+++ b/servo/components/script/dom/medialist.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::Parser;
 use dom::bindings::codegen::Bindings::MediaListBinding;
 use dom::bindings::codegen::Bindings::MediaListBinding::MediaListMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
 use dom::bindings::js::{JS, Root};
 use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 use dom_struct::dom_struct;
 use std::sync::Arc;
 use style::media_queries::{MediaQuery, parse_media_query_list};
@@ -69,18 +70,20 @@ impl MediaListMethods for MediaList {
             *media_queries = StyleMediaList::empty();
             return;
         }
         // Step 3
         let mut parser = Parser::new(&value);
         let global = self.global();
         let win = global.as_window();
         let url = win.get_url();
+        let quirks_mode = win.Document().quirks_mode();
         let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Media),
-                                                   LengthParsingMode::Default);
+                                                   LengthParsingMode::Default,
+                                                   quirks_mode);
         *media_queries = parse_media_query_list(&context, &mut parser);
     }
 
     // https://drafts.csswg.org/cssom/#dom-medialist-length
     fn Length(&self) -> u32 {
         let guard = self.shared_lock().read();
         self.media_queries.read_with(&guard).media_queries.len() as u32
     }
@@ -103,18 +106,20 @@ impl MediaListMethods for MediaList {
 
     // https://drafts.csswg.org/cssom/#dom-medialist-appendmedium
     fn AppendMedium(&self, medium: DOMString) {
         // Step 1
         let mut parser = Parser::new(&medium);
         let global = self.global();
         let win = global.as_window();
         let url = win.get_url();
+        let quirks_mode = win.Document().quirks_mode();
         let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Media),
-                                                   LengthParsingMode::Default);
+                                                   LengthParsingMode::Default,
+                                                   quirks_mode);
         let m = MediaQuery::parse(&context, &mut parser);
         // Step 2
         if let Err(_) = m {
             return;
         }
         // Step 3
         let m_serialized = m.clone().unwrap().to_css_string();
         let mut guard = self.shared_lock().write();
@@ -129,18 +134,20 @@ impl MediaListMethods for MediaList {
 
     // https://drafts.csswg.org/cssom/#dom-medialist-deletemedium
     fn DeleteMedium(&self, medium: DOMString) {
         // Step 1
         let mut parser = Parser::new(&medium);
         let global = self.global();
         let win = global.as_window();
         let url = win.get_url();
+        let quirks_mode = win.Document().quirks_mode();
         let context = ParserContext::new_for_cssom(&url, win.css_error_reporter(), Some(CssRuleType::Media),
-                                                   LengthParsingMode::Default);
+                                                   LengthParsingMode::Default,
+                                                   quirks_mode);
         let m = MediaQuery::parse(&context, &mut parser);
         // Step 2
         if let Err(_) = m {
             return;
         }
         // Step 3
         let m_serialized = m.unwrap().to_css_string();
         let mut guard = self.shared_lock().write();
--- a/servo/components/script/dom/mediaquerylist.rs
+++ b/servo/components/script/dom/mediaquerylist.rs
@@ -72,17 +72,17 @@ impl MediaQueryList {
         self.last_match_state.set(Some(matches));
         result
     }
 
     pub fn evaluate(&self) -> bool {
         if let Some(window_size) = self.document.window().window_size() {
             let viewport_size = window_size.initial_viewport;
             let device = Device::new(MediaType::Screen, viewport_size);
-            self.media_query_list.evaluate(&device)
+            self.media_query_list.evaluate(&device, self.document.quirks_mode())
         } else {
             false
         }
     }
 }
 
 impl MediaQueryListMethods for MediaQueryList {
     // https://drafts.csswg.org/cssom-view/#dom-mediaquerylist-media
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -971,18 +971,20 @@ impl WindowMethods for Window {
             Err(e) => Err(Error::Type(format!("Couldn't open URL: {}", e))),
         }
     }
 
     // https://drafts.csswg.org/cssom-view/#dom-window-matchmedia
     fn MatchMedia(&self, query: DOMString) -> Root<MediaQueryList> {
         let mut parser = Parser::new(&query);
         let url = self.get_url();
+        let quirks_mode = self.Document().quirks_mode();
         let context = CssParserContext::new_for_cssom(&url, self.css_error_reporter(), Some(CssRuleType::Media),
-                                                      LengthParsingMode::Default);
+                                                      LengthParsingMode::Default,
+                                                      quirks_mode);
         let media_query_list = media_queries::parse_media_query_list(&context, &mut parser);
         let document = self.Document();
         let mql = MediaQueryList::new(&document, media_query_list);
         self.media_query_lists.push(&*mql);
         mql
     }
 
     #[allow(unrooted_must_root)]
--- a/servo/components/script/stylesheet_loader.rs
+++ b/servo/components/script/stylesheet_loader.rs
@@ -139,17 +139,18 @@ impl FetchResponseListener for Styleshee
                         let sheet =
                             Arc::new(Stylesheet::from_bytes(&data, final_url,
                                                             protocol_encoding_label,
                                                             Some(environment_encoding),
                                                             Origin::Author,
                                                             media.take().unwrap(),
                                                             shared_lock,
                                                             Some(&loader),
-                                                            win.css_error_reporter()));
+                                                            win.css_error_reporter(),
+                                                            document.quirks_mode()));
 
                         if link.is_alternate() {
                             sheet.set_disabled(true);
                         }
 
                         link.set_stylesheet(sheet);
                     }
                 }
--- a/servo/components/script_layout_interface/message.rs
+++ b/servo/components/script_layout_interface/message.rs
@@ -12,28 +12,28 @@ use msg::constellation_msg::PipelineId;
 use net_traits::image_cache::ImageCache;
 use profile_traits::mem::ReportsChan;
 use rpc::LayoutRPC;
 use script_traits::{ConstellationControlMsg, LayoutControlMsg};
 use script_traits::{LayoutMsg as ConstellationMsg, StackingContextScrollState, WindowSizeData};
 use servo_url::ServoUrl;
 use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender};
-use style::context::ReflowGoal;
+use style::context::{QuirksMode, ReflowGoal};
 use style::properties::PropertyId;
 use style::selector_parser::PseudoElement;
 use style::stylesheets::Stylesheet;
 
 /// Asynchronous messages that script can send to layout.
 pub enum Msg {
     /// Adds the given stylesheet to the document.
     AddStylesheet(Arc<Stylesheet>),
 
-    /// Puts a document into quirks mode, causing the quirks mode stylesheet to be loaded.
-    SetQuirksMode,
+    /// Change the quirks mode.
+    SetQuirksMode(QuirksMode),
 
     /// Requests a reflow.
     Reflow(ScriptReflow),
 
     /// Get an RPC interface.
     GetRPC(Sender<Box<LayoutRPC + Send>>),
 
     /// Requests that the layout thread render the next frame of all animations.
--- a/servo/components/style/animation.rs
+++ b/servo/components/style/animation.rs
@@ -463,17 +463,18 @@ fn compute_style_for_animation_step(cont
                                                /* is_root = */ false,
                                                /* pseudo = */ None,
                                                iter,
                                                previous_style,
                                                previous_style,
                                                /* cascade_info = */ None,
                                                &*context.error_reporter,
                                                font_metrics_provider,
-                                               CascadeFlags::empty());
+                                               CascadeFlags::empty(),
+                                               context.quirks_mode);
             computed
         }
     }
 }
 
 /// Triggers animations for a given node looking at the animation property
 /// values.
 pub fn maybe_start_animations(context: &SharedStyleContext,
--- a/servo/components/style/encoding_support.rs
+++ b/servo/components/style/encoding_support.rs
@@ -1,16 +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/. */
 
 //! Parsing stylesheets from bytes (not `&str`).
 
 extern crate encoding;
 
+use context::QuirksMode;
 use cssparser::{stylesheet_encoding, EncodingSupport};
 use error_reporting::ParseErrorReporter;
 use media_queries::MediaList;
 use self::encoding::{EncodingRef, DecoderTrap};
 use shared_lock::SharedRwLock;
 use std::str;
 use std::sync::Arc;
 use stylesheets::{Stylesheet, StylesheetLoader, Origin, UrlExtraData};
@@ -51,27 +52,29 @@ impl Stylesheet {
     pub fn from_bytes(bytes: &[u8],
                       url_data: UrlExtraData,
                       protocol_encoding_label: Option<&str>,
                       environment_encoding: Option<EncodingRef>,
                       origin: Origin,
                       media: MediaList,
                       shared_lock: SharedRwLock,
                       stylesheet_loader: Option<&StylesheetLoader>,
-                      error_reporter: &ParseErrorReporter)
+                      error_reporter: &ParseErrorReporter,
+                      quirks_mode: QuirksMode)
                       -> Stylesheet {
         let (string, _) = decode_stylesheet_bytes(
             bytes, protocol_encoding_label, environment_encoding);
         Stylesheet::from_str(&string,
                              url_data,
                              origin,
                              Arc::new(shared_lock.wrap(media)),
                              shared_lock,
                              stylesheet_loader,
                              error_reporter,
+                             quirks_mode,
                              0u64)
     }
 
     /// Updates an empty stylesheet with a set of bytes that reached over the
     /// network.
     pub fn update_from_bytes(existing: &Stylesheet,
                              bytes: &[u8],
                              protocol_encoding_label: Option<&str>,
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Gecko's media-query device and expression representation.
 
 use app_units::Au;
+use context::QuirksMode;
 use cssparser::{CssStringWriter, Parser, Token};
 use euclid::Size2D;
 use font_metrics::get_metrics_provider_for_product;
 use gecko_bindings::bindings;
 use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSValue, nsCSSUnit, nsStringBuffer};
 use gecko_bindings::structs::{nsMediaExpression_Range, nsMediaFeature};
 use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType, nsMediaFeature_RequirementFlags};
 use gecko_bindings::structs::RawGeckoPresContextOwned;
@@ -516,35 +517,36 @@ impl Expression {
                 }
             };
 
             Ok(Expression::new(feature, Some(value), range))
         })
     }
 
     /// Returns whether this media query evaluates to true for the given device.
-    pub fn matches(&self, device: &Device) -> bool {
+    pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool {
         let mut css_value = nsCSSValue::null();
         unsafe {
             (self.feature.mGetter.unwrap())(device.pres_context,
                                             self.feature,
                                             &mut css_value)
         };
 
         let value = match MediaExpressionValue::from_css_value(self, &css_value) {
             Some(v) => v,
             None => return false,
         };
 
-        self.evaluate_against(device, &value)
+        self.evaluate_against(device, &value, quirks_mode)
     }
 
     fn evaluate_against(&self,
                         device: &Device,
-                        actual_value: &MediaExpressionValue)
+                        actual_value: &MediaExpressionValue,
+                        quirks_mode: QuirksMode)
                         -> bool {
         use self::MediaExpressionValue::*;
         use std::cmp::Ordering;
 
         debug_assert!(self.range == nsMediaExpression_Range::eEqual ||
                       self.feature.mRangeType == nsMediaFeature_RangeType::eMinMaxAllowed,
                       "Whoops, wrong range");
 
@@ -559,16 +561,18 @@ impl Expression {
             device: device,
             inherited_style: default_values,
             layout_parent_style: default_values,
             // This cloning business is kind of dumb.... It's because Context
             // insists on having an actual ComputedValues inside itself.
             style: default_values.clone(),
             font_metrics_provider: &provider,
             in_media_query: true,
+            // TODO: pass the correct value here.
+            quirks_mode: quirks_mode,
         };
 
         let required_value = match self.value {
             Some(ref v) => v,
             None => {
                 // If there's no value, always match unless it's a zero length
                 // or a zero integer or boolean.
                 return match *actual_value {
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -11,17 +11,17 @@
 //! `components/script/layout_wrapper.rs`.
 //!
 //! This theoretically should live in its own crate, but now it lives in the
 //! style system it's kind of pointless in the Stylo case, and only Servo forces
 //! the separation between the style system implementation and everything else.
 
 use app_units::Au;
 use atomic_refcell::AtomicRefCell;
-use context::{SharedStyleContext, UpdateAnimationsTasks};
+use context::{QuirksMode, SharedStyleContext, UpdateAnimationsTasks};
 use data::ElementData;
 use dom::{self, AnimationRules, DescendantsBit, LayoutIterator, NodeInfo, TElement, TNode, UnsafeNode};
 use dom::{OpaqueNode, PresentationalHintsSynthetizer};
 use element_state::ElementState;
 use error_reporting::RustLogReporter;
 use font_metrics::{FontMetricsProvider, FontMetricsQueryResult};
 use gecko::global_style_data::GLOBAL_STYLE_DATA;
 use gecko::selector_parser::{SelectorImpl, NonTSPseudoClass, PseudoElement};
@@ -320,17 +320,17 @@ impl<'le> fmt::Debug for GeckoElement<'l
         write!(f, "> ({:#x})", self.as_node().opaque().0)
     }
 }
 
 impl<'le> GeckoElement<'le> {
     /// Parse the style attribute of an element.
     pub fn parse_style_attribute(value: &str,
                                  url_data: &UrlExtraData) -> PropertyDeclarationBlock {
-        parse_style_attribute(value, url_data, &RustLogReporter)
+        parse_style_attribute(value, url_data, &RustLogReporter, QuirksMode::NoQuirks)
     }
 
     fn flags(&self) -> u32 {
         self.raw_node()._base._base_1.mFlags
     }
 
     fn raw_node(&self) -> &RawGeckoNode {
         &(self.0)._base._base._base
--- a/servo/components/style/keyframes.rs
+++ b/servo/components/style/keyframes.rs
@@ -126,17 +126,18 @@ impl Keyframe {
     /// Parse a CSS keyframe.
     pub fn parse(css: &str, parent_stylesheet: &Stylesheet)
                  -> Result<Arc<Locked<Self>>, ()> {
         let error_reporter = NullReporter;
         let context = ParserContext::new(parent_stylesheet.origin,
                                          &parent_stylesheet.url_data,
                                          &error_reporter,
                                          Some(CssRuleType::Keyframe),
-                                         LengthParsingMode::Default);
+                                         LengthParsingMode::Default,
+                                         parent_stylesheet.quirks_mode);
         let mut input = Parser::new(css);
 
         let mut rule_parser = KeyframeListParser {
             context: &context,
             shared_lock: &parent_stylesheet.shared_lock,
         };
         parse_one_rule(&mut input, &mut rule_parser)
     }
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -478,17 +478,18 @@ trait PrivateMatchMethods: TElement {
                              rule_node,
                              pseudo,
                              &shared_context.guards,
                              style_to_inherit_from,
                              layout_parent_style,
                              Some(&mut cascade_info),
                              &*shared_context.error_reporter,
                              font_metrics_provider,
-                             cascade_flags));
+                             cascade_flags,
+                             shared_context.quirks_mode));
 
         cascade_info.finish(&self.as_node());
         values
     }
 
     fn cascade_internal(&self,
                         context: &StyleContext<Self>,
                         primary_style: &ComputedStyle,
--- a/servo/components/style/media_queries.rs
+++ b/servo/components/style/media_queries.rs
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! [Media queries][mq].
 //!
 //! [mq]: https://drafts.csswg.org/mediaqueries/
 
 use Atom;
+use context::QuirksMode;
 use cssparser::{Delimiter, Parser, Token};
 use parser::ParserContext;
 use serialize_comma_separated_list;
 use std::ascii::AsciiExt;
 use std::fmt;
 use style_traits::ToCss;
 
 #[cfg(feature = "servo")]
@@ -275,27 +276,27 @@ pub fn parse_media_query_list(context: &
 
     MediaList {
         media_queries: media_queries,
     }
 }
 
 impl MediaList {
     /// Evaluate a whole `MediaList` against `Device`.
-    pub fn evaluate(&self, device: &Device) -> bool {
+    pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> bool {
         // Check if it is an empty media query list or any queries match (OR condition)
         // https://drafts.csswg.org/mediaqueries-4/#mq-list
         self.media_queries.is_empty() || self.media_queries.iter().any(|mq| {
             let media_match = mq.media_type.matches(device.media_type());
 
             // Check if all conditions match (AND condition)
             let query_match =
                 media_match &&
                 mq.expressions.iter()
-                    .all(|expression| expression.matches(&device));
+                    .all(|expression| expression.matches(&device, quirks_mode));
 
             // Apply the logical NOT qualifier to the result
             match mq.qualifier {
                 Some(Qualifier::Not) => !query_match,
                 _ => query_match,
             }
         })
     }
--- a/servo/components/style/parser.rs
+++ b/servo/components/style/parser.rs
@@ -1,16 +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/. */
 
 //! The context within which CSS code is parsed.
 
 #![deny(missing_docs)]
 
+use context::QuirksMode;
 use cssparser::{Parser, SourcePosition, UnicodeRange};
 use error_reporting::ParseErrorReporter;
 use style_traits::OneOrMoreCommaSeparated;
 use stylesheets::{CssRuleType, Origin, UrlExtraData};
 
 /// The mode to use when parsing lengths.
 #[derive(PartialEq, Eq, Copy, Clone)]
 pub enum LengthParsingMode {
@@ -39,73 +40,81 @@ pub struct ParserContext<'a> {
     /// An error reporter to report syntax errors.
     pub error_reporter: &'a ParseErrorReporter,
     /// The current rule type, if any.
     pub rule_type: Option<CssRuleType>,
     /// Line number offsets for inline stylesheets
     pub line_number_offset: u64,
     /// The mode to use when parsing lengths.
     pub length_parsing_mode: LengthParsingMode,
+    /// The quirks mode of this stylesheet.
+    pub quirks_mode: QuirksMode,
 }
 
 impl<'a> ParserContext<'a> {
     /// Create a parser context.
     pub fn new(stylesheet_origin: Origin,
                url_data: &'a UrlExtraData,
                error_reporter: &'a ParseErrorReporter,
                rule_type: Option<CssRuleType>,
-               length_parsing_mode: LengthParsingMode)
+               length_parsing_mode: LengthParsingMode,
+               quirks_mode: QuirksMode)
                -> ParserContext<'a> {
         ParserContext {
             stylesheet_origin: stylesheet_origin,
             url_data: url_data,
             error_reporter: error_reporter,
             rule_type: rule_type,
             line_number_offset: 0u64,
             length_parsing_mode: length_parsing_mode,
+            quirks_mode: quirks_mode,
         }
     }
 
     /// Create a parser context for on-the-fly parsing in CSSOM
     pub fn new_for_cssom(url_data: &'a UrlExtraData,
                          error_reporter: &'a ParseErrorReporter,
                          rule_type: Option<CssRuleType>,
-                         length_parsing_mode: LengthParsingMode)
+                         length_parsing_mode: LengthParsingMode,
+                         quirks_mode: QuirksMode)
                          -> ParserContext<'a> {
-        Self::new(Origin::Author, url_data, error_reporter, rule_type, length_parsing_mode)
+        Self::new(Origin::Author, url_data, error_reporter, rule_type, length_parsing_mode, quirks_mode)
     }
 
     /// Create a parser context based on a previous context, but with a modified rule type.
     pub fn new_with_rule_type(context: &'a ParserContext,
                               rule_type: Option<CssRuleType>)
                               -> ParserContext<'a> {
         ParserContext {
             stylesheet_origin: context.stylesheet_origin,
             url_data: context.url_data,
             error_reporter: context.error_reporter,
             rule_type: rule_type,
             line_number_offset: context.line_number_offset,
             length_parsing_mode: context.length_parsing_mode,
+            quirks_mode: context.quirks_mode,
         }
     }
 
     /// Create a parser context for inline CSS which accepts additional line offset argument.
     pub fn new_with_line_number_offset(stylesheet_origin: Origin,
                                        url_data: &'a UrlExtraData,
                                        error_reporter: &'a ParseErrorReporter,
                                        line_number_offset: u64,
-                                       length_parsing_mode: LengthParsingMode)
+                                       length_parsing_mode: LengthParsingMode,
+                                       quirks_mode: QuirksMode)
                                        -> ParserContext<'a> {
         ParserContext {
             stylesheet_origin: stylesheet_origin,
             url_data: url_data,
             error_reporter: error_reporter,
             rule_type: None,
             line_number_offset: line_number_offset,
             length_parsing_mode: length_parsing_mode,
+            quirks_mode: quirks_mode,
         }
     }
 
     /// Get the rule type, which assumes that one is available.
     pub fn rule_type(&self) -> CssRuleType {
         self.rule_type.expect("Rule type expected, but none was found.")
     }
 }
--- a/servo/components/style/properties/data.py
+++ b/servo/components/style/properties/data.py
@@ -135,17 +135,17 @@ def arg_to_bool(arg):
 
 
 class Longhand(object):
     def __init__(self, style_struct, name, spec=None, animation_value_type=None, derived_from=None, keyword=None,
                  predefined_type=None, custom_cascade=False, experimental=False, internal=False,
                  need_clone=False, need_index=False, gecko_ffi_name=None, depend_on_viewport_size=False,
                  allowed_in_keyframe_block=True, complex_color=False, cast_type='u8',
                  has_uncacheable_values=False, logical=False, alias=None, extra_prefixes=None, boxed=False,
-                 flags=None, allowed_in_page_rule=False):
+                 flags=None, allowed_in_page_rule=False, allow_quirks=False):
         self.name = name
         if not spec:
             raise TypeError("Spec should be specified for %s" % name)
         self.spec = spec
         self.keyword = keyword
         self.predefined_type = predefined_type
         self.ident = to_rust_ident(name)
         self.camel_case = to_camel_case(self.ident)
@@ -161,16 +161,17 @@ class Longhand(object):
         self.complex_color = complex_color
         self.cast_type = cast_type
         self.logical = arg_to_bool(logical)
         self.alias = alias.split() if alias else []
         self.extra_prefixes = extra_prefixes.split() if extra_prefixes else []
         self.boxed = arg_to_bool(boxed)
         self.flags = flags.split() if flags else []
         self.allowed_in_page_rule = arg_to_bool(allowed_in_page_rule)
+        self.allow_quirks = allow_quirks
 
         # https://drafts.csswg.org/css-animations/#keyframes
         # > 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.
         self.allowed_in_keyframe_block = allowed_in_keyframe_block \
             and allowed_in_keyframe_block != "False"
 
--- a/servo/components/style/properties/declaration_block.rs
+++ b/servo/components/style/properties/declaration_block.rs
@@ -1,16 +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/. */
 
 //! A property declaration block.
 
 #![deny(missing_docs)]
 
+use context::QuirksMode;
 use cssparser::{DeclarationListParser, parse_important};
 use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
 use error_reporting::ParseErrorReporter;
 use parser::{LengthParsingMode, ParserContext, log_css_error};
 use std::fmt;
 use style_traits::ToCss;
 use stylesheets::{CssRuleType, Origin, UrlExtraData};
 use super::*;
@@ -636,42 +637,46 @@ pub fn append_serialization<'a, W, I, N>
 
     dest.write_char(';')
 }
 
 /// A helper to parse the style attribute of an element, in order for this to be
 /// shared between Servo and Gecko.
 pub fn parse_style_attribute(input: &str,
                              url_data: &UrlExtraData,
-                             error_reporter: &ParseErrorReporter)
+                             error_reporter: &ParseErrorReporter,
+                             quirks_mode: QuirksMode)
                              -> PropertyDeclarationBlock {
     let context = ParserContext::new(Origin::Author,
                                      url_data,
                                      error_reporter,
                                      Some(CssRuleType::Style),
-                                     LengthParsingMode::Default);
+                                     LengthParsingMode::Default,
+                                     quirks_mode);
     parse_property_declaration_list(&context, &mut Parser::new(input))
 }
 
 /// Parse a given property declaration. Can result in multiple
 /// `PropertyDeclaration`s when expanding a shorthand, for example.
 ///
 /// The vector returned will not have the importance set;
 /// this does not attempt to parse !important at all
 pub fn parse_one_declaration(id: PropertyId,
                              input: &str,
                              url_data: &UrlExtraData,
                              error_reporter: &ParseErrorReporter,
-                             length_parsing_mode: LengthParsingMode)
+                             length_parsing_mode: LengthParsingMode,
+                             quirks_mode: QuirksMode)
                              -> Result<ParsedDeclaration, ()> {
     let context = ParserContext::new(Origin::Author,
                                      url_data,
                                      error_reporter,
                                      Some(CssRuleType::Style),
-                                     length_parsing_mode);
+                                     length_parsing_mode,
+                                     quirks_mode);
     Parser::new(input).parse_entirely(|parser| {
         ParsedDeclaration::parse(id, &context, parser)
             .map_err(|_| ())
     })
 }
 
 /// A struct to parse property declarations.
 struct PropertyDeclarationParser<'a, 'b: 'a> {
--- a/servo/components/style/properties/helpers.mako.rs
+++ b/servo/components/style/properties/helpers.mako.rs
@@ -3,21 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 <%!
     from data import Keyword, to_rust_ident, to_camel_case
     from data import LOGICAL_SIDES, PHYSICAL_SIDES, LOGICAL_SIZES, SYSTEM_FONT_LONGHANDS
 %>
 
 <%def name="predefined_type(name, type, initial_value, parse_method='parse',
-            needs_context=True, vector=False, computed_type=None, initial_specified_value=None, **kwargs)">
+            needs_context=True, vector=False, computed_type=None, initial_specified_value=None,
+            allow_quirks=False, **kwargs)">
     <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
         #[allow(unused_imports)]
         use app_units::Au;
         use cssparser::{Color as CSSParserColor, RGBA};
+        use values::specified::AllowQuirks;
         pub use values::specified::${type} as SpecifiedValue;
         pub mod computed_value {
             % if computed_type:
             pub use ${computed_type} as T;
             % else:
             pub use values::computed::${type} as T;
             % endif
         }
@@ -25,17 +27,19 @@
         % if initial_specified_value:
         #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} }
         % endif
         #[allow(unused_variables)]
         #[inline]
         pub fn parse(context: &ParserContext,
                      input: &mut Parser)
                      -> Result<SpecifiedValue, ()> {
-            % if needs_context:
+            % if allow_quirks:
+            specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::Yes)
+            % elif needs_context:
             specified::${type}::${parse_method}(context, input)
             % else:
             specified::${type}::${parse_method}(input)
             % endif
         }
     </%def>
     % if vector:
         <%call expr="vector_longhand(name, predefined_type=type, **kwargs)">
@@ -272,16 +276,17 @@
                     DeclaredValue::WithVariables(value)
                 },
                 _ => panic!("entered the wrong cascade_property() implementation"),
             };
 
             % if not property.derived_from:
                 {
                     let custom_props = context.style().custom_properties();
+                    let quirks_mode = context.quirks_mode;
                     ::properties::substitute_variables_${property.ident}(
                         &declared_value, &custom_props,
                     |value| {
                         if let Some(ref mut cascade_info) = *cascade_info {
                             cascade_info.on_cascade_property(&declaration,
                                                              &value);
                         }
                         % if property.logical:
@@ -344,17 +349,17 @@
                                         longhands::font_size::cascade_inherit_font_size(context, inherited_struct);
                                     % else:
                                         context.mutate_style().mutate_${data.current_style_struct.name_lower}()
                                             .copy_${property.ident}_from(inherited_struct ${maybe_wm});
                                     % endif
                                 }
                             }
                         }
-                    }, error_reporter);
+                    }, error_reporter, quirks_mode);
                 }
 
                 % if property.custom_cascade:
                     cascade_property_custom(declaration,
                                             inherited_style,
                                             context,
                                             cacheable,
                                             error_reporter);
@@ -365,17 +370,21 @@
         }
         % if not property.derived_from:
             pub fn parse_specified(context: &ParserContext, input: &mut Parser)
                 % if property.boxed:
                                    -> Result<Box<SpecifiedValue>, ()> {
                     parse(context, input).map(|result| Box::new(result))
                 % else:
                                    -> Result<SpecifiedValue, ()> {
-                    parse(context, input)
+                    % if property.allow_quirks:
+                        parse_quirky(context, input, specified::AllowQuirks::Yes)
+                    % else:
+                        parse(context, input)
+                    % endif
                 % endif
             }
             pub fn parse_declared(context: &ParserContext, input: &mut Parser)
                                   -> Result<PropertyDeclaration, ()> {
                 match input.try(|i| CSSWideKeyword::parse(context, i)) {
                     Ok(keyword) => Ok(PropertyDeclaration::CSSWideKeyword(LonghandId::${property.camel_case}, keyword)),
                     Err(()) => {
                         input.look_for_var_functions();
@@ -795,27 +804,30 @@
             }
         }
 
         ${caller.body()}
     }
     % endif
 </%def>
 
-<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function, needs_context=True, **kwargs)">
+<%def name="four_sides_shorthand(name, sub_property_pattern, parser_function,
+                                 needs_context=True, allow_quirks=False, **kwargs)">
     <% sub_properties=' '.join(sub_property_pattern % side for side in ['top', 'right', 'bottom', 'left']) %>
     <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)">
         #[allow(unused_imports)]
         use parser::Parse;
         use super::parse_four_sides;
         use values::specified;
 
         pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
             let (top, right, bottom, left) =
-            % if needs_context:
+            % if allow_quirks:
+                try!(parse_four_sides(input, |i| ${parser_function}_quirky(context, i, specified::AllowQuirks::Yes)));
+            % elif 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)}: ${side},
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -510,16 +510,17 @@ impl AnimationValue {
             PropertyDeclaration::WithVariables(id, ref variables) => {
                 let custom_props = context.style().custom_properties();
                 let reporter = RustLogReporter;
                 match id {
                     % for prop in data.longhands:
                     % if prop.animatable:
                     LonghandId::${prop.camel_case} => {
                         let mut result = None;
+                        let quirks_mode = context.quirks_mode;
                         ::properties::substitute_variables_${prop.ident}_slow(
                             &variables.css,
                             variables.first_token_type,
                             &variables.url_data,
                             variables.from_shorthand,
                             &custom_props,
                             |v| {
                                 let declaration = match *v {
@@ -528,17 +529,18 @@ impl AnimationValue {
                                     },
                                     DeclaredValue::CSSWideKeyword(keyword) => {
                                         PropertyDeclaration::CSSWideKeyword(id, keyword)
                                     },
                                     DeclaredValue::WithVariables(_) => unreachable!(),
                                 };
                                 result = AnimationValue::from_declaration(&declaration, context, initial);
                             },
-                            &reporter);
+                            &reporter,
+                            quirks_mode);
                         result
                     },
                     % else:
                     LonghandId::${prop.camel_case} => None,
                     % endif
                     % endfor
                 }
             },
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -28,17 +28,19 @@
                               alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
                               spec=maybe_logical_spec(side, "style"),
                               animation_value_type="none", logical=side[1])}
 
     ${helpers.predefined_type("border-%s-width" % side[0], "BorderWidth", "Au::from_px(3)",
                               computed_type="::app_units::Au",
                               alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
                               spec=maybe_logical_spec(side, "width"),
-                              animation_value_type="ComputedValue", logical=side[1])}
+                              animation_value_type="ComputedValue",
+                              logical=side[1],
+                              allow_quirks=not side[1])}
 % endfor
 
 ${helpers.gecko_keyword_conversion(Keyword('border-style',
                                    "none solid double dotted dashed hidden groove ridge inset outset"),
                                    type="::values::specified::BorderStyle")}
 
 // FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
 % for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
--- a/servo/components/style/properties/longhand/box.mako.rs
+++ b/servo/components/style/properties/longhand/box.mako.rs
@@ -259,16 +259,17 @@
 
 </%helpers:longhand>
 
 <%helpers:longhand name="vertical-align" animation_value_type="ComputedValue"
                    spec="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align">
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
+    use values::specified::AllowQuirks;
 
     <% vertical_align = data.longhands_by_name["vertical-align"] %>
     <% vertical_align.keyword = Keyword("vertical-align",
                                         "baseline sub super top text-top middle bottom text-bottom",
                                         extra_gecko_values="-moz-middle-with-baseline") %>
     <% vertical_align_keywords = vertical_align.keyword.values_for(product) %>
 
     ${helpers.gecko_keyword_conversion(vertical_align.keyword)}
@@ -301,17 +302,17 @@
                 % endfor
                 SpecifiedValue::LengthOrPercentage(ref 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(|i| specified::LengthOrPercentage::parse(context, i))
+        input.try(|i| specified::LengthOrPercentage::parse_quirky(context, i, AllowQuirks::Yes))
         .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(())
             }
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -545,24 +545,24 @@
                     computed_value::T::Weight${weight} => SpecifiedValue::Weight${weight},
                 % endfor
             }
         }
     }
 </%helpers:longhand>
 
 <%helpers:longhand name="font-size" need_clone="True" animation_value_type="ComputedValue"
-                   spec="https://drafts.csswg.org/css-fonts/#propdef-font-size">
+                   allow_quirks="True" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size">
     use app_units::Au;
     use properties::longhands::system_font::SystemFont;
     use properties::style_structs::Font;
     use std::fmt;
     use style_traits::ToCss;
     use values::{FONT_MEDIUM_PX, HasViewportPercentage};
-    use values::specified::{FontRelativeLength, LengthOrPercentage, Length};
+    use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage, Length};
     use values::specified::{NoCalcLength, Percentage};
     use values::specified::length::FontBaseSize;
 
     impl ToCss for SpecifiedValue {
         fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
             match *self {
                 SpecifiedValue::Length(ref lop) => lop.to_css(dest),
                 SpecifiedValue::Keyword(kw, _) => kw.to_css(dest),
@@ -838,19 +838,29 @@
 
         #[inline]
         fn from_computed_value(computed: &computed_value::T) -> Self {
                 SpecifiedValue::Length(LengthOrPercentage::Length(
                         ToComputedValue::from_computed_value(computed)
                 ))
         }
     }
+
     /// <length> | <percentage> | <absolute-size> | <relative-size>
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        if let Ok(lop) = input.try(|i| specified::LengthOrPercentage::parse_non_negative(context, i)) {
+        parse_quirky(context, input, AllowQuirks::No)
+    }
+
+    /// Parses a font-size, with quirks.
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks)
+                        -> Result<SpecifiedValue, ()> {
+        use self::specified::LengthOrPercentage;
+        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks)) {
             return Ok(SpecifiedValue::Length(lop))
         }
 
         if let Ok(kw) = input.try(KeywordSize::parse) {
             return Ok(SpecifiedValue::Keyword(kw, 1.))
         }
 
         match_ignore_ascii_case! {&*input.expect_ident()?,
--- a/servo/components/style/properties/longhand/inherited_table.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_table.mako.rs
@@ -21,16 +21,17 @@
                          spec="https://drafts.csswg.org/css-tables/#propdef-caption-side")}
 
 <%helpers:longhand name="border-spacing" animation_value_type="ComputedValue" boxed="True"
                    spec="https://drafts.csswg.org/css-tables/#propdef-border-spacing">
     use app_units::Au;
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
+    use values::specified::{AllowQuirks, Length};
 
     pub mod computed_value {
         use app_units::Au;
         use properties::animated_properties::{ComputeDistance, Interpolate};
 
         #[derive(Clone, Copy, Debug, PartialEq)]
         #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
         pub struct T {
@@ -68,18 +69,18 @@
             self.horizontal.has_viewport_percentage() ||
             self.vertical.as_ref().map_or(false, |v| v.has_viewport_percentage())
         }
     }
 
     #[derive(Clone, Debug, PartialEq)]
     #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
     pub struct SpecifiedValue {
-        pub horizontal: specified::Length,
-        pub vertical: Option<specified::Length>,
+        pub horizontal: Length,
+        pub vertical: Option<Length>,
     }
 
     #[inline]
     pub fn get_initial_value() -> computed_value::T {
         computed_value::T {
             horizontal: Au(0),
             vertical: Au(0),
         }
@@ -125,21 +126,21 @@
                 vertical: Some(ToComputedValue::from_computed_value(&computed.vertical)),
             }
         }
     }
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
         let mut first = None;
         let mut second = None;
-        match specified::Length::parse_non_negative(context, input) {
+        match Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes) {
             Err(()) => (),
             Ok(length) => {
                 first = Some(length);
-                if let Ok(len) = input.try(|input| specified::Length::parse_non_negative(context, input)) {
+                if let Ok(len) = input.try(|i| Length::parse_non_negative_quirky(context, i, AllowQuirks::Yes)) {
                     second = Some(len);
                 }
             }
         }
         match (first, second) {
             (None, None) => Err(()),
             (Some(length), None) => {
                 Ok(SpecifiedValue {
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -179,17 +179,18 @@
                          products="gecko", animation_value_type="none",
                          spec="https://drafts.csswg.org/css-size-adjust/#adjustment-control",
                          alias="-webkit-text-size-adjust")}
 
 ${helpers.predefined_type("text-indent",
                           "LengthOrPercentage",
                           "computed::LengthOrPercentage::Length(Au(0))",
                           animation_value_type="ComputedValue",
-                          spec="https://drafts.csswg.org/css-text/#propdef-text-indent")}
+                          spec="https://drafts.csswg.org/css-text/#propdef-text-indent",
+                          allow_quirks=True)}
 
 // Also known as "word-wrap" (which is more popular because of IE), but this is the preferred
 // name per CSS-TEXT 6.2.
 ${helpers.single_keyword("overflow-wrap",
                          "normal break-word",
                          gecko_constant_prefix="NS_STYLE_OVERFLOWWRAP",
                          animation_value_type="none",
                          spec="https://drafts.csswg.org/css-text/#propdef-overflow-wrap",
@@ -406,16 +407,17 @@
     % endif
 </%helpers:longhand>
 
 <%helpers:longhand name="letter-spacing" animation_value_type="ComputedValue"
                    spec="https://drafts.csswg.org/css-text/#propdef-letter-spacing">
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
+    use values::specified::AllowQuirks;
 
     impl HasViewportPercentage for SpecifiedValue {
         fn has_viewport_percentage(&self) -> bool {
             match *self {
                 SpecifiedValue::Specified(ref length) => length.has_viewport_percentage(),
                 _ => false
             }
         }
@@ -482,26 +484,27 @@
             }).unwrap_or(SpecifiedValue::Normal)
         }
     }
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
             Ok(SpecifiedValue::Normal)
         } else {
-            specified::Length::parse(context, input).map(SpecifiedValue::Specified)
+            specified::Length::parse_quirky(context, input, AllowQuirks::Yes).map(SpecifiedValue::Specified)
         }
     }
 </%helpers:longhand>
 
 <%helpers:longhand name="word-spacing" animation_value_type="ComputedValue"
                    spec="https://drafts.csswg.org/css-text/#propdef-word-spacing">
     use std::fmt;
     use style_traits::ToCss;
     use values::HasViewportPercentage;
+    use values::specified::AllowQuirks;
 
     impl HasViewportPercentage for SpecifiedValue {
         fn has_viewport_percentage(&self) -> bool {
             match *self {
                 SpecifiedValue::Specified(ref length) => length.has_viewport_percentage(),
                 _ => false
             }
         }
@@ -567,17 +570,17 @@
             }).unwrap_or(SpecifiedValue::Normal)
         }
     }
 
     pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
         if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
             Ok(SpecifiedValue::Normal)
         } else {
-            specified::LengthOrPercentage::parse(context, input)
+            specified::LengthOrPercentage::parse_quirky(context, input, AllowQuirks::Yes)
                                           .map(SpecifiedValue::Specified)
         }
     }
 </%helpers:longhand>
 
 <%helpers:longhand name="-servo-text-decorations-in-effect"
                    derived_from="display text-decoration"
                    need_clone="True" products="servo"
--- a/servo/components/style/properties/longhand/margin.mako.rs
+++ b/servo/components/style/properties/longhand/margin.mako.rs
@@ -10,11 +10,12 @@
     <%
         spec = "https://drafts.csswg.org/css-box/#propdef-margin-%s" % side[0]
         if side[1]:
             spec = "https://drafts.csswg.org/css-logical-props/#propdef-margin-%s" % side[1]
     %>
     ${helpers.predefined_type("margin-%s" % side[0], "LengthOrPercentageOrAuto",
                               "computed::LengthOrPercentageOrAuto::Length(Au(0))",
                               alias=maybe_moz_logical_alias(product, side, "-moz-margin-%s"),
+                              allow_quirks=not side[1],
                               animation_value_type="ComputedValue", logical = side[1], spec = spec,
                               allowed_in_page_rule=True)}
 % endfor
--- a/servo/components/style/properties/longhand/padding.mako.rs
+++ b/servo/components/style/properties/longhand/padding.mako.rs
@@ -13,10 +13,11 @@
             spec = "https://drafts.csswg.org/css-logical-props/#propdef-padding-%s" % side[1]
     %>
     ${helpers.predefined_type("padding-%s" % side[0], "LengthOrPercentage",
                               "computed::LengthOrPercentage::Length(Au(0))",
                               "parse_non_negative",
                               alias=maybe_moz_logical_alias(product, side, "-moz-padding-%s"),
                               animation_value_type="ComputedValue",
                               logical = side[1],
-                              spec = spec)}
+                              spec = spec,
+                              allow_quirks=not side[1])}
 % endfor
--- a/servo/components/style/properties/longhand/position.mako.rs
+++ b/servo/components/style/properties/longhand/position.mako.rs
@@ -8,17 +8,18 @@
 
 <% data.new_style_struct("Position", inherited=False) %>
 
 // "top" / "left" / "bottom" / "right"
 % for side in PHYSICAL_SIDES:
     ${helpers.predefined_type(side, "LengthOrPercentageOrAuto",
                               "computed::LengthOrPercentageOrAuto::Auto",
                               spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
-                              animation_value_type="ComputedValue")}
+                              animation_value_type="ComputedValue",
+                              allow_quirks=True)}
 % endfor
 // offset-* logical properties, map to "top" / "left" / "bottom" / "right"
 % for side in LOGICAL_SIDES:
     ${helpers.predefined_type("offset-%s" % side, "LengthOrPercentageOrAuto",
                               "computed::LengthOrPercentageOrAuto::Auto",
                               spec="https://drafts.csswg.org/css-logical-props/#propdef-offset-%s" % side,
                               animation_value_type="ComputedValue", logical=True)}
 % endfor
@@ -152,16 +153,17 @@
         spec = "https://drafts.csswg.org/css-logical-props/#propdef-%s"
     %>
     // width, height, block-size, inline-size
     ${helpers.predefined_type("%s" % size,
                               "LengthOrPercentageOrAuto",
                               "computed::LengthOrPercentageOrAuto::Auto",
                               "parse_non_negative",
                               spec=spec % size,
+                              allow_quirks=not logical,
                               animation_value_type="ComputedValue", logical = logical)}
     % if product == "gecko":
         % for min_max in ["min", "max"]:
             <%
                 MinMax = min_max.title()
                 initial = "None" if "max" == min_max else "Auto"
             %>
 
@@ -172,17 +174,17 @@
             // be replaced with auto/none in block.
             <%helpers:longhand name="${min_max}-${size}" spec="${spec % ('%s-%s' % (min_max, size))}"
                                animation_value_type="ComputedValue"
                                logical="${logical}" predefined_type="${MinMax}Length">
 
                 use std::fmt;
                 use style_traits::ToCss;
                 use values::HasViewportPercentage;
-                use values::specified::${MinMax}Length;
+                use values::specified::{AllowQuirks, ${MinMax}Length};
 
                 impl HasViewportPercentage for SpecifiedValue {
                     fn has_viewport_percentage(&self) -> bool {
                         self.0.has_viewport_percentage()
                     }
                 }
 
                 pub mod computed_value {
@@ -194,17 +196,21 @@
                 pub struct SpecifiedValue(${MinMax}Length);
 
                 #[inline]
                 pub fn get_initial_value() -> computed_value::T {
                     use values::computed::${MinMax}Length;
                     ${MinMax}Length::${initial}
                 }
                 fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+                    % if logical:
                     let ret = ${MinMax}Length::parse(context, input);
+                    % else:
+                    let ret = ${MinMax}Length::parse_quirky(context, input, AllowQuirks::Yes);
+                    % endif
                     // Keyword values don't make sense in the block direction; don't parse them
                     % if "block" in size:
                         if let Ok(${MinMax}Length::ExtremumLength(..)) = ret {
                             return Err(())
                         }
                     % endif
                     ret.map(SpecifiedValue)
                 }
@@ -249,23 +255,27 @@
         % endfor
     % else:
         // servo versions (no keyword support)
         ${helpers.predefined_type("min-%s" % size,
                                   "LengthOrPercentage",
                                   "computed::LengthOrPercentage::Length(Au(0))",
                                   "parse_non_negative",
                                   spec=spec % ("min-%s" % size),
-                                  animation_value_type="ComputedValue", logical = logical)}
+                                  animation_value_type="ComputedValue",
+                                  logical=logical,
+                                  allow_quirks=not logical)}
         ${helpers.predefined_type("max-%s" % size,
                                   "LengthOrPercentageOrNone",
                                   "computed::LengthOrPercentageOrNone::None",
                                   "parse_non_negative",
                                   spec=spec % ("min-%s" % size),
-                                  animation_value_type="ComputedValue", logical = logical)}
+                                  animation_value_type="ComputedValue",
+                                  logical=logical,
+                                  allow_quirks=not logical)}
     % endif
 % endfor
 
 ${helpers.single_keyword("box-sizing",
                          "content-box border-box",
                          extra_prefixes="moz webkit",
                          spec="https://drafts.csswg.org/css-ui/#propdef-box-sizing",
                          animation_value_type="none")}
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -16,16 +16,17 @@ use std::fmt;
 use std::sync::Arc;
 
 use app_units::Au;
 #[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
 use cssparser::{Parser, TokenSerializationType};
 use error_reporting::ParseErrorReporter;
 #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
 use computed_values;
+use context::QuirksMode;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")] use gecko_bindings::bindings;
 #[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
 #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
 use logical_geometry::WritingMode;
 use media_queries::Device;
 use parser::{LengthParsingMode, Parse, ParserContext};
 use properties::animated_properties::TransitionProperty;
@@ -323,46 +324,49 @@ impl PropertyDeclarationIdSet {
         fn substitute_variables_${property.ident}<F>(
             % if property.boxed:
                 value: &DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>,
             % else:
                 value: &DeclaredValue<longhands::${property.ident}::SpecifiedValue>,
             % endif
             custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
             f: F,
-            error_reporter: &ParseErrorReporter)
+            error_reporter: &ParseErrorReporter,
+            quirks_mode: QuirksMode)
             % if property.boxed:
                 where F: FnOnce(&DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>)
             % else:
                 where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>)
             % endif
         {
             if let DeclaredValue::WithVariables(ref with_variables) = *value {
                 substitute_variables_${property.ident}_slow(&with_variables.css,
                                                             with_variables.first_token_type,
                                                             &with_variables.url_data,
                                                             with_variables.from_shorthand,
                                                             custom_properties,
                                                             f,
-                                                            error_reporter);
+                                                            error_reporter,
+                                                            quirks_mode);
             } else {
                 f(value);
             }
         }
 
         #[allow(non_snake_case)]
         #[inline(never)]
         fn substitute_variables_${property.ident}_slow<F>(
                 css: &String,
                 first_token_type: TokenSerializationType,
                 url_data: &UrlExtraData,
                 from_shorthand: Option<ShorthandId>,
                 custom_properties: &Option<Arc<::custom_properties::ComputedValuesMap>>,
                 f: F,
-                error_reporter: &ParseErrorReporter)
+                error_reporter: &ParseErrorReporter,
+                quirks_mode: QuirksMode)
                 % if property.boxed:
                     where F: FnOnce(&DeclaredValue<Box<longhands::${property.ident}::SpecifiedValue>>)
                 % else:
                     where F: FnOnce(&DeclaredValue<longhands::${property.ident}::SpecifiedValue>)
                 % endif
         {
             f(&
                 ::custom_properties::substitute(css, first_token_type, custom_properties)
@@ -370,17 +374,18 @@ impl PropertyDeclarationIdSet {
                     // As of this writing, only the base URL is used for property values:
                     //
                     // FIXME(pcwalton): Cloning the error reporter is slow! But so are custom
                     // properties, so whatever...
                     let context = ParserContext::new(Origin::Author,
                                                      url_data,
                                                      error_reporter,
                                                      None,
-                                                     LengthParsingMode::Default);
+                                                     LengthParsingMode::Default,
+                                                     quirks_mode);
                     Parser::new(&css).parse_entirely(|input| {
                         match from_shorthand {
                             None => {
                                 longhands::${property.ident}
                                          ::parse_specified(&context, input).map(DeclaredValueOwned::Value)
                             }
                             Some(ShorthandId::All) => {
                                 // No need to parse the 'all' shorthand as anything other than a CSS-wide
@@ -2111,17 +2116,18 @@ pub fn cascade(device: &Device,
                rule_node: &StrongRuleNode,
                pseudo: Option<<&PseudoElement>,
                guards: &StylesheetGuards,
                parent_style: Option<<&ComputedValues>,
                layout_parent_style: Option<<&ComputedValues>,
                cascade_info: Option<<&mut CascadeInfo>,
                error_reporter: &ParseErrorReporter,
                font_metrics_provider: &FontMetricsProvider,
-               flags: CascadeFlags)
+               flags: CascadeFlags,
+               quirks_mode: QuirksMode)
                -> ComputedValues {
     debug_assert_eq!(parent_style.is_some(), layout_parent_style.is_some());
     let (is_root_element, inherited_style, layout_parent_style) = match parent_style {
         Some(parent_style) => {
             (false,
              parent_style,
              layout_parent_style.unwrap())
         },
@@ -2157,32 +2163,34 @@ pub fn cascade(device: &Device,
                        is_root_element,
                        pseudo,
                        iter_declarations,
                        inherited_style,
                        layout_parent_style,
                        cascade_info,
                        error_reporter,
                        font_metrics_provider,
-                       flags)
+                       flags,
+                       quirks_mode)
 }
 
 /// NOTE: This function expects the declaration with more priority to appear
 /// first.
 #[allow(unused_mut)] // conditionally compiled code for "position"
 pub fn apply_declarations<'a, F, I>(device: &Device,
                                     is_root_element: bool,
                                     pseudo: Option<<&PseudoElement>,
                                     iter_declarations: F,
                                     inherited_style: &ComputedValues,
                                     layout_parent_style: &ComputedValues,
                                     mut cascade_info: Option<<&mut CascadeInfo>,
                                     error_reporter: &ParseErrorReporter,
                                     font_metrics_provider: &FontMetricsProvider,
-                                    flags: CascadeFlags)
+                                    flags: CascadeFlags,
+                                    quirks_mode: QuirksMode)
                                     -> ComputedValues
     where F: Fn() -> I,
           I: Iterator<Item = &'a PropertyDeclaration>,
 {
     let default_style = device.default_computed_values();
     let inherited_custom_properties = inherited_style.custom_properties();
     let mut custom_properties = None;
     let mut seen_custom = HashSet::new();
@@ -2225,16 +2233,17 @@ pub fn apply_declarations<'a, F, I>(devi
     let mut context = computed::Context {
         is_root_element: is_root_element,
         device: device,
         inherited_style: inherited_style,
         layout_parent_style: layout_parent_style,
         style: starting_style,
         font_metrics_provider: font_metrics_provider,
         in_media_query: false,
+        quirks_mode: quirks_mode,
     };
 
     // Set computed values, overwriting earlier declarations for the same
     // property.
     //
     // NB: The cacheable boolean is not used right now, but will be once we
     // start caching computed values in the rule nodes.
     let mut cacheable = true;
--- a/servo/components/style/properties/shorthand/background.mako.rs
+++ b/servo/components/style/properties/shorthand/background.mako.rs
@@ -189,27 +189,27 @@
         }
     }
 </%helpers:shorthand>
 
 <%helpers:shorthand name="background-position"
                     sub_properties="background-position-x background-position-y"
                     spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position">
     use properties::longhands::{background_position_x,background_position_y};
+    use values::specified::AllowQuirks;
     use values::specified::position::Position;
-    use parser::Parse;
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
         let mut position_x = background_position_x::SpecifiedValue(Vec::new());
         let mut position_y = background_position_y::SpecifiedValue(Vec::new());
         let mut any = false;
 
         try!(input.parse_comma_separated(|input| {
             loop {
-                if let Ok(value) = input.try(|input| Position::parse(context, input)) {
+                if let Ok(value) = input.try(|input| Position::parse_quirky(context, input, AllowQuirks::Yes)) {
                     position_x.0.push(value.horizontal);
                     position_y.0.push(value.vertical);
                     any = true;
                     continue
                 }
                 break
             }
             Ok(())
--- a/servo/components/style/properties/shorthand/border.mako.rs
+++ b/servo/components/style/properties/shorthand/border.mako.rs
@@ -12,21 +12,22 @@
                                "specified::BorderStyle::parse",
                                spec="https://drafts.csswg.org/css-backgrounds/#border-style")}
 
 <%helpers:shorthand name="border-width" sub_properties="${
         ' '.join('border-%s-width' % side
                  for side in PHYSICAL_SIDES)}"
     spec="https://drafts.csswg.org/css-backgrounds/#border-width">
     use super::parse_four_sides;
-    use parser::Parse;
-    use values::specified;
+    use values::specified::{AllowQuirks, BorderWidth};
 
     pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
-        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| specified::BorderWidth::parse(context, i)));
+        let (top, right, bottom, left) = try!(parse_four_sides(input, |i| {
+            BorderWidth::parse_quirky(context, i, AllowQuirks::Yes)
+        }));
         Ok(Longhands {
             % for side in PHYSICAL_SIDES:
                 ${to_rust_ident('border-%s-width' % side)}: ${side},
             % endfor
         })
     }
 
     impl<'a> ToCss for LonghandsToSerialize<'a>  {
--- a/servo/components/style/properties/shorthand/margin.mako.rs
+++ b/servo/components/style/properties/shorthand/margin.mako.rs
@@ -1,9 +1,10 @@
 /* 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" />
 
 ${helpers.four_sides_shorthand("margin", "margin-%s", "specified::LengthOrPercentageOrAuto::parse",
                                spec="https://drafts.csswg.org/css-box/#propdef-margin",
-                               allowed_in_page_rule=True)}
+                               allowed_in_page_rule=True,
+                               allow_quirks=True)}
--- a/servo/components/style/properties/shorthand/padding.mako.rs
+++ b/servo/components/style/properties/shorthand/padding.mako.rs
@@ -1,8 +1,9 @@
 /* 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" />
 
 ${helpers.four_sides_shorthand("padding", "padding-%s", "specified::LengthOrPercentage::parse",
-                               spec="https://drafts.csswg.org/css-box-3/#propdef-padding")}
+                               spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
+                               allow_quirks=True)}
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Servo's media-query device and expression representation.
 
 use app_units::Au;
+use context::QuirksMode;
 use cssparser::Parser;
 use euclid::{Size2D, TypedSize2D};
 use font_metrics::ServoMetricsProvider;
 use media_queries::MediaType;
 use parser::ParserContext;
 use properties::ComputedValues;
 use std::fmt;
 use style_traits::{CSSPixel, ToCss};
@@ -123,22 +124,22 @@ impl Expression {
                 },
                 _ => return Err(())
             }))
         })
     }
 
     /// Evaluate this expression and return whether it matches the current
     /// device.
-    pub fn matches(&self, device: &Device) -> bool {
+    pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool {
         let viewport_size = device.au_viewport_size();
         let value = viewport_size.width;
         match self.0 {
             ExpressionKind::Width(ref range) => {
-                match range.to_computed_range(device) {
+                match range.to_computed_range(device, quirks_mode) {
                     Range::Min(ref width) => { value >= *width },
                     Range::Max(ref width) => { value <= *width },
                     Range::Eq(ref width) => { value == *width },
                 }
             }
         }
     }
 }
@@ -170,33 +171,34 @@ pub enum Range<T> {
     Min(T),
     /// At most the inner value.
     Max(T),
     /// Exactly the inner value.
     Eq(T),
 }
 
 impl Range<specified::Length> {
-    fn to_computed_range(&self, device: &Device) -> Range<Au> {
+    fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
         let default_values = device.default_computed_values();
         // http://dev.w3.org/csswg/mediaqueries3/#units
         // em units are relative to the initial font-size.
         let context = computed::Context {
             is_root_element: false,
             device: device,
             inherited_style: default_values,
             layout_parent_style: default_values,
             // This cloning business is kind of dumb.... It's because Context
             // insists on having an actual ComputedValues inside itself.
             style: default_values.clone(),
             // Servo doesn't support font metrics
             // A real provider will be needed here once we do; since
             // ch units can exist in media queries.
             font_metrics_provider: &ServoMetricsProvider,
             in_media_query: true,
+            quirks_mode: quirks_mode,
         };
 
         match *self {
             Range::Min(ref width) => Range::Min(width.to_computed_value(&context)),
             Range::Max(ref width) => Range::Max(width.to_computed_value(&context)),
             Range::Eq(ref width) => Range::Eq(width.to_computed_value(&context))
         }
     }
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Style sheets and their CSS rules.
 
 #![deny(missing_docs)]
 
 use {Atom, Prefix, Namespace};
+use context::QuirksMode;
 use counter_style::{CounterStyleRule, parse_counter_style_name, parse_counter_style_body};
 use cssparser::{AtRuleParser, Parser, QualifiedRuleParser};
 use cssparser::{AtRuleType, RuleListParser, parse_one_rule};
 use cssparser::ToCss as ParserToCss;
 use error_reporting::{ParseErrorReporter, NullReporter};
 #[cfg(feature = "servo")]
 use font_face::FontFaceRuleData;
 use font_face::parse_font_face_block;
@@ -258,16 +259,18 @@ pub struct Stylesheet {
     /// The lock used for objects inside this stylesheet
     pub shared_lock: SharedRwLock,
     /// The namespaces that apply to this stylesheet.
     pub namespaces: RwLock<Namespaces>,
     /// Whether this stylesheet would be dirty when the viewport size changes.
     pub dirty_on_viewport_size_change: AtomicBool,
     /// Whether this stylesheet should be disabled.
     pub disabled: AtomicBool,
+    /// The quirks mode of this stylesheet.
+    pub quirks_mode: QuirksMode,
 }
 
 
 /// This structure holds the user-agent and user stylesheets.
 pub struct UserAgentStylesheets {
     /// The lock used for user-agent stylesheets.
     pub shared_lock: SharedRwLock,
     /// The user or user agent stylesheets.
@@ -410,17 +413,18 @@ impl CssRule {
                  loader: Option<&StylesheetLoader>)
                  -> Result<(Self, State), SingleRuleParseError> {
         let error_reporter = NullReporter;
         let mut namespaces = parent_stylesheet.namespaces.write();
         let context = ParserContext::new(parent_stylesheet.origin,
                                          &parent_stylesheet.url_data,
                                          &error_reporter,
                                          None,
-                                         LengthParsingMode::Default);
+                                         LengthParsingMode::Default,
+                                         parent_stylesheet.quirks_mode);
         let mut input = Parser::new(css);
 
         // nested rules are in the body state
         let state = state.unwrap_or(State::Body);
         let mut rule_parser = TopLevelRuleParser {
             stylesheet_origin: parent_stylesheet.origin,
             context: context,
             shared_lock: &parent_stylesheet.shared_lock,
@@ -658,17 +662,17 @@ impl Stylesheet {
                            stylesheet_loader: Option<&StylesheetLoader>,
                            error_reporter: &ParseErrorReporter) {
         let mut namespaces = Namespaces::default();
         // FIXME: we really should update existing.url_data with the given url_data,
         // otherwise newly inserted rule may not have the right base url.
         let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
             css, url_data, existing.origin, &mut namespaces,
             &existing.shared_lock, stylesheet_loader, error_reporter,
-            0u64);
+            existing.quirks_mode, 0u64);
 
         *existing.namespaces.write() = namespaces;
         existing.dirty_on_viewport_size_change
             .store(dirty_on_viewport_size_change, Ordering::Release);
 
         // Acquire the lock *after* parsing, to minimize the exclusive section.
         let mut guard = existing.shared_lock.write();
         *existing.rules.write_with(&mut guard) = CssRules(rules);
@@ -676,27 +680,29 @@ impl Stylesheet {
 
     fn parse_rules(css: &str,
                    url_data: &UrlExtraData,
                    origin: Origin,
                    namespaces: &mut Namespaces,
                    shared_lock: &SharedRwLock,
                    stylesheet_loader: Option<&StylesheetLoader>,
                    error_reporter: &ParseErrorReporter,
+                   quirks_mode: QuirksMode,
                    line_number_offset: u64)
                    -> (Vec<CssRule>, bool) {
         let mut rules = Vec::new();
         let mut input = Parser::new(css);
         let rule_parser = TopLevelRuleParser {
             stylesheet_origin: origin,
             namespaces: namespaces,
             shared_lock: shared_lock,
             loader: stylesheet_loader,
             context: ParserContext::new_with_line_number_offset(origin, url_data, error_reporter,
-                                                                line_number_offset, LengthParsingMode::Default),
+                                                                line_number_offset, LengthParsingMode::Default,
+                                                                quirks_mode),
             state: Cell::new(State::Start),
         };
 
         input.look_for_viewport_percentages();
 
         {
             let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
             while let Some(result) = iter.next() {
@@ -721,31 +727,34 @@ impl Stylesheet {
     /// `Stylesheet::update_from_str`.
     pub fn from_str(css: &str,
                     url_data: UrlExtraData,
                     origin: Origin,
                     media: Arc<Locked<MediaList>>,
                     shared_lock: SharedRwLock,
                     stylesheet_loader: Option<&StylesheetLoader>,
                     error_reporter: &ParseErrorReporter,
-                    line_number_offset: u64) -> Stylesheet {
+                    quirks_mode: QuirksMode,
+                    line_number_offset: u64)
+                    -> Stylesheet {
         let mut namespaces = Namespaces::default();
         let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
             css, &url_data, origin, &mut namespaces,
-            &shared_lock, stylesheet_loader, error_reporter, line_number_offset
+            &shared_lock, stylesheet_loader, error_reporter, quirks_mode, line_number_offset,
         );
         Stylesheet {
             origin: origin,
             url_data: url_data,
             namespaces: RwLock::new(namespaces),
             rules: CssRules::new(rules, &shared_lock),
             media: media,
             shared_lock: shared_lock,
             dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change),
             disabled: AtomicBool::new(false),
+            quirks_mode: quirks_mode,
         }
     }
 
     /// Whether this stylesheet can be dirty on viewport size change.
     pub fn dirty_on_viewport_size_change(&self) -> bool {
         self.dirty_on_viewport_size_change.load(Ordering::SeqCst)
     }
 
@@ -764,29 +773,29 @@ impl Stylesheet {
         self.dirty_on_viewport_size_change.fetch_or(has_viewport_percentages, Ordering::SeqCst);
     }
 
     /// Returns whether the style-sheet applies for the current device depending
     /// on the associated MediaList.
     ///
     /// Always true if no associated MediaList exists.
     pub fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool {
-        self.media.read_with(guard).evaluate(device)
+        self.media.read_with(guard).evaluate(device, self.quirks_mode)
     }
 
     /// Return an iterator over the effective rules within the style-sheet, as
     /// according to the supplied `Device`.
     ///
     /// If a condition does not hold, its associated conditional group rule and
     /// nested rules will be skipped. Use `rules` if all rules need to be
     /// examined.
     #[inline]
     pub fn effective_rules<F>(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F)
     where F: FnMut(&CssRule) {
-        effective_rules(&self.rules.read_with(guard).0, device, guard, &mut f);
+        effective_rules(&self.rules.read_with(guard).0, device, self.quirks_mode, guard, &mut f);
     }
 
     /// Returns whether the stylesheet has been explicitly disabled through the
     /// CSSOM.
     pub fn disabled(&self) -> bool {
         self.disabled.load(Ordering::SeqCst)
     }
 
@@ -797,27 +806,32 @@ impl Stylesheet {
     ///
     /// Disabled stylesheets remain in the document, but their rules are not
     /// added to the Stylist.
     pub fn set_disabled(&self, disabled: bool) -> bool {
         self.disabled.swap(disabled, Ordering::SeqCst) != disabled
     }
 }
 
-fn effective_rules<F>(rules: &[CssRule], device: &Device, guard: &SharedRwLockReadGuard, f: &mut F)
-where F: FnMut(&CssRule) {
+fn effective_rules<F>(rules: &[CssRule],
+                      device: &Device,
+                      quirks_mode: QuirksMode,
+                      guard: &SharedRwLockReadGuard,
+                      f: &mut F)
+    where F: FnMut(&CssRule)
+{
     for rule in rules {
         f(rule);
         rule.with_nested_rules_and_mq(guard, |rules, mq| {
             if let Some(media_queries) = mq {
-                if !media_queries.evaluate(device) {
+                if !media_queries.evaluate(device, quirks_mode) {
                     return
                 }
             }
-            effective_rules(rules, device, guard, f)
+            effective_rules(rules, device, quirks_mode, guard, f)
         })
     }
 }
 
 macro_rules! rule_filter {
     ($( $method: ident($variant:ident => $rule_type: ident), )+) => {
         impl Stylesheet {
             $(
@@ -968,16 +982,17 @@ impl<'a> AtRuleParser for TopLevelRulePa
                                 rules: CssRules::new(Vec::new(), self.shared_lock),
                                 media: media,
                                 shared_lock: self.shared_lock.clone(),
                                 origin: self.context.stylesheet_origin,
                                 url_data: self.context.url_data.clone(),
                                 namespaces: RwLock::new(Namespaces::default()),
                                 dirty_on_viewport_size_change: AtomicBool::new(false),
                                 disabled: AtomicBool::new(false),
+                                quirks_mode: self.context.quirks_mode,
                             })
                         }
                     }, &mut |import_rule| {
                         Arc::new(self.shared_lock.wrap(import_rule))
                     });
                     return Ok(AtRuleType::WithoutBlock(CssRule::Import(arc)))
                 } else {
                     self.state.set(State::Invalid);
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Selector matching.
 
 #![deny(missing_docs)]
 
 use {Atom, LocalName};
 use bit_vec::BitVec;
+use context::QuirksMode;
 use data::ComputedStyle;
 use dom::{AnimationRules, PresentationalHintsSynthetizer, TElement};
 use error_reporting::RustLogReporter;
 use font_metrics::FontMetricsProvider;
 use keyframes::KeyframesAnimation;
 use media_queries::Device;
 use pdqsort::sort_by;
 use properties::{self, CascadeFlags, ComputedValues};
@@ -71,17 +72,17 @@ pub struct Stylist {
     /// In both cases, the device is actually _owned_ by the Stylist, and it's
     /// only an `Arc` so we can implement `add_stylesheet` more idiomatically.
     pub device: Arc<Device>,
 
     /// Viewport constraints based on the current device.
     viewport_constraints: Option<ViewportConstraints>,
 
     /// If true, the quirks-mode stylesheet is applied.
-    quirks_mode: bool,
+    quirks_mode: QuirksMode,
 
     /// If true, the device has changed, and the stylist needs to be updated.
     is_device_dirty: bool,
 
     /// The current selector maps, after evaluating media
     /// rules against the current device.
     element_map: PerPseudoElementSelectorMap,
 
@@ -161,17 +162,17 @@ impl<'a> ExtraStyleData<'a> {
 impl Stylist {
     /// Construct a new `Stylist`, using a given `Device`.
     #[inline]
     pub fn new(device: Device) -> Self {
         let mut stylist = Stylist {
             viewport_constraints: None,
             device: Arc::new(device),
             is_device_dirty: true,
-            quirks_mode: false,
+            quirks_mode: QuirksMode::NoQuirks,
 
             element_map: PerPseudoElementSelectorMap::new(),
             pseudos_map: Default::default(),
             animations: Default::default(),
             precomputed_pseudo_element_decls: Default::default(),
             rules_source_order: 0,
             rule_tree: RuleTree::new(),
             dependencies: DependencySet::new(),
@@ -235,17 +236,17 @@ impl Stylist {
 
         let cascaded_rule = ViewportRule {
             declarations: viewport::Cascade::from_stylesheets(
                 doc_stylesheets, guards.author, &self.device
             ).finish(),
         };
 
         self.viewport_constraints =
-            ViewportConstraints::maybe_new(&self.device, &cascaded_rule);
+            ViewportConstraints::maybe_new(&self.device, &cascaded_rule, self.quirks_mode);
 
         if let Some(ref constraints) = self.viewport_constraints {
             Arc::get_mut(&mut self.device).unwrap()
                 .account_for_viewport_rule(constraints);
         }
 
         self.element_map = PerPseudoElementSelectorMap::new();
         self.pseudos_map = Default::default();
@@ -264,17 +265,17 @@ impl Stylist {
 
         extra_data.clear_font_faces();
 
         if let Some(ua_stylesheets) = ua_stylesheets {
             for stylesheet in &ua_stylesheets.user_or_user_agent_stylesheets {
                 self.add_stylesheet(&stylesheet, guards.ua_or_user, extra_data);
             }
 
-            if self.quirks_mode {
+            if self.quirks_mode != QuirksMode::NoQuirks {
                 self.add_stylesheet(&ua_stylesheets.quirks_mode_stylesheet,
                                     guards.ua_or_user, extra_data);
             }
         }
 
         // Only use author stylesheets if author styles are enabled.
         let sheets_to_add = doc_stylesheets.iter().filter(|s| {
             !author_style_disabled || s.origin != Origin::Author
@@ -419,17 +420,18 @@ impl Stylist {
                                 &rule_node,
                                 Some(pseudo),
                                 guards,
                                 parent.map(|p| &**p),
                                 parent.map(|p| &**p),
                                 None,
                                 &RustLogReporter,
                                 font_metrics,
-                                cascade_flags);
+                                cascade_flags,
+                                self.quirks_mode);
         ComputedStyle::new(rule_node, Arc::new(computed))
     }
 
     /// Returns the style for an anonymous box of the given type.
     #[cfg(feature = "servo")]
     pub fn style_for_anonymous(&self,
                                guards: &StylesheetGuards,
                                pseudo: &PseudoElement,
@@ -543,17 +545,18 @@ impl Stylist {
                                 &rule_node,
                                 Some(pseudo),
                                 guards,
                                 Some(&**parent),
                                 Some(&**parent),
                                 None,
                                 &RustLogReporter,
                                 font_metrics,
-                                CascadeFlags::empty());
+                                CascadeFlags::empty(),
+                                self.quirks_mode);
 
         Some(ComputedStyle::new(rule_node, Arc::new(computed)))
     }
 
     /// Set a given device, which may change the styles that apply to the
     /// document.
     ///
     /// This means that we may need to rebuild style data even if the
@@ -576,66 +579,66 @@ impl Stylist {
     #[cfg(feature = "servo")]
     pub fn set_device(&mut self, mut device: Device, guard: &SharedRwLockReadGuard,
                       stylesheets: &[Arc<Stylesheet>]) {
         let cascaded_rule = ViewportRule {
             declarations: viewport::Cascade::from_stylesheets(stylesheets, guard, &device).finish(),
         };
 
         self.viewport_constraints =
-            ViewportConstraints::maybe_new(&device, &cascaded_rule);
+            ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode);
 
         if let Some(ref constraints) = self.viewport_constraints {
             device.account_for_viewport_rule(constraints);
         }
 
         fn mq_eval_changed(guard: &SharedRwLockReadGuard, rules: &[CssRule],
-                           before: &Device, after: &Device) -> bool {
+                           before: &Device, after: &Device, quirks_mode: QuirksMode) -> bool {
             for rule in rules {
                 let changed = rule.with_nested_rules_and_mq(guard, |rules, mq| {
                     if let Some(mq) = mq {
-                        if mq.evaluate(before) != mq.evaluate(after) {
+                        if mq.evaluate(before, quirks_mode) != mq.evaluate(after, quirks_mode) {
                             return true
                         }
                     }
-                    mq_eval_changed(guard, rules, before, after)
+                    mq_eval_changed(guard, rules, before, after, quirks_mode)
                 });
                 if changed {
                     return true
                 }
             }
             false
         }
         self.is_device_dirty |= stylesheets.iter().any(|stylesheet| {
             let mq = stylesheet.media.read_with(guard);
-            if mq.evaluate(&self.device) != mq.evaluate(&device) {
+            if mq.evaluate(&self.device, self.quirks_mode) != mq.evaluate(&device, self.quirks_mode) {
                 return true
             }
 
-            mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device)
+            mq_eval_changed(guard, &stylesheet.rules.read_with(guard).0, &self.device, &device, self.quirks_mode)
         });
 
         self.device = Arc::new(device);
     }
 
     /// Returns the viewport constraints that apply to this document because of
     /// a @viewport rule.
     pub fn viewport_constraints(&self) -> Option<&ViewportConstraints> {
         self.viewport_constraints.as_ref()
     }
 
     /// Sets the quirks mode of the document.
-    pub fn set_quirks_mode(&mut self, enabled: bool) {
+    pub fn set_quirks_mode(&mut self, quirks_mode: QuirksMode) {
         // FIXME(emilio): We don't seem to change the quirks mode dynamically
         // during multiple layout passes, but this is totally bogus, in the
         // sense that it's updated asynchronously.
         //
         // This should probably be an argument to `update`, and use the quirks
         // mode info in the `SharedLayoutContext`.
-        self.quirks_mode = enabled;
+        self.quirks_mode = quirks_mode;
     }
 
     /// Returns the applicable CSS declarations for the given element.
     ///
     /// This corresponds to `ElementRuleCollector` in WebKit.
     ///
     /// The returned `StyleRelations` indicate hints about which kind of rules
     /// have matched.
@@ -888,17 +891,18 @@ impl Stylist {
                                      &rule_node,
                                      None,
                                      guards,
                                      Some(parent_style),
                                      Some(parent_style),
                                      None,
                                      &RustLogReporter,
                                      &metrics,
-                                     CascadeFlags::empty()))
+                                     CascadeFlags::empty(),
+                                     self.quirks_mode))
     }
 }
 
 impl Drop for Stylist {
     fn drop(&mut self) {
         // This is the last chance to GC the rule tree.  If we have dropped all
         // strong rule node references before the Stylist is dropped, then this
         // will cause the rule tree to be destroyed correctly.  If we haven't
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Computed values.
 
+use context::QuirksMode;
 use euclid::size::Size2D;
 use font_metrics::FontMetricsProvider;
 use media_queries::Device;
 use properties::ComputedValues;
 use std::fmt;
 use style_traits::ToCss;
 use super::{CSSFloat, CSSInteger, RGBA};
 use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
@@ -58,16 +59,19 @@ pub struct Context<'a> {
     pub style: ComputedValues,
 
     /// A font metrics provider, used to access font metrics to implement
     /// font-relative units.
     pub font_metrics_provider: &'a FontMetricsProvider,
 
     /// Whether or not we are computing the media list in a media query
     pub in_media_query: bool,
+
+    /// The quirks mode of this context.
+    pub quirks_mode: QuirksMode,
 }
 
 impl<'a> Context<'a> {
     /// Whether the current element is the root element.
     pub fn is_root_element(&self) -> bool { self.is_root_element }
     /// The current viewport size.
     pub fn viewport_size(&self) -> Size2D<Au> { self.device.au_viewport_size() }
     /// The style we're inheriting from.
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -12,17 +12,17 @@ use euclid::size::Size2D;
 use font_metrics::FontMetricsQueryResult;
 use parser::{Parse, ParserContext};
 use std::{cmp, fmt, mem};
 use std::ascii::AsciiExt;
 use std::ops::Mul;
 use style_traits::ToCss;
 use style_traits::values::specified::AllowedLengthType;
 use stylesheets::CssRuleType;
-use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time, ToComputedValue};
+use super::{AllowQuirks, Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time, ToComputedValue};
 use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal};
 use values::ExtremumLength;
 use values::computed::{ComputedValueAsSpecified, Context};
 
 pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use super::image::{SizeKeyword, VerticalDirection};
 
@@ -558,39 +558,52 @@ impl Length {
     }
 
     /// Parse a given absolute or relative dimension.
     pub fn parse_dimension(context: &ParserContext, value: CSSFloat, unit: &str) -> Result<Length, ()> {
         NoCalcLength::parse_dimension(context, value, unit).map(Length::NoCalc)
     }
 
     #[inline]
-    fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType)
+    fn parse_internal(context: &ParserContext,
+                      input: &mut Parser,
+                      num_context: AllowedLengthType,
+                      allow_quirks: AllowQuirks)
                       -> Result<Length, ()> {
         match try!(input.next()) {
             Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
                 Length::parse_dimension(context, value.value, unit),
-            Token::Number(ref value) => {
-                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() {
+            Token::Number(ref value) if num_context.is_ok(value.value) => {
+                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() &&
+                   !allow_quirks.allowed(context.quirks_mode) {
                     return Err(())
                 }
                 Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(value.value))))
             },
             Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
                 input.parse_nested_block(|input| {
                     CalcLengthOrPercentage::parse_length(context, input, num_context)
                 }),
             _ => Err(())
         }
     }
 
     /// Parse a non-negative length
     #[inline]
     pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Length, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::NonNegative)
+        Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
+    }
+
+    /// Parse a non-negative length, allowing quirks.
+    #[inline]
+    pub fn parse_non_negative_quirky(context: &ParserContext,
+                                     input: &mut Parser,
+                                     allow_quirks: AllowQuirks)
+                                     -> Result<Length, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
     }
 
     /// Get an absolute length from a px value.
     #[inline]
     pub fn from_px(px_value: CSSFloat) -> Length {
         Length::NoCalc(NoCalcLength::from_px(px_value))
     }
 
@@ -600,28 +613,38 @@ impl Length {
     #[inline]
     pub fn take(&mut self) -> Self {
         mem::replace(self, Length::zero())
     }
 }
 
 impl Parse for Length {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::All)
+        Self::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl Length {
+    /// Parses a length, with quirks.
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks)
+                        -> Result<Self, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
     }
 }
 
 impl<T: Parse> Either<Length, T> {
     /// Parse a non-negative length
     #[inline]
     pub fn parse_non_negative_length(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         if let Ok(v) = input.try(|input| T::parse(context, input)) {
             return Ok(Either::Second(v));
         }
-        Length::parse_internal(context, input, AllowedLengthType::NonNegative).map(Either::First)
+        Length::parse_internal(context, input, AllowedLengthType::NonNegative, AllowQuirks::No).map(Either::First)
     }
 }
 
 /// A calc sum expression node.
 #[derive(Clone, Debug)]
 pub struct CalcSumNode {
     /// The products of this node.
     pub products: Vec<CalcProductNode>,
@@ -1149,67 +1172,76 @@ impl ToCss for LengthOrPercentage {
 
 impl LengthOrPercentage {
     #[inline]
     /// Returns a `zero` length.
     pub fn zero() -> LengthOrPercentage {
         LengthOrPercentage::Length(NoCalcLength::zero())
     }
 
-    fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType)
+    fn parse_internal(context: &ParserContext,
+                      input: &mut Parser,
+                      num_context: AllowedLengthType,
+                      allow_quirks: AllowQuirks)
                       -> Result<LengthOrPercentage, ()>
     {
         match try!(input.next()) {
             Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
                 NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length),
             Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
                 Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
-            Token::Number(ref value) => {
-                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() {
-                    return Err(())
-                }
-                Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(value.value))))
-            }
+            Token::Number(value) if value.value == 0. ||
+                                    (num_context.is_ok(value.value) && allow_quirks.allowed(context.quirks_mode)) =>
+                Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))),
             Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
                 let calc = try!(input.parse_nested_block(|i| {
                     CalcLengthOrPercentage::parse_length_or_percentage(context, i)
                 }));
                 Ok(LengthOrPercentage::Calc(Box::new(calc)))
             },
             _ => Err(())
         }
     }
 
     /// Parse a non-negative length.
     #[inline]
     pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::NonNegative)
+        Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
+    }
+
+    /// Parse a non-negative length, with quirks.
+    #[inline]
+    pub fn parse_non_negative_quirky(context: &ParserContext,
+                                     input: &mut Parser,
+                                     allow_quirks: AllowQuirks)
+                                     -> Result<LengthOrPercentage, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
     }
 
     /// Parse a length, treating dimensionless numbers as pixels
     ///
     /// https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value
     pub fn parse_numbers_are_pixels(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentage, ()> {
-        if let Ok(lop) = input.try(|i| Self::parse_internal(context, i, AllowedLengthType::All)) {
+        if let Ok(lop) = input.try(|i| Self::parse(context, i)) {
             return Ok(lop)
         }
 
         // TODO(emilio): Probably should use Number::parse_non_negative to
         // handle calc()?
         let num = input.expect_number()?;
         Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(num))))
     }
 
     /// Parse a non-negative length, treating dimensionless numbers as pixels
     ///
     /// This is nonstandard behavior used by Firefox for SVG
     pub fn parse_numbers_are_pixels_non_negative(context: &ParserContext,
                                                  input: &mut Parser)
                                                  -> Result<LengthOrPercentage, ()> {
-        if let Ok(lop) = input.try(|i| Self::parse_internal(context, i, AllowedLengthType::NonNegative)) {
+        if let Ok(lop) = input.try(|i| Self::parse_non_negative(context, i)) {
             return Ok(lop)
         }
 
         // TODO(emilio): Probably should use Number::parse_non_negative to
         // handle calc()?
         let num = input.expect_number()?;
         if num >= 0. {
             Ok(LengthOrPercentage::Length(NoCalcLength::Absolute(AbsoluteLength::Px(num))))
@@ -1225,17 +1257,28 @@ impl LengthOrPercentage {
     pub fn take(&mut self) -> Self {
         mem::replace(self, LengthOrPercentage::zero())
     }
 }
 
 impl Parse for LengthOrPercentage {
     #[inline]
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::All)
+        Self::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl LengthOrPercentage {
+    /// Parses a length or a percentage, allowing the unitless length quirk.
+    /// https://quirks.spec.whatwg.org/#the-unitless-length-quirk
+    #[inline]
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks) -> Result<Self, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
     }
 }
 
 /// TODO(emilio): Do the Length and Percentage variants make any sense with
 /// CalcLengthOrPercentage?
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
@@ -1278,25 +1321,29 @@ impl ToCss for LengthOrPercentageOrAuto 
             LengthOrPercentageOrAuto::Percentage(percentage) => percentage.to_css(dest),
             LengthOrPercentageOrAuto::Auto => dest.write_str("auto"),
             LengthOrPercentageOrAuto::Calc(ref calc) => calc.to_css(dest),
         }
     }
 }
 
 impl LengthOrPercentageOrAuto {
-    fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType)
+    fn parse_internal(context: &ParserContext,
+                      input: &mut Parser,
+                      num_context: AllowedLengthType,
+                      allow_quirks: AllowQuirks)
                       -> Result<Self, ()> {
         match try!(input.next()) {
             Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
                 NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrAuto::Length),
             Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
                 Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))),
-            Token::Number(ref value) if value.value == 0. => {
-                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() {
+            Token::Number(ref value) if num_context.is_ok(value.value) => {
+                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() &&
+                   !allow_quirks.allowed(context.quirks_mode) {
                     return Err(())
                 }
                 Ok(LengthOrPercentageOrAuto::Length(
                     NoCalcLength::Absolute(AbsoluteLength::Px(value.value))
                 ))
             }
             Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =>
                 Ok(LengthOrPercentageOrAuto::Auto),
@@ -1308,34 +1355,54 @@ impl LengthOrPercentageOrAuto {
             },
             _ => Err(())
         }
     }
 
     /// Parse a non-negative length, percentage, or auto.
     #[inline]
     pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::NonNegative)
+        Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
+    }
+
+    /// Parse a non-negative length, percentage, or auto.
+    #[inline]
+    pub fn parse_non_negative_quirky(context: &ParserContext,
+                                     input: &mut Parser,
+                                     allow_quirks: AllowQuirks)
+                                     -> Result<Self, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
     }
 
     /// Returns the `auto` value.
     pub fn auto() -> Self {
         LengthOrPercentageOrAuto::Auto
     }
 
     /// Returns a value representing a `0` length.
     pub fn zero() -> Self {
         LengthOrPercentageOrAuto::Length(NoCalcLength::zero())
     }
 }
 
 impl Parse for LengthOrPercentageOrAuto {
     #[inline]
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::All)
+        Self::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl LengthOrPercentageOrAuto {
+    /// Parses, with quirks.
+    #[inline]
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks)
+                        -> Result<Self, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::All, allow_quirks)
     }
 }
 
 /// TODO(emilio): Do the Length and Percentage variants make any sense with
 /// CalcLengthOrPercentage?
 #[derive(Clone, PartialEq, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
@@ -1362,26 +1429,30 @@ impl ToCss for LengthOrPercentageOrNone 
             LengthOrPercentageOrNone::Length(ref length) => length.to_css(dest),
             LengthOrPercentageOrNone::Percentage(ref percentage) => percentage.to_css(dest),
             LengthOrPercentageOrNone::Calc(ref calc) => calc.to_css(dest),
             LengthOrPercentageOrNone::None => dest.write_str("none"),
         }
     }
 }
 impl LengthOrPercentageOrNone {
-    fn parse_internal(context: &ParserContext, input: &mut Parser, num_context: AllowedLengthType)
+    fn parse_internal(context: &ParserContext,
+                      input: &mut Parser,
+                      num_context: AllowedLengthType,
+                      allow_quirks: AllowQuirks)
                       -> Result<LengthOrPercentageOrNone, ()>
     {
         match try!(input.next()) {
             Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
                 NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentageOrNone::Length),
             Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
                 Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))),
-            Token::Number(ref value) if value.value == 0. => {
-                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() {
+            Token::Number(value) if num_context.is_ok(value.value) => {
+                if value.value != 0. && !context.length_parsing_mode.allows_unitless_lengths() &&
+                   !allow_quirks.allowed(context.quirks_mode) {
                     return Err(())
                 }
                 Ok(LengthOrPercentageOrNone::Length(
                     NoCalcLength::Absolute(AbsoluteLength::Px(value.value))
                 ))
             }
             Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
                 let calc = try!(input.parse_nested_block(|i| {
@@ -1389,27 +1460,37 @@ impl LengthOrPercentageOrNone {
                 }));
                 Ok(LengthOrPercentageOrNone::Calc(Box::new(calc)))
             },
             Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
                 Ok(LengthOrPercentageOrNone::None),
             _ => Err(())
         }
     }
+
     /// Parse a non-negative LengthOrPercentageOrNone.
     #[inline]
     pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::NonNegative)
+        Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
+    }
+
+    /// Parse a non-negative LengthOrPercentageOrNone, with quirks.
+    #[inline]
+    pub fn parse_non_negative_quirky(context: &ParserContext,
+                                     input: &mut Parser,
+                                     allow_quirks: AllowQuirks)
+                                     -> Result<Self, ()> {
+        Self::parse_internal(context, input, AllowedLengthType::NonNegative, allow_quirks)
     }
 }
 
 impl Parse for LengthOrPercentageOrNone {
     #[inline]
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        Self::parse_internal(context, input, AllowedLengthType::All)
+        Self::parse_internal(context, input, AllowedLengthType::All, AllowQuirks::No)
     }
 }
 
 /// Either a `<length>` or the `none` keyword.
 pub type LengthOrNone = Either<Length, None_>;
 
 /// Either a `<length>` or the `normal` keyword.
 pub type LengthOrNormal = Either<Length, Normal>;
@@ -1543,18 +1624,27 @@ impl ToCss for MinLength {
             MinLength::ExtremumLength(ref ext) =>
                 ext.to_css(dest),
         }
     }
 }
 
 impl Parse for MinLength {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        MinLength::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl MinLength {
+    /// Parses, with quirks.
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks) -> Result<Self, ()> {
         input.try(ExtremumLength::parse).map(MinLength::ExtremumLength)
-            .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative(context, i))
+            .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks))
                                .map(MinLength::LengthOrPercentage))
             .or_else(|()| input.expect_ident_matching("auto").map(|()| MinLength::Auto))
     }
 }
 
 /// A value suitable for a `max-width` or `max-height` property.
 #[derive(Debug, Clone, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@@ -1584,18 +1674,27 @@ impl ToCss for MaxLength {
             MaxLength::ExtremumLength(ref ext) =>
                 ext.to_css(dest),
         }
     }
 }
 
 impl Parse for MaxLength {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        MaxLength::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl MaxLength {
+    /// Parses, with quirks.
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks) -> Result<Self, ()> {
         input.try(ExtremumLength::parse).map(MaxLength::ExtremumLength)
-            .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative(context, i))
+            .or_else(|()| input.try(|i| LengthOrPercentage::parse_non_negative_quirky(context, i, allow_quirks))
                                .map(MaxLength::LengthOrPercentage))
             .or_else(|()| {
                 match_ignore_ascii_case! { &try!(input.expect_ident()),
                     "none" =>
                         Ok(MaxLength::None),
                     _ => Err(())
                 }
             })
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Specified values.
 //!
 //! TODO(emilio): Enhance docs.
 
 use app_units::Au;
+use context::QuirksMode;
 use cssparser::{self, Parser, Token};
 use euclid::size::Size2D;
 use parser::{ParserContext, Parse};
 use self::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 use self::url::SpecifiedUrl;
 use std::ascii::AsciiExt;
 use std::f32;
 use std::f32::consts::PI;
@@ -485,17 +486,27 @@ pub enum BorderWidth {
     Thin,
     Medium,
     Thick,
     Width(Length),
 }
 
 impl Parse for BorderWidth {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<BorderWidth, ()> {
-        match input.try(|i| Length::parse_non_negative(context, i)) {
+        Self::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl BorderWidth {
+    /// Parses a border width, allowing quirks.
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks)
+                        -> Result<BorderWidth, ()> {
+        match input.try(|i| Length::parse_non_negative_quirky(context, i, allow_quirks)) {
             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(())
             }
         }
@@ -1276,23 +1287,23 @@ impl ToComputedValue for ClipRect {
             bottom: computed.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)),
             left: computed.left.map(|left| ToComputedValue::from_computed_value(&left)),
         }
     }
 }
 
 impl Parse for ClipRect {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        use values::specified::Length;
+        use values::specified::{AllowQuirks, 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(context, input).map(Some)
+                Length::parse_quirky(context, input, AllowQuirks::Yes).map(Some)
             }
         }
 
         if !try!(input.expect_function()).eq_ignore_ascii_case("rect") {
             return Err(())
         }
 
         input.parse_nested_block(|input| {
@@ -1322,8 +1333,24 @@ impl Parse for ClipRect {
     }
 }
 
 /// rect(...) | auto
 pub type ClipRectOrAuto = Either<ClipRect, Auto>;
 
 /// <color> | auto
 pub type ColorOrAuto = Either<CSSColor, Auto>;
+
+/// Whether quirks are allowed in this context.
+#[derive(Clone, Copy, PartialEq)]
+pub enum AllowQuirks {
+    /// Quirks are allowed.
+    Yes,
+    /// Quirks are not allowed.
+    No,
+}
+
+impl AllowQuirks {
+    /// Returns `true` if quirks are allowed in this context.
+    pub fn allowed(self, quirks_mode: QuirksMode) -> bool {
+        self == AllowQuirks::Yes && quirks_mode == QuirksMode::Quirks
+    }
+}
--- a/servo/components/style/values/specified/position.rs
+++ b/servo/components/style/values/specified/position.rs
@@ -14,17 +14,17 @@ use properties::longhands::parse_origin;
 use std::mem;
 use values::Either;
 use values::computed::{CalcLengthOrPercentage, Context};
 use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue};
 use values::computed::position as computed_position;
 use values::generics::position::{Position as GenericPosition, PositionValue, PositionWithKeyword};
 use values::generics::position::HorizontalPosition as GenericHorizontalPosition;
 use values::generics::position::VerticalPosition as GenericVerticalPosition;
-use values::specified::{LengthOrPercentage, Percentage};
+use values::specified::{AllowQuirks, LengthOrPercentage, Percentage};
 
 pub use values::generics::position::Keyword;
 
 /// The specified value of a CSS `<position>`
 pub type Position = PositionWithKeyword<PositionValue<LengthOrPercentage>>;
 
 /// The specified value for `<position>` values without a keyword.
 pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>;
@@ -127,23 +127,33 @@ impl Position {
                 position: None,
             }),
         }
     }
 }
 
 impl Parse for Position {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        let first = input.try(|i| PositionComponent::parse(context, i))?;
-        let second = input.try(|i| PositionComponent::parse(context, i))
+        Position::parse_quirky(context, input, AllowQuirks::No)
+    }
+}
+
+impl Position {
+    /// Parses, with quirks.
+    pub fn parse_quirky(context: &ParserContext,
+                        input: &mut Parser,
+                        allow_quirks: AllowQuirks)
+                        -> Result<Self, ()> {
+        let first = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))?;
+        let second = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))
                           .unwrap_or(Either::Second(Keyword::Center));
 
-        if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) {
+        if let Ok(third) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
             // There's a 3rd value.
-            if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) {
+            if let Ok(fourth) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) {
                 // There's a 4th value.
                 Position::from_components(Some(second), Some(fourth), Some(first), Some(third))
             } else {
                 // For 3 value background position, there are several options.
                 if let Either::First(_) = first {
                     return Err(())      // <length-percentage> must be preceded by <keyword>
                 }
 
@@ -168,16 +178,27 @@ impl Parse for Position {
                     Position::from_components(None, Some(second), Some(first), None),
                 (&Either::Second(_), &Either::Second(_)) =>
                     Position::from_components(None, None, Some(first), Some(second)),
             }
         }
     }
 }
 
+impl PositionComponent {
+    /// Parses, with quirks.
+    fn parse_quirky(context: &ParserContext,
+                    input: &mut Parser,
+                    allow_quirks: AllowQuirks) -> Result<Self, ()> {
+        input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks))
+            .map(Either::First)
+            .or_else(|()| input.try(Keyword::parse).map(Either::Second))
+    }
+}
+
 impl PositionValue<LengthOrPercentage> {
     /// Generic function for the computed value of a position.
     fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage {
         match self.keyword {
             Some(Keyword::Center) => ComputedLengthOrPercentage::Percentage(0.5),
             Some(k) if k.is_other_side() => match self.position {
                 Some(ref x) => {
                     let (length, percentage) = match *x {
--- a/servo/components/style/viewport.rs
+++ b/servo/components/style/viewport.rs
@@ -5,16 +5,17 @@
 //! The [`@viewport`][at] at-rule and [`meta`][meta] element.
 //!
 //! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule
 //! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
 
 #![deny(missing_docs)]
 
 use app_units::Au;
+use context::QuirksMode;
 use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
 use cssparser::ToCss as ParserToCss;
 use euclid::size::TypedSize2D;
 use font_metrics::get_metrics_provider_for_product;
 use media_queries::Device;
 use parser::{Parse, ParserContext, log_css_error};
 use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
 use std::ascii::AsciiExt;
@@ -583,23 +584,25 @@ impl Cascade {
     }
 }
 
 /// Just a helper trait to be able to implement methods on ViewportConstraints.
 pub trait MaybeNew {
     /// Create a ViewportConstraints from a viewport size and a `@viewport`
     /// rule.
     fn maybe_new(device: &Device,
-                 rule: &ViewportRule)
+                 rule: &ViewportRule,
+                 quirks_mode: QuirksMode)
                  -> Option<ViewportConstraints>;
 }
 
 impl MaybeNew for ViewportConstraints {
     fn maybe_new(device: &Device,
-                 rule: &ViewportRule)
+                 rule: &ViewportRule,
+                 quirks_mode: QuirksMode)
                  -> Option<ViewportConstraints>
     {
         use std::cmp;
 
         if rule.declarations.is_empty() {
             return None
         }
 
@@ -679,16 +682,17 @@ impl MaybeNew for ViewportConstraints {
         let context = Context {
             is_root_element: false,
             device: device,
             inherited_style: device.default_computed_values(),
             layout_parent_style: device.default_computed_values(),
             style: device.default_computed_values().clone(),
             font_metrics_provider: &provider,
             in_media_query: false,
+            quirks_mode: quirks_mode,
         };
 
         // DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
         let extend_width;
         let extend_height;
         if let Some(extend_zoom) = max!(initial_zoom, max_zoom) {
             let scale_factor = 1. / extend_zoom;
             extend_width = Some(initial_viewport.width.scale_by(scale_factor));
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -508,17 +508,17 @@ pub extern "C" fn Servo_StyleSheet_Empty
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
     };
     let shared_lock = global_style_data.shared_lock.clone();
     Arc::new(Stylesheet::from_str(
         "", unsafe { dummy_url_data() }.clone(), origin,
         Arc::new(shared_lock.wrap(MediaList::empty())),
-        shared_lock, None, &RustLogReporter, 0u64)
+        shared_lock, None, &RustLogReporter, QuirksMode::NoQuirks, 0u64)
     ).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader,
                                                  stylesheet: *mut ServoStyleSheet,
                                                  data: *const nsACString,
                                                  mode: SheetParsingMode,
@@ -551,17 +551,17 @@ pub extern "C" fn Servo_StyleSheet_FromU
     let media = if media_list.is_null() {
         Arc::new(shared_lock.wrap(MediaList::empty()))
     } else {
         Locked::<MediaList>::as_arc(unsafe { &&*media_list }).clone()
     };
 
     Arc::new(Stylesheet::from_str(
         input, url_data.clone(), origin, media,
-        shared_lock, loader, &RustLogReporter, 0u64)
+        shared_lock, loader, &RustLogReporter, QuirksMode::NoQuirks, 0u64)
     ).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheetBorrowed,
                                                   loader: *mut Loader,
                                                   gecko_stylesheet: *mut ServoStyleSheet,
                                                   data: *const nsACString,
@@ -1007,17 +1007,18 @@ pub extern "C" fn Servo_ParseProperty(pr
                                       -> RawServoDeclarationBlockStrong {
     let id = get_property_id_from_nscsspropertyid!(property,
                                                    RawServoDeclarationBlockStrong::null());
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
     let reporter = RustLogReporter;
     let context = ParserContext::new(Origin::Author, url_data, &reporter,
-                                     Some(CssRuleType::Style), LengthParsingMode::Default);
+                                     Some(CssRuleType::Style), LengthParsingMode::Default,
+                                     QuirksMode::NoQuirks);
 
     match ParsedDeclaration::parse(id, &context, &mut Parser::new(value)) {
         Ok(parsed) => {
             let global_style_data = &*GLOBAL_STYLE_DATA;
             let mut block = PropertyDeclarationBlock::new();
             parsed.expand_push_into(&mut block, Importance::Normal);
             Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
         }
@@ -1030,17 +1031,18 @@ pub extern "C" fn Servo_ParseEasing(easi
                                     data: *mut URLExtraData,
                                     output: nsTimingFunctionBorrowedMut)
                                     -> bool {
     use style::properties::longhands::transition_timing_function;
 
     let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
     let reporter = RustLogReporter;
     let context = ParserContext::new(Origin::Author, url_data, &reporter,
-                                     Some(CssRuleType::Style), LengthParsingMode::Default);
+                                     Some(CssRuleType::Style), LengthParsingMode::Default,
+                                     QuirksMode::NoQuirks);
     let easing = unsafe { (*easing).to_string() };
     match transition_timing_function::single_value::parse(&context, &mut Parser::new(&easing)) {
         Ok(parsed_easing) => {
             *output = parsed_easing.into();
             true
         },
         Err(_) => false
     }
@@ -1171,17 +1173,17 @@ fn set_property(declarations: RawServoDe
                 length_parsing_mode: structs::LengthParsingMode) -> bool {
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { RefPtr::from_ptr_ref(&data) };
     let length_parsing_mode = match length_parsing_mode {
         structs::LengthParsingMode::Default => LengthParsingMode::Default,
         structs::LengthParsingMode::SVG => LengthParsingMode::SVG,
     };
     if let Ok(parsed) = parse_one_declaration(property_id, value, url_data, &RustLogReporter,
-                                              length_parsing_mode) {
+                                              length_parsing_mode, QuirksMode::NoQuirks) {
         let importance = if is_important { Importance::Important } else { Importance::Normal };
         write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
             parsed.expand_set_into(decls, importance)
         })
     } else {
         false
     }
 }
@@ -1238,17 +1240,17 @@ pub extern "C" fn Servo_MediaList_DeepCl
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_Matches(list: RawServoMediaListBorrowed,
                                           raw_data: RawServoStyleSetBorrowed)
                                           -> bool {
     let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     read_locked_arc(list, |list: &MediaList| {
-        list.evaluate(&per_doc_data.stylist.device)
+        list.evaluate(&per_doc_data.stylist.device, QuirksMode::NoQuirks)
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(declarations: RawServoDeclarationBlockBorrowed,
                                                            property: nsCSSPropertyID) -> bool {
     let property_id = get_property_id_from_nscsspropertyid!(property, false);
     read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
@@ -1265,17 +1267,18 @@ pub extern "C" fn Servo_MediaList_GetTex
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_SetText(list: RawServoMediaListBorrowed, text: *const nsACString) {
     let text = unsafe { text.as_ref().unwrap().as_str_unchecked() };
     let mut parser = Parser::new(&text);
     let url_data = unsafe { dummy_url_data() };
     let reporter = RustLogReporter;
     let context = ParserContext::new_for_cssom(url_data, &reporter, Some(CssRuleType::Media),
-                                               LengthParsingMode::Default);
+                                               LengthParsingMode::Default,
+                                               QuirksMode::NoQuirks);
      write_locked_arc(list, |list: &mut MediaList| {
         *list = parse_media_query_list(&context, &mut parser);
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 {
     read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
@@ -1296,30 +1299,32 @@ pub extern "C" fn Servo_MediaList_GetMed
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_AppendMedium(list: RawServoMediaListBorrowed,
                                                new_medium: *const nsACString) {
     let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { dummy_url_data() };
     let reporter = RustLogReporter;
     let context = ParserContext::new_for_cssom(url_data, &reporter, Some(CssRuleType::Media),
-                                               LengthParsingMode::Default);
+                                               LengthParsingMode::Default,
+                                               QuirksMode::NoQuirks);
     write_locked_arc(list, |list: &mut MediaList| {
         list.append_medium(&context, new_medium);
     })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_MediaList_DeleteMedium(list: RawServoMediaListBorrowed,
                                                old_medium: *const nsACString) -> bool {
     let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() };
     let url_data = unsafe { dummy_url_data() };
     let reporter = RustLogReporter;
     let context = ParserContext::new_for_cssom(url_data, &reporter, Some(CssRuleType::Media),
-                                               LengthParsingMode::Default);
+                                               LengthParsingMode::Default,
+                                               QuirksMode::NoQuirks);
     write_locked_arc(list, |list: &mut MediaList| list.delete_medium(&context, old_medium))
 }
 
 macro_rules! get_longhand_from_id {
     ($id:expr, $retval:expr) => {
         match PropertyId::from_nscsspropertyid($id) {
             Ok(PropertyId::Longhand(long)) => long,
             _ => {
@@ -1662,17 +1667,18 @@ pub extern "C" fn Servo_DeclarationBlock
     use style::properties::longhands::background_image::single_value::SpecifiedValue as SingleBackgroundImage;
     use style::values::specified::image::Image;
     use style::values::specified::url::SpecifiedUrl;
 
     let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
     let string = unsafe { (*value).to_string() };
     let error_reporter = RustLogReporter;
     let context = ParserContext::new(Origin::Author, url_data, &error_reporter,
-                                     Some(CssRuleType::Style), LengthParsingMode::Default);
+                                     Some(CssRuleType::Style), LengthParsingMode::Default,
+                                     QuirksMode::NoQuirks);
     if let Ok(url) = SpecifiedUrl::parse_from_string(string.into(), &context) {
         let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
             vec![SingleBackgroundImage(
                 Some(Image::Url(url))
             )]
         ));
         write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
             decls.push(decl, Importance::Normal);
@@ -1700,29 +1706,35 @@ pub extern "C" fn Servo_CSSSupports2(pro
     let id =  if let Ok(id) = PropertyId::parse(property.into()) {
         id
     } else {
         return false
     };
     let value = unsafe { value.as_ref().unwrap().as_str_unchecked() };
 
     let url_data = unsafe { dummy_url_data() };
-    parse_one_declaration(id, &value, url_data, &RustLogReporter, LengthParsingMode::Default).is_ok()
+    parse_one_declaration(id,
+                          &value,
+                          url_data,
+                          &RustLogReporter,
+                          LengthParsingMode::Default,
+                          QuirksMode::NoQuirks).is_ok()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_CSSSupports(cond: *const nsACString) -> bool {
     let condition = unsafe { cond.as_ref().unwrap().as_str_unchecked() };
     let mut input = Parser::new(&condition);
     let cond = parse_condition_or_declaration(&mut input);
     if let Ok(cond) = cond {
         let url_data = unsafe { dummy_url_data() };
         let reporter = RustLogReporter;
         let context = ParserContext::new_for_cssom(url_data, &reporter, Some(CssRuleType::Style),
-                                                   LengthParsingMode::Default);
+                                                   LengthParsingMode::Default,
+                                                   QuirksMode::NoQuirks);
         cond.eval(&context)
     } else {
         false
     }
 }
 
 /// Only safe to call on the main thread, with exclusive access to the element and
 /// its ancestors.
@@ -1942,16 +1954,17 @@ pub extern "C" fn Servo_GetComputedKeyfr
     let mut context = Context {
         is_root_element: false,
         device: &data.stylist.device,
         inherited_style: parent_style.unwrap_or(default_values),
         layout_parent_style: parent_style.unwrap_or(default_values),
         style: (**style).clone(),
         font_metrics_provider: &metrics,
         in_media_query: false,
+        quirks_mode: QuirksMode::NoQuirks,
     };
 
     for (index, keyframe) in keyframes.iter().enumerate() {
         let ref mut animation_values = computed_keyframes[index];
 
         let mut seen = LonghandIdSet::new();
 
         // mServoDeclarationBlock is null in the case where we have an invalid css property.
--- a/servo/tests/unit/style/media_queries.rs
+++ b/servo/tests/unit/style/media_queries.rs
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::{Parser, SourcePosition};
 use euclid::size::TypedSize2D;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::sync::Arc;
 use style::Atom;
+use style::context::QuirksMode;
 use style::error_reporting::ParseErrorReporter;
 use style::media_queries::*;
 use style::servo::media_queries::*;
 use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
 use style::stylesheets::{Stylesheet, Origin, CssRule};
 use style::values::specified;
 use style_traits::ToCss;
 
@@ -32,17 +33,17 @@ fn test_media_rule<F>(css: &str, callbac
     where F: Fn(&MediaList, &str),
 {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let css_str = css.to_owned();
     let lock = SharedRwLock::new();
     let media_list = Arc::new(lock.wrap(MediaList::empty()));
     let stylesheet = Stylesheet::from_str(
         css, url, Origin::Author, media_list, lock,
-        None, &CSSErrorReporterTest, 0u64);
+        None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0u64);
     let mut rule_count = 0;
     let guard = stylesheet.shared_lock.read();
     media_queries(&guard, &stylesheet.rules.read_with(&guard).0, &mut |mq| {
         rule_count += 1;
         callback(mq, css);
     });
     assert!(rule_count > 0, css_str);
 }
@@ -61,17 +62,17 @@ fn media_queries<F>(guard: &SharedRwLock
 }
 
 fn media_query_test(device: &Device, css: &str, expected_rule_count: usize) {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let lock = SharedRwLock::new();
     let media_list = Arc::new(lock.wrap(MediaList::empty()));
     let ss = Stylesheet::from_str(
         css, url, Origin::Author, media_list, lock,
-        None, &CSSErrorReporterTest, 0u64);
+        None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0u64);
     let mut rule_count = 0;
     ss.effective_style_rules(device, &ss.shared_lock.read(), |_| rule_count += 1);
     assert!(rule_count == expected_rule_count, css.to_owned());
 }
 
 #[test]
 fn test_mq_empty() {
     test_media_rule("@media { }", |list, css| {
--- a/servo/tests/unit/style/parsing/image.rs
+++ b/servo/tests/unit/style/parsing/image.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use euclid::size::TypedSize2D;
 use parsing::parse;
 use std::f32::consts::PI;
+use style::context::QuirksMode;
 use style::font_metrics::ServoMetricsProvider;
 use style::media_queries::{Device, MediaType};
 use style::properties::ComputedValues;
 use style::values::computed;
 use style::values::computed::{Angle, Context, ToComputedValue};
 use style::values::specified;
 use style::values::specified::image::*;
 use style_traits::ToCss;
@@ -46,16 +47,17 @@ fn test_linear_gradient() {
     let specified_context = Context {
         is_root_element: true,
         device: &device,
         inherited_style: initial_style,
         layout_parent_style: initial_style,
         style: initial_style.clone(),
         font_metrics_provider: &ServoMetricsProvider,
         in_media_query: false,
+        quirks_mode: QuirksMode::NoQuirks,
     };
     assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
                computed::AngleOrCorner::Angle(Angle::from_radians(PI)));
 }
 
 #[test]
 fn test_radial_gradient() {
     // Parsing with all values
--- a/servo/tests/unit/style/parsing/length.rs
+++ b/servo/tests/unit/style/parsing/length.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::Parser;
 use media_queries::CSSErrorReporterTest;
 use parsing::parse;
+use style::context::QuirksMode;
 use style::parser::{LengthParsingMode, Parse, ParserContext};
 use style::stylesheets::{CssRuleType, Origin};
 use style::values::specified::length::{AbsoluteLength, Length, NoCalcLength};
 use style_traits::ToCss;
 
 #[test]
 fn test_calc() {
     assert!(parse(Length::parse, "calc(1px+ 2px)").is_err());
@@ -33,14 +34,15 @@ fn test_length_literals() {
 fn test_length_parsing_modes() {
     // In default length mode, non-zero lengths must have a unit.
     assert!(parse(Length::parse, "1").is_err());
 
     // In SVG length mode, non-zero lengths are assumed to be px.
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
     let reporter = CSSErrorReporterTest;
     let context = ParserContext::new(Origin::Author, &url, &reporter,
-                                     Some(CssRuleType::Style), LengthParsingMode::SVG);
+                                     Some(CssRuleType::Style), LengthParsingMode::SVG,
+                                     QuirksMode::NoQuirks);
     let mut parser = Parser::new("1");
     let result = Length::parse(&context, &mut parser);
     assert!(result.is_ok());
     assert_eq!(result.unwrap(), Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(1.))));
 }
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -1,24 +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/. */
 
 //! Tests for parsing and serialization of values/properties
 
 use cssparser::Parser;
 use media_queries::CSSErrorReporterTest;
+use style::context::QuirksMode;
 use style::parser::{LengthParsingMode, ParserContext};
 use style::stylesheets::{CssRuleType, Origin};
 
 fn parse<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
     let reporter = CSSErrorReporterTest;
     let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style),
-                                     LengthParsingMode::Default);
+                                     LengthParsingMode::Default,
+                                     QuirksMode::NoQuirks);
     let mut parser = Parser::new(s);
     f(&context, &mut parser)
 }
 
 // This is a macro so that the file/line information
 // is preserved in the panic
 macro_rules! assert_roundtrip_with_context {
     ($fun:expr, $string:expr) => {
--- a/servo/tests/unit/style/properties/mod.rs
+++ b/servo/tests/unit/style/properties/mod.rs
@@ -1,22 +1,24 @@
 /* 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 style::context::QuirksMode;
 use style::parser::{LengthParsingMode, ParserContext};
 use style::stylesheets::{CssRuleType, Origin};
 
 fn parse<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
     let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
     let reporter = CSSErrorReporterTest;
     let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style),
-                                     LengthParsingMode::Default);
+                                     LengthParsingMode::Default,
+                                     QuirksMode::NoQuirks);
     let mut parser = Parser::new(s);
     f(&context, &mut parser)
 }
 
 macro_rules! assert_roundtrip_with_context {
     ($fun:expr, $string:expr) => {
         assert_roundtrip_with_context!($fun, $string, $string);
     };
--- a/servo/tests/unit/style/rule_tree/bench.rs
+++ b/servo/tests/unit/style/rule_tree/bench.rs
@@ -1,16 +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 cssparser::{Parser, SourcePosition};
 use rayon;
 use servo_url::ServoUrl;
 use std::sync::Arc;
+use style::context::QuirksMode;
 use style::error_reporting::ParseErrorReporter;
 use style::media_queries::MediaList;
 use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
 use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
 use style::shared_lock::SharedRwLock;
 use style::stylesheets::{Origin, Stylesheet, CssRule};
 use test::{self, Bencher};
 
@@ -53,16 +54,17 @@ fn parse_rules(css: &str) -> Vec<(StyleS
 
     let s = Stylesheet::from_str(css,
                                  ServoUrl::parse("http://localhost").unwrap(),
                                  Origin::Author,
                                  media,
                                  lock,
                                  None,
                                  &ErrorringErrorReporter,
+                                 QuirksMode::NoQuirks,
                                  0u64);
     let guard = s.shared_lock.read();
     let rules = s.rules.read_with(&guard);
     rules.0.iter().filter_map(|rule| {
         match *rule {
             CssRule::Style(ref style_rule) => Some(style_rule),
             _ => None,
         }
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -8,16 +8,17 @@ use media_queries::CSSErrorReporterTest;
 use parking_lot::RwLock;
 use selectors::parser::*;
 use servo_atoms::Atom;
 use servo_url::ServoUrl;
 use std::borrow::ToOwned;
 use std::sync::Arc;
 use std::sync::Mutex;
 use std::sync::atomic::AtomicBool;
+use style::context::QuirksMode;
 use style::error_reporting::ParseErrorReporter;
 use style::keyframes::{Keyframe, KeyframeSelector, KeyframePercentage};
 use style::media_queries::MediaList;
 use style::properties::Importance;
 use style::properties::{CSSWideKeyword, DeclaredValueOwned, PropertyDeclaration, PropertyDeclarationBlock};
 use style::properties::longhands;
 use style::properties::longhands::animation_play_state;
 use style::shared_lock::SharedRwLock;
@@ -61,27 +62,28 @@ fn test_parse_stylesheet() {
                 animation-name: 'foo'; /* animation properties not allowed here */
                 animation-play-state: running; /* … except animation-play-state */
             }
         }";
     let url = ServoUrl::parse("about::test").unwrap();
     let lock = SharedRwLock::new();
     let media = Arc::new(lock.wrap(MediaList::empty()));
     let stylesheet = Stylesheet::from_str(css, url.clone(), Origin::UserAgent, media, lock,
-                                          None, &CSSErrorReporterTest, 0u64);
+                                          None, &CSSErrorReporterTest, QuirksMode::NoQuirks, 0u64);
     let mut namespaces = Namespaces::default();
     namespaces.default = Some(ns!(html));
     let expected = Stylesheet {
         origin: Origin::UserAgent,
         media: Arc::new(stylesheet.shared_lock.wrap(MediaList::empty())),
         shared_lock: stylesheet.shared_lock.clone(),
         namespaces: RwLock::new(namespaces),
         url_data: url,
         dirty_on_viewport_size_change: AtomicBool::new(false),
         disabled: AtomicBool::new(false),
+        quirks_mode: QuirksMode::NoQuirks,
         rules: CssRules::new(vec![
             CssRule::Namespace(Arc::new(stylesheet.shared_lock.wrap(NamespaceRule {
                 prefix: None,
                 url: NsAtom::from("http://www.w3.org/1999/xhtml")
             }))),
             CssRule::Style(Arc::new(stylesheet.shared_lock.wrap(StyleRule {
                 selectors: SelectorList(vec![
                     Selector {
@@ -311,17 +313,17 @@ fn test_report_error_stylesheet() {
     let url = ServoUrl::parse("about::test").unwrap();
     let error_reporter = CSSInvalidErrorReporterTest::new();
 
     let errors = error_reporter.errors.clone();
 
     let lock = SharedRwLock::new();
     let media = Arc::new(lock.wrap(MediaList::empty()));
     Stylesheet::from_str(css, url.clone(), Origin::UserAgent, media, lock,
-                         None, &error_reporter, 5u64);
+                         None, &error_reporter, QuirksMode::NoQuirks, 5u64);
 
     let mut errors = errors.lock().unwrap();
 
     let error = errors.pop().unwrap();
     assert_eq!("Unsupported property declaration: 'invalid: true;'", error.message);
     assert_eq!(10, error.line);
     assert_eq!(9, error.column);
 
--- a/servo/tests/unit/style/viewport.rs
+++ b/servo/tests/unit/style/viewport.rs
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::Parser;
 use euclid::size::TypedSize2D;
 use media_queries::CSSErrorReporterTest;
 use servo_config::prefs::{PREFS, PrefValue};
 use servo_url::ServoUrl;
 use std::sync::Arc;
+use style::context::QuirksMode;
 use style::media_queries::{Device, MediaList, MediaType};
 use style::parser::{LengthParsingMode, Parse, ParserContext};
 use style::shared_lock::SharedRwLock;
 use style::stylesheets::{CssRuleType, Stylesheet, Origin};
 use style::values::specified::LengthOrPercentageOrAuto::{self, Auto};
 use style::values::specified::NoCalcLength::{self, ViewportPercentage};
 use style::values::specified::ViewportPercentageLength::Vw;
 use style::viewport::*;
@@ -27,16 +28,17 @@ macro_rules! stylesheet {
         Box::new(Stylesheet::from_str(
             $css,
             ServoUrl::parse("http://localhost").unwrap(),
             Origin::$origin,
             Arc::new($shared_lock.wrap(MediaList::empty())),
             $shared_lock,
             None,
             &$error_reporter,
+            QuirksMode::NoQuirks,
             0u64
         ))
     }
 }
 
 fn test_viewport_rule<F>(css: &str,
                          device: &Device,
                          callback: F)
@@ -288,70 +290,73 @@ fn multiple_stylesheets_cascading() {
     assert_decl_eq!(&declarations[2], Author, Zoom: Zoom::Number(3.), !important);
 }
 
 #[test]
 fn constrain_viewport() {
     let url = ServoUrl::parse("http://localhost").unwrap();
     let reporter = CSSErrorReporterTest;
     let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Viewport),
-                                     LengthParsingMode::Default);
+                                     LengthParsingMode::Default,
+                                     QuirksMode::NoQuirks);
 
     macro_rules! from_css {
         ($css:expr) => {
             &ViewportRule::parse(&context, &mut Parser::new($css)).unwrap()
         }
     }
 
     let initial_viewport = TypedSize2D::new(800., 600.);
     let device = Device::new(MediaType::Screen, initial_viewport);
-    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("")), None);
+    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!(""), QuirksMode::NoQuirks), None);
 
-    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto")),
+    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto"), QuirksMode::NoQuirks),
                Some(ViewportConstraints {
                    size: initial_viewport,
 
                    initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 
-    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto")),
+    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto"), QuirksMode::NoQuirks),
                Some(ViewportConstraints {
                    size: initial_viewport,
 
                    initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 
-    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 800px; height: 600px;\
-                                                                     zoom: 1;\
-                                                                     user-zoom: zoom;\
-                                                                     orientation: auto;")),
+    assert_eq!(ViewportConstraints::maybe_new(&device,
+                                              from_css!("width: 800px; height: 600px;\
+                                                         zoom: 1;\
+                                                         user-zoom: zoom;\
+                                                         orientation: auto;"),
+                                              QuirksMode::NoQuirks),
                Some(ViewportConstraints {
                    size: initial_viewport,
 
                    initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,
                    orientation: Orientation::Auto
                }));
 
     let initial_viewport = TypedSize2D::new(200., 150.);
     let device = Device::new(MediaType::Screen, initial_viewport);
-    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto")),
+    assert_eq!(ViewportConstraints::maybe_new(&device, from_css!("width: 320px auto"), QuirksMode::NoQuirks),
                Some(ViewportConstraints {
                    size: TypedSize2D::new(320., 240.),
 
                    initial_zoom: PinchZoomFactor::new(1.),
                    min_zoom: None,
                    max_zoom: None,
 
                    user_zoom: UserZoom::Zoom,