Bug 1307357 part 4 - Add impl class of CSSStyleRule for stylo. r?heycam draft
authorXidorn Quan <me@upsuper.org>
Fri, 04 Nov 2016 17:22:41 +1100
changeset 434693 68060b4d56daf3c12babb3b272ca3ef6d46cf0a6
parent 434692 87566f53170291eb4cb76dc46531c4173c4dec8e
child 434694 cd3433258cf44cc630520165647a2e495e36a6bd
child 434697 436488014372f8341274b59ee33af8bd37e4b1af
push id34791
push userxquan@mozilla.com
push dateMon, 07 Nov 2016 06:12:19 +0000
reviewersheycam
bugs1307357
milestone52.0a1
Bug 1307357 part 4 - Add impl class of CSSStyleRule for stylo. r?heycam MozReview-Commit-ID: CNrvA0HuuL6
layout/style/ServoBindingList.h
layout/style/ServoBindingTypes.h
layout/style/ServoBindings.cpp
layout/style/ServoStyleRule.cpp
layout/style/ServoStyleRule.h
layout/style/ServoStyleSheet.cpp
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/ports/geckolib/glue.rs
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -32,16 +32,18 @@ SERVO_BINDING_FUNC(Servo_StyleSheet_From
 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_ListRuleTypes, void,
                    RawServoStyleSheetBorrowed sheet, nsTArray_uintptr_t result)
+SERVO_BINDING_FUNC(Servo_StyleSheet_GetStyleRuleAt, RawServoStyleRuleStrong,
+                   RawServoStyleSheetBorrowed sheet, uint32_t index)
 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)
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 
 struct ServoComputedValues;
 struct RawServoStyleSheet;
 struct RawServoStyleSet;
 struct RawServoDeclarationBlock;
+struct RawServoStyleRule;
 
 namespace mozilla {
 namespace dom {
 class Element;
 class StyleChildrenIterator;
 } // namespace dom
 } // namespace mozilla
 
@@ -68,16 +69,17 @@ typedef nsIDocument RawGeckoDocument;
 #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(RawServoStyleSheet)
 DECL_ARC_REF_TYPE_FOR(RawServoDeclarationBlock)
+DECL_ARC_REF_TYPE_FOR(RawServoStyleRule)
 // 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)
 DECL_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
 
@@ -116,16 +118,17 @@ DECL_BORROWED_MUT_REF_TYPE_FOR(StyleChil
       Servo_##name_##_Release(aPtr);                 \
     }                                                \
   };                                                 \
   }
 
 DEFINE_REFPTR_TRAITS(StyleSheet, RawServoStyleSheet)
 DEFINE_REFPTR_TRAITS(ComputedValues, ServoComputedValues)
 DEFINE_REFPTR_TRAITS(DeclarationBlock, RawServoDeclarationBlock)
+DEFINE_REFPTR_TRAITS(StyleRule, RawServoStyleRule)
 
 #undef DEFINE_REFPTR_TRAITS
 
 extern "C" void Servo_StyleSet_Drop(RawServoStyleSetOwned ptr);
 
 namespace mozilla {
 template<>
 class DefaultDelete<RawServoStyleSet>
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -41,16 +41,17 @@ using namespace mozilla::dom;
     RefPtr<type_> result;               \
     result.swap(mPtr);                  \
     return result.forget();             \
   }
 
 IMPL_STRONG_REF_TYPE_FOR(ServoComputedValues)
 IMPL_STRONG_REF_TYPE_FOR(RawServoStyleSheet)
 IMPL_STRONG_REF_TYPE_FOR(RawServoDeclarationBlock)
+IMPL_STRONG_REF_TYPE_FOR(RawServoStyleRule)
 
 #undef IMPL_STRONG_REF_TYPE_FOR
 
 uint32_t
 Gecko_ChildrenCount(RawGeckoNodeBorrowed aNode)
 {
   return aNode->GetChildCount();
 }
new file mode 100644
--- /dev/null
+++ b/layout/style/ServoStyleRule.cpp
@@ -0,0 +1,114 @@
+/* -*- 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 CSSStyleRule for stylo */
+
+#include "mozilla/ServoStyleRule.h"
+
+#include "nsDOMClassInfoID.h"
+
+namespace mozilla {
+
+// -- ServoStyleRule --------------------------------------------------
+
+// QueryInterface implementation for ServoStyleRule
+NS_INTERFACE_MAP_BEGIN(ServoStyleRule)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, css::Rule)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(ServoStyleRule)
+NS_IMPL_RELEASE(ServoStyleRule)
+
+already_AddRefed<css::Rule>
+ServoStyleRule::Clone() const
+{
+  // Rule::Clone is only used when CSSStyleSheetInner is cloned in
+  // preparation of being mutated. However, ServoStyleSheet never clones
+  // anything, so this method should never be called.
+  MOZ_ASSERT_UNREACHABLE("Shouldn't be cloning ServoStyleRule");
+  return nullptr;
+}
+
+size_t
+ServoStyleRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  // TODO Implement this!
+  return aMallocSizeOf(this);
+}
+
+#ifdef DEBUG
+void
+ServoStyleRule::List(FILE* out, int32_t aIndent) const
+{
+  // TODO Implement this!
+}
+#endif
+
+/* CSSRule implementation */
+
+NS_IMETHODIMP
+ServoStyleRule::GetType(uint16_t* aType)
+{
+  *aType = nsIDOMCSSRule::STYLE_RULE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ServoStyleRule::GetCssText(nsAString& aCssText)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ServoStyleRule::SetCssText(const nsAString& aCssText)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ServoStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
+{
+  return css::Rule::GetParentStyleSheet(aSheet);
+}
+
+NS_IMETHODIMP
+ServoStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
+{
+  *aParentRule = nullptr;
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+css::Rule*
+ServoStyleRule::GetCSSRule()
+{
+  return this;
+}
+
+/* CSSStyleRule implementation */
+
+NS_IMETHODIMP
+ServoStyleRule::GetSelectorText(nsAString& aSelectorText)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ServoStyleRule::SetSelectorText(const nsAString& aSelectorText)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ServoStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
+{
+  *aStyle = nullptr;
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/ServoStyleRule.h
@@ -0,0 +1,50 @@
+/* -*- 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 CSSStyleRule for stylo */
+
+#ifndef mozilla_ServoStyleRule_h
+#define mozilla_ServoStyleRule_h
+
+#include "mozilla/css/Rule.h"
+#include "mozilla/ServoBindingTypes.h"
+
+#include "nsIDOMCSSStyleRule.h"
+
+namespace mozilla {
+
+class ServoStyleRule final : public css::Rule
+                           , public nsIDOMCSSStyleRule
+{
+public:
+  explicit ServoStyleRule(already_AddRefed<RawServoStyleRule> aRawRule)
+    : css::Rule(0, 0)
+    , mRawRule(aRawRule)
+  {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMCSSRULE
+  NS_DECL_NSIDOMCSSSTYLERULE
+
+  // Methods of mozilla::css::Rule
+  int32_t GetType() const final { return css::Rule::STYLE_RULE; }
+  already_AddRefed<Rule> Clone() const final;
+  nsIDOMCSSRule* GetDOMRule() final { return this; }
+  nsIDOMCSSRule* GetExistingDOMRule() final { return this; }
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const final;
+#ifdef DEBUG
+  void List(FILE* out = stdout, int32_t aIndent = 0) const final;
+#endif
+
+private:
+  ~ServoStyleRule() {}
+
+  RefPtr<RawServoStyleRule> mRawRule;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ServoStyleRule_h
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -2,16 +2,17 @@
 /* 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/ServoStyleRule.h"
 #include "mozilla/dom/CSSRuleList.h"
 
 namespace mozilla {
 
 class ServoCSSRuleList final : public CSSRuleList
 {
 public:
   explicit ServoCSSRuleList(ServoStyleSheet* aSheet);
@@ -72,17 +73,21 @@ ServoCSSRuleList::IndexedGetter(uint32_t
     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::STYLE_RULE: {
+        ruleObj = new ServoStyleRule(
+          Servo_StyleSheet_GetStyleRuleAt(mRawSheet, aIndex).Consume());
+        break;
+      }
       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");
     }
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -93,16 +93,17 @@ EXPORTS.mozilla += [
     'LayerAnimationInfo.h',
     'RuleNodeCacheConditions.h',
     'RuleProcessorCache.h',
     'ServoBindingList.h',
     'ServoBindings.h',
     'ServoBindingTypes.h',
     'ServoDeclarationBlock.h',
     'ServoElementSnapshot.h',
+    'ServoStyleRule.h',
     'ServoStyleSet.h',
     'ServoStyleSheet.h',
     'ServoTypes.h',
     'ServoUtils.h',
     'SheetType.h',
     'StyleAnimationValue.h',
     'StyleBackendType.h',
     'StyleComplexColor.h',
@@ -193,16 +194,17 @@ UNIFIED_SOURCES += [
     'nsStyleTransformMatrix.cpp',
     'nsStyleUtil.cpp',
     'nsTransitionManager.cpp',
     'RuleNodeCacheConditions.cpp',
     'RuleProcessorCache.cpp',
     'ServoBindings.cpp',
     'ServoDeclarationBlock.cpp',
     'ServoElementSnapshot.cpp',
+    'ServoStyleRule.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
@@ -320,17 +320,17 @@ COMPILATION_TARGETS = {
             "nsStyleVisibility",
             "nsStyleXUL",
         ],
         "array_types": {
             "uintptr_t": "usize",
         },
         "servo_nullable_arc_types": [
             "ServoComputedValues", "RawServoStyleSheet",
-            "RawServoDeclarationBlock"
+            "RawServoDeclarationBlock", "RawServoStyleRule",
         ],
         "servo_owned_types": [
             "RawServoStyleSet",
             "StyleChildrenIterator",
         ],
         "servo_immutable_borrow_types": [
             "RawGeckoNode",
             "RawGeckoElement",
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -4,38 +4,44 @@
 
 //! This module contains conversion helpers between Servo and Gecko types
 //! 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_bindings::bindings::{RawServoStyleSheet, ServoComputedValues, RawServoDeclarationBlock};
+use gecko_bindings::bindings::{RawServoStyleSheet, RawServoStyleRule};
+use gecko_bindings::bindings::{ServoComputedValues, RawServoDeclarationBlock};
 use gecko_bindings::structs::nsStyleCoord_CalcValue;
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 use parking_lot::RwLock;
 use properties::{ComputedValues, PropertyDeclarationBlock};
-use stylesheets::Stylesheet;
+use stylesheets::{Stylesheet, StyleRule};
 use values::computed::{CalcLengthOrPercentage, 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<StyleRule> {
+    type FFIType = RawServoStyleRule;
+}
+unsafe impl HasArcFFI for RwLock<StyleRule> {}
+
 impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
     fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
         let has_percentage = other.percentage.is_some();
         nsStyleCoord_CalcValue {
             mLength: other.length.map_or(0, |l| l.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
@@ -14,16 +14,21 @@ pub type RawServoStyleSheetBorrowedOrNul
 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;
 enum RawServoDeclarationBlockVoid{ }
 pub struct RawServoDeclarationBlock(RawServoDeclarationBlockVoid);
+pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoStyleRule>;
+pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;
+pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;
+enum RawServoStyleRuleVoid{ }
+pub struct RawServoStyleRule(RawServoStyleRuleVoid);
 pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;
 pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;
 pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;
 pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;
 pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;
 pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;
 pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;
 pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;
@@ -196,16 +201,22 @@ extern "C" {
     pub fn Servo_DeclarationBlock_AddRef(ptr:
                                              RawServoDeclarationBlockBorrowed);
 }
 extern "C" {
     pub fn Servo_DeclarationBlock_Release(ptr:
                                               RawServoDeclarationBlockBorrowed);
 }
 extern "C" {
+    pub fn Servo_StyleRule_AddRef(ptr: RawServoStyleRuleBorrowed);
+}
+extern "C" {
+    pub fn Servo_StyleRule_Release(ptr: RawServoStyleRuleBorrowed);
+}
+extern "C" {
     pub fn Servo_StyleSet_Drop(ptr: RawServoStyleSetOwned);
 }
 extern "C" {
     pub fn Gecko_EnsureTArrayCapacity(aArray: *mut ::std::os::raw::c_void,
                                       aCapacity: usize, aElementSize: usize);
 }
 extern "C" {
     pub fn Gecko_ClearPODTArray(aArray: *mut ::std::os::raw::c_void,
@@ -880,16 +891,21 @@ extern "C" {
     pub fn Servo_StyleSheet_HasRules(sheet: RawServoStyleSheetBorrowed)
      -> bool;
 }
 extern "C" {
     pub fn Servo_StyleSheet_ListRuleTypes(sheet: RawServoStyleSheetBorrowed,
                                           result: nsTArray_uintptr_t);
 }
 extern "C" {
+    pub fn Servo_StyleSheet_GetStyleRuleAt(sheet: RawServoStyleSheetBorrowed,
+                                           index: u32)
+     -> RawServoStyleRuleStrong;
+}
+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,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -17,16 +17,17 @@ use style::error_reporting::StdoutErrorR
 use style::gecko::data::{NUM_THREADS, PerDocumentStyleData};
 use style::gecko::selector_impl::{GeckoSelectorImpl, PseudoElement};
 use style::gecko::snapshot::GeckoElementSnapshot;
 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::{RawServoStyleRuleBorrowed, RawServoStyleRuleStrong};
 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::{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::nsTArray_uintptr_t;
@@ -41,17 +42,17 @@ use style::parallel;
 use style::parser::{ParserContext, ParserContextExtraData};
 use style::properties::{CascadeFlags, ComputedValues, Importance, PropertyDeclaration};
 use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock};
 use style::properties::{cascade, parse_one_declaration};
 use style::selector_impl::PseudoElementCascadeType;
 use style::selector_matching::ApplicableDeclarationBlock;
 use style::sequential;
 use style::string_cache::Atom;
-use style::stylesheets::{Origin, Stylesheet};
+use style::stylesheets::{CSSRule, Origin, Stylesheet, StyleRule};
 use style::timer::Timer;
 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
  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
@@ -248,26 +249,48 @@ pub extern "C" fn Servo_StyleSheet_ListR
     let iter = Stylesheet::as_arc(&raw_sheet).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_StyleSheet_GetStyleRuleAt(raw_sheet: RawServoStyleSheetBorrowed, index: u32)
+                                                  -> RawServoStyleRuleStrong {
+    let sheet = Stylesheet::as_arc(&raw_sheet);
+    match sheet.rules[index as usize] {
+        CSSRule::Style(ref rule) => rule.clone().into_strong(),
+        _ => {
+            unreachable!("GetStyleRuleAt should only be called on a style rule");
+        }
+    }
+}
+
+#[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_StyleRule_AddRef(rule: RawServoStyleRuleBorrowed) -> () {
+    unsafe { RwLock::<StyleRule>::addref(rule) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_Release(rule: RawServoStyleRuleBorrowed) -> () {
+    unsafe { RwLock::<StyleRule>::release(rule) };
+}
+
+#[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");