servo: Merge #14190 - Immutable CSSOM (from Manishearth:cssom); r=SimonSapin
authorManish Goregaokar <manishsmail@gmail.com>
Wed, 16 Nov 2016 15:05:59 -0600
changeset 340162 8ef847a24d3d382f614259e3333b1d849207faa8
parent 340161 914e8b90e3cbfe8bc91ffe96d0a85e1a93eb4a83
child 340163 f4b7c1063b4a49ee918465118627f64dca7d5c18
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersSimonSapin
servo: Merge #14190 - Immutable CSSOM (from Manishearth:cssom); r=SimonSapin This PR is intended to add basic support for all CSSOM interfaces, with the ability to index `document.styleSheets` and css rule lists, and serializing individual css rules. Handling individual interface methods for CSSRule subclasses can probably be done with easy/medium bugs. Mutation safety isn't dealt with here; if the css rule list is mutated the CSSOM will be in an inconsistent state. I intend to deal with this via zero sized tokens, see https://groups.google.com/forum/#!topic/mozilla.dev.servo/AnxJoVmtMXQ . I'll handle that when I start making the CSSOM mutable. (Getting the immutable bit landed first opens this up for easy bugs) This doesn't really change style aside from adding an extra arc in the CSS rule list as discussed in the linked thread. So far this same design can be used by stylo as well when the time comes. f? @SimonSapin @emilio cc @upsuper part of #11420 Todo: - [x] Stubs for rest of the CSSRule subclasses - [x] <s>ToCSS impls for CSSRules.</s> May make into easy bugs and stub out in this PR https://github.com/servo/servo/issues/14195 - [x] Cache CSSStyleSheet on the relevant node Source-Repo: https://github.com/servo/servo Source-Revision: afc60bee2809059b8b754a1c6d6d10c1d36326fb
servo/components/script/dom/cssfontfacerule.rs
servo/components/script/dom/cssgroupingrule.rs
servo/components/script/dom/csskeyframesrule.rs
servo/components/script/dom/cssmediarule.rs
servo/components/script/dom/cssnamespacerule.rs
servo/components/script/dom/cssrule.rs
servo/components/script/dom/cssrulelist.rs
servo/components/script/dom/cssstylerule.rs
servo/components/script/dom/cssstylesheet.rs
servo/components/script/dom/cssviewportrule.rs
servo/components/script/dom/document.rs
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmetaelement.rs
servo/components/script/dom/htmlstyleelement.rs
servo/components/script/dom/mod.rs
servo/components/script/dom/node.rs
servo/components/script/dom/stylesheet.rs
servo/components/script/dom/stylesheetlist.rs
servo/components/script/dom/webidls/CSS.webidl
servo/components/script/dom/webidls/CSSFontFaceRule.webidl
servo/components/script/dom/webidls/CSSGroupingRule.webidl
servo/components/script/dom/webidls/CSSKeyframesRule.webidl
servo/components/script/dom/webidls/CSSMediaRule.webidl
servo/components/script/dom/webidls/CSSNamespaceRule.webidl
servo/components/script/dom/webidls/CSSRule.webidl
servo/components/script/dom/webidls/CSSRuleList.webidl
servo/components/script/dom/webidls/CSSStyleDeclaration.webidl
servo/components/script/dom/webidls/CSSStyleRule.webidl
servo/components/script/dom/webidls/CSSStyleSheet.webidl
servo/components/script/dom/webidls/CSSViewportRule.webidl
servo/components/script/dom/webidls/StyleSheet.webidl
servo/components/script/dom/webidls/StyleSheetList.webidl
servo/components/style/selector_matching.rs
servo/components/style/stylesheets.rs
servo/ports/geckolib/glue.rs
servo/python/tidy/servo_tidy/tidy.py
servo/tests/unit/style/media_queries.rs
servo/tests/unit/style/stylesheets.rs
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssfontfacerule.rs
@@ -0,0 +1,50 @@
+/* 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 dom::bindings::codegen::Bindings::CSSFontFaceRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::cssrule::{CSSRule, SpecificCSSRule};
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::font_face::FontFaceRule;
+
+#[dom_struct]
+pub struct CSSFontFaceRule {
+    cssrule: CSSRule,
+    #[ignore_heap_size_of = "Arc"]
+    fontfacerule: Arc<RwLock<FontFaceRule>>,
+}
+
+impl CSSFontFaceRule {
+    fn new_inherited(parent: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>) -> CSSFontFaceRule {
+        CSSFontFaceRule {
+            cssrule: CSSRule::new_inherited(parent),
+            fontfacerule: fontfacerule,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet,
+               fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> {
+        reflect_dom_object(box CSSFontFaceRule::new_inherited(parent, fontfacerule),
+                           window,
+                           CSSFontFaceRuleBinding::Wrap)
+    }
+}
+
+impl SpecificCSSRule for CSSFontFaceRule {
+    fn ty(&self) -> u16 {
+        use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
+        CSSRuleConstants::FONT_FACE_RULE
+    }
+
+    fn get_css(&self) -> DOMString {
+        // self.fontfacerule.read().to_css_string().into()
+        "".into()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssgroupingrule.rs
@@ -0,0 +1,30 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::CSSGroupingRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::cssrule::CSSRule;
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+
+#[dom_struct]
+pub struct CSSGroupingRule {
+    cssrule: CSSRule,
+}
+
+impl CSSGroupingRule {
+    pub fn new_inherited(parent: &CSSStyleSheet) -> CSSGroupingRule {
+        CSSGroupingRule {
+            cssrule: CSSRule::new_inherited(parent),
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet) -> Root<CSSGroupingRule> {
+        reflect_dom_object(box CSSGroupingRule::new_inherited(parent),
+                           window,
+                           CSSGroupingRuleBinding::Wrap)
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/csskeyframesrule.rs
@@ -0,0 +1,50 @@
+/* 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 dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::cssrule::{CSSRule, SpecificCSSRule};
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::stylesheets::KeyframesRule;
+
+#[dom_struct]
+pub struct CSSKeyframesRule {
+    cssrule: CSSRule,
+    #[ignore_heap_size_of = "Arc"]
+    keyframesrule: Arc<RwLock<KeyframesRule>>,
+}
+
+impl CSSKeyframesRule {
+    fn new_inherited(parent: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>) -> CSSKeyframesRule {
+        CSSKeyframesRule {
+            cssrule: CSSRule::new_inherited(parent),
+            keyframesrule: keyframesrule,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet,
+               keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> {
+        reflect_dom_object(box CSSKeyframesRule::new_inherited(parent, keyframesrule),
+                           window,
+                           CSSKeyframesRuleBinding::Wrap)
+    }
+}
+
+impl SpecificCSSRule for CSSKeyframesRule {
+    fn ty(&self) -> u16 {
+        use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
+        CSSRuleConstants::KEYFRAMES_RULE
+    }
+
+    fn get_css(&self) -> DOMString {
+        // self.keyframesrule.read().to_css_string().into()
+        "".into()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssmediarule.rs
@@ -0,0 +1,51 @@
+/* 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 dom::bindings::codegen::Bindings::CSSMediaRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::cssgroupingrule::CSSGroupingRule;
+use dom::cssrule::SpecificCSSRule;
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::stylesheets::MediaRule;
+
+#[dom_struct]
+pub struct CSSMediaRule {
+    cssrule: CSSGroupingRule,
+    #[ignore_heap_size_of = "Arc"]
+    mediarule: Arc<RwLock<MediaRule>>,
+}
+
+impl CSSMediaRule {
+    fn new_inherited(parent: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>) -> CSSMediaRule {
+        CSSMediaRule {
+            cssrule: CSSGroupingRule::new_inherited(parent),
+            mediarule: mediarule,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet,
+               mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> {
+        reflect_dom_object(box CSSMediaRule::new_inherited(parent, mediarule),
+                           window,
+                           CSSMediaRuleBinding::Wrap)
+    }
+}
+
+impl SpecificCSSRule for CSSMediaRule {
+    fn ty(&self) -> u16 {
+        use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
+        CSSRuleConstants::MEDIA_RULE
+    }
+
+    fn get_css(&self) -> DOMString {
+        // self.mediarule.read().to_css_string().into()
+        "".into()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssnamespacerule.rs
@@ -0,0 +1,50 @@
+/* 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 dom::bindings::codegen::Bindings::CSSNamespaceRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::cssrule::{CSSRule, SpecificCSSRule};
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::stylesheets::NamespaceRule;
+
+#[dom_struct]
+pub struct CSSNamespaceRule {
+    cssrule: CSSRule,
+    #[ignore_heap_size_of = "Arc"]
+    namespacerule: Arc<RwLock<NamespaceRule>>,
+}
+
+impl CSSNamespaceRule {
+    fn new_inherited(parent: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>) -> CSSNamespaceRule {
+        CSSNamespaceRule {
+            cssrule: CSSRule::new_inherited(parent),
+            namespacerule: namespacerule,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet,
+               namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> {
+        reflect_dom_object(box CSSNamespaceRule::new_inherited(parent, namespacerule),
+                           window,
+                           CSSNamespaceRuleBinding::Wrap)
+    }
+}
+
+impl SpecificCSSRule for CSSNamespaceRule {
+    fn ty(&self) -> u16 {
+        use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
+        CSSRuleConstants::NAMESPACE_RULE
+    }
+
+    fn get_css(&self) -> DOMString {
+        // self.namespacerule.read().to_css_string().into()
+        "".into()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssrule.rs
@@ -0,0 +1,103 @@
+/* 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 dom::bindings::codegen::Bindings::CSSRuleBinding;
+use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::{JS, MutNullableHeap, Root};
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::cssfontfacerule::CSSFontFaceRule;
+use dom::csskeyframesrule::CSSKeyframesRule;
+use dom::cssmediarule::CSSMediaRule;
+use dom::cssnamespacerule::CSSNamespaceRule;
+use dom::cssstylerule::CSSStyleRule;
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::cssviewportrule::CSSViewportRule;
+use dom::window::Window;
+use style::stylesheets::CssRule as StyleCssRule;
+
+
+#[dom_struct]
+pub struct CSSRule {
+    reflector_: Reflector,
+    parent: MutNullableHeap<JS<CSSStyleSheet>>,
+}
+
+impl CSSRule {
+    #[allow(unrooted_must_root)]
+    pub fn new_inherited(parent: &CSSStyleSheet) -> CSSRule {
+        CSSRule {
+            reflector_: Reflector::new(),
+            parent: MutNullableHeap::new(Some(parent)),
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet) -> Root<CSSRule> {
+        reflect_dom_object(box CSSRule::new_inherited(parent),
+                           window,
+                           CSSRuleBinding::Wrap)
+    }
+
+    pub fn as_specific(&self) -> &SpecificCSSRule {
+        if let Some(rule) = self.downcast::<CSSStyleRule>() {
+            rule as &SpecificCSSRule
+        } else if let Some(rule) = self.downcast::<CSSFontFaceRule>() {
+            rule as &SpecificCSSRule
+        } else if let Some(rule) = self.downcast::<CSSKeyframesRule>() {
+            rule as &SpecificCSSRule
+        } else if let Some(rule) = self.downcast::<CSSMediaRule>() {
+            rule as &SpecificCSSRule
+        } else if let Some(rule) = self.downcast::<CSSNamespaceRule>() {
+            rule as &SpecificCSSRule
+        } else if let Some(rule) = self.downcast::<CSSViewportRule>() {
+            rule as &SpecificCSSRule
+        } else {
+            unreachable!()
+        }
+    }
+
+    // Given a StyleCssRule, create a new instance of a derived class of
+    // CSSRule based on which rule it is
+    pub fn new_specific(window: &Window, parent: &CSSStyleSheet,
+                        rule: StyleCssRule) -> Root<CSSRule> {
+        // be sure to update the match in as_specific when this is updated
+        match rule {
+            StyleCssRule::Style(s) => Root::upcast(CSSStyleRule::new(window, parent, s)),
+            StyleCssRule::FontFace(s) => Root::upcast(CSSFontFaceRule::new(window, parent, s)),
+            StyleCssRule::Keyframes(s) => Root::upcast(CSSKeyframesRule::new(window, parent, s)),
+            StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent, s)),
+            StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent, s)),
+            StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent, s)),
+        }
+    }
+}
+
+impl CSSRuleMethods for CSSRule {
+    // https://drafts.csswg.org/cssom/#dom-cssrule-type
+    fn Type(&self) -> u16 {
+        self.as_specific().ty()
+    }
+
+    // https://drafts.csswg.org/cssom/#dom-cssrule-parentstylesheet
+    fn GetParentStyleSheet(&self) -> Option<Root<CSSStyleSheet>> {
+        self.parent.get()
+    }
+
+    // https://drafts.csswg.org/cssom/#dom-cssrule-csstext
+    fn CssText(&self) -> DOMString {
+        self.as_specific().get_css()
+    }
+
+    // https://drafts.csswg.org/cssom/#dom-cssrule-csstext
+    fn SetCssText(&self, _: DOMString) {
+        // do nothing
+    }
+}
+
+pub trait SpecificCSSRule {
+    fn ty(&self) -> u16;
+    fn get_css(&self) -> DOMString;
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssrulelist.rs
@@ -0,0 +1,67 @@
+/* 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 dom::bindings::codegen::Bindings::CSSRuleListBinding;
+use dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods;
+use dom::bindings::js::{JS, MutNullableHeap, Root};
+use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
+use dom::cssrule::CSSRule;
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use style::stylesheets::CssRules;
+
+no_jsmanaged_fields!(CssRules);
+
+#[dom_struct]
+pub struct CSSRuleList {
+    reflector_: Reflector,
+    sheet: JS<CSSStyleSheet>,
+    #[ignore_heap_size_of = "Arc"]
+    rules: CssRules,
+    dom_rules: Vec<MutNullableHeap<JS<CSSRule>>>
+}
+
+impl CSSRuleList {
+    #[allow(unrooted_must_root)]
+    pub fn new_inherited(sheet: &CSSStyleSheet, rules: CssRules) -> CSSRuleList {
+        let dom_rules = rules.0.read().iter().map(|_| MutNullableHeap::new(None)).collect();
+        CSSRuleList {
+            reflector_: Reflector::new(),
+            sheet: JS::from_ref(sheet),
+            rules: rules,
+            dom_rules: dom_rules,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, sheet: &CSSStyleSheet, rules: CssRules) -> Root<CSSRuleList> {
+        reflect_dom_object(box CSSRuleList::new_inherited(sheet, rules),
+                           window,
+                           CSSRuleListBinding::Wrap)
+    }
+}
+
+impl CSSRuleListMethods for CSSRuleList {
+    // https://drafts.csswg.org/cssom/#ref-for-dom-cssrulelist-item-1
+    fn Item(&self, idx: u32) -> Option<Root<CSSRule>> {
+        self.dom_rules.get(idx as usize).map(|rule| {
+            rule.or_init(|| {
+                CSSRule::new_specific(self.global().as_window(),
+                                     &self.sheet,
+                                     self.rules.0.read()[idx as usize].clone())
+            })
+        })
+    }
+
+    // https://drafts.csswg.org/cssom/#dom-cssrulelist-length
+    fn Length(&self) -> u32 {
+        self.dom_rules.len() as u32
+    }
+
+    // check-tidy: no specs after this line
+    fn IndexedGetter(&self, index: u32) -> Option<Root<CSSRule>> {
+        self.Item(index)
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssstylerule.rs
@@ -0,0 +1,50 @@
+/* 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 dom::bindings::codegen::Bindings::CSSStyleRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::cssrule::{CSSRule, SpecificCSSRule};
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::stylesheets::StyleRule;
+use style_traits::ToCss;
+
+#[dom_struct]
+pub struct CSSStyleRule {
+    cssrule: CSSRule,
+    #[ignore_heap_size_of = "Arc"]
+    stylerule: Arc<RwLock<StyleRule>>,
+}
+
+impl CSSStyleRule {
+    fn new_inherited(parent: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>) -> CSSStyleRule {
+        CSSStyleRule {
+            cssrule: CSSRule::new_inherited(parent),
+            stylerule: stylerule,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet,
+               stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> {
+        reflect_dom_object(box CSSStyleRule::new_inherited(parent, stylerule),
+                           window,
+                           CSSStyleRuleBinding::Wrap)
+    }
+}
+
+impl SpecificCSSRule for CSSStyleRule {
+    fn ty(&self) -> u16 {
+        use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
+        CSSRuleConstants::STYLE_RULE
+    }
+
+    fn get_css(&self) -> DOMString {
+        self.stylerule.read().to_css_string().into()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssstylesheet.rs
@@ -0,0 +1,51 @@
+/* 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 dom::bindings::codegen::Bindings::CSSStyleSheetBinding;
+use dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods;
+use dom::bindings::js::{JS, Root, MutNullableHeap};
+use dom::bindings::reflector::{reflect_dom_object, Reflectable};
+use dom::bindings::str::DOMString;
+use dom::cssrulelist::CSSRuleList;
+use dom::stylesheet::StyleSheet;
+use dom::window::Window;
+use std::sync::Arc;
+use style::stylesheets::Stylesheet as StyleStyleSheet;
+
+#[dom_struct]
+pub struct CSSStyleSheet {
+    stylesheet: StyleSheet,
+    rulelist: MutNullableHeap<JS<CSSRuleList>>,
+    #[ignore_heap_size_of = "Arc"]
+    style_stylesheet: Arc<StyleStyleSheet>,
+}
+
+impl CSSStyleSheet {
+    fn new_inherited(type_: DOMString, href: Option<DOMString>,
+                     title: Option<DOMString>, stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet {
+        CSSStyleSheet {
+            stylesheet: StyleSheet::new_inherited(type_, href, title),
+            rulelist: MutNullableHeap::new(None),
+            style_stylesheet: stylesheet,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, type_: DOMString,
+               href: Option<DOMString>,
+               title: Option<DOMString>,
+               stylesheet: Arc<StyleStyleSheet>) -> Root<CSSStyleSheet> {
+        reflect_dom_object(box CSSStyleSheet::new_inherited(type_, href, title, stylesheet),
+                           window,
+                           CSSStyleSheetBinding::Wrap)
+    }
+}
+
+impl CSSStyleSheetMethods for CSSStyleSheet {
+    // https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssrules
+    fn CssRules(&self) -> Root<CSSRuleList> {
+        self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(), self, self.style_stylesheet.rules.clone()))
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/cssviewportrule.rs
@@ -0,0 +1,50 @@
+/* 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 dom::bindings::codegen::Bindings::CSSViewportRuleBinding;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::cssrule::{CSSRule, SpecificCSSRule};
+use dom::cssstylesheet::CSSStyleSheet;
+use dom::window::Window;
+use parking_lot::RwLock;
+use std::sync::Arc;
+use style::viewport::ViewportRule;
+
+#[dom_struct]
+pub struct CSSViewportRule {
+    cssrule: CSSRule,
+    #[ignore_heap_size_of = "Arc"]
+    viewportrule: Arc<RwLock<ViewportRule>>,
+}
+
+impl CSSViewportRule {
+    fn new_inherited(parent: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule {
+        CSSViewportRule {
+            cssrule: CSSRule::new_inherited(parent),
+            viewportrule: viewportrule,
+        }
+    }
+
+    #[allow(unrooted_must_root)]
+    pub fn new(window: &Window, parent: &CSSStyleSheet,
+               viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> {
+        reflect_dom_object(box CSSViewportRule::new_inherited(parent, viewportrule),
+                           window,
+                           CSSViewportRuleBinding::Wrap)
+    }
+}
+
+impl SpecificCSSRule for CSSViewportRule {
+    fn ty(&self) -> u16 {
+        use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants;
+        CSSRuleConstants::VIEWPORT_RULE
+    }
+
+    fn get_css(&self) -> DOMString {
+        // self.viewportrule.read().to_css_string().into()
+        "".into()
+    }
+}
--- a/servo/components/script/dom/document.rs
+++ b/servo/components/script/dom/document.rs
@@ -54,20 +54,17 @@ use dom::htmlbodyelement::HTMLBodyElemen
 use dom::htmlcollection::{CollectionFilter, HTMLCollection};
 use dom::htmlelement::HTMLElement;
 use dom::htmlembedelement::HTMLEmbedElement;
 use dom::htmlformelement::HTMLFormElement;
 use dom::htmlheadelement::HTMLHeadElement;
 use dom::htmlhtmlelement::HTMLHtmlElement;
 use dom::htmliframeelement::HTMLIFrameElement;
 use dom::htmlimageelement::HTMLImageElement;
-use dom::htmllinkelement::HTMLLinkElement;
-use dom::htmlmetaelement::HTMLMetaElement;
 use dom::htmlscriptelement::HTMLScriptElement;
-use dom::htmlstyleelement::HTMLStyleElement;
 use dom::htmltitleelement::HTMLTitleElement;
 use dom::keyboardevent::KeyboardEvent;
 use dom::location::Location;
 use dom::messageevent::MessageEvent;
 use dom::mouseevent::MouseEvent;
 use dom::node::{self, CloneChildrenFlag, Node, NodeDamage, window_from_node};
 use dom::nodeiterator::NodeIterator;
 use dom::nodelist::NodeList;
@@ -147,20 +144,20 @@ pub enum IsHTMLDocument {
 #[derive(PartialEq)]
 enum ParserBlockedByScript {
     Blocked,
     Unblocked,
 }
 
 #[derive(JSTraceable, HeapSizeOf)]
 #[must_root]
-struct StylesheetInDocument {
-    node: JS<Node>,
+pub struct StylesheetInDocument {
+    pub node: JS<Node>,
     #[ignore_heap_size_of = "Arc"]
-    stylesheet: Arc<Stylesheet>,
+    pub stylesheet: Arc<Stylesheet>,
 }
 
 // https://dom.spec.whatwg.org/#document
 #[dom_struct]
 pub struct Document {
     node: Node,
     window: JS<Window>,
     /// https://html.spec.whatwg.org/multipage/#concept-document-bc
@@ -184,16 +181,17 @@ pub struct Document {
     forms: MutNullableHeap<JS<HTMLCollection>>,
     scripts: MutNullableHeap<JS<HTMLCollection>>,
     anchors: MutNullableHeap<JS<HTMLCollection>>,
     applets: MutNullableHeap<JS<HTMLCollection>>,
     /// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed.
     stylesheets: DOMRefCell<Option<Vec<StylesheetInDocument>>>,
     /// Whether the list of stylesheets has changed since the last reflow was triggered.
     stylesheets_changed_since_reflow: Cell<bool>,
+    stylesheet_list: MutNullableHeap<JS<StyleSheetList>>,
     ready_state: Cell<DocumentReadyState>,
     /// Whether the DOMContentLoaded event has already been dispatched.
     domcontentloaded_dispatched: Cell<bool>,
     /// The element that has most recently requested focus for itself.
     possibly_focused: MutNullableHeap<JS<Element>>,
     /// The element that currently has the document focus context.
     focused: MutNullableHeap<JS<Element>>,
     /// The script element that is currently executing.
@@ -1806,16 +1804,17 @@ impl Document {
             embeds: Default::default(),
             links: Default::default(),
             forms: Default::default(),
             scripts: Default::default(),
             anchors: Default::default(),
             applets: Default::default(),
             stylesheets: DOMRefCell::new(None),
             stylesheets_changed_since_reflow: Cell::new(false),
+            stylesheet_list: MutNullableHeap::new(None),
             ready_state: Cell::new(ready_state),
             domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched),
             possibly_focused: Default::default(),
             focused: Default::default(),
             current_script: Default::default(),
             pending_parsing_blocking_script: Default::default(),
             script_blocking_stylesheets_count: Cell::new(0u32),
             deferred_scripts: DOMRefCell::new(vec![]),
@@ -1905,45 +1904,47 @@ impl Document {
                              .filter(|node| callback(&node));
         NodeList::new_simple_list(&self.window, iter)
     }
 
     fn get_html_element(&self) -> Option<Root<HTMLHtmlElement>> {
         self.GetDocumentElement().and_then(Root::downcast)
     }
 
+    // Ensure that the stylesheets vector is populated
+    fn ensure_stylesheets(&self) {
+        let mut stylesheets = self.stylesheets.borrow_mut();
+        if stylesheets.is_none() {
+            *stylesheets = Some(self.upcast::<Node>()
+                .traverse_preorder()
+                .filter_map(|node| {
+                    node.get_stylesheet()
+                        .map(|stylesheet| StylesheetInDocument {
+                        node: JS::from_ref(&*node),
+                        stylesheet: stylesheet,
+                    })
+                })
+                .collect());
+        };
+    }
+
     /// Returns the list of stylesheets associated with nodes in the document.
     pub fn stylesheets(&self) -> Vec<Arc<Stylesheet>> {
-        {
-            let mut stylesheets = self.stylesheets.borrow_mut();
-            if stylesheets.is_none() {
-                *stylesheets = Some(self.upcast::<Node>()
-                    .traverse_preorder()
-                    .filter_map(|node| {
-                        if let Some(node) = node.downcast::<HTMLStyleElement>() {
-                            node.get_stylesheet()
-                        } else if let Some(node) = node.downcast::<HTMLLinkElement>() {
-                            node.get_stylesheet()
-                        } else if let Some(node) = node.downcast::<HTMLMetaElement>() {
-                            node.get_stylesheet()
-                        } else {
-                            None
-                        }.map(|stylesheet| StylesheetInDocument {
-                            node: JS::from_ref(&*node),
-                            stylesheet: stylesheet
-                        })
-                    })
-                    .collect());
-            };
-        }
+        self.ensure_stylesheets();
         self.stylesheets.borrow().as_ref().unwrap().iter()
                         .map(|s| s.stylesheet.clone())
                         .collect()
     }
 
+    pub fn with_style_sheets_in_document<F, T>(&self, mut f: F) -> T
+            where F: FnMut(&[StylesheetInDocument]) -> T {
+        self.ensure_stylesheets();
+        f(&self.stylesheets.borrow().as_ref().unwrap())
+    }
+
     /// https://html.spec.whatwg.org/multipage/#appropriate-template-contents-owner-document
     pub fn appropriate_template_contents_owner_document(&self) -> Root<Document> {
         self.appropriate_template_contents_owner_document.or_init(|| {
             let doctype = if self.is_html_document {
                 IsHTMLDocument::HTMLDocument
             } else {
                 IsHTMLDocument::NonHTMLDocument
             };
@@ -2033,17 +2034,17 @@ impl Element {
             _ => false,
         }
     }
 }
 
 impl DocumentMethods for Document {
     // https://drafts.csswg.org/cssom/#dom-document-stylesheets
     fn StyleSheets(&self) -> Root<StyleSheetList> {
-        StyleSheetList::new(&self.window, JS::from_ref(&self))
+        self.stylesheet_list.or_init(|| StyleSheetList::new(&self.window, JS::from_ref(&self)))
     }
 
     // https://dom.spec.whatwg.org/#dom-document-implementation
     fn Implementation(&self) -> Root<DOMImplementation> {
         self.implementation.or_init(|| DOMImplementation::new(self))
     }
 
     // https://dom.spec.whatwg.org/#dom-document-url
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -9,16 +9,17 @@ use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods;
 use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
 use dom::bindings::codegen::Bindings::HTMLLinkElementBinding::HTMLLinkElementMethods;
 use dom::bindings::inheritance::Castable;
 use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
 use dom::bindings::refcounted::Trusted;
 use dom::bindings::reflector::Reflectable;
 use dom::bindings::str::DOMString;
+use dom::cssstylesheet::CSSStyleSheet;
 use dom::document::Document;
 use dom::domtokenlist::DOMTokenList;
 use dom::element::{AttributeMutation, Element, ElementCreator};
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::htmlelement::HTMLElement;
 use dom::node::{Node, document_from_node, window_from_node};
 use dom::virtualmethods::VirtualMethods;
@@ -51,45 +52,59 @@ use url::Url;
 no_jsmanaged_fields!(Stylesheet);
 
 #[dom_struct]
 pub struct HTMLLinkElement {
     htmlelement: HTMLElement,
     rel_list: MutNullableHeap<JS<DOMTokenList>>,
     #[ignore_heap_size_of = "Arc"]
     stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
+    cssom_stylesheet: MutNullableHeap<JS<CSSStyleSheet>>,
 
     /// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts
     parser_inserted: Cell<bool>,
 }
 
 impl HTMLLinkElement {
     fn new_inherited(local_name: LocalName, prefix: Option<DOMString>, document: &Document,
                      creator: ElementCreator) -> HTMLLinkElement {
         HTMLLinkElement {
             htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
             rel_list: Default::default(),
             parser_inserted: Cell::new(creator == ElementCreator::ParserCreated),
             stylesheet: DOMRefCell::new(None),
+            cssom_stylesheet: MutNullableHeap::new(None),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(local_name: LocalName,
                prefix: Option<DOMString>,
                document: &Document,
                creator: ElementCreator) -> Root<HTMLLinkElement> {
         Node::reflect_node(box HTMLLinkElement::new_inherited(local_name, prefix, document, creator),
                            document,
                            HTMLLinkElementBinding::Wrap)
     }
 
     pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
         self.stylesheet.borrow().clone()
     }
+
+    pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
+        self.get_stylesheet().map(|sheet| {
+            self.cssom_stylesheet.or_init(|| {
+                CSSStyleSheet::new(&window_from_node(self),
+                                   "text/css".into(),
+                                   None, // todo handle location
+                                   None, // todo handle title
+                                   sheet)
+            })
+        })
+    }
 }
 
 fn get_attr(element: &Element, local_name: &LocalName) -> Option<String> {
     let elem = element.get_attribute(&ns!(), local_name);
     elem.map(|e| {
         let value = e.value();
         (**value).to_owned()
     })
--- a/servo/components/script/dom/htmlmetaelement.rs
+++ b/servo/components/script/dom/htmlmetaelement.rs
@@ -3,63 +3,78 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use dom::attr::Attr;
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
 use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
 use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
 use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{Root, RootedReference};
+use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
 use dom::bindings::str::DOMString;
+use dom::cssstylesheet::CSSStyleSheet;
 use dom::document::Document;
 use dom::element::{AttributeMutation, Element};
 use dom::htmlelement::HTMLElement;
 use dom::htmlheadelement::HTMLHeadElement;
-use dom::node::{Node, UnbindContext, document_from_node};
+use dom::node::{Node, UnbindContext, document_from_node, window_from_node};
 use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
 use parking_lot::RwLock;
 use std::ascii::AsciiExt;
 use std::sync::Arc;
 use style::attr::AttrValue;
 use style::str::HTML_SPACE_CHARACTERS;
 use style::stylesheets::{Stylesheet, CssRule, Origin};
 use style::viewport::ViewportRule;
 
 #[dom_struct]
 pub struct HTMLMetaElement {
     htmlelement: HTMLElement,
     #[ignore_heap_size_of = "Arc"]
     stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
+    cssom_stylesheet: MutNullableHeap<JS<CSSStyleSheet>>,
 }
 
 impl HTMLMetaElement {
     fn new_inherited(local_name: LocalName,
                      prefix: Option<DOMString>,
                      document: &Document) -> HTMLMetaElement {
         HTMLMetaElement {
             htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
             stylesheet: DOMRefCell::new(None),
+            cssom_stylesheet: MutNullableHeap::new(None),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(local_name: LocalName,
                prefix: Option<DOMString>,
                document: &Document) -> Root<HTMLMetaElement> {
         Node::reflect_node(box HTMLMetaElement::new_inherited(local_name, prefix, document),
                            document,
                            HTMLMetaElementBinding::Wrap)
     }
 
     pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
         self.stylesheet.borrow().clone()
     }
 
+    pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
+        self.get_stylesheet().map(|sheet| {
+            self.cssom_stylesheet.or_init(|| {
+                CSSStyleSheet::new(&window_from_node(self),
+                                   "text/css".into(),
+                                   None, // todo handle location
+                                   None, // todo handle title
+                                   sheet)
+            })
+        })
+    }
+
     fn process_attributes(&self) {
         let element = self.upcast::<Element>();
         if let Some(name) = element.get_attribute(&ns!(), &local_name!("name")).r() {
             let name = name.value().to_ascii_lowercase();
             let name = name.trim_matches(HTML_SPACE_CHARACTERS);
 
             if name == "viewport" {
                 self.apply_viewport();
@@ -76,17 +91,17 @@ impl HTMLMetaElement {
             return;
         }
         let element = self.upcast::<Element>();
         if let Some(content) = element.get_attribute(&ns!(), &local_name!("content")).r() {
             let content = content.value();
             if !content.is_empty() {
                 if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
                     *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
-                        rules: vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))],
+                        rules: vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))].into(),
                         origin: Origin::Author,
                         media: Default::default(),
                         // Viewport constraints are always recomputed on resize; they don't need to
                         // force all styles to be recomputed.
                         dirty_on_viewport_size_change: false,
                     }));
                     let doc = document_from_node(self);
                     doc.invalidate_stylesheets();
--- a/servo/components/script/dom/htmlstyleelement.rs
+++ b/servo/components/script/dom/htmlstyleelement.rs
@@ -2,18 +2,19 @@
  * 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 as CssParser;
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::HTMLStyleElementBinding;
 use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
 use dom::bindings::inheritance::Castable;
-use dom::bindings::js::Root;
+use dom::bindings::js::{JS, MutNullableHeap, Root};
 use dom::bindings::str::DOMString;
+use dom::cssstylesheet::CSSStyleSheet;
 use dom::document::Document;
 use dom::element::Element;
 use dom::htmlelement::HTMLElement;
 use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node};
 use dom::virtualmethods::VirtualMethods;
 use html5ever_atoms::LocalName;
 use script_layout_interface::message::Msg;
 use std::sync::Arc;
@@ -21,25 +22,27 @@ use style::media_queries::parse_media_qu
 use style::parser::ParserContextExtraData;
 use style::stylesheets::{Stylesheet, Origin};
 
 #[dom_struct]
 pub struct HTMLStyleElement {
     htmlelement: HTMLElement,
     #[ignore_heap_size_of = "Arc"]
     stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
+    cssom_stylesheet: MutNullableHeap<JS<CSSStyleSheet>>,
 }
 
 impl HTMLStyleElement {
     fn new_inherited(local_name: LocalName,
                      prefix: Option<DOMString>,
                      document: &Document) -> HTMLStyleElement {
         HTMLStyleElement {
             htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
             stylesheet: DOMRefCell::new(None),
+            cssom_stylesheet: MutNullableHeap::new(None),
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(local_name: LocalName,
                prefix: Option<DOMString>,
                document: &Document) -> Root<HTMLStyleElement> {
         Node::reflect_node(box HTMLStyleElement::new_inherited(local_name, prefix, document),
@@ -72,16 +75,28 @@ impl HTMLStyleElement {
         *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>> {
+        self.get_stylesheet().map(|sheet| {
+            self.cssom_stylesheet.or_init(|| {
+                CSSStyleSheet::new(&window_from_node(self),
+                                   "text/css".into(),
+                                   None, // todo handle location
+                                   None, // todo handle title
+                                   sheet)
+            })
+        })
+    }
 }
 
 impl VirtualMethods for HTMLStyleElement {
     fn super_type(&self) -> Option<&VirtualMethods> {
         Some(self.upcast::<HTMLElement>() as &VirtualMethods)
     }
 
     fn children_changed(&self, mutation: &ChildrenMutation) {
--- a/servo/components/script/dom/mod.rs
+++ b/servo/components/script/dom/mod.rs
@@ -237,17 +237,27 @@ pub mod canvaspattern;
 pub mod canvasrenderingcontext2d;
 pub mod characterdata;
 pub mod client;
 pub mod closeevent;
 pub mod comment;
 pub mod console;
 pub mod crypto;
 pub mod css;
+pub mod cssfontfacerule;
+pub mod cssgroupingrule;
+pub mod csskeyframesrule;
+pub mod cssmediarule;
+pub mod cssnamespacerule;
+pub mod cssrule;
+pub mod cssrulelist;
 pub mod cssstyledeclaration;
+pub mod cssstylerule;
+pub mod cssstylesheet;
+pub mod cssviewportrule;
 pub mod customevent;
 pub mod dedicatedworkerglobalscope;
 pub mod document;
 pub mod documentfragment;
 pub mod documenttype;
 pub mod domexception;
 pub mod domimplementation;
 pub mod dommatrix;
--- a/servo/components/script/dom/node.rs
+++ b/servo/components/script/dom/node.rs
@@ -25,29 +25,33 @@ use dom::bindings::inheritance::{EventTa
 use dom::bindings::inheritance::{SVGElementTypeId, SVGGraphicsElementTypeId};
 use dom::bindings::js::{JS, LayoutJS, MutNullableHeap};
 use dom::bindings::js::Root;
 use dom::bindings::js::RootedReference;
 use dom::bindings::reflector::{Reflectable, reflect_dom_object};
 use dom::bindings::str::{DOMString, USVString};
 use dom::bindings::xmlname::namespace_from_domstring;
 use dom::characterdata::{CharacterData, LayoutCharacterDataHelpers};
+use dom::cssstylesheet::CSSStyleSheet;
 use dom::document::{Document, DocumentSource, IsHTMLDocument};
 use dom::documentfragment::DocumentFragment;
 use dom::documenttype::DocumentType;
 use dom::element::{Element, ElementCreator};
 use dom::eventtarget::EventTarget;
 use dom::globalscope::GlobalScope;
 use dom::htmlbodyelement::HTMLBodyElement;
 use dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
 use dom::htmlcollection::HTMLCollection;
 use dom::htmlelement::HTMLElement;
 use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods};
 use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
 use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
+use dom::htmllinkelement::HTMLLinkElement;
+use dom::htmlmetaelement::HTMLMetaElement;
+use dom::htmlstyleelement::HTMLStyleElement;
 use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
 use dom::nodelist::NodeList;
 use dom::processinginstruction::ProcessingInstruction;
 use dom::range::WeakRangeVec;
 use dom::servoparser::ServoParser;
 use dom::svgsvgelement::{SVGSVGElement, LayoutSVGSVGElementHelpers};
 use dom::text::Text;
 use dom::virtualmethods::{VirtualMethods, vtable_for};
@@ -71,18 +75,20 @@ use selectors::parser::Selector;
 use selectors::parser::parse_author_origin_selector_list_from_str;
 use std::borrow::ToOwned;
 use std::cell::{Cell, UnsafeCell};
 use std::cmp::max;
 use std::default::Default;
 use std::iter;
 use std::mem;
 use std::ops::Range;
+use std::sync::Arc;
 use style::dom::OpaqueNode;
 use style::selector_impl::ServoSelectorImpl;
+use style::stylesheets::Stylesheet;
 use style::thread_state;
 use url::Url;
 use uuid::Uuid;
 
 //
 // The basic Node structure
 //
 
@@ -896,16 +902,40 @@ impl Node {
                 Some(element) => element,
                 None => return Err(Error::IndexSize),
             },
         };
 
         element.upcast::<Node>().remove_self();
         Ok(())
     }
+
+    pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
+        if let Some(node) = self.downcast::<HTMLStyleElement>() {
+            node.get_stylesheet()
+        } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
+            node.get_stylesheet()
+        } else if let Some(node) = self.downcast::<HTMLMetaElement>() {
+            node.get_stylesheet()
+        } else {
+            None
+        }
+    }
+
+    pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
+        if let Some(node) = self.downcast::<HTMLStyleElement>() {
+            node.get_cssom_stylesheet()
+        } else if let Some(node) = self.downcast::<HTMLLinkElement>() {
+            node.get_cssom_stylesheet()
+        } else if let Some(node) = self.downcast::<HTMLMetaElement>() {
+            node.get_cssom_stylesheet()
+        } else {
+            None
+        }
+    }
 }
 
 
 /// Iterate through `nodes` until we find a `Node` that is not in `not_in`
 fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<Root<Node>>
         where I: Iterator<Item=Root<Node>>
 {
     nodes.find(|node| {
--- a/servo/components/script/dom/stylesheet.rs
+++ b/servo/components/script/dom/stylesheet.rs
@@ -15,17 +15,17 @@ pub struct StyleSheet {
     reflector_: Reflector,
     type_: DOMString,
     href: Option<DOMString>,
     title: Option<DOMString>,
 }
 
 impl StyleSheet {
     #[allow(unrooted_must_root)]
-    fn new_inherited(type_: DOMString, href: Option<DOMString>, title: Option<DOMString>) -> StyleSheet {
+    pub fn new_inherited(type_: DOMString, href: Option<DOMString>, title: Option<DOMString>) -> StyleSheet {
         StyleSheet {
             reflector_: Reflector::new(),
             type_: type_,
             href: href,
             title: title
         }
     }
 
--- a/servo/components/script/dom/stylesheetlist.rs
+++ b/servo/components/script/dom/stylesheetlist.rs
@@ -30,22 +30,27 @@ impl StyleSheetList {
         reflect_dom_object(box StyleSheetList::new_inherited(document),
                            window, StyleSheetListBinding::Wrap)
     }
 }
 
 impl StyleSheetListMethods for StyleSheetList {
     // https://drafts.csswg.org/cssom/#dom-stylesheetlist-length
     fn Length(&self) -> u32 {
-       self.document.stylesheets().len() as u32
+       self.document.with_style_sheets_in_document(|s| s.len() as u32)
     }
 
     // https://drafts.csswg.org/cssom/#dom-stylesheetlist-item
-    fn Item(&self, _index: u32) -> Option<Root<StyleSheet>> {
-        None
-        //TODO Create a new StyleSheet object and return it
+    fn Item(&self, index: u32) -> Option<Root<StyleSheet>> {
+        // XXXManishearth this  doesn't handle the origin clean flag
+        // and is a cors vulnerability
+        self.document.with_style_sheets_in_document(|sheets| {
+            sheets.get(index as usize)
+                  .and_then(|sheet| sheet.node.get_cssom_stylesheet())
+                  .map(Root::upcast)
+        })
     }
 
     // check-tidy: no specs after this line
     fn IndexedGetter(&self, index: u32) -> Option<Root<StyleSheet>> {
         self.Item(index)
     }
 }
--- a/servo/components/script/dom/webidls/CSS.webidl
+++ b/servo/components/script/dom/webidls/CSS.webidl
@@ -1,13 +1,13 @@
 /* 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 origin of this IDL file is
  * http://dev.w3.org/csswg/cssom/#the-css-interface
  */
 
-[Abstract, Exposed=(Window,Worker)]
+[Abstract, Exposed=Window]
 interface CSS {
   [Throws]
   static DOMString escape(DOMString ident);
 };
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSFontFaceRule.webidl
@@ -0,0 +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/. */
+
+// https://drafts.csswg.org/css-fonts/#cssfontfacerule
+[Exposed=Window]
+interface CSSFontFaceRule : CSSRule {
+  // attribute DOMString family;
+  // attribute DOMString src;
+  // attribute DOMString style;
+  // attribute DOMString weight;
+  // attribute DOMString stretch;
+  // attribute DOMString unicodeRange;
+  // attribute DOMString variant;
+  // attribute DOMString featureSettings;
+};
+
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSGroupingRule.webidl
@@ -0,0 +1,12 @@
+/* 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/. */
+
+// https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
+[Exposed=Window]
+interface CSSGroupingRule : CSSRule {
+  // [SameObject] readonly attribute CSSRuleList cssRules;
+  // unsigned long insertRule(DOMString rule, unsigned long index);
+  // void deleteRule(unsigned long index);
+};
+
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSKeyframesRule.webidl
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// https://drafts.csswg.org/css-animations/#interface-csskeyframesrule
+[Exposed=Window]
+interface CSSKeyframesRule : CSSRule {
+  //          attribute DOMString   name;
+  // readonly attribute CSSRuleList cssRules;
+
+  // void            appendRule(DOMString rule);
+  // void            deleteRule(DOMString select);
+  // CSSKeyframeRule? findRule(DOMString select);
+};
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSMediaRule.webidl
@@ -0,0 +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/. */
+
+// https://drafts.csswg.org/cssom/#the-cssmediarule-interface
+[Exposed=Window]
+interface CSSMediaRule : CSSGroupingRule {
+  // [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
+};
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSNamespaceRule.webidl
@@ -0,0 +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/. */
+
+// https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface
+[Exposed=Window]
+interface CSSNamespaceRule : CSSRule {
+  // readonly attribute DOMString namespaceURI;
+  // readonly attribute DOMString prefix;
+};
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSRule.webidl
@@ -0,0 +1,33 @@
+/* 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/. */
+
+// https://drafts.csswg.org/cssom/#the-cssrule-interface
+[Exposed=Window]
+interface CSSRule {
+  const unsigned short STYLE_RULE = 1;
+  const unsigned short CHARSET_RULE = 2; // historical
+  const unsigned short IMPORT_RULE = 3;
+  const unsigned short MEDIA_RULE = 4;
+  const unsigned short FONT_FACE_RULE = 5;
+  const unsigned short PAGE_RULE = 6;
+  const unsigned short MARGIN_RULE = 9;
+  const unsigned short NAMESPACE_RULE = 10;
+
+  readonly attribute unsigned short type;
+  attribute DOMString cssText;
+  // readonly attribute CSSRule? parentRule;
+  readonly attribute CSSStyleSheet? parentStyleSheet;
+};
+
+// https://drafts.csswg.org/css-animations/#interface-cssrule-idl
+partial interface CSSRule {
+    const unsigned short KEYFRAMES_RULE = 7;
+    const unsigned short KEYFRAME_RULE = 8;
+};
+
+// https://drafts.csswg.org/css-device-adapt/#css-rule-interface
+partial interface CSSRule {
+    const unsigned short VIEWPORT_RULE = 15;
+};
+
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSRuleList.webidl
@@ -0,0 +1,11 @@
+/* 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/. */
+
+// https://drafts.csswg.org/cssom/#cssrulelist
+// [LegacyArrayClass]
+[Exposed=Window]
+interface CSSRuleList {
+  getter CSSRule? item(unsigned long index);
+  readonly attribute unsigned long length;
+};
--- a/servo/components/script/dom/webidls/CSSStyleDeclaration.webidl
+++ b/servo/components/script/dom/webidls/CSSStyleDeclaration.webidl
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 /*
  * The origin of this IDL file is
  * http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
  *
  * Copyright © 2013 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
  */
 
-[Exposed=(Window,Worker)]
+[Exposed=(Window, Worker)]
 interface CSSStyleDeclaration {
   [SetterThrows]
            attribute DOMString cssText;
   readonly attribute unsigned long length;
   getter DOMString item(unsigned long index);
   DOMString getPropertyValue(DOMString property);
   DOMString getPropertyPriority(DOMString property);
   [Throws]
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSStyleRule.webidl
@@ -0,0 +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/. */
+
+// https://drafts.csswg.org/cssom/#the-cssstylerule-interface
+[Exposed=Window]
+interface CSSStyleRule : CSSRule {
+  // attribute DOMString selectorText;
+  // [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
+};
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSStyleSheet.webidl
@@ -0,0 +1,12 @@
+/* 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/. */
+
+// https://drafts.csswg.org/cssom/#the-cssstylesheet-interface
+[Exposed=Window]
+interface CSSStyleSheet : StyleSheet {
+  // readonly attribute CSSRule? ownerRule;
+  [SameObject] readonly attribute CSSRuleList cssRules;
+  // unsigned long insertRule(DOMString rule, unsigned long index);
+  // void deleteRule(unsigned long index);
+};
new file mode 100644
--- /dev/null
+++ b/servo/components/script/dom/webidls/CSSViewportRule.webidl
@@ -0,0 +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/. */
+
+// https://drafts.csswg.org/css-device-adapt/#css-viewport-rule-interface
+[Exposed=Window]
+interface CSSViewportRule : CSSRule {
+    // readonly attribute CSSStyleDeclaration style;
+};
--- a/servo/components/script/dom/webidls/StyleSheet.webidl
+++ b/servo/components/script/dom/webidls/StyleSheet.webidl
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // https://drafts.csswg.org/cssom/#the-stylesheet-interface
-[Exposed=(Window,Worker)]
+[Exposed=Window]
 interface StyleSheet {
   readonly attribute DOMString type_;
   readonly attribute DOMString? href;
 
   // readonly attribute (Element or ProcessingInstruction)? ownerNode;
   // readonly attribute StyleSheet? parentStyleSheet;
   readonly attribute DOMString? title;
 
--- a/servo/components/script/dom/webidls/StyleSheetList.webidl
+++ b/servo/components/script/dom/webidls/StyleSheetList.webidl
@@ -1,11 +1,11 @@
 /* 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/. */
 
 // https://drafts.csswg.org/cssom/#the-stylesheetlist-interface
 // [ArrayClass]
-[Exposed=(Window,Worker)]
+[Exposed=Window]
 interface StyleSheetList {
   getter StyleSheet? item(unsigned long index);
   readonly attribute unsigned long length;
 };
--- a/servo/components/style/selector_matching.rs
+++ b/servo/components/style/selector_matching.rs
@@ -383,17 +383,17 @@ impl Stylist {
                     mq_eval_changed(rules, before, after)
                 }) {
                     return true
                 }
             }
             false
         }
         self.is_device_dirty |= stylesheets.iter().any(|stylesheet| {
-            mq_eval_changed(&stylesheet.rules, &self.device, &device)
+            mq_eval_changed(&stylesheet.rules.0.read(), &self.device, &device)
         });
 
         self.device = device;
     }
 
     pub fn viewport_constraints(&self) -> &Option<ViewportConstraints> {
         &self.viewport_constraints
     }
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -2,28 +2,31 @@
  * 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.
 
 use {Atom, Prefix, Namespace};
 use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
 use cssparser::{AtRuleType, RuleListParser, Token};
+use cssparser::ToCss as ParserToCss;
 use encoding::EncodingRef;
 use error_reporting::ParseErrorReporter;
 use font_face::{FontFaceRule, parse_font_face_block};
 use keyframes::{Keyframe, parse_keyframe_list};
 use media_queries::{Device, MediaList, parse_media_query_list};
 use parking_lot::RwLock;
 use parser::{ParserContext, ParserContextExtraData, log_css_error};
 use properties::{PropertyDeclarationBlock, parse_property_declaration_list};
 use selector_impl::TheSelectorImpl;
 use selectors::parser::{Selector, parse_selector_list};
 use std::cell::Cell;
+use std::fmt;
 use std::sync::Arc;
+use style_traits::ToCss;
 use url::Url;
 use viewport::ViewportRule;
 
 
 /// Each style rule has an origin, which determines where it enters the cascade.
 ///
 /// http://dev.w3.org/csswg/css-cascade/#cascading-origins
 #[derive(Clone, PartialEq, Eq, Copy, Debug)]
@@ -34,37 +37,45 @@ pub enum Origin {
 
     /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-author
     Author,
 
     /// http://dev.w3.org/csswg/css-cascade/#cascade-origin-user
     User,
 }
 
+#[derive(Debug, Clone)]
+pub struct CssRules(pub Arc<RwLock<Vec<CssRule>>>);
+
+impl From<Vec<CssRule>> for CssRules {
+    fn from(other: Vec<CssRule>) -> Self {
+        CssRules(Arc::new(RwLock::new(other)))
+    }
+}
 
 #[derive(Debug)]
 pub struct Stylesheet {
     /// List of rules in the order they were found (important for
     /// cascading order)
-    pub rules: Vec<CssRule>,
+    pub rules: CssRules,
     /// List of media associated with the Stylesheet.
     pub media: MediaList,
     pub origin: Origin,
     pub dirty_on_viewport_size_change: bool,
 }
 
 
 /// This structure holds the user-agent and user stylesheets.
 pub struct UserAgentStylesheets {
     pub user_or_user_agent_stylesheets: Vec<Stylesheet>,
     pub quirks_mode_stylesheet: Stylesheet,
 }
 
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum CssRule {
     // No Charset here, CSSCharsetRule has been removed from CSSOM
     // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
 
     Namespace(Arc<RwLock<NamespaceRule>>),
     Style(Arc<RwLock<StyleRule>>),
     Media(Arc<RwLock<MediaRule>>),
     FontFace(Arc<RwLock<FontFaceRule>>),
@@ -84,17 +95,18 @@ impl CssRule {
             CssRule::FontFace(_) |
             CssRule::Viewport(_) |
             CssRule::Keyframes(_) => {
                 f(&[], None)
             }
             CssRule::Media(ref lock) => {
                 let media_rule = lock.read();
                 let mq = media_rule.media_queries.read();
-                f(&media_rule.rules, Some(&mq))
+                let rules = media_rule.rules.0.read();
+                f(&rules, Some(&mq))
             }
         }
     }
 }
 
 #[derive(Debug, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct NamespaceRule {
@@ -107,25 +119,60 @@ pub struct NamespaceRule {
 pub struct KeyframesRule {
     pub name: Atom,
     pub keyframes: Vec<Arc<RwLock<Keyframe>>>,
 }
 
 #[derive(Debug)]
 pub struct MediaRule {
     pub media_queries: Arc<RwLock<MediaList>>,
-    pub rules: Vec<CssRule>,
+    pub rules: CssRules,
 }
 
 #[derive(Debug)]
 pub struct StyleRule {
     pub selectors: Vec<Selector<TheSelectorImpl>>,
     pub block: Arc<RwLock<PropertyDeclarationBlock>>,
 }
 
+impl StyleRule {
+    /// Serialize the group of selectors for this rule.
+    ///
+    /// https://drafts.csswg.org/cssom/#serialize-a-group-of-selectors
+    pub fn selectors_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        let mut iter = self.selectors.iter();
+        try!(iter.next().unwrap().to_css(dest));
+        for selector in iter {
+            try!(write!(dest, ", "));
+            try!(selector.to_css(dest));
+        }
+        Ok(())
+    }
+}
+
+impl ToCss for StyleRule {
+    // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        // Step 1
+        try!(self.selectors_to_css(dest));
+        // Step 2
+        try!(dest.write_str(" { "));
+        // Step 3
+        let declaration_block = self.block.read();
+        try!(declaration_block.to_css(dest));
+        // Step 4
+        if declaration_block.declarations.len() > 0 {
+            try!(write!(dest, " "));
+        }
+        // Step 5
+        try!(dest.write_str("}"));
+        Ok(())
+    }
+}
+
 
 impl Stylesheet {
     pub fn from_bytes_iter<I: Iterator<Item=Vec<u8>>>(
             input: I, base_url: Url, protocol_encoding_label: Option<&str>,
             environment_encoding: Option<EncodingRef>, origin: Origin,
             error_reporter: Box<ParseErrorReporter + Send>,
             extra_data: ParserContextExtraData) -> Stylesheet {
         let mut bytes = vec![];
@@ -175,17 +222,17 @@ impl Stylesheet {
                         log_css_error(iter.input, pos, &*message, &context);
                     }
                 }
             }
         }
 
         Stylesheet {
             origin: origin,
-            rules: rules,
+            rules: rules.into(),
             media: Default::default(),
             dirty_on_viewport_size_change:
                 input.seen_viewport_percentages(),
         }
     }
 
     /// Set the MediaList associated with the style-sheet.
     pub fn set_media(&mut self, media: MediaList) {
@@ -203,17 +250,17 @@ impl Stylesheet {
     /// 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, mut f: F) where F: FnMut(&CssRule) {
-        effective_rules(&self.rules, device, &mut f);
+        effective_rules(&self.rules.0.read(), device, &mut f);
     }
 }
 
 fn effective_rules<F>(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) {
     for rule in rules {
         f(rule);
         rule.with_nested_rules_and_mq(|rules, mq| {
             if let Some(media_queries) = mq {
@@ -246,31 +293,31 @@ macro_rules! rule_filter {
 rule_filter! {
     effective_style_rules(Style => StyleRule),
     effective_media_rules(Media => MediaRule),
     effective_font_face_rules(FontFace => FontFaceRule),
     effective_viewport_rules(Viewport => ViewportRule),
     effective_keyframes_rules(Keyframes => KeyframesRule),
 }
 
-fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> Vec<CssRule> {
+fn parse_nested_rules(context: &ParserContext, input: &mut Parser) -> CssRules {
     let mut iter = RuleListParser::new_for_nested_rule(input,
                                                        NestedRuleParser { context: context });
     let mut rules = Vec::new();
     while let Some(result) = iter.next() {
         match result {
             Ok(rule) => rules.push(rule),
             Err(range) => {
                 let pos = range.start;
                 let message = format!("Unsupported rule: '{}'", iter.input.slice(range));
                 log_css_error(iter.input, pos, &*message, &context);
             }
         }
     }
-    rules
+    rules.into()
 }
 
 
 struct TopLevelRuleParser<'a> {
     context: ParserContext<'a>,
     state: Cell<State>,
 }
 
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -250,17 +250,17 @@ pub extern "C" fn Servo_StyleSet_RemoveS
     let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let sheet = HasArcFFI::as_arc(&raw_sheet);
     data.stylesheets.retain(|x| !arc_ptr_eq(x, sheet));
     data.stylesheets_changed = true;
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool {
-    !Stylesheet::as_arc(&raw_sheet).rules.is_empty()
+    !Stylesheet::as_arc(&raw_sheet).rules.0.read().is_empty()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_AddRef(sheet: RawServoStyleSheetBorrowed) -> () {
     unsafe { Stylesheet::addref(sheet) };
 }
 
 #[no_mangle]
--- a/servo/python/tidy/servo_tidy/tidy.py
+++ b/servo/python/tidy/servo_tidy/tidy.py
@@ -58,17 +58,17 @@ WEBIDL_STANDARDS = [
     "//www.khronos.org/registry/webgl/specs",
     "//developer.mozilla.org/en-US/docs/Web/API",
     "//dev.w3.org/2006/webapi",
     "//dev.w3.org/csswg",
     "//dev.w3.org/fxtf",
     "//dvcs.w3.org/hg",
     "//dom.spec.whatwg.org",
     "//domparsing.spec.whatwg.org",
-    "//drafts.csswg.org/cssom",
+    "//drafts.csswg.org",
     "//drafts.fxtf.org",
     "//encoding.spec.whatwg.org",
     "//fetch.spec.whatwg.org",
     "//html.spec.whatwg.org",
     "//url.spec.whatwg.org",
     "//xhr.spec.whatwg.org",
     "//w3c.github.io",
     "//heycam.github.io/webidl",
--- a/servo/tests/unit/style/media_queries.rs
+++ b/servo/tests/unit/style/media_queries.rs
@@ -24,17 +24,17 @@ impl ParseErrorReporter for CSSErrorRepo
      }
 }
 
 fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaList, &str) {
     let url = Url::parse("http://localhost").unwrap();
     let stylesheet = Stylesheet::from_str(css, url, Origin::Author, Box::new(CSSErrorReporterTest),
                                           ParserContextExtraData::default());
     let mut rule_count = 0;
-    media_queries(&stylesheet.rules, &mut |mq| {
+    media_queries(&stylesheet.rules.0.read(), &mut |mq| {
         rule_count += 1;
         callback(mq, css);
     });
     assert!(rule_count > 0);
 }
 
 fn media_queries<F>(rules: &[CssRule], f: &mut F) where F: FnMut(&MediaList) {
     for rule in rules {
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -251,17 +251,17 @@ fn test_parse_stylesheet() {
                                  Importance::Normal),
                             ],
                             important_count: 0,
                         })),
                     })),
                 ]
             })))
 
-        ],
+        ].into(),
     };
 
     assert_eq!(format!("{:#?}", stylesheet), format!("{:#?}", expected));
 }
 
 struct CSSError {
     pub line: usize,
     pub column: usize,