Bug 1367904 - Part 10: stylo: Switch Gecko over to ServoStyleContext; r?bholley draft
authorManish Goregaokar <manishearth@gmail.com>
Thu, 15 Jun 2017 22:49:50 -0700
changeset 607487 83f5d1487934a17e4c9a35b4229816991a6c0de3
parent 607345 bd97455bce1e44690ce3ea9f54a1c4b1d808362b
child 607488 20be949ec55606c714803ae098dcff75048b5607
push id67989
push userbmo:manishearth@gmail.com
push dateWed, 12 Jul 2017 08:49:55 +0000
reviewersbholley
bugs1367904
milestone56.0a1
Bug 1367904 - Part 10: stylo: Switch Gecko over to ServoStyleContext; r?bholley MozReview-Commit-ID: EmopKVjEzlz
dom/canvas/CanvasRenderingContext2D.cpp
layout/base/ServoRestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/style/GeckoStyleContext.h
layout/style/ServoBindingList.h
layout/style/ServoBindingTypes.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoStyleContext.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/ServoTypes.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
layout/style/nsStyleContextInlines.h
servo/components/layout/flow.rs
servo/components/script/dom/cssrulelist.rs
servo/components/script/layout_wrapper.rs
servo/components/script_layout_interface/wrapper_traits.rs
servo/components/style/gecko/arc_types.rs
servo/components/style/gecko/pseudo_element_definition.mako.rs
servo/components/style/gecko/restyle_damage.rs
servo/components/style/gecko/wrapper.rs
servo/components/style/matching.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/servo/selector_parser.rs
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2839,17 +2839,17 @@ CreateDeclarationForServo(nsCSSPropertyI
 
 static already_AddRefed<RawServoDeclarationBlock>
 CreateFontDeclarationForServo(const nsAString& aFont,
                               nsIDocument* aDocument)
 {
   return CreateDeclarationForServo(eCSSProperty_font, aFont, aDocument);
 }
 
-static already_AddRefed<ServoComputedValues>
+static already_AddRefed<ServoStyleContext>
 GetFontStyleForServo(Element* aElement, const nsAString& aFont,
                      nsIPresShell* aPresShell,
                      nsAString& aOutUsedFont,
                      ErrorResult& aError)
 {
   MOZ_ASSERT(aPresShell->StyleSet()->IsServo());
 
   RefPtr<RawServoDeclarationBlock> declarations =
@@ -2864,44 +2864,45 @@ GetFontStyleForServo(Element* aElement, 
   // at font-size-adjust, which the font shorthand resets to 'none'.
   if (Servo_DeclarationBlock_HasCSSWideKeyword(declarations,
                                                eCSSProperty_font_size_adjust)) {
     return nullptr;
   }
 
   ServoStyleSet* styleSet = aPresShell->StyleSet()->AsServo();
 
-  RefPtr<ServoComputedValues> parentStyle;
+  RefPtr<ServoStyleContext> parentStyle;
   // have to get a parent style context for inherit-like relative
   // values (2em, bolder, etc.)
   if (aElement && aElement->IsInUncomposedDoc()) {
     // Inherit from the canvas element.
     aPresShell->FlushPendingNotifications(FlushType::Style);
     // We need to use ResolveTransientServoStyle, which involves traversal,
     // instead of ResolveServoStyle() because we need up-to-date style even if
     // the canvas element is display:none.
     parentStyle =
       styleSet->ResolveTransientServoStyle(aElement,
-                                           CSSPseudoElementType::NotPseudo);
+                                           CSSPseudoElementType::NotPseudo,
+                                           nullptr);
   } else {
     RefPtr<RawServoDeclarationBlock> declarations =
       CreateFontDeclarationForServo(NS_LITERAL_STRING("10px sans-serif"),
                                     aPresShell->GetDocument());
     MOZ_ASSERT(declarations);
 
     parentStyle = aPresShell->StyleSet()->AsServo()->
       ResolveForDeclarations(nullptr, declarations);
   }
 
   MOZ_RELEASE_ASSERT(parentStyle, "Should have a valid parent style");
 
   MOZ_ASSERT(!aPresShell->IsDestroying(),
              "GetFontParentStyleContext should have returned an error if the presshell is being destroyed.");
 
-  RefPtr<ServoComputedValues> sc =
+  RefPtr<ServoStyleContext> sc =
     styleSet->ResolveForDeclarations(parentStyle, declarations);
 
   // The font getter is required to be reserialized based on what we
   // parsed (including having line-height removed).  (Older drafts of
   // the spec required font sizes be converted to pixels, but that no
   // longer seems to be required.)
   Servo_SerializeFontValueForCanvas(declarations, &aOutUsedFont);
 
@@ -2955,19 +2956,19 @@ ResolveFilterStyle(const nsAString& aFil
 
 static already_AddRefed<RawServoDeclarationBlock>
 CreateFilterDeclarationForServo(const nsAString& aFilter,
                                 nsIDocument* aDocument)
 {
   return CreateDeclarationForServo(eCSSProperty_filter, aFilter, aDocument);
 }
 
-static already_AddRefed<ServoComputedValues>
+static already_AddRefed<ServoStyleContext>
 ResolveFilterStyleForServo(const nsAString& aFilterString,
-                           const ServoComputedValues* aParentStyle,
+                           const ServoStyleContext* aParentStyle,
                            nsIPresShell* aPresShell,
                            ErrorResult& aError)
 {
   MOZ_ASSERT(aPresShell->StyleSet()->IsServo());
 
   RefPtr<RawServoDeclarationBlock> declarations =
     CreateFilterDeclarationForServo(aFilterString, aPresShell->GetDocument());
   if (!declarations) {
@@ -2978,17 +2979,17 @@ ResolveFilterStyleForServo(const nsAStri
   // In addition to unparseable values, the spec says we need to reject
   // 'inherit' and 'initial'.
   if (Servo_DeclarationBlock_HasCSSWideKeyword(declarations,
                                                eCSSProperty_filter)) {
     return nullptr;
   }
 
   ServoStyleSet* styleSet = aPresShell->StyleSet()->AsServo();
-  RefPtr<ServoComputedValues> computedValues =
+  RefPtr<ServoStyleContext> computedValues =
     styleSet->ResolveForDeclarations(aParentStyle, declarations);
 
   return computedValues.forget();
 }
 
 bool
 CanvasRenderingContext2D::ParseFilter(const nsAString& aString,
                                       nsTArray<nsStyleFilter>& aFilterChain,
@@ -3023,36 +3024,36 @@ CanvasRenderingContext2D::ParseFilter(co
     }
     aFilterChain = sc->StyleEffects()->mFilters;
     return true;
   }
 
   // For stylo
   MOZ_ASSERT(presShell->StyleSet()->IsServo());
 
-  RefPtr<ServoComputedValues> parentStyle =
+  RefPtr<ServoStyleContext> parentStyle =
     GetFontStyleForServo(mCanvasElement,
                          GetFont(),
                          presShell,
                          usedFont,
                          aError);
   if (!parentStyle) {
     return false;
   }
 
-  RefPtr<ServoComputedValues> computedValues =
+  RefPtr<ServoStyleContext> computedValues =
     ResolveFilterStyleForServo(aString,
                                parentStyle,
                                presShell,
                                aError);
   if (!computedValues) {
      return false;
   }
 
-  const nsStyleEffects* effects = Servo_GetStyleEffects(computedValues);
+  const nsStyleEffects* effects = Servo_GetStyleEffects(computedValues->ComputedValues());
   // XXX: This mFilters is a one shot object, we probably could avoid copying.
   aFilterChain = effects->mFilters;
   return true;
 }
 
 void
 CanvasRenderingContext2D::SetFilter(const nsAString& aFilter, ErrorResult& aError)
 {
@@ -3950,29 +3951,29 @@ CanvasRenderingContext2D::SetFontInterna
 
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell) {
     aError.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   RefPtr<nsStyleContext> sc;
-  RefPtr<ServoComputedValues> computedValues;
+  RefPtr<ServoStyleContext> computedValues;
   nsString usedFont;
   const nsStyleFont* fontStyle;
   if (presShell->StyleSet()->IsServo()) {
     computedValues = GetFontStyleForServo(mCanvasElement,
                                           aFont,
                                           presShell,
                                           usedFont,
                                           aError);
     if (!computedValues) {
       return false;
     }
-    fontStyle = Servo_GetStyleFont(computedValues);
+    fontStyle = Servo_GetStyleFont(computedValues->ComputedValues());
   } else {
     sc = GetFontStyleContext(mCanvasElement,
                              aFont,
                              presShell,
                              usedFont,
                              aError);
     if (!sc) {
       return false;
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -427,16 +427,17 @@ UpdateFramePseudoElementStyles(nsIFrame*
 }
 
 bool
 ServoRestyleManager::ProcessPostTraversal(Element* aElement,
                                           nsStyleContext* aParentContext,
                                           ServoRestyleState& aRestyleState)
 {
   nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aElement);
+  ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
 
   // NOTE(emilio): This is needed because for table frames the bit is set on the
   // table wrapper (which is the primary frame), not on the table itself.
   const bool isOutOfFlow =
     aElement->GetPrimaryFrame() &&
     aElement->GetPrimaryFrame()->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
 
   // Grab the change hint from Servo.
@@ -494,31 +495,31 @@ ServoRestyleManager::ProcessPostTraversa
   if (!oldStyleContext) {
     displayContentsNode =
       PresContext()->FrameConstructor()->GetDisplayContentsNodeFor(aElement);
     if (displayContentsNode) {
       oldStyleContext = displayContentsNode->mStyle->AsServo();
     }
   }
 
-  RefPtr<ServoComputedValues> computedValues =
+  RefPtr<ServoStyleContext> currentContext =
     aRestyleState.StyleSet().ResolveServoStyle(aElement);
 
   // Note that we rely in the fact that we don't cascade pseudo-element styles
   // separately right now (that is, if a pseudo style changes, the normal style
   // changes too).
   //
   // Otherwise we should probably encode that information somehow to avoid
   // expensive checks in the common case.
   //
   // Also, we're going to need to check for pseudos of display: contents
   // elements, though that is buggy right now even in non-stylo mode, see
   // bug 1251799.
   const bool recreateContext = oldStyleContext &&
-    oldStyleContext->ComputedValues() != computedValues;
+    oldStyleContext->ComputedValues() != currentContext->ComputedValues();
 
   Maybe<ServoRestyleState> thisFrameRestyleState;
   if (styleFrame) {
     auto type = isOutOfFlow
       ? ServoRestyleState::Type::OutOfFlow
       : ServoRestyleState::Type::InFlow;
 
     thisFrameRestyleState.emplace(*styleFrame, aRestyleState, changeHint, type);
@@ -532,18 +533,22 @@ ServoRestyleManager::ProcessPostTraversa
   RefPtr<ServoStyleContext> newContext = nullptr;
   if (recreateContext) {
     MOZ_ASSERT(styleFrame || displayContentsNode);
 
     auto pseudo = aElement->GetPseudoElementType();
     nsIAtom* pseudoTag = pseudo == CSSPseudoElementType::NotPseudo
       ? nullptr : nsCSSPseudoElements::GetPseudoAtom(pseudo);
 
-    newContext = aRestyleState.StyleSet().GetContext(
-      computedValues.forget(), aParentContext, pseudoTag, pseudo, aElement);
+    // XXXManishearth we should just reuse the old one here
+    RefPtr<ServoStyleContext> tempContext =
+      Servo_StyleContext_NewContext(currentContext->ComputedValues(), parent,
+                                    PresContext(), pseudo, pseudoTag).Consume();
+    newContext = aRestyleState.StyleSet().GetContext(tempContext.forget(), aParentContext,
+                                                     pseudoTag, pseudo, aElement);
 
     newContext->ResolveSameStructsAs(PresContext(), oldStyleContext);
 
     // We want to walk all the continuations here, even the ones with different
     // styles.  In practice, the only reason we get continuations with different
     // styles here is ::first-line (::first-letter never affects element
     // styles).  But in that case, newContext is the right context for the
     // _later_ continuations anyway (the ones not affected by ::first-line), not
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1920,21 +1920,21 @@ nsCSSFrameConstructor::CreateGeneratedCo
     return;
   }
 
   // Servo has already eagerly computed the style for the container, so we can
   // just stick the style on the element and avoid an additional traversal.
   //
   // We don't do this for pseudos that may trigger animations or transitions,
   // since those need to be kicked off by the traversal machinery.
-  bool isServo = pseudoStyleContext->IsServo();
   bool hasServoAnimations = false;
-  if (isServo) {
-    ServoComputedValues* servoStyle = pseudoStyleContext->ComputedValues();
-    hasServoAnimations = Servo_ComputedValues_SpecifiesAnimationsOrTransitions(servoStyle);
+  ServoStyleContext* servoStyle = pseudoStyleContext->GetAsServo();
+  if (servoStyle) {
+    hasServoAnimations =
+      Servo_ComputedValues_SpecifiesAnimationsOrTransitions(servoStyle->ComputedValues());
     if (!hasServoAnimations) {
       Servo_SetExplicitStyle(container, servoStyle);
     }
   }
 
   // stylo: ServoRestyleManager does not handle transitions yet, and when it
   // does it probably won't need to track reframed style contexts to start
   // transitions correctly.
@@ -1966,17 +1966,17 @@ nsCSSFrameConstructor::CreateGeneratedCo
       container->AppendChildTo(content, false);
       if (content->IsElement()) {
         createdChildElement = true;
       }
     }
   }
 
   // We may need to do a synchronous servo traversal in various uncommon cases.
-  if (isServo) {
+  if (servoStyle) {
     if (hasServoAnimations) {
       // If animations are involved, we avoid the SetExplicitStyle optimization
       // above.
       mPresShell->StyleSet()->AsServo()->StyleNewSubtree(container);
     } else if (createdChildElement) {
       // If we created any children elements, Servo needs to traverse them, but
       // the root is already set up.
       mPresShell->StyleSet()->AsServo()->StyleNewChildren(container);
--- a/layout/style/GeckoStyleContext.h
+++ b/layout/style/GeckoStyleContext.h
@@ -105,16 +105,40 @@ public:
 
   bool HasNoChildren() const;
 
   nsRuleNode* RuleNode() const {
     MOZ_ASSERT(mRuleNode);
     return mRuleNode;
   }
 
+  void AddRef() {
+    if (mRefCnt == UINT32_MAX) {
+      NS_WARNING("refcount overflow, leaking object");
+      return;
+    }
+    ++mRefCnt;
+    NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
+    return;
+  }
+
+  void Release() {
+    if (mRefCnt == UINT32_MAX) {
+      NS_WARNING("refcount overflow, leaking object");
+      return;
+    }
+    --mRefCnt;
+    NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
+    if (mRefCnt == 0) {
+      Destroy();
+      return;
+    }
+    return;
+  }
+
   ~GeckoStyleContext() {
     Destructor();
   }
 
   /**
    * Swaps owned style struct pointers between this and aNewContext, on
    * the assumption that aNewContext is the new style context for a frame
    * and this is the old one.  aStructs indicates which structs to consider
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -75,19 +75,19 @@ SERVO_BINDING_FUNC(Servo_StyleSet_GetKey
                    nsTimingFunctionBorrowed timing_function,
                    RawGeckoKeyframeListBorrowedMut keyframe_list)
 SERVO_BINDING_FUNC(Servo_StyleSet_GetFontFaceRules, void,
                    RawServoStyleSetBorrowed set,
                    RawGeckoFontFaceRuleListBorrowedMut list)
 SERVO_BINDING_FUNC(Servo_StyleSet_GetCounterStyleRule, nsCSSCounterStyleRule*,
                    RawServoStyleSetBorrowed set, nsIAtom* name)
 SERVO_BINDING_FUNC(Servo_StyleSet_ResolveForDeclarations,
-                   ServoComputedValuesStrong,
+                   ServoStyleContextStrong,
                    RawServoStyleSetBorrowed set,
-                   ServoComputedValuesBorrowedOrNull parent_style,
+                   ServoStyleContextBorrowedOrNull parent_style,
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_StyleSet_MightHaveAttributeDependency, bool,
                    RawServoStyleSetBorrowed set,
                    RawGeckoElementBorrowed element,
                    nsIAtom* local_name)
 SERVO_BINDING_FUNC(Servo_StyleSet_HasStateDependency, bool,
                    RawServoStyleSetBorrowed set,
                    RawGeckoElementBorrowed element,
@@ -454,72 +454,88 @@ SERVO_BINDING_FUNC(Servo_MediaList_Delet
 // CSS supports()
 SERVO_BINDING_FUNC(Servo_CSSSupports2, bool,
                    const nsACString* name, const nsACString* value)
 SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
                    const nsACString* cond)
 
 // Computed style data
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox,
-                   ServoComputedValuesStrong,
-                   ServoComputedValuesBorrowedOrNull parent_style_or_null,
+                   ServoStyleContextStrong,
+                   ServoStyleContextBorrowedOrNull parent_style_or_null,
+                   mozilla::CSSPseudoElementType pseudo_type,
                    nsIAtom* pseudo_tag, bool skip_display_fixup,
                    RawServoStyleSetBorrowed set)
-SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoComputedValuesStrong,
+SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoStyleContextStrong,
                    RawServoStyleSetBorrowed set,
-                   ServoComputedValuesBorrowedOrNull parent_style,
+                   mozilla::CSSPseudoElementType pseudo_type,
+                   nsIAtom* pseudo_tag,
+                   ServoStyleContextBorrowedOrNull parent_style,
                    mozilla::InheritTarget target)
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetVisitedStyle,
-                   ServoComputedValuesStrong,
+                   ServoStyleContextStrong,
                    ServoComputedValuesBorrowed values)
 // Gets the source style rules for the computed values. This returns
 // the result via rules, which would include a list of unowned pointers
 // to RawServoStyleRule.
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetStyleRuleList, void,
                    ServoComputedValuesBorrowed values,
                    RawGeckoServoStyleRuleListBorrowedMut rules)
 
+SERVO_BINDING_FUNC(Servo_StyleContext_NewContext,
+                   ServoStyleContextStrong,
+                   ServoComputedValuesBorrowed values,
+                   ServoStyleContextBorrowedOrNull parent,
+                   RawGeckoPresContextBorrowed pres_context,
+                   mozilla::CSSPseudoElementType pseudo_type,
+                   nsIAtom* pseudo_tag)
+
+
 // Initialize Servo components. Should be called exactly once at startup.
 SERVO_BINDING_FUNC(Servo_Initialize, void,
                    RawGeckoURLExtraData* dummy_url_data)
 // Shut down Servo components. Should be called exactly once at shutdown.
 SERVO_BINDING_FUNC(Servo_Shutdown, void)
 
 // Restyle and change hints.
 SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed element,
                    nsRestyleHint restyle_hint, nsChangeHint change_hint)
 SERVO_BINDING_FUNC(Servo_TakeChangeHint, nsChangeHint, RawGeckoElementBorrowed element)
-SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoComputedValuesStrong,
+SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoStyleContextStrong,
                    RawGeckoElementBorrowed element,
                    RawServoStyleSetBorrowed set)
-SERVO_BINDING_FUNC(Servo_ResolvePseudoStyle, ServoComputedValuesStrong,
+SERVO_BINDING_FUNC(Servo_ResolvePseudoStyle, ServoStyleContextStrong,
                    RawGeckoElementBorrowed element,
                    mozilla::CSSPseudoElementType pseudo_type,
+                   nsIAtom* pseudo_tag,
                    bool is_probe,
                    ServoComputedValuesBorrowedOrNull inherited_style,
+                   ServoStyleContextBorrowedOrNull parent_style_context,
                    RawServoStyleSetBorrowed set)
 SERVO_BINDING_FUNC(Servo_SetExplicitStyle, void,
                    RawGeckoElementBorrowed element,
-                   ServoComputedValuesBorrowed primary_style)
+                   ServoStyleContextBorrowed primary_style)
 SERVO_BINDING_FUNC(Servo_HasAuthorSpecifiedRules, bool,
                    RawGeckoElementBorrowed element,
                    uint32_t rule_type_mask,
                    bool author_colors_allowed)
 
 // Resolves style for an element or pseudo-element without processing pending
 // restyles first. The Element and its ancestors may be unstyled, have pending
 // restyles, or be in a display:none subtree. Styles are cached when possible,
 // though caching is not possible within display:none subtrees, and the styles
 // may be invalidated by already-scheduled restyles.
 //
 // The tree must be in a consistent state such that a normal traversal could be
 // performed, and this function maintains that invariant.
-SERVO_BINDING_FUNC(Servo_ResolveStyleLazily, ServoComputedValuesStrong,
+SERVO_BINDING_FUNC(Servo_ResolveStyleLazily, ServoStyleContextStrong,
                    RawGeckoElementBorrowed element,
                    mozilla::CSSPseudoElementType pseudo_type,
+                   nsIAtom* pseudo_tag,
+                   ServoStyleContextBorrowedOrNull parent_style_context,
                    mozilla::StyleRuleInclusion rule_inclusion,
                    const mozilla::ServoElementSnapshotTable* snapshots,
                    RawServoStyleSetBorrowed set)
 
 // Use ServoStyleSet::PrepareAndTraverseSubtree instead of calling this
 // directly
 SERVO_BINDING_FUNC(Servo_TraverseSubtree,
                    bool,
@@ -533,17 +549,17 @@ SERVO_BINDING_FUNC(Servo_TraverseSubtree
 SERVO_BINDING_FUNC(Servo_AssertTreeIsClean, void, RawGeckoElementBorrowed root)
 
 // Checks whether the rule tree has crossed its threshold for unused rule nodes,
 // and if so, frees them.
 SERVO_BINDING_FUNC(Servo_MaybeGCRuleTree, void, RawServoStyleSetBorrowed set)
 
 // Returns computed values for the given element without any animations rules.
 SERVO_BINDING_FUNC(Servo_StyleSet_GetBaseComputedValuesForElement,
-                   ServoComputedValuesStrong,
+                   ServoStyleContextStrong,
                    RawServoStyleSetBorrowed set,
                    RawGeckoElementBorrowed element,
                    const mozilla::ServoElementSnapshotTable* snapshots,
                    mozilla::CSSPseudoElementType pseudo_type)
 
 // For canvas font.
 SERVO_BINDING_FUNC(Servo_SerializeFontValueForCanvas, void,
                    RawServoDeclarationBlockBorrowed declarations,
@@ -559,17 +575,17 @@ SERVO_BINDING_FUNC(Servo_GetCustomProper
 
 SERVO_BINDING_FUNC(Servo_GetCustomPropertyNameAt, bool,
                    ServoComputedValuesBorrowed, uint32_t index,
                    nsAString* name)
 
 // Style-struct management.
 #define STYLE_STRUCT(name, checkdata_cb)                            \
   struct nsStyle##name;                                             \
-  SERVO_BINDING_FUNC(Servo_GetStyle##name, const nsStyle##name*,  \
+  SERVO_BINDING_FUNC(Servo_GetStyle##name, const nsStyle##name*,    \
                      ServoComputedValuesBorrowedOrNull computed_values)
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 
 // AddRef / Release functions
 #define SERVO_ARC_TYPE(name_, type_)                                \
   SERVO_BINDING_FUNC(Servo_##name_##_AddRef, void, type_##Borrowed) \
   SERVO_BINDING_FUNC(Servo_##name_##_Release, void, type_##Borrowed)
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -19,16 +19,17 @@ struct RawServoStyleSet;
 struct RawServoAnimationValueMap;
 
 #define SERVO_ARC_TYPE(name_, type_) struct type_;
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
 
 namespace mozilla {
 class ServoElementSnapshot;
+class ServoStyleContext;
 struct StyleAnimation;
 struct URLExtraData;
 namespace dom {
 class Element;
 class StyleChildrenIterator;
 } // namespace dom
 struct AnimationPropertySegment;
 struct ComputedTiming;
@@ -97,16 +98,24 @@ typedef mozilla::dom::StyleChildrenItera
   struct MOZ_MUST_USE_TYPE type_##Strong     \
   {                                          \
     type_* mPtr;                             \
     already_AddRefed<type_> Consume();       \
   };
 #include "mozilla/ServoArcTypeList.h"
 #undef SERVO_ARC_TYPE
 
+typedef mozilla::ServoStyleContext const* ServoStyleContextBorrowed;
+typedef mozilla::ServoStyleContext const* ServoStyleContextBorrowedOrNull;
+struct MOZ_MUST_USE_TYPE ServoStyleContextStrong
+{
+  mozilla::ServoStyleContext* mPtr;
+  already_AddRefed<mozilla::ServoStyleContext> Consume();
+};
+
 #define DECL_OWNED_REF_TYPE_FOR(type_)    \
   typedef type_* type_##Owned;            \
   DECL_BORROWED_REF_TYPE_FOR(type_)       \
   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_)       \
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -77,19 +77,19 @@ using namespace mozilla::dom;
 #define SERVO_ARC_TYPE(name_, type_) \
   already_AddRefed<type_>            \
   type_##Strong::Consume() {         \
     RefPtr<type_> result;            \
     result.swap(mPtr);               \
     return result.forget();          \
   }
 #include "mozilla/ServoArcTypeList.h"
+SERVO_ARC_TYPE(StyleContext, ServoStyleContext)
 #undef SERVO_ARC_TYPE
 
-
 static Mutex* sServoFontMetricsLock = nullptr;
 static RWLock* sServoLangFontPrefsLock = nullptr;
 
 
 static
 const nsFont*
 ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext,
                                nsIAtom* aLanguage, uint8_t aGenericId)
@@ -202,16 +202,36 @@ Gecko_GetAnonymousContentForElement(RawG
 void
 Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent)
 {
   MOZ_ASSERT(aAnonContent);
   delete aAnonContent;
 }
 
 void
+Gecko_ServoStyleContext_Init(ServoStyleContext* aContext,
+                             const ServoStyleContext* aParentContext,
+                             RawGeckoPresContextBorrowed aPresContext, ServoComputedValuesStrong aValues,
+                             mozilla::CSSPseudoElementType aPseudoType, nsIAtom* aPseudoTag)
+{
+  // because it is within an Arc it is unsafe for the Rust side to ever
+  // carry around a mutable non opaque reference to the context, so we
+  // cast it here.
+  ServoStyleContext* parent = const_cast<ServoStyleContext*>(aParentContext);
+  nsPresContext* pres = const_cast<nsPresContext*>(aPresContext);
+  new (KnownNotNull, aContext) ServoStyleContext(parent, pres, aPseudoTag, aPseudoType, aValues.Consume());
+}
+
+void
+Gecko_ServoStyleContext_Destroy(ServoStyleContext* aContext)
+{
+  aContext->~ServoStyleContext();
+}
+
+void
 Gecko_ConstructStyleChildrenIterator(
   RawGeckoElementBorrowed aElement,
   RawGeckoStyleChildrenIteratorBorrowedMut aIterator)
 {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aIterator);
   new (aIterator) StyleChildrenIterator(aElement);
 }
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -45,16 +45,17 @@ namespace mozilla {
     struct ImageValue;
     class LoaderReusableStyleSheets;
   };
   namespace dom {
     enum class IterationCompositeOperation : uint8_t;
   };
   enum class UpdateAnimationsTasks : uint8_t;
   struct LangGroupFontPrefs;
+  class ServoStyleContext;
   class ServoStyleSheet;
   class ServoElementSnapshotTable;
 }
 using mozilla::FontFamilyList;
 using mozilla::FontFamilyType;
 using mozilla::ServoElementSnapshot;
 class nsCSSCounterStyleRule;
 class nsCSSFontFaceRule;
@@ -135,16 +136,22 @@ bool Gecko_IsSignificantChild(RawGeckoNo
                               bool text_is_significant,
                               bool whitespace_is_significant);
 RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
 RawGeckoNodeBorrowedOrNull Gecko_GetFlattenedTreeParentNode(RawGeckoNodeBorrowed node);
 RawGeckoElementBorrowedOrNull Gecko_GetBeforeOrAfterPseudo(RawGeckoElementBorrowed element, bool is_before);
 nsTArray<nsIContent*>* Gecko_GetAnonymousContentForElement(RawGeckoElementBorrowed element);
 void Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* anon_content);
 
+void Gecko_ServoStyleContext_Init(mozilla::ServoStyleContext* context,
+                                  ServoStyleContextBorrowedOrNull parent_context,
+                                  RawGeckoPresContextBorrowed pres_context, ServoComputedValuesStrong values,
+                                  mozilla::CSSPseudoElementType pseudo_type, nsIAtom* pseudo_tag);
+void Gecko_ServoStyleContext_Destroy(mozilla::ServoStyleContext* context);
+
 // By default, Servo walks the DOM by traversing the siblings of the DOM-view
 // first child. This generally works, but misses anonymous children, which we
 // want to traverse during styling. To support these cases, we create an
 // optional stack-allocated iterator in aIterator for nodes that need it.
 void Gecko_ConstructStyleChildrenIterator(RawGeckoElementBorrowed aElement,
                                           RawGeckoStyleChildrenIteratorBorrowedMut aIterator);
 void Gecko_DestroyStyleChildrenIterator(RawGeckoStyleChildrenIteratorBorrowedMut aIterator);
 RawGeckoNodeBorrowedOrNull Gecko_GetNextStyleChild(RawGeckoStyleChildrenIteratorBorrowedMut it);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -58,16 +58,17 @@ headers = [
     "mozilla/ServoElementSnapshotTable.h",
     "mozilla/css/ErrorReporter.h",
     "mozilla/dom/Element.h",
     "mozilla/dom/ChildIterator.h",
     "mozilla/dom/NameSpaceConstants.h",
     "mozilla/LookAndFeel.h",
     "mozilla/ServoBindings.h",
     "mozilla/ServoMediaList.h",
+    "mozilla/ServoStyleContext.h",
     "nsCSSCounterStyleRule.h",
     "nsCSSFontFaceRule.h",
     "nsMediaFeatures.h",
     "nsMediaList.h",
     "nsXBLBinding.h",
 ]
 raw-lines = [
     # FIXME(emilio): Incrementally remove these "pub use"s. Probably
@@ -115,18 +116,18 @@ whitelist-vars = [
     "kPresContext_.*",
 ]
 whitelist-types = [
     "RawGecko.*",
     "mozilla::AnimationPropertySegment",
     "mozilla::ComputedTiming",
     "mozilla::ComputedTimingFunction",
     "mozilla::ComputedTimingFunction::BeforeFlag",
-    "mozilla::ServoComputedValues2",
     "mozilla::ServoElementSnapshot.*",
+    "mozilla::ServoStyleContext",
     "mozilla::ServoStyleSheetInner",
     "mozilla::CSSPseudoClassType",
     "mozilla::css::ErrorReporter",
     "mozilla::css::SheetParsingMode",
     "mozilla::css::URLMatchingFunction",
     "mozilla::dom::IterationCompositeOperation",
     "mozilla::dom::StyleChildrenIterator",
     "mozilla::HalfCorner",
@@ -241,17 +242,21 @@ whitelist-types = [
     "nsStyleXUL",
     "nsTArray",
     "nsTArrayHeader",
     "Position",
     "PropertyValuePair",
     "Runnable",
     "ServoAttrSnapshot",
     "ServoBundledURI",
+    "ServoComputedValues",
     "ServoElementSnapshot",
+    "ServoStyleContextStrong",
+    "ServoStyleContextBorrowed",
+    "ServoStyleContextBorrowedOrNull",
     "SheetParsingMode",
     "StaticRefPtr",
     "StyleAnimation",
     "StyleBasicShape",
     "StyleBasicShapeType",
     "StyleGeometryBox",
     "StyleShapeSource",
     "StyleTransition",
@@ -313,33 +318,38 @@ mapped-generic-types = [
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoFontComputationData", servo = "::properties::FontComputationData" },
     { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::stylearc::Arc<::custom_properties::CustomPropertiesMap>>" },
     { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
     { generic = false, gecko = "mozilla::ServoVisitedStyle", servo = "Option<::stylearc::Arc<::properties::ComputedValues>>" },
     { generic = false, gecko = "mozilla::ServoComputedValueFlags", servo = "::properties::computed_value_flags::ComputedValueFlags" },
     { generic = true, gecko = "mozilla::ServoRawOffsetArc", servo = "::stylearc::RawOffsetArc" },
+    { generic = false, gecko = "ServoStyleContextStrong", servo = "::gecko_bindings::sugar::ownership::Strong<ServoStyleContext>" },
 ]
 fixups = [
     { pat = "root::nsString", rep = "::nsstring::nsStringRepr" },
 ]
 
 [bindings]
 headers = ["mozilla/ServoBindings.h"]
 hide-types = [
     "nsACString_internal",
     "nsAString_internal",
+    "ServoStyleContextBorrowed",
+    "ServoStyleContextBorrowedOrNull",
 ]
 raw-lines = [
     "pub use nsstring::{nsACString, nsAString, nsString, nsStringRepr};",
     "use gecko_bindings::structs::nsStyleTransformMatrix;",
     "use gecko_bindings::structs::nsTArray;",
     "type nsACString_internal = nsACString;",
     "type nsAString_internal = nsAString;",
+    "pub type ServoStyleContextBorrowed<'a> = &'a ServoStyleContext;",
+    "pub type ServoStyleContextBorrowedOrNull<'a> = Option<&'a ::properties::ComputedValues>;",
 ]
 whitelist-functions = ["Servo_.*", "Gecko_.*"]
 structs-types = [
     "mozilla::css::GridTemplateAreasValue",
     "mozilla::css::ErrorReporter",
     "mozilla::css::ImageValue",
     "mozilla::css::URLValue",
     "mozilla::css::URLValueData",
@@ -455,16 +465,19 @@ structs-types = [
     "nsStyleXUL",
     "nsTimingFunction",
     "nscolor",
     "nscoord",
     "nsresult",
     "Loader",
     "LoaderReusableStyleSheets",
     "ServoStyleSheet",
+    "ServoComputedValues",
+    "ServoStyleContext",
+    "ServoStyleContextStrong",
     "EffectCompositor_CascadeLevel",
     "UpdateAnimationsTasks",
     "ParsingMode",
     "InheritTarget",
     "URLMatchingFunction",
     "StyleRuleInclusion",
     "nsStyleTransformMatrix::MatrixTransformOperator",
     "RawGeckoGfxMatrix4x4",
--- a/layout/style/ServoStyleContext.h
+++ b/layout/style/ServoStyleContext.h
@@ -8,37 +8,38 @@
 #define mozilla_ServoStyleContext_h
 
 #include "nsStyleContext.h"
 
 namespace mozilla {
 
 class ServoStyleContext final : public nsStyleContext {
 public:
-
-  static already_AddRefed<ServoStyleContext>
-  Create(nsStyleContext* aParentContext,
-         nsPresContext* aPresContext,
-         nsIAtom* aPseudoTag,
-         mozilla::CSSPseudoElementType aPseudoType,
-         already_AddRefed<ServoComputedValues> aComputedValues);
-
   ServoStyleContext(nsStyleContext* aParent,
                     nsPresContext* aPresContext,
                     nsIAtom* aPseudoTag,
                     CSSPseudoElementType aPseudoType,
                     already_AddRefed<ServoComputedValues> aComputedValues);
 
   nsPresContext* PresContext() const {
     return mPresContext;
   }
 
   ServoComputedValues* ComputedValues() const {
     return mSource;
   }
+
+  void AddRef() {
+    Servo_StyleContext_AddRef(this);
+  }
+
+  void Release() {
+    Servo_StyleContext_Release(this);
+  }
+
   ~ServoStyleContext() {
     Destructor();
   }
 
   /**
    * Makes this context match |aOther| in terms of which style structs have
    * been resolved.
    */
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -182,80 +182,85 @@ ServoStyleSet::GetContext(nsIContent* aC
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
                           CSSPseudoElementType aPseudoType,
                           LazyComputeBehavior aMayCompute)
 {
   MOZ_ASSERT(aContent->IsElement());
   Element* element = aContent->AsElement();
 
-  RefPtr<ServoComputedValues> computedValues;
+  RefPtr<ServoStyleContext> computedValues;
+  ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
   if (aMayCompute == LazyComputeBehavior::Allow) {
     PreTraverseSync();
-    computedValues =
-      ResolveStyleLazily(element, CSSPseudoElementType::NotPseudo);
+    RefPtr<ServoStyleContext> tmp =
+      ResolveStyleLazily(element, CSSPseudoElementType::NotPseudo, aPseudoTag, parent);
+      computedValues = GetContext(tmp.forget(), parent, aPseudoTag, aPseudoType,
+                                  element);
   } else {
     computedValues = ResolveServoStyle(element);
   }
 
   MOZ_ASSERT(computedValues);
-  return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType,
-                    element);
+  return computedValues.forget();
 }
 
 already_AddRefed<ServoStyleContext>
-ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
+ServoStyleSet::GetContext(already_AddRefed<ServoStyleContext> aComputedValues,
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
                           CSSPseudoElementType aPseudoType,
                           Element* aElementForAnimation)
 {
   bool isLink = false;
   bool isVisitedLink = false;
   // If we need visited styles for callers where `aElementForAnimation` is null,
   // we can precompute these and pass them as flags, similar to nsStyleSet.cpp.
   if (aElementForAnimation) {
     isLink = nsCSSRuleProcessor::IsLink(aElementForAnimation);
     isVisitedLink = nsCSSRuleProcessor::GetContentState(aElementForAnimation)
                                        .HasState(NS_EVENT_STATE_VISITED);
   }
 
-  RefPtr<ServoComputedValues> computedValues = Move(aComputedValues);
-  RefPtr<ServoComputedValues> visitedComputedValues =
+  RefPtr<ServoStyleContext> result = Move(aComputedValues);
+  RefPtr<ServoComputedValues> computedValues = result->ComputedValues();
+
+  MOZ_ASSERT(result->GetPseudoType() == aPseudoType);
+  MOZ_ASSERT(result->GetPseudo() == aPseudoTag);
+
+  RefPtr<ServoStyleContext> resultIfVisited =
     Servo_ComputedValues_GetVisitedStyle(computedValues).Consume();
 
-  // If `visitedComputedValues` is non-null, then there was a relevant link and
+  // If `resultIfVisited` is non-null, then there was a relevant link and
   // visited styles were computed.  This corresponds to the cases where Gecko's
   // style system produces `aVisitedRuleNode`.
   // Set up `parentIfVisited` depending on whether our parent context has a
   // a visited style.  If it doesn't but we do have visited styles, use the
   // regular parent context for visited.
   nsStyleContext *parentIfVisited =
     aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
   if (!parentIfVisited) {
-    if (visitedComputedValues) {
+    if (resultIfVisited) {
       parentIfVisited = aParentContext;
     }
   }
 
+  ServoStyleContext* parentIfVisitedServo = parentIfVisited ? parentIfVisited->AsServo() : nullptr;
+
   // The true visited state of the relevant link is used to decided whether
   // visited styles should be consulted for all visited dependent properties.
   bool relevantLinkVisited = isLink ? isVisitedLink :
     (aParentContext && aParentContext->RelevantLinkVisited());
 
-  RefPtr<ServoStyleContext> result =
-    ServoStyleContext::Create(aParentContext, mPresContext, aPseudoTag, aPseudoType,
-                              computedValues.forget());
-
-  if (visitedComputedValues) {
-    RefPtr<ServoStyleContext> resultIfVisited =
-      ServoStyleContext::Create(parentIfVisited, mPresContext, aPseudoTag, aPseudoType,
-                                visitedComputedValues.forget());
-    resultIfVisited->SetIsStyleIfVisited();
-    result->SetStyleIfVisited(resultIfVisited.forget());
+  if (resultIfVisited) {
+    RefPtr<ServoStyleContext> visitedContext =
+    Servo_StyleContext_NewContext(resultIfVisited->ComputedValues(), parentIfVisitedServo,
+                                  mPresContext, aPseudoType, aPseudoTag).Consume();
+    visitedContext->SetIsStyleIfVisited();
+    result->SetStyleIfVisited(visitedContext.forget());
 
     if (relevantLinkVisited) {
       result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
     }
   }
 
   // Set the body color on the pres context. See nsStyleSet::GetContext
   if (aElementForAnimation &&
@@ -420,36 +425,36 @@ ServoStyleSet::ResolveStyleForText(nsICo
   MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
   MOZ_ASSERT(aTextNode->GetParent());
   MOZ_ASSERT(aParentContext);
 
   // Gecko expects text node style contexts to be like elements that match no
   // rules: inherit the inherit structs, reset the reset structs. This is cheap
   // enough to do on the main thread, which means that the parallel style system
   // can avoid worrying about text nodes.
-  const ServoComputedValues* parentComputedValues =
-    aParentContext->ComputedValues();
-  RefPtr<ServoComputedValues> computedValues =
+  RefPtr<ServoStyleContext> computedValues =
     Servo_ComputedValues_Inherit(mRawSet.get(),
-                                 parentComputedValues,
+                                 CSSPseudoElementType::InheritingAnonBox,
+                                 nsCSSAnonBoxes::mozText,
+                                 aParentContext->AsServo(),
                                  InheritTarget::Text).Consume();
-
   return GetContext(computedValues.forget(), aParentContext,
                     nsCSSAnonBoxes::mozText,
                     CSSPseudoElementType::InheritingAnonBox,
                     nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveStyleForFirstLetterContinuation(nsStyleContext* aParentContext)
 {
-  const ServoComputedValues* parent =
-    aParentContext->ComputedValues();
-  RefPtr<ServoComputedValues> computedValues =
+  ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
+  RefPtr<ServoStyleContext> computedValues =
     Servo_ComputedValues_Inherit(mRawSet.get(),
+                                 CSSPseudoElementType::InheritingAnonBox,
+                                 nsCSSAnonBoxes::firstLetterContinuation,
                                  parent,
                                  InheritTarget::FirstLetterContinuation)
                                  .Consume();
   MOZ_ASSERT(computedValues);
 
   return GetContext(computedValues.forget(), aParentContext,
                     nsCSSAnonBoxes::firstLetterContinuation,
                     CSSPseudoElementType::InheritingAnonBox,
@@ -461,18 +466,20 @@ ServoStyleSet::ResolveStyleForPlaceholde
 {
   RefPtr<nsStyleContext>& cache =
     mNonInheritingStyleContexts[nsCSSAnonBoxes::NonInheriting::oofPlaceholder];
   if (cache) {
     RefPtr<nsStyleContext> retval = cache;
     return retval.forget();
   }
 
-  RefPtr<ServoComputedValues> computedValues =
+  RefPtr<ServoStyleContext> computedValues =
     Servo_ComputedValues_Inherit(mRawSet.get(),
+                                 CSSPseudoElementType::NonInheritingAnonBox,
+                                 nsCSSAnonBoxes::oofPlaceholder,
                                  nullptr,
                                  InheritTarget::PlaceholderFrame)
                                  .Consume();
   MOZ_ASSERT(computedValues);
 
   RefPtr<nsStyleContext> retval =
     GetContext(computedValues.forget(), nullptr,
                nsCSSAnonBoxes::oofPlaceholder,
@@ -487,84 +494,88 @@ ServoStyleSet::ResolvePseudoElementStyle
                                          CSSPseudoElementType aType,
                                          nsStyleContext* aParentContext,
                                          Element* aPseudoElement)
 {
   UpdateStylistIfNeeded();
 
   MOZ_ASSERT(aType < CSSPseudoElementType::Count);
 
-  RefPtr<ServoComputedValues> computedValues;
+  RefPtr<ServoStyleContext> computedValues;
+
+  nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
   if (aPseudoElement) {
     MOZ_ASSERT(aType == aPseudoElement->GetPseudoElementType());
     computedValues = Servo_ResolveStyle(aPseudoElement,
                                         mRawSet.get()).Consume();
   } else {
     const ServoComputedValues* parentStyle =
       aParentContext ? aParentContext->ComputedValues() : nullptr;
+    ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
     computedValues =
       Servo_ResolvePseudoStyle(aOriginatingElement,
                                aType,
+                               pseudoTag,
                                /* is_probe = */ false,
                                parentStyle,
+                               parent,
                                mRawSet.get()).Consume();
   }
 
   MOZ_ASSERT(computedValues);
 
   bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
                          aType == CSSPseudoElementType::after;
 
-  nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
   return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType,
                     isBeforeOrAfter ? aOriginatingElement : nullptr);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveTransientStyle(Element* aElement,
+                                     CSSPseudoElementType aPseudoType,
                                      nsIAtom* aPseudoTag,
-                                     CSSPseudoElementType aPseudoType,
                                      StyleRuleInclusion aRuleInclusion)
 {
-  RefPtr<ServoComputedValues> computedValues =
-    ResolveTransientServoStyle(aElement, aPseudoType, aRuleInclusion);
+  RefPtr<ServoStyleContext> computedValues =
+    ResolveTransientServoStyle(aElement, aPseudoType, aPseudoTag, aRuleInclusion);
 
   return GetContext(computedValues.forget(),
                     nullptr,
                     aPseudoTag,
                     aPseudoType, nullptr);
 }
 
-already_AddRefed<ServoComputedValues>
+already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveTransientServoStyle(
     Element* aElement,
     CSSPseudoElementType aPseudoType,
+    nsIAtom* aPseudoTag,
     StyleRuleInclusion aRuleInclusion)
 {
   PreTraverseSync();
-  return ResolveStyleLazily(aElement, aPseudoType, aRuleInclusion);
+  return ResolveStyleLazily(aElement, aPseudoType, aPseudoTag, nullptr, aRuleInclusion);
 }
 
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
                                                   nsStyleContext* aParentContext)
 {
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
              !nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
 
   UpdateStylistIfNeeded();
 
   bool skipFixup =
     nsCSSAnonBoxes::AnonBoxSkipsParentDisplayBasedStyleFixup(aPseudoTag);
 
-  const ServoComputedValues* parentStyle =
-    aParentContext ? aParentContext->ComputedValues()
-                   : nullptr;
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_ComputedValues_GetForAnonymousBox(parentStyle, aPseudoTag, skipFixup,
+  ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
+  RefPtr<ServoStyleContext> computedValues =
+    Servo_ComputedValues_GetForAnonymousBox(parent, CSSPseudoElementType::InheritingAnonBox,
+                                            aPseudoTag, skipFixup,
                                             mRawSet.get()).Consume();
 #ifdef DEBUG
   if (!computedValues) {
     nsString pseudo;
     aPseudoTag->ToString(pseudo);
     NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
              NS_ConvertUTF16toUTF8(pseudo).get()).get());
     MOZ_CRASH();
@@ -597,18 +608,19 @@ ServoStyleSet::ResolveNonInheritingAnony
   UpdateStylistIfNeeded();
 
   // We always want to skip parent-based display fixup here.  It never makes
   // sense for non-inheriting anonymous boxes.  (Static assertions in
   // nsCSSAnonBoxes.cpp ensure that all non-inheriting non-anonymous boxes
   // are indeed annotated as skipping this fixup.)
   MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(nsCSSAnonBoxes::viewport),
              "viewport needs fixup to handle blockifying it");
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_ComputedValues_GetForAnonymousBox(nullptr, aPseudoTag, true,
+  RefPtr<ServoStyleContext> computedValues =
+    Servo_ComputedValues_GetForAnonymousBox(nullptr, CSSPseudoElementType::NonInheritingAnonBox,
+                                            aPseudoTag, true,
                                             mRawSet.get()).Consume();
 #ifdef DEBUG
   if (!computedValues) {
     nsString pseudo;
     aPseudoTag->ToString(pseudo);
     NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
              NS_ConvertUTF16toUTF8(pseudo).get()).get());
     MOZ_CRASH();
@@ -827,41 +839,43 @@ ServoStyleSet::ProbePseudoElementStyle(E
   UpdateStylistIfNeeded();
 
   // NB: We ignore aParentContext, because in some cases
   // (first-line/first-letter on anonymous box blocks) Gecko passes something
   // nonsensical there.  In all other cases we want to inherit directly from
   // aOriginatingElement's styles anyway.
   MOZ_ASSERT(aType < CSSPseudoElementType::Count);
 
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_ResolvePseudoStyle(aOriginatingElement, aType,
+  nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
+  ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
+  RefPtr<ServoStyleContext> computedValues =
+    Servo_ResolvePseudoStyle(aOriginatingElement, aType, pseudoTag,
                              /* is_probe = */ true,
                              nullptr,
+                             parent,
                              mRawSet.get()).Consume();
   if (!computedValues) {
     return nullptr;
   }
 
   // For :before and :after pseudo-elements, having display: none or no
   // 'content' property is equivalent to not having the pseudo-element
   // at all.
   bool isBeforeOrAfter = aType == CSSPseudoElementType::before ||
                          aType == CSSPseudoElementType::after;
   if (isBeforeOrAfter) {
-    const nsStyleDisplay* display = Servo_GetStyleDisplay(computedValues);
-    const nsStyleContent* content = Servo_GetStyleContent(computedValues);
+    const nsStyleDisplay* display = Servo_GetStyleDisplay(computedValues->ComputedValues());
+    const nsStyleContent* content = Servo_GetStyleContent(computedValues->ComputedValues());
     // XXXldb What is contentCount for |content: ""|?
     if (display->mDisplay == StyleDisplay::None ||
         content->ContentCount() == 0) {
       return nullptr;
     }
   }
 
-  nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
   return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType,
                     isBeforeOrAfter ? aOriginatingElement : nullptr);
 }
 
 nsRestyleHint
 ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
                                       EventStates aStateMask)
 {
@@ -1075,22 +1089,20 @@ ServoStyleSet::GetAnimationValues(
 
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::GetBaseContextForElement(dom::Element* aElement,
                          nsStyleContext* aParentContext,
                          nsPresContext* aPresContext,
                          nsIAtom* aPseudoTag,
                          CSSPseudoElementType aPseudoType)
 {
-  RefPtr<ServoComputedValues> cv = Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
+  return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
                                                         aElement,
                                                         &Snapshots(),
                                                         aPseudoType).Consume();
-  return ServoStyleContext::Create(nullptr, aPresContext, aPseudoTag,
-                                   aPseudoType, cv.forget());
 }
 
 already_AddRefed<RawServoAnimationValue>
 ServoStyleSet::ComputeAnimationValue(
   Element* aElement,
   RawServoDeclarationBlock* aDeclarations,
   ServoComputedValuesBorrowed aComputedValues)
 {
@@ -1147,34 +1159,36 @@ ServoStyleSet::ClearDataAndMarkDeviceDir
 }
 
 void
 ServoStyleSet::CompatibilityModeChanged()
 {
   Servo_StyleSet_CompatModeChanged(mRawSet.get());
 }
 
-already_AddRefed<ServoComputedValues>
+already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveServoStyle(Element* aElement)
 {
   UpdateStylistIfNeeded();
   return Servo_ResolveStyle(aElement, mRawSet.get()).Consume();
 }
 
 void
 ServoStyleSet::ClearNonInheritingStyleContexts()
 {
   for (RefPtr<nsStyleContext>& ptr : mNonInheritingStyleContexts) {
     ptr = nullptr;
   }
 }
 
-already_AddRefed<ServoComputedValues>
+already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveStyleLazily(Element* aElement,
                                   CSSPseudoElementType aPseudoType,
+                                  nsIAtom* aPseudoTag,
+                                  const ServoStyleContext* aParentContext,
                                   StyleRuleInclusion aRuleInclusion)
 {
   mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType);
   MOZ_ASSERT(!StylistNeedsUpdate());
 
   AutoSetInServoTraversal guard(this);
 
   /**
@@ -1197,27 +1211,31 @@ ServoStyleSet::ResolveStyleLazily(Elemen
     }
   } else if (aPseudoType == CSSPseudoElementType::after) {
     if (Element* pseudo = nsLayoutUtils::GetAfterPseudo(aElement)) {
       elementForStyleResolution = pseudo;
       pseudoTypeForStyleResolution = CSSPseudoElementType::NotPseudo;
     }
   }
 
-  RefPtr<ServoComputedValues> computedValues =
+  RefPtr<ServoStyleContext> computedValues =
     Servo_ResolveStyleLazily(elementForStyleResolution,
                              pseudoTypeForStyleResolution,
+                             aPseudoTag,
+                             aParentContext,
                              aRuleInclusion,
                              &Snapshots(),
                              mRawSet.get()).Consume();
 
   if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
     computedValues =
       Servo_ResolveStyleLazily(elementForStyleResolution,
                                pseudoTypeForStyleResolution,
+                               aPseudoTag,
+                               aParentContext,
                                aRuleInclusion,
                                &Snapshots(),
                                mRawSet.get()).Consume();
   }
 
   return computedValues.forget();
 }
 
@@ -1230,19 +1248,19 @@ ServoStyleSet::AppendFontFaceRules(nsTAr
 }
 
 nsCSSCounterStyleRule*
 ServoStyleSet::CounterStyleRuleForName(nsIAtom* aName)
 {
   return Servo_StyleSet_GetCounterStyleRule(mRawSet.get(), aName);
 }
 
-already_AddRefed<ServoComputedValues>
+already_AddRefed<ServoStyleContext>
 ServoStyleSet::ResolveForDeclarations(
-  ServoComputedValuesBorrowedOrNull aParentOrNull,
+  const ServoStyleContext* aParentOrNull,
   RawServoDeclarationBlockBorrowed aDeclarations)
 {
   UpdateStylistIfNeeded();
   return Servo_StyleSet_ResolveForDeclarations(mRawSet.get(),
                                                aParentOrNull,
                                                aDeclarations).Consume();
 }
 
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -183,26 +183,27 @@ public:
                             dom::Element* aPseudoElement);
 
   // Resolves style for a (possibly-pseudo) Element without assuming that the
   // style has been resolved, and without worrying about setting the style
   // context up to live in the style context tree (a null parent is used).
   // |aPeudoTag| and |aPseudoType| must match.
   already_AddRefed<nsStyleContext>
   ResolveTransientStyle(dom::Element* aElement,
+                        CSSPseudoElementType aPseudoType,
                         nsIAtom* aPseudoTag,
-                        CSSPseudoElementType aPseudoType,
                         StyleRuleInclusion aRules =
                           StyleRuleInclusion::All);
 
   // Similar to ResolveTransientStyle() but returns ServoComputedValues.
   // Unlike ResolveServoStyle() this function calls PreTraverseSync().
-  already_AddRefed<ServoComputedValues>
+  already_AddRefed<ServoStyleContext>
   ResolveTransientServoStyle(dom::Element* aElement,
-                             CSSPseudoElementType aPseudoTag,
+                             CSSPseudoElementType aPseudoType,
+                             nsIAtom* aPseudoTag,
                              StyleRuleInclusion aRules =
                                StyleRuleInclusion::All);
 
   // Get a style context for an anonymous box.  aPseudoTag is the pseudo-tag to
   // use and must be non-null.  It must be an anon box, and must be one that
   // inherits style from the given aParentContext.
   already_AddRefed<ServoStyleContext>
   ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
@@ -356,17 +357,17 @@ public:
    * Notifies the Servo stylesheet that the document's compatibility mode has changed.
    */
   void CompatibilityModeChanged();
 
   /**
    * Resolve style for the given element, and return it as a
    * ServoComputedValues, not an nsStyleContext.
    */
-  already_AddRefed<ServoComputedValues> ResolveServoStyle(dom::Element* aElement);
+  already_AddRefed<ServoStyleContext> ResolveServoStyle(dom::Element* aElement);
 
   bool GetKeyframesForName(const nsString& aName,
                            const nsTimingFunction& aTimingFunction,
                            nsTArray<Keyframe>& aKeyframes);
 
   nsTArray<ComputedKeyframeValues>
   GetComputedKeyframeValuesFor(const nsTArray<Keyframe>& aKeyframes,
                                dom::Element* aElement,
@@ -389,18 +390,18 @@ public:
                            nsIAtom* aPseudoTag,
                            CSSPseudoElementType aPseudoType);
 
   /**
    * Resolve style for a given declaration block with/without the parent style.
    * If the parent style is not specified, the document default computed values
    * is used.
    */
-  already_AddRefed<ServoComputedValues>
-  ResolveForDeclarations(ServoComputedValuesBorrowedOrNull aParentOrNull,
+  already_AddRefed<ServoStyleContext>
+  ResolveForDeclarations(const ServoStyleContext* aParentOrNull,
                          RawServoDeclarationBlockBorrowed aDeclarations);
 
   already_AddRefed<RawServoAnimationValue>
   ComputeAnimationValue(dom::Element* aElement,
                         RawServoDeclarationBlock* aDeclaration,
                         ServoComputedValuesBorrowed aComputedValues);
 
   void AppendTask(PostTraversalTask aTask)
@@ -471,17 +472,17 @@ private:
       sInServoTraversal = nullptr;
       mSet->RunPostTraversalTasks();
     }
 
   private:
     ServoStyleSet* mSet;
   };
 
-  already_AddRefed<ServoStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
+  already_AddRefed<ServoStyleContext> GetContext(already_AddRefed<ServoStyleContext>,
                                                  nsStyleContext* aParentContext,
                                                  nsIAtom* aPseudoTag,
                                                  CSSPseudoElementType aPseudoType,
                                                  dom::Element* aElementForAnimation);
 
   already_AddRefed<ServoStyleContext> GetContext(nsIContent* aContent,
                                                  nsStyleContext* aParentContext,
                                                  nsIAtom* aPseudoTag,
@@ -553,19 +554,21 @@ private:
 
   /**
    * Update the stylist as needed to ensure style data is up-to-date.
    *
    * This should only be called if StylistNeedsUpdate returns true.
    */
   void UpdateStylist();
 
-  already_AddRefed<ServoComputedValues>
+  already_AddRefed<ServoStyleContext>
     ResolveStyleLazily(dom::Element* aElement,
                        CSSPseudoElementType aPseudoType,
+                       nsIAtom* aPseudoTag,
+                       const ServoStyleContext* aParentContext,
                        StyleRuleInclusion aRules =
                          StyleRuleInclusion::All);
 
   void RunPostTraversalTasks();
 
   void PrependSheetOfType(SheetType aType,
                           ServoStyleSheet* aSheet);
 
--- a/layout/style/ServoTypes.h
+++ b/layout/style/ServoTypes.h
@@ -160,43 +160,43 @@ struct ServoComputedValueFlags {
 };
 
 #define STYLE_STRUCT(name_, checkdata_cb_) struct Gecko##name_;
 #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 #undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
 
+} // namespace mozilla
+
 
 /**
  * We want C++ to be abe to read the style struct fields of ComputedValues
  * so we define this type on the C++ side and use the bindgenned version
  * on the Rust side.
  *
  * C++ just sees pointers and opaque types here, so bindgen will attempt to generate a Copy
  * impl. This will fail because the bindgenned version contains owned types. Opt out.
  *
  * <div rustbindgen nocopy></div>
  */
-struct ServoComputedValues2 {
-#define STYLE_STRUCT(name_, checkdata_cb_) ServoRawOffsetArc<Gecko##name_> name_;
+struct ServoComputedValues {
+#define STYLE_STRUCT(name_, checkdata_cb_) mozilla::ServoRawOffsetArc<mozilla::Gecko##name_> name_;
   #define STYLE_STRUCT_LIST_IGNORE_VARIABLES
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
   #undef STYLE_STRUCT_LIST_IGNORE_VARIABLES
-  ServoCustomPropertiesMap custom_properties;
-  ServoWritingMode writing_mode;
-  ServoFontComputationData font_computation_data;
+  mozilla::ServoCustomPropertiesMap custom_properties;
+  mozilla::ServoWritingMode writing_mode;
+  mozilla::ServoFontComputationData font_computation_data;
   /// The rule node representing the ordered list of rules matched for this
   /// node.  Can be None for default values and text nodes.  This is
   /// essentially an optimization to avoid referencing the root rule node.
-  ServoRuleNode rules;
+  mozilla::ServoRuleNode rules;
   /// The element's computed values if visited, only computed if there's a
   /// relevant link for this element. A element's "relevant link" is the
   /// element being matched if it is a link or the nearest ancestor link.
-  ServoVisitedStyle visited_style;
-  ServoComputedValueFlags flags;
-  ~ServoComputedValues2() {} // do nothing, but prevent Copy from being impl'd by bindgen
+  mozilla::ServoVisitedStyle visited_style;
+  mozilla::ServoComputedValueFlags flags;
+  ~ServoComputedValues() {} // do nothing, but prevent Copy from being impl'd by bindgen
 };
 
-} // namespace mozilla
-
 #endif // mozilla_ServoTypes_h
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -664,17 +664,17 @@ nsComputedDOMStyle::DoGetStyleContextNoF
 
   // For Servo, compute the result directly without recursively building up
   // a throwaway style context chain.
   if (ServoStyleSet* servoSet = styleSet->GetAsServo()) {
     StyleRuleInclusion rules = aStyleType == eDefaultOnly
                                ? StyleRuleInclusion::DefaultOnly
                                : StyleRuleInclusion::All;
     RefPtr<nsStyleContext> result =
-       servoSet->ResolveTransientStyle(aElement, aPseudo, pseudoType, rules);
+       servoSet->ResolveTransientStyle(aElement, pseudoType, aPseudo, rules);
     if (aAnimationFlag == eWithAnimation) {
       return result.forget();
     }
 
     return servoSet->GetBaseContextForElement(aElement, nullptr, presContext,
                                               aPseudo, pseudoType);
   }
 
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -161,23 +161,22 @@ nsStyleContext::Destructor()
                "destroying style context from old rule tree too late");
 
   if (mParent) {
     mParent->RemoveChild(this);
   } else {
     presContext->StyleSet()->RootStyleContextRemoved();
   }
 
-  // Free up our data structs.
+  // Free up our caches.
   if (gecko) {
     gecko->DestroyCachedStructs(presContext);
+    // Servo doesn't store things here, and it's not threadsafe
+    CSSVariableImageTable::RemoveAll(this);
   }
-
-  // Free any ImageValues we were holding on to for CSS variable values.
-  CSSVariableImageTable::RemoveAll(this);
 }
 
 void nsStyleContext::AddChild(nsStyleContext* aChild)
 {
   if (GeckoStyleContext* gecko = GetAsGecko()) {
     gecko->AddChild(aChild->AsGecko());
   }
 }
@@ -480,16 +479,44 @@ nsStyleContext::CalcStyleDifference(nsSt
                                     uint32_t* aEqualStructs,
                                     uint32_t* aSamePointerStructs)
 {
   return CalcStyleDifferenceInternal(aNewContext,
                                      aEqualStructs,
                                      aSamePointerStructs);
 }
 
+void
+nsStyleContext::SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
+{
+  MOZ_ASSERT(!IsStyleIfVisited(), "this context is not visited data");
+  NS_ASSERTION(!mStyleIfVisited, "should only be set once");
+
+  mStyleIfVisited = aStyleIfVisited;
+
+  MOZ_ASSERT(mStyleIfVisited->IsStyleIfVisited(),
+             "other context is visited data");
+  MOZ_ASSERT(!mStyleIfVisited->GetStyleIfVisited(),
+             "other context does not have visited data");
+  NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
+               "pseudo tag mismatch");
+  if (GetParentAllowServo() && GetParentAllowServo()->GetStyleIfVisited()) {
+    NS_ASSERTION(GetStyleIfVisited()->GetParentAllowServo() ==
+                   GetParentAllowServo()->GetStyleIfVisited() ||
+                 GetStyleIfVisited()->GetParentAllowServo() ==
+                   GetParentAllowServo(),
+                 "parent mismatch");
+  } else {
+    NS_ASSERTION(GetStyleIfVisited()->GetParentAllowServo() ==
+                   GetParentAllowServo(),
+                 "parent mismatch");
+  }
+}
+
+
 class MOZ_STACK_CLASS FakeStyleContext
 {
 public:
   explicit FakeStyleContext(const ServoComputedValues* aComputedValues)
     : mComputedValues(aComputedValues) {}
 
   nsStyleContext* GetStyleIfVisited() {
     // Bug 1364484: Figure out what to do here for Stylo visited values.  We can
@@ -623,33 +650,16 @@ NS_NewStyleContext(nsStyleContext* aPare
   RefPtr<nsRuleNode> node = aRuleNode;
   RefPtr<GeckoStyleContext> context =
     new (aRuleNode->PresContext())
     GeckoStyleContext(aParentContext, aPseudoTag, aPseudoType, node.forget(),
                    aSkipParentDisplayBasedStyleFixup);
   return context.forget();
 }
 
-namespace mozilla {
-
-already_AddRefed<ServoStyleContext>
-ServoStyleContext::Create(nsStyleContext* aParentContext,
-                          nsPresContext* aPresContext,
-                          nsIAtom* aPseudoTag,
-                          CSSPseudoElementType aPseudoType,
-                          already_AddRefed<ServoComputedValues> aComputedValues)
-{
-  RefPtr<ServoStyleContext> context =
-    new ServoStyleContext(aParentContext, aPresContext, aPseudoTag, aPseudoType,
-                          Move(aComputedValues));
-  return context.forget();
-}
-
-} // namespace mozilla
-
 nsIPresShell*
 nsStyleContext::Arena()
 {
   return PresContext()->PresShell();
 }
 
 template<typename Func>
 static nscolor
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -21,16 +21,18 @@ class nsPresContext;
 
 namespace mozilla {
 enum class CSSPseudoElementType : uint8_t;
 class GeckoStyleContext;
 class ServoStyleContext;
 } // namespace mozilla
 
 extern "C" {
+  void Servo_StyleContext_AddRef(mozilla::ServoStyleContext* aContext);
+  void Servo_StyleContext_Release(mozilla::ServoStyleContext* aContext);
 #define STYLE_STRUCT(name_, checkdata_cb_)     \
   struct nsStyle##name_;                       \
   const nsStyle##name_* Servo_GetStyle##name_( \
     ServoComputedValuesBorrowedOrNull computed_values);
 #include "nsStyleStructList.h"
 #undef STYLE_STRUCT
 }
 
@@ -77,39 +79,18 @@ public:
 
 #ifdef DEBUG
   /**
    * Initializes a cached pref, which is only used in DEBUG code.
    */
   static void Initialize();
 #endif
 
-  nsrefcnt AddRef() {
-    if (mRefCnt == UINT32_MAX) {
-      NS_WARNING("refcount overflow, leaking object");
-      return mRefCnt;
-    }
-    ++mRefCnt;
-    NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
-    return mRefCnt;
-  }
-
-  nsrefcnt Release() {
-    if (mRefCnt == UINT32_MAX) {
-      NS_WARNING("refcount overflow, leaking object");
-      return mRefCnt;
-    }
-    --mRefCnt;
-    NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
-    if (mRefCnt == 0) {
-      Destroy();
-      return 0;
-    }
-    return mRefCnt;
-  }
+  inline void AddRef();
+  inline void Release();
 
 #ifdef DEBUG
   void FrameAddRef() {
     ++mFrameRefCnt;
   }
 
   void FrameRelease() {
     --mFrameRefCnt;
@@ -217,41 +198,17 @@ public:
   // Structs on this context should never be examined without also
   // examining the corresponding struct on |this|.  Doing so will likely
   // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
   // related to the Peek code in nsStyleContext::CalcStyleDifference.
   nsStyleContext* GetStyleIfVisited() const
     { return mStyleIfVisited; }
 
   // To be called only from nsStyleSet / ServoStyleSet.
-  void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
-  {
-    MOZ_ASSERT(!IsStyleIfVisited(), "this context is not visited data");
-    NS_ASSERTION(!mStyleIfVisited, "should only be set once");
-
-    mStyleIfVisited = aStyleIfVisited;
-
-    MOZ_ASSERT(mStyleIfVisited->IsStyleIfVisited(),
-               "other context is visited data");
-    MOZ_ASSERT(!mStyleIfVisited->GetStyleIfVisited(),
-               "other context does not have visited data");
-    NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
-                 "pseudo tag mismatch");
-    if (GetParentAllowServo() && GetParentAllowServo()->GetStyleIfVisited()) {
-      NS_ASSERTION(GetStyleIfVisited()->GetParentAllowServo() ==
-                     GetParentAllowServo()->GetStyleIfVisited() ||
-                   GetStyleIfVisited()->GetParentAllowServo() ==
-                     GetParentAllowServo(),
-                   "parent mismatch");
-    } else {
-      NS_ASSERTION(GetStyleIfVisited()->GetParentAllowServo() ==
-                     GetParentAllowServo(),
-                   "parent mismatch");
-    }
-  }
+  void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited);
 
   // Does any descendant of this style context have any style values
   // that were computed based on this style context's ancestors?
   bool HasChildThatUsesGrandancestorStyle() const
     { return !!(mBits & NS_STYLE_CHILD_USES_GRANDANCESTOR_STYLE); }
 
   // Is this style context shared with a sibling or cousin?
   // (See nsStyleSet::GetContext.)
--- a/layout/style/nsStyleContextInlines.h
+++ b/layout/style/nsStyleContextInlines.h
@@ -32,16 +32,28 @@ nsStyleContext::RuleNode()
 
 ServoComputedValues*
 nsStyleContext::ComputedValues()
 {
     MOZ_RELEASE_ASSERT(IsServo());
     return AsServo()->ComputedValues();
 }
 
+void
+nsStyleContext::AddRef()
+{
+  MOZ_STYLO_FORWARD(AddRef, ())
+}
+
+void
+nsStyleContext::Release()
+{
+  MOZ_STYLO_FORWARD(Release, ())
+}
+
 #define STYLE_STRUCT(name_, checkdata_cb_)                      \
 const nsStyle##name_ *                                          \
 nsStyleContext::Style##name_() {                                \
   return DoGetStyle##name_<true>();                             \
 }                                                               \
 const nsStyle##name_ *                                          \
 nsStyleContext::ThreadsafeStyle##name_() {                      \
   if (mozilla::ServoStyleSet::IsInServoTraversal()) {           \
@@ -191,9 +203,10 @@ nsStyleContext::IsLinkContext() const
 
 void
 nsStyleContext::StartBackgroundImageLoads()
 {
   // Just get our background struct; that should do the trick
   StyleBackground();
 }
 
+
 #endif // nsStyleContextInlines_h
--- a/servo/components/layout/flow.rs
+++ b/servo/components/layout/flow.rs
@@ -1114,17 +1114,17 @@ impl BaseFlow {
             scroll_root_id: None,
         }
     }
 
     /// Update the 'flags' field when computed styles have changed.
     ///
     /// These flags are initially set during flow construction.  They only need to be updated here
     /// if they are based on properties that can change without triggering `RECONSTRUCT_FLOW`.
-    pub fn update_flags_if_needed(&mut self, style: &ServoComputedValues) {
+    pub fn update_flags_if_needed(&mut self, style: &ComputedValues) {
         // For absolutely-positioned flows, changes to top/bottom/left/right can cause these flags
         // to get out of date:
         if self.restyle_damage.contains(REFLOW_OUT_OF_FLOW) {
             // Note: We don't need to check whether IS_ABSOLUTELY_POSITIONED has changed, because
             // changes to the 'position' property trigger flow reconstruction.
             if self.flags.contains(IS_ABSOLUTELY_POSITIONED) {
                 let logical_position = style.logical_position();
                 self.flags.set(INLINE_POSITION_IS_STATIC,
--- a/servo/components/script/dom/cssrulelist.rs
+++ b/servo/components/script/dom/cssrulelist.rs
@@ -85,23 +85,25 @@ impl CSSRuleList {
             panic!("Called insert_rule on non-CssRule-backed CSSRuleList");
         };
 
         let global = self.global();
         let window = global.as_window();
         let index = idx as usize;
 
         let parent_stylesheet = self.parent_stylesheet.style_stylesheet();
-        let new_rule =
-            css_rules.insert_rule(&parent_stylesheet.shared_lock,
-                                  rule,
-                                  &parent_stylesheet.contents,
-                                  index,
-                                  nested,
-                                  None)?;
+        let new_rule = css_rules.with_raw_offset_arc(|arc| {
+            arc.insert_rule(&parent_stylesheet.shared_lock,
+                            rule,
+                            &parent_stylesheet.contents,
+                            index,
+                            nested,
+                            None)
+        })?;
+
 
         let parent_stylesheet = &*self.parent_stylesheet;
         let dom_rule = CSSRule::new_specific(&window, parent_stylesheet, new_rule);
         self.dom_rules.borrow_mut().insert(index, MutNullableJS::new(Some(&*dom_rule)));
         Ok((idx))
     }
 
     // In case of a keyframe rule, index must be valid.
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -72,17 +72,17 @@ use style::dom::{DescendantsBit, DirtyDe
 use style::dom::{PresentationalHintsSynthesizer, TElement, TNode, UnsafeNode};
 use style::element_state::*;
 use style::font_metrics::ServoMetricsProvider;
 use style::properties::{ComputedValues, PropertyDeclarationBlock};
 use style::selector_parser::{AttrValue as SelectorAttrValue, NonTSPseudoClass, PseudoClassStringArg};
 use style::selector_parser::{PseudoElement, SelectorImpl, extended_filtering};
 use style::shared_lock::{SharedRwLock as StyleSharedRwLock, Locked as StyleLocked};
 use style::str::is_whitespace;
-use style::stylearc::Arc;
+use style::stylearc::{Arc, ArcBorrow};
 
 #[derive(Copy, Clone)]
 pub struct ServoLayoutNode<'a> {
     /// The wrapped node.
     node: LayoutJS<Node>,
 
     /// Being chained to a PhantomData prevents `LayoutNode`s from escaping.
     chain: PhantomData<&'a ()>,
@@ -389,19 +389,19 @@ impl<'le> TElement for ServoLayoutElemen
     type ConcreteNode = ServoLayoutNode<'le>;
 
     type FontMetricsProvider = ServoMetricsProvider;
 
     fn as_node(&self) -> ServoLayoutNode<'le> {
         ServoLayoutNode::from_layout_js(self.element.upcast())
     }
 
-    fn style_attribute(&self) -> Option<&Arc<StyleLocked<PropertyDeclarationBlock>>> {
+    fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
         unsafe {
-            (*self.element.style_attribute()).as_ref()
+            (*self.element.style_attribute()).as_ref().map(|x| x.borrow_arc())
         }
     }
 
     fn get_state(&self) -> ElementState {
         self.element.get_state_for_layout()
     }
 
     #[inline]
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -410,29 +410,29 @@ pub trait ThreadSafeLayoutElement: Clone
                             .unwrap().clone()
                     },
                     PseudoElementCascadeType::Precomputed => {
                         context.stylist.precomputed_values_for_pseudo(
                             &context.guards,
                             &style_pseudo,
                             Some(data.styles.primary()),
                             CascadeFlags::empty(),
-                            &ServoMetricsProvider)
+                            &ServoMetricsProvider, (), ())
                             .clone()
                     }
                     PseudoElementCascadeType::Lazy => {
                         context.stylist
                                .lazily_compute_pseudo_element_style(
                                    &context.guards,
                                    unsafe { &self.unsafe_get() },
                                    &style_pseudo,
                                    RuleInclusion::All,
                                    data.styles.primary(),
                                    /* is_probe = */ false,
-                                   &ServoMetricsProvider)
+                                   &ServoMetricsProvider, (), ())
                                .unwrap()
                                .clone()
                     }
                 }
             }
         }
     }
 
--- a/servo/components/style/gecko/arc_types.rs
+++ b/servo/components/style/gecko/arc_types.rs
@@ -5,24 +5,25 @@
 //! This file lists all arc FFI types and defines corresponding addref
 //! and release functions. This list corresponds to ServoArcTypeList.h
 //! file in Gecko.
 
 #![allow(non_snake_case, missing_docs)]
 
 use gecko_bindings::bindings::{RawServoImportRule, RawServoSupportsRule};
 use gecko_bindings::bindings::{RawServoKeyframe, RawServoKeyframesRule};
+use gecko_bindings::bindings::RawServoMediaRule;
 use gecko_bindings::bindings::{RawServoNamespaceRule, RawServoPageRule};
-use gecko_bindings::bindings::{RawServoRuleNode, RawServoRuleNodeStrong, RawServoDocumentRule, RawServoMediaRule};
-use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules};
+use gecko_bindings::bindings::{RawServoRuleNode, RawServoRuleNodeStrong, RawServoDocumentRule};
+use gecko_bindings::bindings::ServoCssRules;
 use gecko_bindings::structs::{RawServoAnimationValue, RawServoDeclarationBlock, RawServoStyleRule, RawServoMediaList};
-use gecko_bindings::structs::RawServoStyleSheetContents;
+use gecko_bindings::structs::{RawServoStyleSheetContents, ServoComputedValues, ServoStyleContext};
 use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
 use media_queries::MediaList;
-use properties::{ComputedValues, PropertyDeclarationBlock};
+use properties::{ComputedValues, ComputedValuesInner, PropertyDeclarationBlock};
 use properties::animated_properties::AnimationValue;
 use rule_tree::StrongRuleNode;
 use shared_lock::Locked;
 use std::{mem, ptr};
 use stylesheets::{CssRules, StylesheetContents, StyleRule, ImportRule, KeyframesRule, MediaRule};
 use stylesheets::{NamespaceRule, PageRule, SupportsRule, DocumentRule};
 use stylesheets::keyframes_rule::Keyframe;
 
@@ -46,19 +47,22 @@ macro_rules! impl_arc_ffi {
 }
 
 impl_arc_ffi!(Locked<CssRules> => ServoCssRules
               [Servo_CssRules_AddRef, Servo_CssRules_Release]);
 
 impl_arc_ffi!(StylesheetContents => RawServoStyleSheetContents
               [Servo_StyleSheetContents_AddRef, Servo_StyleSheetContents_Release]);
 
-impl_arc_ffi!(ComputedValues => ServoComputedValues
+impl_arc_ffi!(ComputedValuesInner => ServoComputedValues
               [Servo_ComputedValues_AddRef, Servo_ComputedValues_Release]);
 
+impl_arc_ffi!(ComputedValues => ServoStyleContext
+              [Servo_StyleContext_AddRef, Servo_StyleContext_Release]);
+
 impl_arc_ffi!(Locked<PropertyDeclarationBlock> => RawServoDeclarationBlock
               [Servo_DeclarationBlock_AddRef, Servo_DeclarationBlock_Release]);
 
 impl_arc_ffi!(Locked<StyleRule> => RawServoStyleRule
               [Servo_StyleRule_AddRef, Servo_StyleRule_Release]);
 
 impl_arc_ffi!(Locked<ImportRule> => RawServoImportRule
               [Servo_ImportRule_AddRef, Servo_ImportRule_Release]);
--- a/servo/components/style/gecko/pseudo_element_definition.mako.rs
+++ b/servo/components/style/gecko/pseudo_element_definition.mako.rs
@@ -86,16 +86,35 @@ impl PseudoElement {
                         Some(PseudoElement::${pseudo.capitalized()})
                     },
                 % endif
             % endfor
             _ => None,
         }
     }
 
+
+    /// Construct a `CSSPseudoElementType` from a pseudo-element
+    #[inline]
+    pub fn pseudo_type(&self) -> CSSPseudoElementType {
+        match *self {
+            % for pseudo in PSEUDOS:
+                % if not pseudo.is_anon_box():
+                    PseudoElement::${pseudo.capitalized()} => CSSPseudoElementType::${pseudo.original_ident},
+                % endif
+            % endfor
+            _ => CSSPseudoElementType::NotPseudo
+        }
+    }
+
+    /// Get a PseudoInfo for a pseudo
+    pub fn pseudo_info(&self) -> (*mut structs::nsIAtom, CSSPseudoElementType) {
+        (self.atom().as_ptr(), self.pseudo_type())
+    }
+
     /// Construct a pseudo-element from an anonymous box `Atom`.
     #[inline]
     pub fn from_anon_box_atom(atom: &Atom) -> Option<Self> {
         % for pseudo in PSEUDOS:
             % if pseudo.is_anon_box():
                 if atom == &atom!("${pseudo.value}") {
                     return Some(PseudoElement::${pseudo.capitalized()});
                 }
--- a/servo/components/style/gecko/restyle_damage.rs
+++ b/servo/components/style/gecko/restyle_damage.rs
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Gecko's restyle damage computation (aka change hints, aka `nsChangeHint`).
 
 use gecko_bindings::bindings;
 use gecko_bindings::structs;
 use gecko_bindings::structs::{nsChangeHint, nsStyleContext};
-use gecko_bindings::sugar::ownership::FFIArcHelpers;
 use matching::{StyleChange, StyleDifference};
 use properties::ComputedValues;
 use std::ops::{BitAnd, BitOr, BitOrAssign, Not};
 use stylearc::Arc;
 
 /// The representation of Gecko's restyle damage is just a wrapper over
 /// `nsChangeHint`.
 #[derive(Clone, Copy, Debug, PartialEq)]
@@ -51,17 +50,17 @@ impl GeckoRestyleDamage {
         source: &nsStyleContext,
         new_style: &Arc<ComputedValues>
     ) -> StyleDifference {
         // TODO(emilio): Const-ify this?
         let context = source as *const nsStyleContext as *mut nsStyleContext;
         let mut any_style_changed: bool = false;
         let hint = unsafe {
             bindings::Gecko_CalcStyleDifference(context,
-                                                new_style.as_borrowed(),
+                                                &new_style,
                                                 &mut any_style_changed)
         };
         let change = if any_style_changed { StyleChange::Changed } else { StyleChange::Unchanged };
         StyleDifference::new(GeckoRestyleDamage(hint), change)
     }
 
     /// Returns true if this restyle damage contains all the damage of |other|.
     pub fn contains(self, other: Self) -> bool {
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -59,17 +59,17 @@ use gecko_bindings::structs::{nsIAtom, n
 use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
 use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
 use gecko_bindings::structs::ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
 use gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
 use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
 use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
 use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
 use gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme;
-use gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasSimpleFFI};
+use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI};
 use logical_geometry::WritingMode;
 use media_queries::Device;
 use properties::{ComputedValues, parse_style_attribute};
 use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
 use properties::animated_properties::{AnimatableLonghand, AnimationValue, AnimationValueMap};
 use properties::animated_properties::TransitionProperty;
 use properties::style_structs::Font;
 use rule_tree::CascadeLevel as ServoCascadeLevel;
@@ -1099,20 +1099,19 @@ impl<'le> TElement for GeckoElement<'le>
                          before_change_style: Option<Arc<ComputedValues>>,
                          tasks: UpdateAnimationsTasks) {
         // We have to update animations even if the element has no computed
         // style since it means the element is in a display:none subtree, we
         // should destroy all CSS animations in display:none subtree.
         let computed_data = self.borrow_data();
         let computed_values =
             computed_data.as_ref().map(|d| d.styles.primary());
-        let computed_values_opt =
-            computed_values.map(|v| v.as_borrowed());
         let before_change_values =
-            before_change_style.as_ref().map(|v| v.as_borrowed());
+            before_change_style.as_ref().map(|x| &***x);
+        let computed_values_opt = computed_values.as_ref().map(|x| &****x);
         unsafe {
             Gecko_UpdateAnimations(self.0,
                                    before_change_values,
                                    computed_values_opt,
                                    tasks.bits());
         }
     }
 
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -334,17 +334,18 @@ trait PrivateMatchMethods: TElement {
     fn cascade_with_rules(&self,
                           shared_context: &SharedStyleContext,
                           font_metrics_provider: &FontMetricsProvider,
                           rule_node: &StrongRuleNode,
                           primary_style: Option<&Arc<ComputedValues>>,
                           cascade_target: CascadeTarget,
                           cascade_visited: CascadeVisitedMode,
                           parent_info: Option<&ParentElementAndStyle<Self>>,
-                          visited_values_to_insert: Option<Arc<ComputedValues>>)
+                          visited_values_to_insert: Option<Arc<ComputedValues>>,
+                          pseudo: Option<&PseudoElement>)
                           -> Arc<ComputedValues> {
         let mut cascade_info = CascadeInfo::new();
         let mut cascade_flags = CascadeFlags::empty();
         if self.skip_root_and_item_based_display_fixup() {
             cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP)
         }
         if cascade_visited.visited_dependent_only() {
             cascade_flags.insert(VISITED_DEPENDENT_ONLY);
@@ -380,45 +381,50 @@ trait PrivateMatchMethods: TElement {
         let layout_parent_data;
         let mut layout_parent_style = style_to_inherit_from;
         if style_to_inherit_from.map_or(false, |s| s.is_display_contents()) {
             layout_parent_el = Some(layout_parent_el.unwrap().layout_parent());
             layout_parent_data = layout_parent_el.as_ref().unwrap().borrow_data().unwrap();
             layout_parent_style = Some(cascade_visited.values(layout_parent_data.styles.primary()));
         }
 
-        let style_to_inherit_from = style_to_inherit_from.map(|x| &x.inner);
-        let layout_parent_style = layout_parent_style.map(|x| &x.inner);
-
         // Propagate the "can be fragmented" bit. It would be nice to
         // encapsulate this better.
         //
         // Note that this is technically not needed for pseudos since we already
         // do that when we resolve the non-pseudo style, but it doesn't hurt
         // anyway.
         //
         // TODO(emilio): This is servo-only, move somewhere else?
         if let Some(ref p) = layout_parent_style {
             let can_be_fragmented =
                 p.is_multicol() ||
                 layout_parent_el.as_ref().unwrap().as_node().can_be_fragmented();
             unsafe { self.as_node().set_can_be_fragmented(can_be_fragmented); }
         }
 
+        #[cfg(feature = "gecko")]
+        let parent_style_context = style_to_inherit_from.map(|x| &**x);
+        #[cfg(feature = "servo")]
+        let parent_style_context = ();
+
         // Invoke the cascade algorithm.
         let values = cascade(shared_context.stylist.device(),
                              rule_node,
                              &shared_context.guards,
-                             style_to_inherit_from,
-                             layout_parent_style,
+                             style_to_inherit_from.map(|x| &***x),
+                             layout_parent_style.map(|x| &***x),
                              visited_values_to_insert,
                              Some(&mut cascade_info),
                              font_metrics_provider,
                              cascade_flags,
-                             shared_context.quirks_mode).to_outer();
+                             shared_context.quirks_mode)
+            .to_outer(shared_context.stylist.device(),
+                           parent_style_context,
+                           pseudo.map(|x| x.pseudo_info()));
 
         cascade_info.finish(&self.as_node());
         values
     }
 
     /// A common path for the cascade used by both primary elements and eager
     /// pseudo-elements.
     ///
@@ -427,17 +433,18 @@ trait PrivateMatchMethods: TElement {
     /// `parent_info` is our style parent and its primary style, if
     /// it's already been computed.
     fn cascade_internal(&self,
                         context: &StyleContext<Self>,
                         primary_style: Option<&Arc<ComputedValues>>,
                         primary_inputs: &CascadeInputs,
                         eager_pseudo_inputs: Option<&CascadeInputs>,
                         parent_info: Option<&ParentElementAndStyle<Self>>,
-                        cascade_visited: CascadeVisitedMode)
+                        cascade_visited: CascadeVisitedMode,
+                        pseudo: Option<&PseudoElement>)
                         -> Arc<ComputedValues> {
         if let Some(pseudo) = self.implemented_pseudo_element() {
             debug_assert!(eager_pseudo_inputs.is_none());
 
             // This is an element-backed pseudo, just grab the styles from the
             // parent if it's eager, and recascade otherwise.
             //
             // We also recascade if the eager pseudo-style has any animation
@@ -491,17 +498,18 @@ trait PrivateMatchMethods: TElement {
 
         self.cascade_with_rules(context.shared,
                                 &context.thread_local.font_metrics_provider,
                                 rule_node,
                                 primary_style,
                                 cascade_target,
                                 cascade_visited,
                                 parent_info,
-                                visited_values_to_insert)
+                                visited_values_to_insert,
+                                pseudo)
     }
 
     /// Computes values and damage for the primary style of an element, setting
     /// them on the ElementData.
     ///
     /// `parent_info` is our style parent and its primary style.
     fn cascade_primary(&self,
                        context: &mut StyleContext<Self>,
@@ -533,17 +541,18 @@ trait PrivateMatchMethods: TElement {
             }
 
             // Compute the new values.
             self.cascade_internal(context,
                                   None,
                                   primary_inputs,
                                   None,
                                   /* parent_info = */ None,
-                                  cascade_visited)
+                                  cascade_visited,
+                                  self.implemented_pseudo_element().as_ref())
         };
 
         // NB: Animations for pseudo-elements in Gecko are handled while
         // traversing the pseudo-elements themselves.
         if !context.shared.traversal_flags.for_animation_only() &&
            cascade_visited.should_process_animations() {
             self.process_animations(context,
                                     &mut old_values,
@@ -636,17 +645,18 @@ trait PrivateMatchMethods: TElement {
             let primary_inputs = context.cascade_inputs().primary();
             debug_assert!(cascade_visited.has_rules(primary_inputs));
 
             self.cascade_internal(context,
                                   data.styles.get_primary(),
                                   primary_inputs,
                                   Some(pseudo_inputs),
                                   /* parent_info = */ None,
-                                  cascade_visited)
+                                  cascade_visited,
+                                  Some(&pseudo))
         };
 
         if cascade_visited.should_accumulate_damage() {
             self.accumulate_damage(&context.shared,
                                    &mut data.restyle,
                                    old_values.as_ref().map(|v| v.as_ref()),
                                    &new_values,
                                    Some(pseudo));
@@ -681,17 +691,18 @@ trait PrivateMatchMethods: TElement {
         // well, along with updating the rest of the animation processing.
         Some(self.cascade_with_rules(context.shared,
                                      &context.thread_local.font_metrics_provider,
                                      &without_transition_rules,
                                      Some(primary_style),
                                      CascadeTarget::Normal,
                                      CascadeVisitedMode::Unvisited,
                                      /* parent_info = */ None,
-                                     primary_style.get_visited_style().cloned()))
+                                     primary_style.get_visited_style().cloned(),
+                                     /* pseudo */ None))
     }
 
     #[cfg(feature = "gecko")]
     fn needs_animations_update(&self,
                                context: &mut StyleContext<Self>,
                                old_values: Option<&Arc<ComputedValues>>,
                                new_values: &ComputedValues)
                                -> bool {
@@ -1694,14 +1705,14 @@ pub trait MatchMethods : TElement {
         // as existing browsers don't appear to animate visited styles.
         self.cascade_with_rules(shared_context,
                                 font_metrics_provider,
                                 &without_animation_rules,
                                 Some(primary_style),
                                 CascadeTarget::Normal,
                                 CascadeVisitedMode::Unvisited,
                                 /* parent_info = */ None,
-                                None)
+                                None, None)
     }
 
 }
 
 impl<E: TElement> MatchMethods for E {}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -41,49 +41,64 @@ use gecko_bindings::bindings::Gecko_SetL
 use gecko_bindings::bindings::Gecko_SetNullImageValue;
 use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
 use gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
 use gecko_bindings::bindings::RawGeckoPresContextBorrowed;
 use gecko_bindings::structs;
 use gecko_bindings::structs::nsCSSPropertyID;
 use gecko_bindings::structs::nsStyleVariables;
 use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
-use gecko_bindings::sugar::ownership::HasArcFFI;
 use gecko::values::convert_nscolor_to_rgba;
 use gecko::values::convert_rgba_to_nscolor;
 use gecko::values::GeckoStyleCoordConvertible;
 use gecko::values::round_border_to_device_pixels;
 use logical_geometry::WritingMode;
 use media_queries::Device;
 use properties::animated_properties::TransitionProperty;
 use properties::computed_value_flags::ComputedValueFlags;
 use properties::{longhands, FontComputationData, Importance, LonghandId};
 use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId};
 use rule_tree::StrongRuleNode;
-use std::mem::{forget, transmute, zeroed};
+use std::mem::{forget, uninitialized, transmute, zeroed};
 use std::{cmp, ops, ptr};
 use stylearc::{Arc, RawOffsetArc};
 use values::{Auto, CustomIdent, Either, KeyframesName};
 use values::computed::ToComputedValue;
 use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
 use values::specified::length::Percentage;
 use computed_values::border_style;
 
 pub mod style_structs {
     % for style_struct in data.style_structs:
     pub use super::${style_struct.gecko_struct_name} as ${style_struct.name};
     % endfor
 }
 
 
-pub use ::gecko_bindings::structs::mozilla::ServoComputedValues2 as ComputedValuesInner;
-
-#[derive(Clone, Debug)]
-pub struct ComputedValues {
-    pub inner: ComputedValuesInner
+pub type ComputedValuesInner = ::gecko_bindings::structs::ServoComputedValues;
+
+#[derive(Debug)]
+#[repr(C)]
+pub struct ComputedValues(::gecko_bindings::structs::mozilla::ServoStyleContext);
+
+impl Drop for ComputedValues {
+    fn drop(&mut self) {
+        unsafe {
+            bindings::Gecko_ServoStyleContext_Destroy(&mut self.0);
+        }
+    }
+}
+
+unsafe impl Sync for ComputedValues {}
+unsafe impl Send for ComputedValues {}
+
+impl Clone for ComputedValues {
+    fn clone(&self) -> Self {
+        unreachable!()
+    }
 }
 
 impl Clone for ComputedValuesInner {
     fn clone(&self) -> Self {
         ComputedValuesInner {
             % for style_struct in data.style_structs:
                 ${style_struct.gecko_name}: self.${style_struct.gecko_name}.clone(),
             % endfor
@@ -92,16 +107,19 @@ impl Clone for ComputedValuesInner {
             font_computation_data: self.font_computation_data.clone(),
             flags: self.flags.clone(),
             rules: self.rules.clone(),
             visited_style: self.visited_style.clone(),
         }
     }
 }
 
+pub type PseudoInfo = (*mut structs::nsIAtom, structs::CSSPseudoElementType);
+pub type ParentStyleContextInfo<'a> = Option< &'a ComputedValues>;
+
 impl ComputedValuesInner {
     pub fn new(custom_properties: Option<Arc<CustomPropertiesMap>>,
                writing_mode: WritingMode,
                font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
                flags: ComputedValueFlags,
                rules: Option<StrongRuleNode>,
                visited_style: Option<Arc<ComputedValues>>,
                % for style_struct in data.style_structs:
@@ -129,31 +147,52 @@ impl ComputedValuesInner {
                 rules: None,
                 visited_style: None,
                 flags: ComputedValueFlags::initial(),
                 % for style_struct in data.style_structs:
                     ${style_struct.gecko_name}: Arc::into_raw_offset(style_structs::${style_struct.name}::default(pres_context)),
                 % endfor
         }
     }
-    pub fn to_outer(self) -> Arc<ComputedValues> {
-        Arc::new(ComputedValues {inner: self})
+    pub fn to_outer(self, device: &Device, parent: ParentStyleContextInfo,
+                    info: Option<PseudoInfo>) -> Arc<ComputedValues> {
+        let (tag, ty) = if let Some(info) = info {
+            info
+        } else {
+            (ptr::null_mut(), structs::CSSPseudoElementType::NotPseudo)
+        };
+
+        unsafe { Self::to_outer_from_arc(Arc::new(self), device.pres_context(), parent, ty, tag) }
+    }
+
+    pub unsafe fn to_outer_from_arc(s: Arc<Self>, pres_context: bindings::RawGeckoPresContextBorrowed,
+                                    parent: ParentStyleContextInfo,
+                                    pseudo_ty: structs::CSSPseudoElementType,
+                                    pseudo_tag: *mut structs::nsIAtom) -> Arc<ComputedValues> {
+        use gecko_bindings::sugar::ownership::FFIArcHelpers;
+        let arc = unsafe {
+            let arc: Arc<ComputedValues> = Arc::new(uninitialized());
+            bindings::Gecko_ServoStyleContext_Init(&arc.0 as *const _ as *mut _, parent, pres_context,
+                                                   s.into_strong(), pseudo_ty, pseudo_tag);
+            arc
+        };
+        arc
     }
 }
 
 impl ops::Deref for ComputedValues {
     type Target = ComputedValuesInner;
     fn deref(&self) -> &ComputedValuesInner {
-        &self.inner
+        unsafe { &*self.0.mSource.mRawPtr }
     }
 }
 
 impl ops::DerefMut for ComputedValues {
     fn deref_mut(&mut self) -> &mut ComputedValuesInner {
-        &mut self.inner
+        unsafe { &mut *self.0.mSource.mRawPtr }
     }
 }
 
 impl ComputedValuesInner {
     #[inline]
     pub fn is_display_contents(&self) -> bool {
         self.get_box().clone_display() == longhands::display::computed_value::T::contents
     }
@@ -4791,17 +4830,17 @@ clip-path
     }
 </%self:impl_trait>
 
 <%def name="define_ffi_struct_accessor(style_struct)">
 #[no_mangle]
 #[allow(non_snake_case, unused_variables)]
 pub unsafe extern "C" fn Servo_GetStyle${style_struct.gecko_name}(computed_values:
         ServoComputedValuesBorrowedOrNull) -> *const ${style_struct.gecko_ffi_name} {
-    ComputedValues::arc_from_borrowed(&computed_values).unwrap().get_${style_struct.name_lower}().get_gecko()
+    computed_values.unwrap().get_${style_struct.name_lower}().get_gecko()
         as *const ${style_struct.gecko_ffi_name}
 }
 </%def>
 
 % for style_struct in data.style_structs:
 ${declare_style_struct(style_struct)}
 ${impl_style_struct(style_struct)}
 % if not style_struct.name in data.manual_style_structs:
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -1797,19 +1797,24 @@ pub mod style_structs {
                 }
             }
         % endif
     % endfor
 % endfor
 
 
 #[cfg(feature = "gecko")]
-pub use gecko_properties::ComputedValues;
-#[cfg(feature = "gecko")]
-pub use gecko_properties::ComputedValuesInner;
+pub use gecko_properties::{ComputedValues, ComputedValuesInner, ParentStyleContextInfo, PseudoInfo};
+
+#[cfg(feature = "servo")]
+/// Servo doesn't have style contexts so this is extraneous info
+pub type PseudoInfo = ();
+#[cfg(feature = "servo")]
+/// Servo doesn't have style contexts so this is extraneous info
+pub type ParentStyleContextInfo = ();
 
 
 #[cfg(feature = "servo")]
 #[cfg_attr(feature = "servo", derive(Clone, Debug))]
 /// Actual data of ComputedValues, to match up with Gecko
 pub struct ComputedValuesInner {
     % for style_struct in data.active_style_structs():
         ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
@@ -1861,17 +1866,16 @@ impl ComputedValuesInner {
         font_size_keyword: Option<(longhands::font_size::KeywordSize, f32)>,
         flags: ComputedValueFlags,
         rules: Option<StrongRuleNode>,
         visited_style: Option<Arc<ComputedValues>>,
         % for style_struct in data.active_style_structs():
         ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
         % endfor
     ) -> Self {
-        let font_computation_data = FontComputationData::new(font_size_keyword);
         ComputedValuesInner {
             custom_properties: custom_properties,
             writing_mode: writing_mode,
             font_computation_data: FontComputationData::new(font_size_keyword),
             rules: rules,
             visited_style: visited_style,
             flags: flags,
         % for style_struct in data.active_style_structs():
@@ -1897,17 +1901,18 @@ impl ops::DerefMut for ComputedValues {
     fn deref_mut(&mut self) -> &mut ComputedValuesInner {
         &mut self.inner
     }
 }
 
 #[cfg(feature = "servo")]
 impl ComputedValuesInner {
     /// Convert to an Arc<ComputedValues>
-    pub fn to_outer(self) -> Arc<ComputedValues> {
+    pub fn to_outer(self, _: &Device, _: ParentStyleContextInfo,
+                    _: Option<PseudoInfo>) -> Arc<ComputedValues> {
         Arc::new(ComputedValues {inner: self})
     }
 
     % for style_struct in data.active_style_structs():
         /// Clone the ${style_struct.name} struct.
         #[inline]
         pub fn clone_${style_struct.name_lower}(&self) -> Arc<style_structs::${style_struct.name}> {
             self.${style_struct.ident}.clone()
@@ -2532,17 +2537,17 @@ mod lazy_static_module {
                     % endif
                 }),
             % endfor
             custom_properties: None,
             writing_mode: WritingMode::empty(),
             font_computation_data: FontComputationData::default_values(),
             rules: None,
             visited_style: None,
-            flags: flags,
+            flags: ComputedValueFlags::initial(),
         };
     }
 }
 
 /// A per-longhand function that performs the CSS cascade for that longhand.
 pub type CascadePropertyFn =
     extern "Rust" fn(declaration: &PropertyDeclaration,
                      inherited_style: &ComputedValuesInner,
--- a/servo/components/style/servo/selector_parser.rs
+++ b/servo/components/style/servo/selector_parser.rs
@@ -161,16 +161,19 @@ impl PseudoElement {
         }
     }
 
     /// Covert non-canonical pseudo-element to canonical one, and keep a
     /// canonical one as it is.
     pub fn canonical(&self) -> PseudoElement {
         self.clone()
     }
+
+    /// Stub, only Gecko needs this
+    pub fn pseudo_info(&self) -> () { () }
 }
 
 /// The type used for storing pseudo-class string arguments.
 pub type PseudoClassStringArg = Box<str>;
 
 /// A non tree-structural pseudo-class.
 /// See https://drafts.csswg.org/selectors-4/#structural-pseudos
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -13,17 +13,17 @@ use element_state::ElementState;
 use font_metrics::FontMetricsProvider;
 #[cfg(feature = "gecko")]
 use gecko_bindings::structs::{nsIAtom, StyleRuleInclusion};
 use invalidation::element::invalidation_map::InvalidationMap;
 use invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey};
 use matching::CascadeVisitedMode;
 use media_queries::Device;
 use properties::{self, CascadeFlags, ComputedValues, ComputedValuesInner};
-use properties::{AnimationRules, PropertyDeclarationBlock};
+use properties::{AnimationRules, PropertyDeclarationBlock, PseudoInfo, ParentStyleContextInfo};
 #[cfg(feature = "servo")]
 use properties::INHERIT_ALL;
 use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
 use selector_map::{SelectorMap, SelectorMapEntry};
 use selector_parser::{SelectorImpl, PseudoElement};
 use selectors::attr::NamespaceConstraint;
 use selectors::bloom::BloomFilter;
 use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
@@ -596,17 +596,19 @@ impl Stylist {
     /// parent; otherwise, non-inherited properties are reset to their initial
     /// values. The flow constructor uses this flag when constructing anonymous
     /// flows.
     pub fn precomputed_values_for_pseudo(&self,
                                          guards: &StylesheetGuards,
                                          pseudo: &PseudoElement,
                                          parent: Option<&ComputedValuesInner>,
                                          cascade_flags: CascadeFlags,
-                                         font_metrics: &FontMetricsProvider)
+                                         font_metrics: &FontMetricsProvider,
+                                         pseudo_info: PseudoInfo,
+                                         parent_style_context: ParentStyleContextInfo)
                                          -> Arc<ComputedValues> {
         debug_assert!(pseudo.is_precomputed());
 
         let rule_node = match self.precomputed_pseudo_element_decls.get(pseudo) {
             Some(declarations) => {
                 // FIXME(emilio): When we've taken rid of the cascade we can just
                 // use into_iter.
                 self.rule_tree.insert_ordered_rules_with_important(
@@ -634,17 +636,18 @@ impl Stylist {
                             &rule_node,
                             guards,
                             parent,
                             parent,
                             None,
                             None,
                             font_metrics,
                             cascade_flags,
-                            self.quirks_mode).to_outer()
+                            self.quirks_mode).to_outer(self.device(), parent_style_context,
+                                                       Some(pseudo_info))
     }
 
     /// Returns the style for an anonymous box of the given type.
     #[cfg(feature = "servo")]
     pub fn style_for_anonymous(&self,
                                guards: &StylesheetGuards,
                                pseudo: &PseudoElement,
                                parent_style: &ComputedValuesInner)
@@ -671,54 +674,60 @@ impl Stylist {
                 unreachable!("That pseudo doesn't represent an anonymous box!")
             }
         };
         let mut cascade_flags = CascadeFlags::empty();
         if inherit_all {
             cascade_flags.insert(INHERIT_ALL);
         }
         self.precomputed_values_for_pseudo(guards, &pseudo, Some(parent_style), cascade_flags,
-                                           &ServoMetricsProvider)
+                                           &ServoMetricsProvider, (), ())
     }
 
     /// Computes a pseudo-element style lazily during layout.
     ///
     /// This can only be done for a certain set of pseudo-elements, like
     /// :selection.
     ///
     /// Check the documentation on lazy pseudo-elements in
     /// docs/components/style.md
     pub fn lazily_compute_pseudo_element_style<E>(&self,
                                                   guards: &StylesheetGuards,
                                                   element: &E,
                                                   pseudo: &PseudoElement,
                                                   rule_inclusion: RuleInclusion,
                                                   parent_style: &ComputedValuesInner,
                                                   is_probe: bool,
-                                                  font_metrics: &FontMetricsProvider)
+                                                  font_metrics: &FontMetricsProvider,
+                                                  pseudo_info: PseudoInfo,
+                                                  parent_style_context: ParentStyleContextInfo)
                                                   -> Option<Arc<ComputedValues>>
         where E: TElement,
     {
         let cascade_inputs =
             self.lazy_pseudo_rules(guards, element, pseudo, is_probe, rule_inclusion);
         self.compute_pseudo_element_style_with_inputs(&cascade_inputs,
                                                       guards,
                                                       parent_style,
-                                                      font_metrics)
+                                                      font_metrics,
+                                                      pseudo_info,
+                                                      parent_style_context)
     }
 
     /// Computes a pseudo-element style lazily using the given CascadeInputs.
     /// This can be used for truly lazy pseudo-elements or to avoid redoing
     /// selector matching for eager pseudo-elements when we need to recompute
     /// their style with a new parent style.
     pub fn compute_pseudo_element_style_with_inputs(&self,
                                                     inputs: &CascadeInputs,
                                                     guards: &StylesheetGuards,
                                                     parent_style: &ComputedValuesInner,
-                                                    font_metrics: &FontMetricsProvider)
+                                                    font_metrics: &FontMetricsProvider,
+                                                    pseudo_info: PseudoInfo,
+                                                    parent_style_context: ParentStyleContextInfo)
                                                     -> Option<Arc<ComputedValues>>
     {
         // We may have only visited rules in cases when we are actually
         // resolving, not probing, pseudo-element style.
         if !inputs.has_rules() && !inputs.has_visited_rules() {
             return None
         }
 
@@ -741,17 +750,18 @@ impl Stylist {
                                     rule_node,
                                     guards,
                                     Some(inherited_style),
                                     Some(inherited_style),
                                     None,
                                     None,
                                     font_metrics,
                                     CascadeFlags::empty(),
-                                    self.quirks_mode).to_outer();
+                                    self.quirks_mode).to_outer(self.device(), parent_style_context,
+                                                               Some(pseudo_info.clone()));
 
             Some(computed)
         } else {
             None
         };
 
         // We may not have non-visited rules, if we only had visited ones.  In
         // that case we want to use the root rulenode for our non-visited rules.
@@ -771,17 +781,19 @@ impl Stylist {
                             rules,
                             guards,
                             Some(parent_style),
                             Some(parent_style),
                             visited_values,
                             None,
                             font_metrics,
                             CascadeFlags::empty(),
-                            self.quirks_mode).to_outer())
+                            self.quirks_mode).to_outer(self.device(),
+                                                       parent_style_context,
+                                                       Some(pseudo_info)))
     }
 
     /// Computes the cascade inputs for a lazily-cascaded pseudo-element.
     ///
     /// See the documentation on lazy pseudo-elements in
     /// docs/components/style.md
     pub fn lazy_pseudo_rules<E>(&self,
                                 guards: &StylesheetGuards,
@@ -1331,17 +1343,18 @@ impl Stylist {
 
         results
     }
 
     /// Computes styles for a given declaration with parent_style.
     pub fn compute_for_declarations(&self,
                                     guards: &StylesheetGuards,
                                     parent_style: &ComputedValuesInner,
-                                    declarations: Arc<Locked<PropertyDeclarationBlock>>)
+                                    declarations: Arc<Locked<PropertyDeclarationBlock>>,
+                                    parent_style_context: ParentStyleContextInfo)
                                     -> Arc<ComputedValues> {
         use font_metrics::get_metrics_provider_for_product;
 
         let v = vec![
             ApplicableDeclarationBlock::from_declarations(declarations.clone(),
                                                           CascadeLevel::StyleAttributeNormal)
         ];
         let rule_node =
@@ -1355,17 +1368,17 @@ impl Stylist {
                             &rule_node,
                             guards,
                             Some(parent_style),
                             Some(parent_style),
                             None,
                             None,
                             &metrics,
                             CascadeFlags::empty(),
-                            self.quirks_mode).to_outer()
+                            self.quirks_mode).to_outer(self.device(), parent_style_context, None)
     }
 
     /// Accessor for a shared reference to the device.
     pub fn device(&self) -> &Device {
         &self.device
     }
 
     /// Accessor for a mutable reference to the device.
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -34,17 +34,17 @@ use style::gecko_bindings::bindings::{Ra
 use style::gecko_bindings::bindings::{RawServoKeyframe, RawServoKeyframeBorrowed, RawServoKeyframeStrong};
 use style::gecko_bindings::bindings::{RawServoKeyframesRule, RawServoKeyframesRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoMediaListBorrowed, RawServoMediaListStrong};
 use style::gecko_bindings::bindings::{RawServoMediaRule, RawServoMediaRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoPageRule, RawServoPageRuleBorrowed};
 use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
 use style::gecko_bindings::bindings::{RawServoStyleSheetContentsBorrowed, ServoComputedValuesBorrowed};
-use style::gecko_bindings::bindings::{RawServoStyleSheetContentsStrong, ServoComputedValuesStrong};
+use style::gecko_bindings::bindings::{RawServoStyleSheetContentsStrong, ServoStyleContextBorrowed};
 use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed};
 use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
 use style::gecko_bindings::bindings::{nsACString, nsAString, nsCSSPropertyIDSetBorrowedMut};
 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
 use style::gecko_bindings::bindings::Gecko_NewNoneTransform;
@@ -56,23 +56,24 @@ use style::gecko_bindings::bindings::Raw
 use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowed;
 use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowedMut;
 use style::gecko_bindings::bindings::RawGeckoServoStyleRuleListBorrowedMut;
 use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed;
 use style::gecko_bindings::bindings::RawServoAnimationValueMapBorrowedMut;
 use style::gecko_bindings::bindings::RawServoAnimationValueStrong;
 use style::gecko_bindings::bindings::RawServoStyleRuleBorrowed;
 use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
+use style::gecko_bindings::bindings::ServoStyleContextBorrowedOrNull;
 use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t;
 use style::gecko_bindings::bindings::nsTimingFunctionBorrowed;
 use style::gecko_bindings::bindings::nsTimingFunctionBorrowedMut;
 use style::gecko_bindings::structs;
 use style::gecko_bindings::structs::{CSSPseudoElementType, CompositeOperation, Loader};
-use style::gecko_bindings::structs::{RawServoStyleRule, ServoStyleSheet};
-use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom, nsCSSPropertyID};
+use style::gecko_bindings::structs::{RawServoStyleRule, ServoStyleContextStrong};
+use style::gecko_bindings::structs::{ServoStyleSheet, SheetParsingMode, nsIAtom, nsCSSPropertyID};
 use style::gecko_bindings::structs::{nsCSSFontFaceRule, nsCSSCounterStyleRule};
 use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair};
 use style::gecko_bindings::structs::IterationCompositeOperation;
 use style::gecko_bindings::structs::MallocSizeOf;
 use style::gecko_bindings::structs::RawGeckoGfxMatrix4x4;
 use style::gecko_bindings::structs::RawGeckoPresContextOwned;
 use style::gecko_bindings::structs::ServoElementSnapshotTable;
 use style::gecko_bindings::structs::StyleRuleInclusion;
@@ -87,17 +88,17 @@ use style::gecko_bindings::sugar::owners
 use style::gecko_bindings::sugar::refptr::RefPtr;
 use style::gecko_properties::{self, style_structs};
 use style::invalidation::element::restyle_hints::{self, RestyleHint};
 use style::media_queries::{MediaList, parse_media_query_list};
 use style::parallel;
 use style::parser::ParserContext;
 use style::properties::{CascadeFlags, ComputedValues, ComputedValuesInner, Importance, SourcePropertyDeclaration};
 use style::properties::{LonghandIdSet, PropertyDeclaration, PropertyDeclarationBlock, PropertyId, StyleBuilder};
-use style::properties::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
+use style::properties::{SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, PseudoInfo, ParentStyleContextInfo};
 use style::properties::animated_properties::{Animatable, AnimatableLonghand, AnimationValue};
 use style::properties::parse_one_declaration_into;
 use style::rule_tree::StyleSource;
 use style::selector_parser::PseudoElementCascadeType;
 use style::sequential;
 use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
 use style::string_cache::Atom;
 use style::style_adjuster::StyleAdjuster;
@@ -651,17 +652,17 @@ pub extern "C" fn Servo_AnimationValue_U
         PropertyDeclarationBlock::with_one(value.uncompute(), Importance::Normal))).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawServoStyleSetBorrowed,
                                                                  element: RawGeckoElementBorrowed,
                                                                  snapshots: *const ServoElementSnapshotTable,
                                                                  pseudo_type: CSSPseudoElementType)
-                                                                 -> ServoComputedValuesStrong
+                                                                 -> ServoStyleContextStrong
 {
     use style::matching::MatchMethods;
     debug_assert!(!snapshots.is_null());
 
     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let shared_context = create_shared_context(&global_style_data,
@@ -697,17 +698,16 @@ pub extern "C" fn Servo_ComputedValues_E
                                                              property_id: nsCSSPropertyID)
                                                              -> RawServoAnimationValueStrong
 {
     let property = match AnimatableLonghand::from_nscsspropertyid(property_id) {
         Some(longhand) => longhand,
         None => { return Strong::null(); }
     };
 
-    let computed_values = ComputedValues::as_arc(&computed_values);
     Arc::new(AnimationValue::from_computed_values(&property, computed_values)).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_Property_IsAnimatable(property: nsCSSPropertyID) -> bool {
     use style::properties::animated_properties;
     animated_properties::nscsspropertyid_is_animatable(property)
 }
@@ -1468,95 +1468,101 @@ pub extern "C" fn Servo_SupportsRule_Get
 pub extern "C" fn Servo_DocumentRule_GetConditionText(rule: RawServoDocumentRuleBorrowed,
                                                       result: *mut nsAString) {
     read_locked_arc(rule, |rule: &DocumentRule| {
         rule.condition.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
     })
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: ServoComputedValuesBorrowedOrNull,
+pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: ServoStyleContextBorrowedOrNull,
+                                                          pseudo_type: CSSPseudoElementType,
                                                           pseudo_tag: *mut nsIAtom,
                                                           skip_display_fixup: bool,
                                                           raw_data: RawServoStyleSetBorrowed)
-     -> ServoComputedValuesStrong {
+     -> ServoStyleContextStrong {
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let guards = StylesheetGuards::same(&guard);
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
     let atom = Atom::from(pseudo_tag);
     let pseudo = PseudoElement::from_anon_box_atom(&atom)
         .expect("Not an anon box pseudo?");
 
-
-    let maybe_parent = ComputedValues::arc_from_borrowed(&parent_style_or_null)
-                        .map(|p| &p.inner);
     let mut cascade_flags = CascadeFlags::empty();
     if skip_display_fixup {
         cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
     }
     let metrics = get_metrics_provider_for_product();
-    data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, maybe_parent,
-                                               cascade_flags, &metrics)
+    data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, parent_style_or_null.map(|x| &**x),
+                                               cascade_flags, &metrics,
+                                               (pseudo_tag, pseudo_type),
+                                               parent_style_or_null)
         .into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
                                            pseudo_type: CSSPseudoElementType,
+                                           pseudo_tag: *mut nsIAtom,
                                            is_probe: bool,
                                            inherited_style: ServoComputedValuesBorrowedOrNull,
+                                           parent_style_context: ServoStyleContextBorrowedOrNull,
                                            raw_data: RawServoStyleSetBorrowed)
-     -> ServoComputedValuesStrong
+     -> ServoStyleContextStrong
 {
     let element = GeckoElement(element);
     let data = unsafe { element.ensure_data() }.borrow_mut();
     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
 
     debug!("Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
            element, PseudoElement::from_pseudo_type(pseudo_type), is_probe);
 
     // FIXME(bholley): Assert against this.
     if !data.has_styles() {
         warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
         return if is_probe {
             Strong::null()
         } else {
-            doc_data.default_computed_values().clone().to_outer().into_strong()
+            doc_data.default_computed_values()
+                    .clone().to_outer(doc_data.stylist.device(), parent_style_context,
+                                      Some((pseudo_tag, pseudo_type))).into_strong()
         };
     }
 
     let pseudo = PseudoElement::from_pseudo_type(pseudo_type)
                     .expect("ResolvePseudoStyle with a non-pseudo?");
 
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let style = get_pseudo_style(
         &guard,
         element,
         &pseudo,
         RuleInclusion::All,
         &data.styles,
-        ComputedValues::arc_from_borrowed(&inherited_style).map(|x| &***x),
+        inherited_style,
         &*doc_data,
-        is_probe
+        is_probe,
+        (pseudo_tag, pseudo_type),
+        parent_style_context
     );
 
     match style {
         Some(s) => s.into_strong(),
         None => {
             debug_assert!(is_probe);
             Strong::null()
         }
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_SetExplicitStyle(element: RawGeckoElementBorrowed,
-                                         style: ServoComputedValuesBorrowed)
+                                         style: ServoStyleContextBorrowed)
 {
     let element = GeckoElement(element);
     let style = ComputedValues::as_arc(&style);
     debug!("Servo_SetExplicitStyle: {:?}", element);
     // We only support this API for initial styling. There's no reason it couldn't
     // work for other things, we just haven't had a reason to do so.
     debug_assert!(element.get_data().is_none());
     let mut data = unsafe { element.ensure_data() }.borrow_mut();
@@ -1587,16 +1593,18 @@ fn get_pseudo_style(
     guard: &SharedRwLockReadGuard,
     element: GeckoElement,
     pseudo: &PseudoElement,
     rule_inclusion: RuleInclusion,
     styles: &ElementStyles,
     inherited_styles: Option<&ComputedValuesInner>,
     doc_data: &PerDocumentStyleDataImpl,
     is_probe: bool,
+    pseudo_info: PseudoInfo,
+    parent_style_context: ParentStyleContextInfo,
 ) -> Option<Arc<ComputedValues>> {
     let style = match pseudo.cascade_type() {
         PseudoElementCascadeType::Eager => {
             match *pseudo {
                 PseudoElement::FirstLetter => {
                     styles.pseudos.get(&pseudo).and_then(|pseudo_styles| {
                         // inherited_styles can be None when doing lazy resolution
                         // (e.g. for computed style) or when probing.  In that case
@@ -1608,17 +1616,19 @@ fn get_pseudo_style(
                         let guards = StylesheetGuards::same(guard);
                         let metrics = get_metrics_provider_for_product();
                         let inputs = CascadeInputs::new_from_style(pseudo_styles);
                         doc_data.stylist
                             .compute_pseudo_element_style_with_inputs(
                                 &inputs,
                                 &guards,
                                 inherited_styles,
-                                &metrics)
+                                &metrics,
+                                pseudo_info.clone(),
+                                parent_style_context)
                     })
                 },
                 _ => {
                     debug_assert!(inherited_styles.is_none() ||
                                   ptr::eq(&*inherited_styles.unwrap(),
                                           &***styles.primary()));
                     styles.pseudos.get(&pseudo).cloned()
                 },
@@ -1639,73 +1649,96 @@ fn get_pseudo_style(
             doc_data.stylist
                 .lazily_compute_pseudo_element_style(
                     &guards,
                     &element,
                     &pseudo,
                     rule_inclusion,
                     base,
                     is_probe,
-                    &metrics)
+                    &metrics,
+                    pseudo_info.clone(),
+                    parent_style_context)
         },
     };
 
     if is_probe {
         return style;
     }
 
     Some(style.unwrap_or_else(|| {
         StyleBuilder::for_inheritance(
             styles.primary(),
             doc_data.default_computed_values(),
-        ).build().to_outer()
+        ).build().to_outer(doc_data.stylist.device(), parent_style_context,
+                           Some(pseudo_info))
     }))
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_Inherit(
     raw_data: RawServoStyleSetBorrowed,
-    parent_style: ServoComputedValuesBorrowedOrNull,
+    pseudo_type: CSSPseudoElementType,
+    pseudo_tag: *mut nsIAtom,
+    parent_style_context: ServoStyleContextBorrowedOrNull,
     target: structs::InheritTarget
-) -> ServoComputedValuesStrong {
+) -> ServoStyleContextStrong {
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
-    let maybe_arc = ComputedValues::arc_from_borrowed(&parent_style);
 
     let for_text = target == structs::InheritTarget::Text;
-    let style = if let Some(reference) = maybe_arc.as_ref() {
+    let style = if let Some(reference) = parent_style_context {
         let mut style =
             StyleBuilder::for_inheritance(reference,
                                           &data.default_computed_values());
         if for_text {
             StyleAdjuster::new(&mut style)
                 .adjust_for_text();
         }
 
         style.build()
     } else {
         debug_assert!(!for_text);
         data.default_computed_values().clone()
     };
 
-    style.to_outer().into_strong()
+    let pseudo_info = if pseudo_tag.is_null() {
+        None
+    } else {
+        Some((pseudo_tag, pseudo_type))
+    };
+
+    style.to_outer(data.stylist.device(), parent_style_context, pseudo_info).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetVisitedStyle(values: ServoComputedValuesBorrowed)
-                                                       -> ServoComputedValuesStrong {
-    match ComputedValues::as_arc(&values).get_visited_style() {
+                                                       -> ServoStyleContextStrong {
+    match values.get_visited_style() {
         Some(v) => v.clone().into_strong(),
         None => Strong::null(),
     }
 }
 
 #[no_mangle]
+pub extern "C" fn Servo_StyleContext_NewContext(values: ServoComputedValuesBorrowed,
+                                                parent: ServoStyleContextBorrowedOrNull,
+                                                pres_context: bindings::RawGeckoPresContextBorrowed,
+                                                pseudo_type: CSSPseudoElementType,
+                                                pseudo_tag: *mut nsIAtom)
+                                                       -> ServoStyleContextStrong {
+    let arc = ComputedValuesInner::as_arc(&values);
+    unsafe {
+        ComputedValuesInner::to_outer_from_arc(arc.clone_arc(), pres_context, parent,
+                                               pseudo_type, pseudo_tag).into_strong()
+    }
+}
+
+#[no_mangle]
 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(values: ServoComputedValuesBorrowed)
                                                                         -> bool {
-    let values = ComputedValues::as_arc(&values);
     let b = values.get_box();
     b.specifies_animations() || b.specifies_transitions()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(values: ServoComputedValuesBorrowed,
                                                         rules: RawGeckoServoStyleRuleListBorrowedMut) {
     if let Some(ref rule_node) = values.rules {
@@ -2700,39 +2733,43 @@ pub extern "C" fn Servo_TakeChangeHint(e
 
     debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
     damage.as_change_hint()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
                                      raw_data: RawServoStyleSetBorrowed)
-                                     -> ServoComputedValuesStrong
+                                     -> ServoStyleContextStrong
 {
     let element = GeckoElement(element);
     debug!("Servo_ResolveStyle: {:?}", element);
     let data = unsafe { element.ensure_data() }.borrow();
 
     if !element.has_current_styles(&*data) {
         debug_assert!(false, "Resolving style on element without current styles with lazy \
                               computation forbidden.");
         let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
-        return per_doc_data.default_computed_values().clone().to_outer().into_strong();
+        return per_doc_data.default_computed_values().clone()
+                           .to_outer(per_doc_data.stylist.device(), None, None)
+                           .into_strong();
     }
 
     data.styles.primary().clone().into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
                                            pseudo_type: CSSPseudoElementType,
+                                           pseudo_tag: *mut nsIAtom,
+                                           parent_style_context: ServoStyleContextBorrowedOrNull,
                                            rule_inclusion: StyleRuleInclusion,
                                            snapshots: *const ServoElementSnapshotTable,
                                            raw_data: RawServoStyleSetBorrowed)
-     -> ServoComputedValuesStrong
+     -> ServoStyleContextStrong
 {
     debug_assert!(!snapshots.is_null());
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let element = GeckoElement(element);
     let doc_data = PerDocumentStyleData::from_ffi(raw_data);
     let data = doc_data.borrow();
     let rule_inclusion = RuleInclusion::from(rule_inclusion);
@@ -2743,16 +2780,18 @@ pub extern "C" fn Servo_ResolveStyleLazi
                     &guard,
                     element,
                     pseudo,
                     rule_inclusion,
                     styles,
                     /* inherited_styles = */ None,
                     &*data,
                     /* is_probe = */ false,
+                    (pseudo_tag, pseudo_type),
+                    parent_style_context
                 ).expect("We're not probing, so we should always get a style \
                          back")
             }
             None => styles.primary().clone(),
         }
     };
 
     // In the common case we already have the style. Check that before setting
@@ -2815,21 +2854,21 @@ fn simulate_compute_values_failure(prope
 
 #[cfg(not(feature = "gecko_debug"))]
 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
     false
 }
 
 fn create_context<'a>(per_doc_data: &'a PerDocumentStyleDataImpl,
                       font_metrics_provider: &'a FontMetricsProvider,
-                      style: &'a ComputedValues,
-                      parent_style: &'a Option<&Arc<ComputedValues>>)
+                      style: &'a ComputedValuesInner,
+                      parent_style: &'a Option<&ComputedValuesInner>)
                       -> Context<'a> {
     let default_values = per_doc_data.default_computed_values();
-    let inherited_style = parent_style.map(|x| &x.inner).unwrap_or(default_values);
+    let inherited_style = parent_style.unwrap_or(default_values);
 
     Context {
         is_root_element: false,
         device: per_doc_data.stylist.device(),
         inherited_style: inherited_style,
         layout_parent_style: inherited_style,
         style: StyleBuilder::for_derived_style(&style),
         font_metrics_provider: font_metrics_provider,
@@ -2846,22 +2885,21 @@ pub extern "C" fn Servo_GetComputedKeyfr
                                                   raw_data: RawServoStyleSetBorrowed,
                                                   computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut)
 {
     use std::mem;
     use style::properties::LonghandIdSet;
 
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let metrics = get_metrics_provider_for_product();
-    let style = ComputedValues::as_arc(&style);
 
     let element = GeckoElement(element);
     let parent_element = element.inheritance_parent();
     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
-    let parent_style = parent_data.as_ref().map(|d| d.styles.primary());
+    let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &***x);
 
     let mut context = create_context(&data, &metrics, style, &parent_style);
 
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let default_values = data.default_computed_values();
 
     for (index, keyframe) in keyframes.iter().enumerate() {
@@ -2926,23 +2964,22 @@ pub extern "C" fn Servo_GetComputedKeyfr
 
 #[no_mangle]
 pub extern "C" fn Servo_GetAnimationValues(declarations: RawServoDeclarationBlockBorrowed,
                                            element: RawGeckoElementBorrowed,
                                            style: ServoComputedValuesBorrowed,
                                            raw_data: RawServoStyleSetBorrowed,
                                            animation_values: RawGeckoServoAnimationValueListBorrowedMut) {
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
-    let style = ComputedValues::as_arc(&style);
     let metrics = get_metrics_provider_for_product();
 
     let element = GeckoElement(element);
     let parent_element = element.inheritance_parent();
     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
-    let parent_style = parent_data.as_ref().map(|d| d.styles.primary());
+    let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &***x);
 
     let mut context = create_context(&data, &metrics, style, &parent_style);
 
     let default_values = data.default_computed_values();
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
 
     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
@@ -2955,23 +2992,22 @@ pub extern "C" fn Servo_GetAnimationValu
 
 #[no_mangle]
 pub extern "C" fn Servo_AnimationValue_Compute(element: RawGeckoElementBorrowed,
                                                declarations: RawServoDeclarationBlockBorrowed,
                                                style: ServoComputedValuesBorrowed,
                                                raw_data: RawServoStyleSetBorrowed)
                                                -> RawServoAnimationValueStrong {
     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
-    let style = ComputedValues::as_arc(&style);
     let metrics = get_metrics_provider_for_product();
 
     let element = GeckoElement(element);
     let parent_element = element.inheritance_parent();
     let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
-    let parent_style = parent_data.as_ref().map(|d| d.styles.primary());
+    let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &***x);
 
     let mut context = create_context(&data, &metrics, style, &parent_style);
 
     let default_values = data.default_computed_values();
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
     // We only compute the first element in declarations.
@@ -3205,34 +3241,35 @@ pub extern "C" fn Servo_StyleSet_GetCoun
         let guard = global_style_data.shared_lock.read();
         rule.read_with(&guard).get()
     }).unwrap_or(ptr::null_mut())
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
     raw_data: RawServoStyleSetBorrowed,
-    parent_style_or_null: ServoComputedValuesBorrowedOrNull,
-    declarations: RawServoDeclarationBlockBorrowed
-) -> ServoComputedValuesStrong {
+    parent_style_context: ServoStyleContextBorrowedOrNull,
+    declarations: RawServoDeclarationBlockBorrowed,
+) -> ServoStyleContextStrong {
     let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
     let global_style_data = &*GLOBAL_STYLE_DATA;
     let guard = global_style_data.shared_lock.read();
     let guards = StylesheetGuards::same(&guard);
 
-    let parent_style = match ComputedValues::arc_from_borrowed(&parent_style_or_null) {
-        Some(parent) => &parent.inner,
+    let parent_style = match parent_style_context {
+        Some(parent) => &**parent,
         None => doc_data.default_computed_values(),
     };
 
     let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
 
     doc_data.stylist.compute_for_declarations(&guards,
                                               parent_style,
-                                              declarations.clone_arc()).into_strong()
+                                              declarations.clone_arc(),
+                                              parent_style_context).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
     raw_data: RawServoStyleSetBorrowed,
     element: RawGeckoElementBorrowed,
     local_name: *mut nsIAtom,
 ) -> bool {
@@ -3282,44 +3319,45 @@ pub extern "C" fn Servo_StyleSet_HasStat
 
     has_dep
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_GetCustomPropertyValue(computed_values: ServoComputedValuesBorrowed,
                                                name: *const nsAString,
                                                value: *mut nsAString) -> bool {
-    let custom_properties = match ComputedValues::as_arc(&computed_values).custom_properties() {
+
+    let custom_properties = match computed_values.custom_properties() {
         Some(p) => p,
         None => return false,
     };
 
     let name = unsafe { Atom::from((&*name)) };
     let computed_value = match custom_properties.get_computed_value(&name) {
         Some(v) => v,
         None => return false,
     };
 
     computed_value.to_css(unsafe { value.as_mut().unwrap() }).unwrap();
     true
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: ServoComputedValuesBorrowed) -> u32 {
-    match ComputedValues::as_arc(&computed_values).custom_properties() {
+    match ComputedValuesInner::as_arc(&computed_values).custom_properties() {
         Some(p) => p.len() as u32,
         None => 0,
     }
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_GetCustomPropertyNameAt(computed_values: ServoComputedValuesBorrowed,
                                                 index: u32,
                                                 name: *mut nsAString) -> bool {
-    let custom_properties = match ComputedValues::as_arc(&computed_values).custom_properties() {
+    let custom_properties = match ComputedValuesInner::as_arc(&computed_values).custom_properties() {
         Some(p) => p,
         None => return false,
     };
 
     let property_name = match custom_properties.get_name_at(index) {
         Some(n) => n,
         None => return false,
     };