Bug 1307357 part 3 - Implement CSSRuleList interface for stylo. r?heycam,manishearth draft
authorXidorn Quan <me@upsuper.org>
Tue, 08 Nov 2016 11:19:52 +1100
changeset 441104 5fd53408e83895508cf201283285596a4c4b5117
parent 441103 262b7cb8fe34655f6497f7ebabe28bdd7cf7a107
child 441105 4b1ee8b0a5529db11f315f6765a6f61140a3eeae
push id36358
push userxquan@mozilla.com
push dateFri, 18 Nov 2016 11:59:57 +0000
reviewersheycam, manishearth
bugs1307357
milestone53.0a1
Bug 1307357 part 3 - Implement CSSRuleList interface for stylo. r?heycam,manishearth MozReview-Commit-ID: Ecnbj66yKOE
layout/style/ServoBindingList.h
layout/style/ServoBindingTypes.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoCSSRuleList.cpp
layout/style/ServoCSSRuleList.h
layout/style/ServoStyleSheet.cpp
layout/style/ServoStyleSheet.h
layout/style/moz.build
servo/components/style/binding_tools/regen.py
servo/components/style/gecko/conversions.rs
servo/components/style/gecko_bindings/bindings.rs
servo/components/style/stylesheets.rs
servo/ports/geckolib/glue.rs
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -32,28 +32,35 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_From
                    ThreadSafeURIHolder* referrer,
                    ThreadSafePrincipalHolder* principal)
 SERVO_BINDING_FUNC(Servo_StyleSheet_AddRef, void,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_Release, void,
                    RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
                    RawServoStyleSheetBorrowed sheet)
+SERVO_BINDING_FUNC(Servo_StyleSheet_GetRules, ServoCssRulesStrong,
+                   RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned)
 SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
 SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void,
                    RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_PrependStyleSheet, void,
                    RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void,
                    RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void,
                    RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet,
                    RawServoStyleSheetBorrowed reference)
 
+// CSSRuleList
+SERVO_BINDING_FUNC(Servo_CssRules_ListTypes, void,
+                   ServoCssRulesBorrowed rules,
+                   nsTArrayBorrowed_uintptr_t result)
+
 // Animations API
 SERVO_BINDING_FUNC(Servo_ParseProperty,
                    RawServoDeclarationBlockStrong,
                    const nsACString* property, const nsACString* value,
                    const nsACString* base_url, ThreadSafeURIHolder* base,
                    ThreadSafeURIHolder* referrer,
                    ThreadSafePrincipalHolder* principal)
 SERVO_BINDING_FUNC(Servo_RestyleWithAddedDeclaration,
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_ServoBindingTypes_h
 #define mozilla_ServoBindingTypes_h
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 
 struct ServoComputedValues;
+struct ServoCssRules;
 struct RawServoStyleSheet;
 struct RawServoStyleSet;
 struct RawServoDeclarationBlock;
 
 namespace mozilla {
 namespace dom {
 class Element;
 class StyleChildrenIterator;
@@ -67,16 +68,17 @@ typedef nsIDocument RawGeckoDocument;
   DECL_BORROWED_MUT_REF_TYPE_FOR(type_)
 
 #define DECL_NULLABLE_OWNED_REF_TYPE_FOR(type_)    \
   typedef type_* type_##OwnedOrNull;               \
   DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_)       \
   DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
 
 DECL_ARC_REF_TYPE_FOR(ServoComputedValues)
+DECL_ARC_REF_TYPE_FOR(ServoCssRules)
 DECL_ARC_REF_TYPE_FOR(RawServoStyleSheet)
 DECL_ARC_REF_TYPE_FOR(RawServoDeclarationBlock)
 // This is a reference to a reference of RawServoDeclarationBlock, which
 // corresponds to Option<&Arc<RawServoDeclarationBlock>> in Servo side.
 DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoDeclarationBlockStrong)
 
 DECL_OWNED_REF_TYPE_FOR(RawServoStyleSet)
 DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
@@ -116,16 +118,17 @@ DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSValu
       Servo_##name_##_AddRef(aPtr);                  \
     }                                                \
     static void Release(type_* aPtr) {               \
       Servo_##name_##_Release(aPtr);                 \
     }                                                \
   };                                                 \
   }
 
+DEFINE_REFPTR_TRAITS(CssRules, ServoCssRules)
 DEFINE_REFPTR_TRAITS(StyleSheet, RawServoStyleSheet)
 DEFINE_REFPTR_TRAITS(ComputedValues, ServoComputedValues)
 DEFINE_REFPTR_TRAITS(DeclarationBlock, RawServoDeclarationBlock)
 
 #undef DEFINE_REFPTR_TRAITS
 
 extern "C" void Servo_StyleSet_Drop(RawServoStyleSetOwned ptr);
 
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -40,16 +40,17 @@ using namespace mozilla::dom;
   already_AddRefed<type_>               \
   type_##Strong::Consume() {            \
     RefPtr<type_> result;               \
     result.swap(mPtr);                  \
     return result.forget();             \
   }
 
 IMPL_STRONG_REF_TYPE_FOR(ServoComputedValues)
+IMPL_STRONG_REF_TYPE_FOR(ServoCssRules)
 IMPL_STRONG_REF_TYPE_FOR(RawServoStyleSheet)
 IMPL_STRONG_REF_TYPE_FOR(RawServoDeclarationBlock)
 
 #undef IMPL_STRONG_REF_TYPE_FOR
 
 uint32_t
 Gecko_ChildrenCount(RawGeckoNodeBorrowed aNode)
 {
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -59,16 +59,26 @@ struct nsStyleDisplay;
   void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr); \
   void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr);
 #define NS_IMPL_HOLDER_FFI_REFCOUNTING(class_, name_)                         \
   void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr)  \
   { NS_ADDREF(aPtr); }                                                        \
   void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr) \
   { NS_RELEASE(aPtr); }                                                       \
 
+
+#define DEFINE_ARRAY_TYPE_FOR(type_)                                \
+  struct nsTArrayBorrowed_##type_ {                                 \
+    nsTArray<type_>* mArray;                                        \
+    MOZ_IMPLICIT nsTArrayBorrowed_##type_(nsTArray<type_>* aArray)  \
+      : mArray(aArray) {}                                           \
+  }
+DEFINE_ARRAY_TYPE_FOR(uintptr_t);
+#undef DEFINE_ARRAY_TYPE_FOR
+
 extern "C" {
 
 // Object refcounting.
 NS_DECL_HOLDER_FFI_REFCOUNTING(nsIPrincipal, Principal)
 NS_DECL_HOLDER_FFI_REFCOUNTING(nsIURI, URI)
 
 // DOM Traversal.
 uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
new file mode 100644
--- /dev/null
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* representation of CSSRuleList for stylo */
+
+#include "mozilla/ServoCSSRuleList.h"
+
+#include "mozilla/ServoBindings.h"
+
+namespace mozilla {
+
+ServoCSSRuleList::ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
+                                   already_AddRefed<ServoCssRules> aRawRules)
+  : mStyleSheet(aStyleSheet)
+  , mRawRules(aRawRules)
+{
+  Servo_CssRules_ListTypes(mRawRules, &mRules);
+  // XXX We may want to eagerly create object for import rule, so that
+  //     we don't lose the reference to child stylesheet when our own
+  //     stylesheet goes away.
+}
+
+nsIDOMCSSRule*
+ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
+{
+  if (aIndex >= mRules.Length()) {
+    aFound = false;
+    return nullptr;
+  }
+  aFound = true;
+  uintptr_t rule = mRules[aIndex];
+  if (rule <= kMaxRuleType) {
+    RefPtr<css::Rule> ruleObj = nullptr;
+    switch (rule) {
+      case nsIDOMCSSRule::STYLE_RULE:
+      case nsIDOMCSSRule::MEDIA_RULE:
+      case nsIDOMCSSRule::FONT_FACE_RULE:
+      case nsIDOMCSSRule::KEYFRAMES_RULE:
+      case nsIDOMCSSRule::NAMESPACE_RULE:
+        // XXX create corresponding rules
+      default:
+        MOZ_CRASH("stylo: not implemented yet");
+    }
+    ruleObj->SetStyleSheet(mStyleSheet);
+    rule = CastToUint(ruleObj.forget().take());
+    mRules[aIndex] = rule;
+  }
+  return CastToPtr(rule)->GetDOMRule();
+}
+
+template<typename Func>
+void
+ServoCSSRuleList::EnumerateRules(Func aCallback)
+{
+  for (uintptr_t rule : mRules) {
+    if (rule > kMaxRuleType) {
+      aCallback(CastToPtr(rule));
+    }
+  }
+}
+
+void
+ServoCSSRuleList::DropReference()
+{
+  mStyleSheet = nullptr;
+  EnumerateRules([](css::Rule* rule) { rule->SetStyleSheet(nullptr); });
+}
+
+ServoCSSRuleList::~ServoCSSRuleList()
+{
+  EnumerateRules([](css::Rule* rule) { rule->Release(); });
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/ServoCSSRuleList.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/* representation of CSSRuleList for stylo */
+
+#ifndef mozilla_ServoCSSRuleList_h
+#define mozilla_ServoCSSRuleList_h
+
+#include "mozilla/ServoBindingTypes.h"
+#include "mozilla/dom/CSSRuleList.h"
+
+namespace mozilla {
+
+class ServoStyleSheet;
+namespace css {
+class Rule;
+} // namespace css
+
+class ServoCSSRuleList final : public CSSRuleList
+{
+public:
+  ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
+                   already_AddRefed<ServoCssRules> aRawRules);
+
+  ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
+
+  nsIDOMCSSRule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
+  uint32_t Length() final { return mRules.Length(); }
+
+  void DropReference();
+
+private:
+  virtual ~ServoCSSRuleList();
+
+  // XXX Is it possible to have an address lower than or equal to 255?
+  //     Is it possible to have more than 255 CSS rule types?
+  static const uintptr_t kMaxRuleType = UINT8_MAX;
+
+  static uintptr_t CastToUint(css::Rule* aPtr) {
+    return reinterpret_cast<uintptr_t>(aPtr);
+  }
+  static css::Rule* CastToPtr(uintptr_t aInt) {
+    MOZ_ASSERT(aInt > kMaxRuleType);
+    return reinterpret_cast<css::Rule*>(aInt);
+  }
+
+  template<typename Func>
+  void EnumerateRules(Func aCallback);
+
+  // mStyleSheet may be nullptr when it drops the reference to us.
+  ServoStyleSheet* mStyleSheet;
+  RefPtr<ServoCssRules> mRawRules;
+  // Array stores either a number indicating rule type, or a pointer to
+  // css::Rule. If the value is less than kMaxRuleType, the given rule
+  // instance has not been constructed, and the value means the type
+  // of the rule. Otherwise, it is a pointer.
+  nsTArray<uintptr_t> mRules;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ServoCSSRuleList_h
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -1,31 +1,37 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #include "mozilla/ServoStyleSheet.h"
 #include "mozilla/StyleBackendType.h"
+#include "mozilla/ServoBindings.h"
+#include "mozilla/ServoCSSRuleList.h"
+#include "mozilla/dom/CSSRuleList.h"
 
 namespace mozilla {
 
 ServoStyleSheet::ServoStyleSheet(css::SheetParsingMode aParsingMode,
                                  CORSMode aCORSMode,
                                  net::ReferrerPolicy aReferrerPolicy,
                                  const dom::SRIMetadata& aIntegrity)
   : StyleSheet(StyleBackendType::Servo, aParsingMode)
   , mSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity)
 {
 }
 
 ServoStyleSheet::~ServoStyleSheet()
 {
   DropSheet();
+  if (mRuleList) {
+    mRuleList->DropReference();
+  }
 }
 
 bool
 ServoStyleSheet::HasRules() const
 {
   return mSheet && Servo_StyleSheet_HasRules(mSheet);
 }
 
@@ -117,18 +123,21 @@ nsIDOMCSSRule*
 ServoStyleSheet::GetDOMOwnerRule() const
 {
   return nullptr;
 }
 
 CSSRuleList*
 ServoStyleSheet::GetCssRulesInternal(ErrorResult& aRv)
 {
-  aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
-  return nullptr;
+  if (!mRuleList) {
+    RefPtr<ServoCssRules> rawRules = Servo_StyleSheet_GetRules(mSheet).Consume();
+    mRuleList = new ServoCSSRuleList(this, rawRules.forget());
+  }
+  return mRuleList;
 }
 
 uint32_t
 ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
                                     uint32_t aIndex, ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   return 0;
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -11,16 +11,18 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInfo.h"
 #include "nsStringFwd.h"
 
 namespace mozilla {
 
+class ServoCSSRuleList;
+
 /**
  * CSS style sheet object that is a wrapper for a Servo Stylesheet.
  */
 class ServoStyleSheet : public StyleSheet
 {
 public:
   ServoStyleSheet(css::SheetParsingMode aParsingMode,
                   CORSMode aCORSMode,
@@ -75,16 +77,17 @@ protected:
   uint32_t InsertRuleInternal(const nsAString& aRule,
                               uint32_t aIndex, ErrorResult& aRv);
   void DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv);
 
 private:
   void DropSheet();
 
   RefPtr<RawServoStyleSheet> mSheet;
+  RefPtr<ServoCSSRuleList> mRuleList;
   StyleSheetInfo mSheetInfo;
 
   friend class StyleSheet;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ServoStyleSheet_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -91,16 +91,17 @@ EXPORTS.mozilla += [
     'HandleRefPtr.h',
     'IncrementalClearCOMRuleArray.h',
     'LayerAnimationInfo.h',
     'RuleNodeCacheConditions.h',
     'RuleProcessorCache.h',
     'ServoBindingList.h',
     'ServoBindings.h',
     'ServoBindingTypes.h',
+    'ServoCSSRuleList.h',
     'ServoDeclarationBlock.h',
     'ServoElementSnapshot.h',
     'ServoStyleSet.h',
     'ServoStyleSheet.h',
     'ServoTypes.h',
     'ServoUtils.h',
     'SheetType.h',
     'StyleAnimationValue.h',
@@ -191,16 +192,17 @@ UNIFIED_SOURCES += [
     'nsStyleSet.cpp',
     'nsStyleStruct.cpp',
     'nsStyleTransformMatrix.cpp',
     'nsStyleUtil.cpp',
     'nsTransitionManager.cpp',
     'RuleNodeCacheConditions.cpp',
     'RuleProcessorCache.cpp',
     'ServoBindings.cpp',
+    'ServoCSSRuleList.cpp',
     'ServoDeclarationBlock.cpp',
     'ServoElementSnapshot.cpp',
     'ServoStyleSet.cpp',
     'ServoStyleSheet.cpp',
     'StyleAnimationValue.cpp',
     'StyleRule.cpp',
     'StyleSheet.cpp',
     'SVGAttrAnimationRuleProcessor.cpp',
--- a/servo/components/style/binding_tools/regen.py
+++ b/servo/components/style/binding_tools/regen.py
@@ -321,18 +321,23 @@ COMPILATION_TARGETS = {
             "nsStyleUIReset",
             "nsStyleUnion",
             "nsStyleUnit",
             "nsStyleUserInterface",
             "nsStyleVariables",
             "nsStyleVisibility",
             "nsStyleXUL",
         ],
+        "array_types": {
+            "uintptr_t": "usize",
+        },
         "servo_nullable_arc_types": [
-            "ServoComputedValues", "RawServoStyleSheet",
+            "ServoComputedValues",
+            "ServoCssRules",
+            "RawServoStyleSheet",
             "RawServoDeclarationBlock"
         ],
         "servo_owned_types": [
             "RawServoStyleSet",
             "StyleChildrenIterator",
         ],
         "servo_immutable_borrow_types": [
             "RawGeckoNode",
@@ -523,16 +528,24 @@ def build(objdir, target_name, debug, de
             flags.append("--whitelist-var")
             flags.append(header)
 
     if "opaque_types" in current_target:
         for ty in current_target["opaque_types"]:
             flags.append("--opaque-type")
             flags.append(ty)
 
+    if "array_types" in current_target:
+        for cpp_type, rust_type in current_target["array_types"].items():
+            flags.append("--blacklist-type")
+            flags.append("nsTArrayBorrowed_{}".format(cpp_type))
+            flags.append("--raw-line")
+            flags.append("pub type nsTArrayBorrowed_{0}<'a> = &'a mut ::gecko_bindings::structs::nsTArray<{1}>;"
+                         .format(cpp_type, rust_type))
+
     if "blacklist_types" in current_target:
         for ty in current_target["blacklist_types"]:
             flags.append("--blacklist-type")
             flags.append(ty)
 
     if "servo_nullable_arc_types" in current_target:
         for ty in current_target["servo_nullable_arc_types"]:
             flags.append("--blacklist-type")
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -6,39 +6,44 @@
 //! Ideally, it would be in geckolib itself, but coherence
 //! forces us to keep the traits and implementations here
 
 #![allow(unsafe_code)]
 
 use app_units::Au;
 use gecko::values::{convert_rgba_to_nscolor, StyleCoordHelpers};
 use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue};
-use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, ServoComputedValues};
+use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, ServoComputedValues, ServoCssRules};
 use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage};
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 use parking_lot::RwLock;
 use properties::{ComputedValues, PropertyDeclarationBlock};
-use stylesheets::Stylesheet;
+use stylesheets::{CssRule, Stylesheet};
 use values::computed::{CalcLengthOrPercentage, Gradient, Image, LengthOrPercentage, LengthOrPercentageOrAuto};
 
 unsafe impl HasFFI for Stylesheet {
     type FFIType = RawServoStyleSheet;
 }
 unsafe impl HasArcFFI for Stylesheet {}
 unsafe impl HasFFI for ComputedValues {
     type FFIType = ServoComputedValues;
 }
 unsafe impl HasArcFFI for ComputedValues {}
 
 unsafe impl HasFFI for RwLock<PropertyDeclarationBlock> {
     type FFIType = RawServoDeclarationBlock;
 }
 unsafe impl HasArcFFI for RwLock<PropertyDeclarationBlock> {}
 
+unsafe impl HasFFI for RwLock<Vec<CssRule>> {
+    type FFIType = ServoCssRules;
+}
+unsafe impl HasArcFFI for RwLock<Vec<CssRule>> {}
+
 impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
     fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
         let has_percentage = other.percentage.is_some();
         nsStyleCoord_CalcValue {
             mLength: other.length.0,
             mPercent: other.percentage.unwrap_or(0.0),
             mHasPercent: has_percentage,
         }
--- a/servo/components/style/gecko_bindings/bindings.rs
+++ b/servo/components/style/gecko_bindings/bindings.rs
@@ -1,18 +1,24 @@
 /* automatically generated by rust-bindgen */
 
 pub use nsstring::{nsACString, nsAString};
 type nsACString_internal = nsACString;
 type nsAString_internal = nsAString;
+pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>;
 pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoComputedValues>;
 pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;
 pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;
 enum ServoComputedValuesVoid{ }
 pub struct ServoComputedValues(ServoComputedValuesVoid);
+pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoCssRules>;
+pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;
+pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;
+enum ServoCssRulesVoid{ }
+pub struct ServoCssRules(ServoCssRulesVoid);
 pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoStyleSheet>;
 pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;
 pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;
 enum RawServoStyleSheetVoid{ }
 pub struct RawServoStyleSheet(RawServoStyleSheetVoid);
 pub type RawServoDeclarationBlockStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoDeclarationBlock>;
 pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlock>;
 pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;
@@ -183,16 +189,22 @@ unsafe impl Sync for nsStyleVisibility {
 use gecko_bindings::structs::nsStyleXUL;
 unsafe impl Send for nsStyleXUL {}
 unsafe impl Sync for nsStyleXUL {}
 
 pub type RawGeckoNode = nsINode;
 pub type RawGeckoElement = Element;
 pub type RawGeckoDocument = nsIDocument;
 extern "C" {
+    pub fn Servo_CssRules_AddRef(ptr: ServoCssRulesBorrowed);
+}
+extern "C" {
+    pub fn Servo_CssRules_Release(ptr: ServoCssRulesBorrowed);
+}
+extern "C" {
     pub fn Servo_StyleSheet_AddRef(ptr: RawServoStyleSheetBorrowed);
 }
 extern "C" {
     pub fn Servo_StyleSheet_Release(ptr: RawServoStyleSheetBorrowed);
 }
 extern "C" {
     pub fn Servo_ComputedValues_AddRef(ptr: ServoComputedValuesBorrowed);
 }
@@ -930,16 +942,20 @@ extern "C" {
                                               *mut ThreadSafePrincipalHolder)
      -> RawServoStyleSheetStrong;
 }
 extern "C" {
     pub fn Servo_StyleSheet_HasRules(sheet: RawServoStyleSheetBorrowed)
      -> bool;
 }
 extern "C" {
+    pub fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed)
+     -> ServoCssRulesStrong;
+}
+extern "C" {
     pub fn Servo_StyleSet_Init() -> RawServoStyleSetOwned;
 }
 extern "C" {
     pub fn Servo_StyleSet_AppendStyleSheet(set: RawServoStyleSetBorrowed,
                                            sheet: RawServoStyleSheetBorrowed);
 }
 extern "C" {
     pub fn Servo_StyleSet_PrependStyleSheet(set: RawServoStyleSetBorrowed,
@@ -954,16 +970,20 @@ extern "C" {
     pub fn Servo_StyleSet_InsertStyleSheetBefore(set:
                                                      RawServoStyleSetBorrowed,
                                                  sheet:
                                                      RawServoStyleSheetBorrowed,
                                                  reference:
                                                      RawServoStyleSheetBorrowed);
 }
 extern "C" {
+    pub fn Servo_CssRules_ListRuleTypes(rules: ServoCssRulesBorrowed,
+                                        result: nsTArrayBorrowed_uintptr_t);
+}
+extern "C" {
     pub fn Servo_ParseProperty(property: *const nsACString_internal,
                                value: *const nsACString_internal,
                                base_url: *const nsACString_internal,
                                base: *mut ThreadSafeURIHolder,
                                referrer: *mut ThreadSafeURIHolder,
                                principal: *mut ThreadSafePrincipalHolder)
      -> RawServoDeclarationBlockStrong;
 }
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -78,17 +78,52 @@ pub enum CssRule {
     Namespace(Arc<RwLock<NamespaceRule>>),
     Style(Arc<RwLock<StyleRule>>),
     Media(Arc<RwLock<MediaRule>>),
     FontFace(Arc<RwLock<FontFaceRule>>),
     Viewport(Arc<RwLock<ViewportRule>>),
     Keyframes(Arc<RwLock<KeyframesRule>>),
 }
 
+pub enum CssRuleType {
+    // https://drafts.csswg.org/cssom/#the-cssrule-interface
+    Style               = 1,
+    Charset             = 2,
+    Import              = 3,
+    Media               = 4,
+    FontFace            = 5,
+    Page                = 6,
+    // https://drafts.csswg.org/css-animations-1/#interface-cssrule-idl
+    Keyframes           = 7,
+    Keyframe            = 8,
+    // https://drafts.csswg.org/cssom/#the-cssrule-interface
+    Margin              = 9,
+    Namespace           = 10,
+    // https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
+    CounterStyle        = 11,
+    // https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
+    Supports            = 12,
+    // https://drafts.csswg.org/css-fonts-3/#om-fontfeaturevalues
+    FontFeatureValues   = 14,
+    // https://drafts.csswg.org/css-device-adapt/#css-rule-interface
+    Viewport            = 15,
+}
+
 impl CssRule {
+    pub fn rule_type(&self) -> CssRuleType {
+        match *self {
+            CssRule::Style(_)     => CssRuleType::Style,
+            CssRule::Media(_)     => CssRuleType::Media,
+            CssRule::FontFace(_)  => CssRuleType::FontFace,
+            CssRule::Keyframes(_) => CssRuleType::Keyframes,
+            CssRule::Namespace(_) => CssRuleType::Namespace,
+            CssRule::Viewport(_)  => CssRuleType::Viewport,
+        }
+    }
+
     /// Call `f` with the slice of rules directly contained inside this rule.
     ///
     /// Note that only some types of rules can contain rules. An empty slice is used for others.
     pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R
     where F: FnMut(&[CssRule], Option<&MediaList>) -> R {
         match *self {
             CssRule::Namespace(_) |
             CssRule::Style(_) |
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -20,36 +20,38 @@ use style::gecko::snapshot::GeckoElement
 use style::gecko::traversal::RecalcStyleOnly;
 use style::gecko::wrapper::{GeckoElement, GeckoNode};
 use style::gecko::wrapper::DUMMY_BASE_URL;
 use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoNodeBorrowed};
 use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
 use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
 use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed};
 use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong};
+use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
 use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
 use style::gecko_bindings::bindings::{nsACString, nsAString};
 use style::gecko_bindings::bindings::Gecko_Utf8SliceToString;
 use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
+use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t;
 use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom};
 use style::gecko_bindings::structs::ServoElementSnapshot;
 use style::gecko_bindings::structs::nsRestyleHint;
 use style::gecko_bindings::structs::nsString;
 use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI};
 use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong};
 use style::gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI};
 use style::parallel;
 use style::parser::{ParserContext, ParserContextExtraData};
 use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration};
 use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock};
 use style::properties::{apply_declarations, parse_one_declaration};
 use style::selector_impl::PseudoElementCascadeType;
 use style::sequential;
 use style::string_cache::Atom;
-use style::stylesheets::{Origin, Stylesheet};
+use style::stylesheets::{CssRule, Origin, Stylesheet};
 use style::timer::Timer;
 use style_traits::ToCss;
 use url::Url;
 
 /*
  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
@@ -254,26 +256,52 @@ pub extern "C" fn Servo_StyleSet_RemoveS
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowed) -> bool {
     !Stylesheet::as_arc(&raw_sheet).rules.0.read().is_empty()
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) -> ServoCssRulesStrong {
+    Stylesheet::as_arc(&sheet).rules.0.clone().into_strong()
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_StyleSheet_AddRef(sheet: RawServoStyleSheetBorrowed) -> () {
     unsafe { Stylesheet::addref(sheet) };
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_Release(sheet: RawServoStyleSheetBorrowed) -> () {
     unsafe { Stylesheet::release(sheet) };
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
+                                           result: nsTArrayBorrowed_uintptr_t) -> () {
+    let rules = RwLock::<Vec<CssRule>>::as_arc(&rules).read();
+    let iter = rules.iter().map(|rule| rule.rule_type() as usize);
+    let (size, upper) = iter.size_hint();
+    debug_assert_eq!(size, upper.unwrap());
+    unsafe { result.set_len(size as u32) };
+    result.iter_mut().zip(iter).fold((), |_, (r, v)| *r = v);
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_CssRules_AddRef(rules: ServoCssRulesBorrowed) -> () {
+    unsafe { RwLock::<Vec<CssRule>>::addref(rules) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_CssRules_Release(rules: ServoCssRulesBorrowed) -> () {
+    unsafe { RwLock::<Vec<CssRule>>::release(rules) };
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_ComputedValues_Get(node: RawGeckoNodeBorrowed)
      -> ServoComputedValuesStrong {
     let node = GeckoNode(node);
 
     // Gecko erroneously calls this function from ServoRestyleManager::RecreateStyleContexts.
     // We plan to fix that, but just support it for now until that code gets rewritten.
     if node.is_text_node() {
         error!("Don't call Servo_ComputedValue_Get() for text nodes");