servo: Merge #14330 - Implement access to CSSStyleRule for stylo (from upsuper:bug1307357); r=heycam
authorXidorn Quan <me@upsuper.org>
Wed, 23 Nov 2016 15:47:18 -0800
changeset 340213 d334362e9defefe12985d668d13f9968cac8f824
parent 340212 0e8508d060455b04712106c7db14562146fc2e4d
child 340214 09f116c8c2e021d2cf62879f3ccf414e36b77805
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)
reviewersheycam
bugs1307357
servo: Merge #14330 - Implement access to CSSStyleRule for stylo (from upsuper:bug1307357); r=heycam <!-- Please describe your changes on the following line: --> This is the servo part of [bug 1307357](https://bugzilla.mozilla.org/show_bug.cgi?id=1307357) which has been reviewed by @heycam, @Manishearth and @SimonSapin. r? @heycam (`./mach test-tidy` reports several issues on bindings.rs... which I don't think is introduced by my patch... so I have no idea what to do here...) --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: c8e39dcdf6fbdc36bed42d3f0d46ad78133d83cf
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/servo/components/style/binding_tools/regen.py
+++ b/servo/components/style/binding_tools/regen.py
@@ -323,19 +323,25 @@ COMPILATION_TARGETS = {
             "nsStyleUIReset",
             "nsStyleUnion",
             "nsStyleUnit",
             "nsStyleUserInterface",
             "nsStyleVariables",
             "nsStyleVisibility",
             "nsStyleXUL",
         ],
+        "array_types": {
+            "uintptr_t": "usize",
+        },
         "servo_nullable_arc_types": [
-            "ServoComputedValues", "RawServoStyleSheet",
-            "RawServoDeclarationBlock"
+            "ServoComputedValues",
+            "ServoCssRules",
+            "RawServoStyleSheet",
+            "RawServoDeclarationBlock",
+            "RawServoStyleRule",
         ],
         "servo_owned_types": [
             "RawServoStyleSet",
             "StyleChildrenIterator",
         ],
         "servo_immutable_borrow_types": [
             "RawGeckoNode",
             "RawGeckoElement",
@@ -530,16 +536,24 @@ def build(objdir, target_name, debug, de
             flags.append("--bitfield-enum")
             flags.append(ty)
 
     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,50 @@
 //! 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, RawServoStyleRule};
+use gecko_bindings::bindings::{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, StyleRule};
 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>> {}
+
+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.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,28 +1,39 @@
 /* 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;
 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>;
@@ -184,16 +195,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);
 }
@@ -204,16 +221,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,
@@ -946,16 +969,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,
@@ -970,16 +997,46 @@ extern "C" {
     pub fn Servo_StyleSet_InsertStyleSheetBefore(set:
                                                      RawServoStyleSetBorrowed,
                                                  sheet:
                                                      RawServoStyleSheetBorrowed,
                                                  reference:
                                                      RawServoStyleSheetBorrowed);
 }
 extern "C" {
+    pub fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
+                                    result: nsTArrayBorrowed_uintptr_t);
+}
+extern "C" {
+    pub fn Servo_CssRules_GetStyleRuleAt(rules: ServoCssRulesBorrowed,
+                                         index: u32)
+     -> RawServoStyleRuleStrong;
+}
+extern "C" {
+    pub fn Servo_StyleRule_Debug(rule: RawServoStyleRuleBorrowed,
+                                 result: *mut nsACString_internal);
+}
+extern "C" {
+    pub fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed)
+     -> RawServoDeclarationBlockStrong;
+}
+extern "C" {
+    pub fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
+                                    declarations:
+                                        RawServoDeclarationBlockBorrowed);
+}
+extern "C" {
+    pub fn Servo_StyleRule_GetCssText(rule: RawServoStyleRuleBorrowed,
+                                      result: *mut nsAString_internal);
+}
+extern "C" {
+    pub fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed,
+                                           result: *mut nsAString_internal);
+}
+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
@@ -131,16 +131,40 @@ 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,
+}
+
 /// Error reporter which silently forgets errors
 pub struct MemoryHoleReporter;
 
 impl ParseErrorReporter for MemoryHoleReporter {
     fn report_error(&self,
             _: &mut Parser,
             _: SourcePosition,
             _: &str) {
@@ -152,16 +176,27 @@ impl ParseErrorReporter for MemoryHoleRe
 }
 
 pub enum SingleRuleParseError {
     Syntax,
     Hierarchy,
 }
 
 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
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use cssparser::Parser;
+use cssparser::ToCss as ParserToCss;
 use env_logger;
 use euclid::Size2D;
 use parking_lot::RwLock;
 use servo_url::ServoUrl;
 use std::fmt::Write;
 use std::mem::transmute;
 use std::sync::{Arc, Mutex};
 use style::arc_ptr_eq;
@@ -18,39 +19,42 @@ use style::error_reporting::StdoutErrorR
 use style::gecko::data::{NUM_THREADS, PerDocumentStyleData};
 use style::gecko::selector_parser::{SelectorImpl, 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::{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_parser::PseudoElementCascadeType;
 use style::sequential;
 use style::string_cache::Atom;
-use style::stylesheets::{Origin, Stylesheet};
+use style::stylesheets::{CssRule, Origin, Stylesheet, StyleRule};
 use style::thread_state;
 use style::timer::Timer;
 use style_traits::ToCss;
 
 /*
  * 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
@@ -258,26 +262,107 @@ 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_GetStyleRuleAt(rules: ServoCssRulesBorrowed, index: u32)
+                                                -> RawServoStyleRuleStrong {
+    let rules = RwLock::<Vec<CssRule>>::as_arc(&rules).read();
+    match 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_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_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_StyleRule_Debug(rule: RawServoStyleRuleBorrowed, result: *mut nsACString) -> () {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    let result = unsafe { result.as_mut().unwrap() };
+    write!(result, "{:?}", *rule.read()).unwrap();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    rule.read().block.clone().into_strong()
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
+                                           declarations: RawServoDeclarationBlockBorrowed) -> () {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+    rule.write().block = declarations.clone();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetCssText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
+    let rule = RwLock::<StyleRule>::as_arc(&rule);
+    rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
+}
+
+#[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");