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 609455 1c0bc87e8a12ae9c9e3c2147b4e1e0e4f3a05680
parent 609454 f9b937c190f17634032ad8f7478e0ba533e45e69
child 609456 df1fecedb5a7b0fc34d5c95aa14e8ceec5d38fa4
push id68579
push userbmo:manishearth@gmail.com
push dateSun, 16 Jul 2017 18:55:44 +0000
reviewersbholley
bugs1367904
milestone56.0a1
Bug 1367904 - Part 10: stylo: Switch Gecko over to ServoStyleContext; r?bholley MozReview-Commit-ID: EmopKVjEzlz
dom/animation/EffectCompositor.cpp
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
dom/animation/KeyframeUtils.cpp
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/nsAnimationManager.cpp
layout/style/nsAnimationManager.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
layout/style/nsStyleContextInlines.h
layout/style/nsStyleSet.cpp
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.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/properties/gecko.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/servo/selector_parser.rs
servo/components/style/style_resolver.rs
servo/components/style/stylist.rs
servo/components/style/traversal.rs
servo/ports/geckolib/glue.rs
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -1279,20 +1279,20 @@ EffectCompositor::AnimationStyleRuleProc
   MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
 }
 
 template
 void
 EffectCompositor::UpdateEffectProperties(
-  nsStyleContext* aStyleContext,
+  GeckoStyleContext* aStyleContext,
   Element* aElement,
   CSSPseudoElementType aPseudoType);
 
 template
 void
 EffectCompositor::UpdateEffectProperties(
-  const ServoComputedValues* aServoValues,
+  const ServoStyleContext* aStyleContext,
   Element* aElement,
   CSSPseudoElementType aPseudoType);
 
 } // namespace mozilla
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -181,43 +181,53 @@ KeyframeEffectReadOnly::SetKeyframes(JSC
 {
   nsTArray<Keyframe> keyframes =
     KeyframeUtils::GetKeyframesFromObject(aContext, mDocument, aKeyframes, aRv);
   if (aRv.Failed()) {
     return;
   }
 
   RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
-  SetKeyframes(Move(keyframes), styleContext);
+  if (styleContext) {
+    if (auto gecko = styleContext->GetAsGecko()) {
+      SetKeyframes(Move(keyframes), gecko);
+    } else {
+      SetKeyframes(Move(keyframes), styleContext->AsServo());
+    }
+  } else {
+    // SetKeyframes has the same behavior for null StyleType* for
+    // both backends, just pick one and use it.
+    SetKeyframes(Move(keyframes), (GeckoStyleContext*) nullptr);
+  }
 }
 
 void
 KeyframeEffectReadOnly::SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
-                                     nsStyleContext* aStyleContext)
+                                     GeckoStyleContext* aStyleContext)
 {
   DoSetKeyframes(Move(aKeyframes), Move(aStyleContext));
 }
 
 void
 KeyframeEffectReadOnly::SetKeyframes(
   nsTArray<Keyframe>&& aKeyframes,
-  const ServoComputedValues* aComputedValues)
+  const ServoStyleContext* aComputedValues)
 {
   DoSetKeyframes(Move(aKeyframes), aComputedValues);
 }
 
 template<typename StyleType>
 void
 KeyframeEffectReadOnly::DoSetKeyframes(nsTArray<Keyframe>&& aKeyframes,
                                        StyleType* aStyle)
 {
-  static_assert(IsSame<StyleType, nsStyleContext>::value ||
-                IsSame<StyleType, const ServoComputedValues>::value,
-                "StyleType should be nsStyleContext* or "
-                "const ServoComputedValues*");
+  static_assert(IsSame<StyleType, GeckoStyleContext>::value ||
+                IsSame<StyleType, const ServoStyleContext>::value,
+                "StyleType should be GeckoStyleContext* or "
+                "const ServoStyleContext*");
 
   if (KeyframesEqualIgnoringComputedOffsets(aKeyframes, mKeyframes)) {
     return;
   }
 
   mKeyframes = Move(aKeyframes);
   KeyframeUtils::DistributeKeyframes(mKeyframes);
 
@@ -291,31 +301,29 @@ SpecifiedKeyframeArraysAreEqual(const ns
 }
 #endif
 
 void
 KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
 {
   MOZ_ASSERT(aStyleContext);
 
-  if (!mDocument->IsStyledByServo()) {
-    DoUpdateProperties(Move(aStyleContext));
+  if (auto gecko = aStyleContext->GetAsGecko()) {
+    DoUpdateProperties(Move(gecko));
     return;
   }
 
-  const ServoComputedValues* currentStyle = aStyleContext->ComputedValues();
-
-  DoUpdateProperties(currentStyle);
+  UpdateProperties(aStyleContext->AsServo());
 }
 
 void
 KeyframeEffectReadOnly::UpdateProperties(
-  const ServoComputedValues* aComputedValues)
+  const ServoStyleContext* aStyleContext)
 {
-  DoUpdateProperties(aComputedValues);
+  DoUpdateProperties(aStyleContext);
 }
 
 template<typename StyleType>
 void
 KeyframeEffectReadOnly::DoUpdateProperties(StyleType* aStyle)
 {
   MOZ_ASSERT(aStyle);
 
@@ -435,17 +443,17 @@ KeyframeEffectReadOnly::CompositeValue(
   return CompositeValue(aProperty,
                         aValueToComposite,
                         underlyingValue,
                         aCompositeOperation);
 }
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyles(
-  nsStyleContext* aStyleContext,
+  GeckoStyleContext* aStyleContext,
   const nsTArray<AnimationProperty>& aProperties)
 {
   if (!mTarget) {
     return;
   }
 
   mBaseStyleValues.Clear();
 
@@ -463,17 +471,17 @@ KeyframeEffectReadOnly::EnsureBaseStyles
       break;
     }
   }
 }
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyle(
   nsCSSPropertyID aProperty,
-  nsStyleContext* aStyleContext,
+  GeckoStyleContext* aStyleContext,
   RefPtr<nsStyleContext>& aCachedBaseStyleContext)
 {
   if (mBaseStyleValues.Contains(aProperty)) {
     return;
   }
 
   if (!aCachedBaseStyleContext) {
     aCachedBaseStyleContext =
@@ -492,17 +500,17 @@ KeyframeEffectReadOnly::EnsureBaseStyle(
   MOZ_ASSERT(success, "Should be able to extract computed animation value");
   MOZ_ASSERT(!result.IsNull(), "Should have a valid StyleAnimationValue");
 
   mBaseStyleValues.Put(aProperty, result);
 }
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyles(
-  const ServoComputedValues* aComputedValues,
+  const ServoStyleContext* aComputedValues,
   const nsTArray<AnimationProperty>& aProperties)
 {
   if (!mTarget) {
     return;
   }
 
   mBaseStyleValuesForServo.Clear();
 
@@ -523,17 +531,17 @@ KeyframeEffectReadOnly::EnsureBaseStyles
   }
 }
 
 void
 KeyframeEffectReadOnly::EnsureBaseStyle(
   const AnimationProperty& aProperty,
   CSSPseudoElementType aPseudoType,
   nsPresContext* aPresContext,
-  const ServoComputedValues* aComputedStyle,
+  const ServoStyleContext* aComputedStyle,
  RefPtr<ServoStyleContext>& aBaseStyleContext)
 {
   bool hasAdditiveValues = false;
 
   for (const AnimationPropertySegment& segment : aProperty.mSegments) {
     if (!segment.HasReplaceableValues()) {
       hasAdditiveValues = true;
       break;
@@ -904,20 +912,20 @@ KeyframeEffectReadOnly::ConstructKeyfram
   effect->mProperties = aSource.mProperties;
   return effect.forget();
 }
 
 template<typename StyleType>
 nsTArray<AnimationProperty>
 KeyframeEffectReadOnly::BuildProperties(StyleType* aStyle)
 {
-  static_assert(IsSame<StyleType, nsStyleContext>::value ||
-                IsSame<StyleType, const ServoComputedValues>::value,
-                "StyleType should be nsStyleContext* or "
-                "const ServoComputedValues*");
+  static_assert(IsSame<StyleType, GeckoStyleContext>::value ||
+                IsSame<StyleType, const ServoStyleContext>::value,
+                "StyleType should be GeckoStyleContext* or "
+                "const ServoStyleContext*");
 
   MOZ_ASSERT(aStyle);
 
   nsTArray<AnimationProperty> result;
   // If mTarget is null, return an empty property array.
   if (!mTarget) {
     return result;
   }
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -41,16 +41,17 @@ namespace mozilla {
 
 class AnimValuesStyleRule;
 enum class CSSPseudoElementType : uint8_t;
 class ErrorResult;
 struct AnimationRule;
 struct TimingParams;
 class EffectSet;
 class ServoStyleContext;
+class GeckoStyleContext;
 
 namespace dom {
 class ElementOrCSSPseudoElement;
 class GlobalObject;
 class OwningElementOrCSSPseudoElement;
 class UnrestrictedDoubleOrKeyframeAnimationOptions;
 class UnrestrictedDoubleOrKeyframeEffectOptions;
 enum class IterationCompositeOperation : uint8_t;
@@ -160,19 +161,19 @@ public:
   IterationCompositeOperation IterationComposite() const;
   CompositeOperation Composite() const;
   void NotifyAnimationTimingUpdated();
   void RequestRestyle(EffectCompositor::RestyleType aRestyleType);
   void SetAnimation(Animation* aAnimation) override;
   void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
                     ErrorResult& aRv);
   void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
-                    nsStyleContext* aStyleContext);
+                    GeckoStyleContext* aStyleContext);
   void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
-                    const ServoComputedValues* aComputedValues);
+                    const ServoStyleContext* aComputedValues);
 
   // Returns true if the effect includes |aProperty| regardless of whether the
   // property is overridden by !important rule.
   bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const;
 
   // GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
   // to a given CSS property if the effect includes the property and the
   // property is not overridden by !important rules.
@@ -191,17 +192,17 @@ public:
   {
     return mProperties;
   }
 
   // Update |mProperties| by recalculating from |mKeyframes| using
   // |aStyleContext| to resolve specified values.
   void UpdateProperties(nsStyleContext* aStyleContext);
   // Servo version of the above function.
-  void UpdateProperties(const ServoComputedValues* aComputedValues);
+  void UpdateProperties(const ServoStyleContext* aComputedValues);
 
   // Update various bits of state related to running ComposeStyle().
   // We need to update this outside ComposeStyle() because we should avoid
   // mutating any state in ComposeStyle() since it might be called during
   // parallel traversal.
   void WillComposeStyle();
 
   // Updates |aComposeResult| with the animation values produced by this
@@ -254,17 +255,17 @@ public:
     const AnimationPerformanceWarning& aWarning);
 
   // Record telemetry about the size of the content being animated.
   void RecordFrameSizeTelemetry(uint32_t aPixelArea);
 
   // Cumulative change hint on each segment for each property.
   // This is used for deciding the animation is paint-only.
   void CalculateCumulativeChangeHint(nsStyleContext* aStyleContext);
-  void CalculateCumulativeChangeHint(const ServoComputedValues* aComputedValues)
+  void CalculateCumulativeChangeHint(const ServoStyleContext* aComputedValues)
   {
   }
 
   // Returns true if all of animation properties' change hints
   // can ignore painting if the animation is not visible.
   // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
   // in detail which change hint can be ignored.
   bool CanIgnoreIfNotVisible() const;
@@ -362,35 +363,35 @@ protected:
     CompositeOperation aCompositeOperation);
 
   // Returns underlying style animation value for |aProperty|.
   StyleAnimationValue GetUnderlyingStyle(
     nsCSSPropertyID aProperty,
     const RefPtr<AnimValuesStyleRule>& aAnimationRule);
 
   // Ensure the base styles is available for any properties in |aProperties|.
-  void EnsureBaseStyles(nsStyleContext* aStyleContext,
+  void EnsureBaseStyles(GeckoStyleContext* aStyleContext,
                         const nsTArray<AnimationProperty>& aProperties);
-  void EnsureBaseStyles(const ServoComputedValues* aComputedValues,
+  void EnsureBaseStyles(const ServoStyleContext* aComputedValues,
                         const nsTArray<AnimationProperty>& aProperties);
 
   // If no base style is already stored for |aProperty|, resolves the base style
   // for |aProperty| using |aStyleContext| and stores it in mBaseStyleValues.
   // If |aCachedBaseStyleContext| is non-null, it will be used, otherwise the
   // base style context will be resolved and stored in
   // |aCachedBaseStyleContext|.
   void EnsureBaseStyle(nsCSSPropertyID aProperty,
-                       nsStyleContext* aStyleContext,
+                       GeckoStyleContext* aStyleContext,
                        RefPtr<nsStyleContext>& aCachedBaseStyleContext);
   // Stylo version of the above function that also first checks for an additive
   // value in |aProperty|'s list of segments.
   void EnsureBaseStyle(const AnimationProperty& aProperty,
                        CSSPseudoElementType aPseudoType,
                        nsPresContext* aPresContext,
-                       const ServoComputedValues* aComputedValues,
+                       const ServoStyleContext* aComputedValues,
                        RefPtr<mozilla::ServoStyleContext>& aBaseComputedValues);
 
   Maybe<OwningAnimationTarget> mTarget;
 
   KeyframeEffectParams mEffectOptions;
 
   // The specified keyframes.
   nsTArray<Keyframe>          mKeyframes;
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -363,22 +363,22 @@ MarkAsComputeValuesFailureKey(PropertyVa
 
 static bool
 IsComputeValuesFailureKey(const PropertyValuePair& aPair);
 #endif
 
 static nsTArray<ComputedKeyframeValues>
 GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                           dom::Element* aElement,
-                          nsStyleContext* aStyleContext);
+                          GeckoStyleContext* aStyleContext);
 
 static nsTArray<ComputedKeyframeValues>
 GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                           dom::Element* aElement,
-                          const ServoComputedValues* aComputedValues);
+                          const ServoStyleContext* aComputedValues);
 
 static void
 BuildSegmentsFromValueEntries(nsTArray<KeyframeValueEntry>& aEntries,
                               nsTArray<AnimationProperty>& aResult);
 
 static void
 GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx,
                                            nsIDocument* aDocument,
@@ -1007,17 +1007,17 @@ IsComputeValuesFailureKey(const Property
  * @param aElement The context element.
  * @param aStyleContext The style context to use when computing values.
  * @return The set of ComputedKeyframeValues. The length will be the same as
  *   aFrames.
  */
 static nsTArray<ComputedKeyframeValues>
 GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                           dom::Element* aElement,
-                          nsStyleContext* aStyleContext)
+                          GeckoStyleContext* aStyleContext)
 {
   MOZ_ASSERT(aStyleContext);
   MOZ_ASSERT(aElement);
 
   const size_t len = aKeyframes.Length();
   nsTArray<ComputedKeyframeValues> result(len);
 
   for (const Keyframe& frame : aKeyframes) {
@@ -1082,26 +1082,26 @@ GetComputedKeyframeValues(const nsTArray
 }
 
 /**
  * The variation of the above function. This is for Servo backend.
  */
 static nsTArray<ComputedKeyframeValues>
 GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                           dom::Element* aElement,
-                          const ServoComputedValues* aComputedValues)
+                          const ServoStyleContext* aStyleContext)
 {
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aElement->IsStyledByServo());
 
   nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
   MOZ_ASSERT(presContext);
 
   return presContext->StyleSet()->AsServo()
-    ->GetComputedKeyframeValuesFor(aKeyframes, aElement, aComputedValues);
+    ->GetComputedKeyframeValuesFor(aKeyframes, aElement, aStyleContext->ComputedValues());
 }
 
 static void
 AppendInitialSegment(AnimationProperty* aAnimationProperty,
                      const KeyframeValueEntry& aFirstEntry)
 {
   AnimationPropertySegment* segment =
     aAnimationProperty->mSegments.AppendElement();
--- 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
@@ -6,16 +6,17 @@
 
 #include "mozilla/ServoRestyleManager.h"
 
 #include "mozilla/AutoRestyleTimelineMarker.h"
 #include "mozilla/AutoTimelineMarker.h"
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoStyleSet.h"
+#include "mozilla/ServoStyleContext.h"
 #include "mozilla/Unused.h"
 #include "mozilla/ViewportFrame.h"
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "nsBlockFrame.h"
 #include "nsBulletFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsContentUtils.h"
@@ -434,16 +435,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.
@@ -501,31 +503,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);
@@ -539,18 +541,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);
@@ -5881,18 +5881,20 @@ nsCSSFrameConstructor::AddFrameConstruct
           // XXX: We should have a better way to restyle ourselves.
           ServoRestyleManager::ClearServoDataFromSubtree(element);
           styleSet->StyleNewSubtree(element);
 
           // Servo's should_traverse_children() in traversal.rs skips
           // styling descendants of elements with a -moz-binding the
           // first time. Thus call StyleNewChildren() again.
           styleSet->StyleNewChildren(element);
+
           styleContext =
-            styleSet->ResolveStyleFor(element, nullptr, LazyComputeBehavior::Assert);
+            styleSet->ResolveStyleFor(element, styleContext->GetParentAllowServo()->AsServo(),
+                                      LazyComputeBehavior::Assert);
         } else {
           styleContext =
             ResolveStyleContext(styleContext->GetParent(), aContent, &aState);
         }
 
         display = styleContext->StyleDisplay();
         aStyleContext = styleContext;
       }
--- 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,77 +454,93 @@ 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,
                    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)
 SERVO_BINDING_FUNC(Servo_ComputedValues_GetStyleBits, uint64_t,
                    ServoComputedValuesBorrowed values)
 SERVO_BINDING_FUNC(Servo_ComputedValues_EqualCustomProperties, bool,
                    ServoComputedValuesBorrowed first,
                    ServoComputedValuesBorrowed second)
 // 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,
@@ -538,20 +554,20 @@ 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,
-                   ServoComputedValuesBorrowed existing_style,
+                   ServoStyleContextBorrowed existing_style,
                    const mozilla::ServoElementSnapshotTable* snapshots,
                    mozilla::CSSPseudoElementType pseudo_type)
 
 // For canvas font.
 SERVO_BINDING_FUNC(Servo_SerializeFontValueForCanvas, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsAString* buffer)
 
@@ -565,17 +581,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
@@ -78,19 +78,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 bool sFramesTimingFunctionEnabled;
 
 static
 const nsFont*
 ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext,
@@ -204,16 +204,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);
 }
@@ -600,18 +620,18 @@ bool
 Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed aA,
                             RawGeckoStyleAnimationListBorrowed aB)
 {
   return *aA == *aB;
 }
 
 void
 Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
-                       ServoComputedValuesBorrowedOrNull aOldComputedValues,
-                       ServoComputedValuesBorrowedOrNull aComputedValues,
+                       ServoStyleContextBorrowedOrNull aOldComputedValues,
+                       ServoStyleContextBorrowedOrNull aComputedValues,
                        UpdateAnimationsTasks aTasks)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aElement);
 
   if (!aElement->IsInComposedDoc()) {
     return;
   }
@@ -639,17 +659,18 @@ Gecko_UpdateAnimations(RawGeckoElementBo
   if (!aComputedValues) {
     return;
   }
 
   if (aTasks & UpdateAnimationsTasks::CSSTransitions) {
     MOZ_ASSERT(aOldComputedValues);
     presContext->TransitionManager()->
       UpdateTransitions(const_cast<dom::Element*>(aElement), pseudoType,
-                        aOldComputedValues, aComputedValues);
+                        aOldComputedValues,
+                        aComputedValues);
   }
 
   if (aTasks & UpdateAnimationsTasks::EffectProperties) {
     presContext->EffectCompositor()->UpdateEffectProperties(
       aComputedValues, const_cast<dom::Element*>(aElement), pseudoType);
   }
 
   if (aTasks & UpdateAnimationsTasks::CascadeResults) {
--- 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);
@@ -220,18 +227,18 @@ bool
 Gecko_GetAnimationRule(RawGeckoElementBorrowed aElementOrPseudo,
                        mozilla::EffectCompositor::CascadeLevel aCascadeLevel,
                        RawServoAnimationValueMapBorrowedMut aAnimationValues);
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetSMILOverrideDeclarationBlock(RawGeckoElementBorrowed element);
 bool Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed,
                                  RawGeckoStyleAnimationListBorrowed);
 void Gecko_UpdateAnimations(RawGeckoElementBorrowed aElementOrPseudo,
-                            ServoComputedValuesBorrowedOrNull aOldComputedValues,
-                            ServoComputedValuesBorrowedOrNull aComputedValues,
+                            ServoStyleContextBorrowedOrNull aOldComputedValues,
+                            ServoStyleContextBorrowedOrNull aComputedValues,
                             mozilla::UpdateAnimationsTasks aTasks);
 bool Gecko_ElementHasAnimations(RawGeckoElementBorrowed aElementOrPseudo);
 bool Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElementOrPseudo);
 bool Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElementOrPseudo);
 size_t Gecko_ElementTransitions_Length(RawGeckoElementBorrowed aElementOrPseudo);
 nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(
   RawGeckoElementBorrowed aElementOrPseudo,
   size_t aIndex);
--- 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,62 +8,59 @@
 #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.
    */
-  void ResolveSameStructsAs(nsPresContext* aPresContext, ServoStyleContext* aOther) {
-    // NB: This function is only called on newly-minted style contexts, but
-    // those may already have resolved style structs given the SetStyleBits call
-    // in FinishConstruction. So we carefully xor out the bits that are new so
-    // that we don't call FinishStyle twice.
+  void ResolveSameStructsAs(nsPresContext* aPresContext, const ServoStyleContext* aOther) {
+    // Only resolve structs that are not already resolved in this struct.
     uint64_t ourBits = mBits & NS_STYLE_INHERIT_MASK;
     uint64_t otherBits = aOther->mBits & NS_STYLE_INHERIT_MASK;
-    MOZ_ASSERT((otherBits | ourBits) == otherBits, "otherBits should be a superset");
-    uint64_t newBits = (ourBits ^ otherBits) & NS_STYLE_INHERIT_MASK;
+    uint64_t newBits = otherBits & ~ourBits & NS_STYLE_INHERIT_MASK;
 
-#define STYLE_STRUCT(name_, checkdata_cb)                                             \
+  #define STYLE_STRUCT(name_, checkdata_cb)                                           \
     if (nsStyle##name_::kHasFinishStyle && newBits & NS_STYLE_INHERIT_BIT(name_)) {   \
       const nsStyle##name_* data = Servo_GetStyle##name_(ComputedValues());           \
       const_cast<nsStyle##name_*>(data)->FinishStyle(aPresContext);                   \
     }
-#include "nsStyleStructList.h"
-#undef STYLE_STRUCT
+  #include "nsStyleStructList.h"
+  #undef STYLE_STRUCT
 
     mBits |= newBits;
   }
 
 private:
   nsPresContext* mPresContext;
   RefPtr<ServoComputedValues> mSource;
 };
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -184,80 +184,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 &&
@@ -439,36 +444,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,
@@ -480,18 +485,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,
@@ -506,81 +513,84 @@ 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);
-
-  return GetContext(computedValues.forget(),
+  RefPtr<ServoStyleContext> result =
+    ResolveTransientServoStyle(aElement, aPseudoType, aPseudoTag, aRuleInclusion);
+  return GetContext(result.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();
 
-  const ServoComputedValues* parentStyle =
-    aParentContext ? aParentContext->ComputedValues()
-                   : nullptr;
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_ComputedValues_GetForAnonymousBox(parentStyle, aPseudoTag,
+  ServoStyleContext* parent = aParentContext ? aParentContext->AsServo() : nullptr;
+  RefPtr<ServoStyleContext> computedValues =
+    Servo_ComputedValues_GetForAnonymousBox(parent, CSSPseudoElementType::InheritingAnonBox,
+                                            aPseudoTag,
                                             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();
@@ -613,18 +623,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,
+  RefPtr<ServoStyleContext> computedValues =
+    Servo_ComputedValues_GetForAnonymousBox(nullptr, CSSPseudoElementType::NonInheritingAnonBox,
+                                            aPseudoTag,
                                             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();
@@ -843,41 +854,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)
 {
@@ -1091,25 +1104,23 @@ ServoStyleSet::GetAnimationValues(
 
 already_AddRefed<ServoStyleContext>
 ServoStyleSet::GetBaseContextForElement(
   Element* aElement,
   nsStyleContext* aParentContext,
   nsPresContext* aPresContext,
   nsIAtom* aPseudoTag,
   CSSPseudoElementType aPseudoType,
-  ServoComputedValuesBorrowed aStyle)
+  const ServoStyleContext* aStyle)
 {
-  RefPtr<ServoComputedValues> cv = Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
+  return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
                                                         aElement,
                                                         aStyle,
                                                         &Snapshots(),
                                                         aPseudoType).Consume();
-  return ServoStyleContext::Create(nullptr, aPresContext, aPseudoTag,
-                                   aPseudoType, cv.forget());
 }
 
 already_AddRefed<RawServoAnimationValue>
 ServoStyleSet::ComputeAnimationValue(
   Element* aElement,
   RawServoDeclarationBlock* aDeclarations,
   ServoComputedValuesBorrowed aComputedValues)
 {
@@ -1166,34 +1177,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);
 
   /**
@@ -1216,27 +1229,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();
 }
 
@@ -1249,19 +1266,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,
@@ -383,25 +384,25 @@ public:
   nsCSSCounterStyleRule* CounterStyleRuleForName(nsIAtom* aName);
 
   already_AddRefed<ServoStyleContext>
   GetBaseContextForElement(dom::Element* aElement,
                            nsStyleContext* aParentContext,
                            nsPresContext* aPresContext,
                            nsIAtom* aPseudoTag,
                            CSSPseudoElementType aPseudoType,
-                           ServoComputedValuesBorrowed aStyle);
+                           const ServoStyleContext* aStyle);
 
   /**
    * 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)
@@ -472,17 +473,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,
@@ -554,19 +555,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/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -399,41 +399,41 @@ ResolvedStyleCache::Get(nsPresContext *a
     mCache.Put(aKeyframeDeclaration, resultStrong);
     result = resultStrong;
   }
   return result;
 }
 
 class MOZ_STACK_CLASS ServoCSSAnimationBuilder final {
 public:
-  explicit ServoCSSAnimationBuilder(const ServoComputedValues* aComputedValues)
-    : mComputedValues(aComputedValues)
+  explicit ServoCSSAnimationBuilder(const ServoStyleContext* aStyleContext)
+    : mStyleContext(aStyleContext)
   {
-    MOZ_ASSERT(aComputedValues);
+    MOZ_ASSERT(aStyleContext);
   }
 
   bool BuildKeyframes(nsPresContext* aPresContext,
                       const StyleAnimation& aSrc,
                       nsTArray<Keyframe>& aKeyframes)
   {
     ServoStyleSet* styleSet = aPresContext->StyleSet()->AsServo();
     MOZ_ASSERT(styleSet);
     const nsTimingFunction& timingFunction = aSrc.GetTimingFunction();
     return styleSet->GetKeyframesForName(aSrc.GetName(),
                                          timingFunction,
                                          aKeyframes);
   }
   void SetKeyframes(KeyframeEffectReadOnly& aEffect,
                     nsTArray<Keyframe>&& aKeyframes)
   {
-    aEffect.SetKeyframes(Move(aKeyframes), mComputedValues);
+    aEffect.SetKeyframes(Move(aKeyframes), mStyleContext);
   }
 
 private:
-  const ServoComputedValues* mComputedValues;
+  const ServoStyleContext* mStyleContext;
 };
 
 class MOZ_STACK_CLASS GeckoCSSAnimationBuilder final {
 public:
   GeckoCSSAnimationBuilder(nsStyleContext* aStyleContext,
                            const NonOwningAnimationTarget& aTarget)
     : mStyleContext(aStyleContext)
     , mTarget(aTarget)
@@ -443,17 +443,17 @@ public:
   }
 
   bool BuildKeyframes(nsPresContext* aPresContext,
                       const StyleAnimation& aSrc,
                       nsTArray<Keyframe>& aKeyframs);
   void SetKeyframes(KeyframeEffectReadOnly& aEffect,
                     nsTArray<Keyframe>&& aKeyframes)
   {
-    aEffect.SetKeyframes(Move(aKeyframes), mStyleContext);
+    aEffect.SetKeyframes(Move(aKeyframes), mStyleContext->AsGecko());
   }
 
 private:
   nsTArray<Keyframe> BuildAnimationFrames(nsPresContext* aPresContext,
                                           const StyleAnimation& aSrc,
                                           const nsCSSKeyframesRule* aRule);
   Maybe<ComputedTimingFunction> GetKeyframeTimingFunction(
     nsPresContext* aPresContext,
@@ -985,17 +985,17 @@ BuildAnimations(nsPresContext* aPresCont
 
     dest->SetAnimationIndex(static_cast<uint64_t>(animIdx));
     result.AppendElement(dest);
   }
   return result;
 }
 
 void
-nsAnimationManager::UpdateAnimations(nsStyleContext* aStyleContext,
+nsAnimationManager::UpdateAnimations(GeckoStyleContext* aStyleContext,
                                      mozilla::dom::Element* aElement)
 {
   MOZ_ASSERT(mPresContext->IsDynamic(),
              "Should not update animations for print or print preview");
   MOZ_ASSERT(aElement->IsInComposedDoc(),
              "Should not update animations that are not attached to the "
              "document tree");
 
@@ -1010,37 +1010,37 @@ nsAnimationManager::UpdateAnimations(nsS
   const nsStyleDisplay* disp = aStyleContext->StyleDisplay();
   DoUpdateAnimations(target, *disp, builder);
 }
 
 void
 nsAnimationManager::UpdateAnimations(
   dom::Element* aElement,
   CSSPseudoElementType aPseudoType,
-  const ServoComputedValues* aComputedValues)
+  const ServoStyleContext* aStyleContext)
 {
   MOZ_ASSERT(mPresContext->IsDynamic(),
              "Should not update animations for print or print preview");
   MOZ_ASSERT(aElement->IsInComposedDoc(),
              "Should not update animations that are not attached to the "
              "document tree");
 
-  if (!aComputedValues) {
+  if (!aStyleContext) {
     // If we are in a display:none subtree we will have no computed values.
     // Since CSS animations should not run in display:none subtrees we should
     // stop (actually, destroy) any animations on this element here.
     StopAnimationsForElement(aElement, aPseudoType);
     return;
   }
 
   NonOwningAnimationTarget target(aElement, aPseudoType);
-  ServoCSSAnimationBuilder builder(aComputedValues);
+  ServoCSSAnimationBuilder builder(aStyleContext);
 
   const nsStyleDisplay *disp =
-    Servo_GetStyleDisplay(aComputedValues);
+    Servo_GetStyleDisplay(aStyleContext->ComputedValues());
   DoUpdateAnimations(target, *disp, builder);
 }
 
 template<class BuilderType>
 void
 nsAnimationManager::DoUpdateAnimations(
   const NonOwningAnimationTarget& aTarget,
   const nsStyleDisplay& aStyleDisplay,
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -27,16 +27,19 @@ class Declaration;
 namespace dom {
 class KeyframeEffectReadOnly;
 class Promise;
 } /* namespace dom */
 
 enum class CSSPseudoElementType : uint8_t;
 struct NonOwningAnimationTarget;
 
+class GeckoStyleContext;
+class ServoStyleContext;
+
 struct AnimationEventInfo {
   RefPtr<dom::Element> mElement;
   RefPtr<dom::Animation> mAnimation;
   InternalAnimationEvent mEvent;
   TimeStamp mTimeStamp;
 
   AnimationEventInfo(dom::Element* aElement,
                      CSSPseudoElementType aPseudoType,
@@ -318,27 +321,27 @@ public:
   /**
    * Update the set of animations on |aElement| based on |aStyleContext|.
    * If necessary, this will notify the corresponding EffectCompositor so
    * that it can update its animation rule.
    *
    * aStyleContext may be a style context for aElement or for its
    * :before or :after pseudo-element.
    */
-  void UpdateAnimations(nsStyleContext* aStyleContext,
+  void UpdateAnimations(mozilla::GeckoStyleContext* aStyleContext,
                         mozilla::dom::Element* aElement);
 
   /**
    * This function does the same thing as the above UpdateAnimations()
    * but with servo's computed values.
    */
   void UpdateAnimations(
     mozilla::dom::Element* aElement,
     mozilla::CSSPseudoElementType aPseudoType,
-    const ServoComputedValues* aComputedValues);
+    const mozilla::ServoStyleContext* aComputedValues);
 
   /**
    * Add a pending event.
    */
   void QueueEvent(mozilla::AnimationEventInfo&& aEventInfo)
   {
     mEventDispatcher.QueueEvent(
       mozilla::Forward<mozilla::AnimationEventInfo>(aEventInfo));
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -637,17 +637,17 @@ nsComputedDOMStyle::DoGetStyleContextNoF
           MOZ_ASSERT(presContext, "Should have a prescontext if we have a frame");
           if (presContext && presContext->StyleSet()->IsGecko()) {
             nsStyleSet* styleSet = presContext->StyleSet()->AsGecko();
             return styleSet->ResolveStyleByRemovingAnimation(
                      aElement, result, eRestyle_AllHintsWithAnimations);
           } else {
               return presContext->StyleSet()->AsServo()->
                 GetBaseContextForElement(aElement, nullptr, presContext,
-                                         aPseudo, pseudoType, result->ComputedValues());
+                                         aPseudo, pseudoType, result->AsServo());
           }
         }
 
         // this function returns an addrefed style context
         RefPtr<nsStyleContext> ret = result;
         return ret.forget();
       }
     }
@@ -664,23 +664,23 @@ 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, result->ComputedValues());
+                                              aPseudo, pseudoType, result->AsServo());
   }
 
   RefPtr<nsStyleContext> parentContext;
   nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
   // Don't resolve parent context for document fragments.
   if (parent && parent->IsElement()) {
     parentContext = GetStyleContextNoFlush(parent->AsElement(), nullptr,
                                            aPresShell, aStyleType);
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -160,23 +160,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());
   }
 }
@@ -487,16 +486,54 @@ 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");
+  // XXXManishearth
+  // Servo currently mints fresh visited contexts on calls to GetContext()
+  // in line with the previous behavior.
+  // This is suboptimal and should be phased out when we phase out GetContext()
+  NS_ASSERTION(IsServo() || !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");
+  // XXXManishearth In Servo mode this can be called during ResolveTransientServoStyle
+  // in which case we may already have a visited style context but the
+  // expected parent is gone. Will be fixed when the aforementioned suboptimal
+  // behavior is removed
+  if (IsGecko()) {
+    if (GetParent() && GetParent()->GetStyleIfVisited()) {
+      MOZ_ASSERT(GetStyleIfVisited()->GetParent() ==
+                     GetParent()->GetStyleIfVisited() ||
+                   GetStyleIfVisited()->GetParent() ==
+                     GetParent(),
+                   "parent mismatch");
+    } else {
+      MOZ_ASSERT(GetStyleIfVisited()->GetParent() ==
+                     GetParent(),
+                   "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
@@ -632,33 +669,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/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -957,20 +957,20 @@ nsStyleSet::GetContext(nsStyleContext* a
     nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
     nsIStyleRule *animRule = nullptr;
 
     // Ignore animations for print or print preview, and for elements
     // that are not attached to the document tree.
     if (PresContext()->IsDynamic() &&
         aElementForAnimation->IsInComposedDoc()) {
       // Update CSS animations in case the animation-name has just changed.
-      PresContext()->AnimationManager()->UpdateAnimations(result,
+      PresContext()->AnimationManager()->UpdateAnimations(result->AsGecko(),
                                                           aElementForAnimation);
       PresContext()->EffectCompositor()->UpdateEffectProperties(
-        result.get(), aElementForAnimation, result->GetPseudoType());
+        result->AsGecko(), aElementForAnimation, result->GetPseudoType());
 
       animRule = PresContext()->EffectCompositor()->
                    GetAnimationRule(aElementForAnimation,
                                     result->GetPseudoType(),
                                     EffectCompositor::CascadeLevel::Animations,
                                     result);
     }
 
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -440,26 +440,26 @@ ExtractNonDiscreteComputedValue(nsCSSPro
   return (nsCSSProps::kAnimTypeTable[aProperty] != eStyleAnimType_Discrete ||
           aProperty == eCSSProperty_visibility) &&
          StyleAnimationValue::ExtractComputedValue(aProperty, aStyleContext,
                                                    aAnimationValue.mGecko);
 }
 
 static inline bool
 ExtractNonDiscreteComputedValue(nsCSSPropertyID aProperty,
-                                const ServoComputedValues* aComputedStyle,
+                                const ServoStyleContext* aComputedStyle,
                                 AnimationValue& aAnimationValue)
 {
   if (Servo_Property_IsDiscreteAnimatable(aProperty) &&
       aProperty != eCSSProperty_visibility) {
     return false;
   }
 
   aAnimationValue.mServo =
-    Servo_ComputedValues_ExtractAnimationValue(aComputedStyle,
+    Servo_ComputedValues_ExtractAnimationValue(aComputedStyle->ComputedValues(),
                                                aProperty).Consume();
   return !!aAnimationValue.mServo;
 }
 
 void
 nsTransitionManager::StyleContextChanged(dom::Element *aElement,
                                          nsStyleContext *aOldStyleContext,
                                          RefPtr<nsStyleContext>* aNewStyleContext /* inout */)
@@ -584,18 +584,18 @@ nsTransitionManager::StyleContextChanged
   DebugOnly<bool> startedAny = false;
   // We don't have to update transitions if display:none, although we will
   // cancel them after restyling.
   if (!afterChangeStyle->IsInDisplayNoneSubtree()) {
     startedAny = DoUpdateTransitions(disp,
                                      aElement,
                                      afterChangeStyle->GetPseudoType(),
                                      collection,
-                                     aOldStyleContext,
-                                     afterChangeStyle.get());
+                                     aOldStyleContext->AsGecko(),
+                                     afterChangeStyle->AsGecko());
   }
 
   MOZ_ASSERT(!startedAny || collection,
              "must have element transitions if we started any transitions");
 
   EffectCompositor::CascadeLevel cascadeLevel =
     EffectCompositor::CascadeLevel::Transitions;
 
@@ -619,27 +619,27 @@ nsTransitionManager::StyleContextChanged
                                                               cascadeLevel);
   }
 }
 
 bool
 nsTransitionManager::UpdateTransitions(
   dom::Element *aElement,
   CSSPseudoElementType aPseudoType,
-  const ServoComputedValues* aOldStyle,
-  const ServoComputedValues* aNewStyle)
+  const ServoStyleContext* aOldStyle,
+  const ServoStyleContext* aNewStyle)
 {
   if (!mPresContext->IsDynamic()) {
     // For print or print preview, ignore transitions.
     return false;
   }
 
   CSSTransitionCollection* collection =
     CSSTransitionCollection::GetAnimationCollection(aElement, aPseudoType);
-  const nsStyleDisplay *disp = Servo_GetStyleDisplay(aNewStyle);
+  const nsStyleDisplay *disp = Servo_GetStyleDisplay(aNewStyle->ComputedValues());
   return DoUpdateTransitions(disp,
                              aElement, aPseudoType,
                              collection,
                              aOldStyle, aNewStyle);
 }
 
 template<typename StyleType>
 bool
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -21,16 +21,17 @@ class nsIGlobalObject;
 class nsStyleContext;
 class nsPresContext;
 class nsCSSPropertyIDSet;
 
 namespace mozilla {
 enum class CSSPseudoElementType : uint8_t;
 struct Keyframe;
 struct StyleTransition;
+class ServoStyleContext;
 } // namespace mozilla
 
 /*****************************************************************************
  * Per-Element data                                                          *
  *****************************************************************************/
 
 namespace mozilla {
 
@@ -372,18 +373,18 @@ public:
                            RefPtr<nsStyleContext>* aNewStyleContext /* inout */);
 
   /**
    * Update transitions for stylo.
    */
   bool UpdateTransitions(
     mozilla::dom::Element *aElement,
     mozilla::CSSPseudoElementType aPseudoType,
-    const ServoComputedValues* aOldStyle,
-    const ServoComputedValues* aNewStyle);
+    const mozilla::ServoStyleContext* aOldStyle,
+    const mozilla::ServoStyleContext* aNewStyle);
 
   /**
    * When we're resolving style for an element that previously didn't have
    * style, we might have some old finished transitions for it, if,
    * say, it was display:none for a while, but previously displayed.
    *
    * This method removes any finished transitions that don't match the
    * new style.
--- 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
@@ -102,16 +102,35 @@ impl PseudoElement {
                         Some(${pseudo_element_variant(pseudo)})
                     },
                 % 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_tree_pseudo_element():
                 // We cannot generate ${pseudo_element_variant(pseudo)} from just an atom.
             % elif pseudo.is_anon_box():
                 if atom == &atom!("${pseudo.value}") {
--- 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/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::empty(),
                 % 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
     }
@@ -192,22 +231,22 @@ impl ComputedValuesInner {
     }
 
     /// Whether there is a visited style.
     pub fn has_visited_style(&self) -> bool {
         self.visited_style.is_some()
     }
 
     /// Gets a reference to the visited style, if any.
-    pub fn get_visited_style(&self) -> Option< & ComputedValuesInner> {
-        self.visited_style.as_ref().map(|x| &***x)
+    pub fn get_visited_style(&self) -> Option< & ComputedValues> {
+        self.visited_style.as_ref().map(|x| &**x)
     }
 
     /// Gets a reference to the visited style. Panic if no visited style exists.
-    pub fn visited_style(&self) -> &ComputedValuesInner {
+    pub fn visited_style(&self) -> &ComputedValues {
         self.get_visited_style().unwrap()
     }
 
     /// Clone the visited style.  Used for inheriting parent styles in
     /// StyleBuilder::for_inheritance.
     pub fn clone_visited_style(&self) -> Option<Arc<ComputedValues>> {
         self.visited_style.clone()
     }
@@ -4796,17 +4835,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
@@ -1866,19 +1866,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}>,
@@ -1930,17 +1935,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():
@@ -1966,17 +1970,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()
@@ -2007,23 +2012,23 @@ impl ComputedValuesInner {
     }
 
     /// Whether there is a visited style.
     pub fn has_visited_style(&self) -> bool {
         self.visited_style.is_some()
     }
 
     /// Gets a reference to the visited style, if any.
-    pub fn get_visited_style(&self) -> Option< & ComputedValuesInner> {
-        self.visited_style.as_ref().map(|x| &**x)
+    pub fn get_visited_style(&self) -> Option< & ComputedValues> {
+        self.visited_style.as_ref().map(|x| &*x)
     }
 
     /// Gets a reference to the visited style. Panic if no visited style exists.
-    pub fn visited_style(&self) -> &ComputedValuesInner {
-        self.get_visited_style().as_ref().map(|x| &**x).unwrap()
+    pub fn visited_style(&self) -> &ComputedValues {
+        self.get_visited_style().unwrap()
     }
 
     /// Clone the visited style.  Used for inheriting parent styles in
     /// StyleBuilder::for_inheritance.
     pub fn clone_visited_style(&self) -> Option<Arc<ComputedValues>> {
         self.visited_style.clone()
     }
 
--- 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/style_resolver.rs
+++ b/servo/components/style/style_resolver.rs
@@ -42,17 +42,17 @@ struct MatchingResults {
 pub struct PrimaryStyle {
     /// The style per se.
     pub style: Arc<ComputedValues>,
 }
 
 fn with_default_parent_styles<E, F, R>(element: E, f: F) -> R
 where
     E: TElement,
-    F: FnOnce(Option<&ComputedValuesInner>, Option<&ComputedValuesInner>) -> R,
+    F: FnOnce(Option<&ComputedValues>, Option<&ComputedValuesInner>) -> R,
 {
     let parent_el = element.inheritance_parent();
     let parent_data = parent_el.as_ref().and_then(|e| e.borrow_data());
     let parent_style = parent_data.as_ref().map(|d| {
         // Sometimes Gecko eagerly styles things without processing
         // pending restyles first. In general we'd like to avoid this,
         // but there can be good reasons (for example, needing to
         // construct a frame for some small piece of newly-added
@@ -67,17 +67,17 @@ where
     let layout_parent_data;
     let mut layout_parent_style = parent_style;
     if parent_style.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(layout_parent_data.styles.primary());
     }
 
-    f(parent_style.map(|s| &***s), layout_parent_style.map(|s| &***s))
+    f(parent_style.map(|x| &**x), layout_parent_style.map(|s| &***s))
 }
 
 impl<'a, 'ctx, 'le, E> StyleResolverForElement<'a, 'ctx, 'le, E>
 where
     'ctx: 'a,
     'le: 'ctx,
     E: TElement + MatchMethods + 'le,
 {
@@ -93,17 +93,17 @@ where
             rule_inclusion,
             _marker: ::std::marker::PhantomData,
         }
     }
 
     /// Resolve just the style of a given element.
     pub fn resolve_primary_style(
         &mut self,
-        parent_style: Option<&ComputedValuesInner>,
+        parent_style: Option<&ComputedValues>,
         layout_parent_style: Option<&ComputedValuesInner>,
     ) -> PrimaryStyle {
         let primary_results =
             self.match_primary(VisitedHandlingMode::AllLinksUnvisited);
 
         let relevant_link_found = primary_results.relevant_link_found;
 
         let visited_rules = if relevant_link_found {
@@ -114,44 +114,44 @@ where
             None
         };
 
         let mut visited_style = None;
         let should_compute_visited_style =
             relevant_link_found ||
             parent_style.and_then(|s| s.get_visited_style()).is_some();
 
+        let pseudo = self.element.implemented_pseudo_element();
         if should_compute_visited_style {
             visited_style = Some(self.cascade_style(
                 visited_rules.as_ref(),
                 /* style_if_visited = */ None,
                 parent_style,
                 layout_parent_style,
                 CascadeVisitedMode::Visited,
-                /* pseudo = */ None,
+                /* pseudo = */ pseudo.as_ref(),
             ));
         }
-
         let style = self.cascade_style(
             Some(&primary_results.rule_node),
             visited_style,
             parent_style,
             layout_parent_style,
             CascadeVisitedMode::Unvisited,
-            /* pseudo = */ None,
+            /* pseudo = */ pseudo.as_ref(),
         );
 
         PrimaryStyle { style, }
     }
 
 
     /// Resolve the style of a given element, and all its eager pseudo-elements.
     pub fn resolve_style(
         &mut self,
-        parent_style: Option<&ComputedValuesInner>,
+        parent_style: Option<&ComputedValues>,
         layout_parent_style: Option<&ComputedValuesInner>,
     ) -> ElementStyles {
         use properties::longhands::display::computed_value::T as display;
 
         let primary_style =
             self.resolve_primary_style(parent_style, layout_parent_style);
 
         let mut pseudo_styles = EagerPseudoStyles::default();
@@ -210,17 +210,17 @@ where
                 /* pseudo = */ None
             )
         })
     }
 
     fn cascade_style_and_visited(
         &mut self,
         inputs: CascadeInputs,
-        parent_style: Option<&ComputedValuesInner>,
+        parent_style: Option<&ComputedValues>,
         layout_parent_style: Option<&ComputedValuesInner>,
         pseudo: Option<&PseudoElement>,
     ) -> Arc<ComputedValues> {
         let mut style_if_visited = None;
         if parent_style.map_or(false, |s| s.get_visited_style().is_some()) ||
             inputs.visited_rules.is_some() {
             style_if_visited = Some(self.cascade_style(
                 inputs.visited_rules.as_ref(),
@@ -457,17 +457,17 @@ where
 
         Some(rule_node)
     }
 
     fn cascade_style(
         &mut self,
         rules: Option<&StrongRuleNode>,
         style_if_visited: Option<Arc<ComputedValues>>,
-        mut parent_style: Option<&ComputedValuesInner>,
+        mut parent_style: Option<&ComputedValues>,
         layout_parent_style: Option<&ComputedValuesInner>,
         cascade_visited: CascadeVisitedMode,
         pseudo: Option<&PseudoElement>,
     ) -> Arc<ComputedValues> {
         let mut cascade_info = CascadeInfo::new();
         let mut cascade_flags = CascadeFlags::empty();
 
         if self.element.skip_root_and_item_based_display_fixup() {
@@ -480,26 +480,43 @@ where
             cascade_flags.insert(VISITED_DEPENDENT_ONLY);
         }
         if self.element.is_native_anonymous() || pseudo.is_some() {
             cascade_flags.insert(PROHIBIT_DISPLAY_CONTENTS);
         } else if self.element.is_root() {
             cascade_flags.insert(IS_ROOT_ELEMENT);
         }
 
+        #[cfg(feature = "gecko")]
+        let parent_style_context = parent_style;
+        #[cfg(feature = "servo")]
+        let parent_style_context = ();
+
         let values =
             cascade(
                 self.context.shared.stylist.device(),
                 rules.unwrap_or(self.context.shared.stylist.rule_tree().root()),
                 &self.context.shared.guards,
-                parent_style,
+                parent_style.map(|x| &**x),
                 layout_parent_style,
                 style_if_visited,
                 Some(&mut cascade_info),
                 &self.context.thread_local.font_metrics_provider,
                 cascade_flags,
                 self.context.shared.quirks_mode
             );
 
         cascade_info.finish(&self.element.as_node());
-        values.to_outer()
+
+        // In case of NAC like ::placeholder we style it via
+        // cascade_primary without a PseudoElement, but
+        // the element itself is a pseudo, so try to use that
+        // when `pseudo` is unset
+        let pseudo_info = if let Some(pseudo) = pseudo {
+            Some(pseudo.pseudo_info())
+        } else {
+            self.element.implemented_pseudo_element().map(|x| x.pseudo_info())
+        };
+        values.to_outer(self.context.shared.stylist.device(),
+                        parent_style_context,
+                       pseudo_info)
     }
 }
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -12,17 +12,17 @@ use dom::TElement;
 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 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, 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) => {
                 self.rule_tree.insert_ordered_rules_with_important(
                     declarations.into_iter().map(|a| (a.source.clone(), a.level())),
                     guards
@@ -633,17 +635,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)
@@ -670,54 +673,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.rules.is_none() && inputs.visited_rules.is_none() {
             return None
         }
 
@@ -729,34 +738,35 @@ impl Stylist {
             // maybe it just has visited rules, so can't unwrap_or.
             let rule_node = match inputs.visited_rules.as_ref() {
                 Some(rules) => rules,
                 None => inputs.rules.as_ref().unwrap(),
             };
             // We want to use the visited bits (if any) from our parent style as
             // our parent.
             let inherited_style =
-                parent_style.get_visited_style().unwrap_or(parent_style);
+                parent_style.get_visited_style().map(|x| &**x).unwrap_or(parent_style);
 
             // FIXME(emilio): The lack of layout_parent_style here could be
             // worrying, but we're probably dropping the display fixup for
             // pseudos other than before and after, so it's probably ok.
             //
             // (Though the flags don't indicate so!)
             let computed =
                 properties::cascade(&self.device,
                                     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.
@@ -770,17 +780,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,
@@ -1308,17 +1320,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 =
@@ -1332,17 +1345,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/components/style/traversal.rs
+++ b/servo/components/style/traversal.rs
@@ -571,34 +571,34 @@ where
     }
 
     for ancestor in ancestors_requiring_style_resolution.iter().rev() {
         context.thread_local.bloom_filter.assert_complete(*ancestor);
 
         let primary_style =
             StyleResolverForElement::new(*ancestor, context, rule_inclusion)
                 .resolve_primary_style(
-                    style.as_ref().map(|s| &***s),
+                    style.as_ref().map(|s| &**s),
                     layout_parent_style.as_ref().map(|s| &***s)
                 );
 
         let is_display_contents = primary_style.style.is_display_contents();
 
         style = Some(primary_style.style);
         if !is_display_contents {
             layout_parent_style = style.clone();
         }
 
         context.thread_local.bloom_filter.push(*ancestor);
     }
 
     context.thread_local.bloom_filter.assert_complete(element);
     StyleResolverForElement::new(element, context, rule_inclusion)
         .resolve_style(
-            style.as_ref().map(|s| &***s),
+            style.as_ref().map(|s| &**s),
             layout_parent_style.as_ref().map(|s| &***s)
         )
 }
 
 /// Calculates the style for a single node.
 #[inline]
 #[allow(unsafe_code)]
 pub fn recalc_style_at<E, D>(
--- 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::{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;
@@ -649,20 +650,20 @@ pub extern "C" fn Servo_AnimationValue_U
     let global_style_data = &*GLOBAL_STYLE_DATA;
     Arc::new(global_style_data.shared_lock.wrap(
         PropertyDeclarationBlock::with_one(value.uncompute(), Importance::Normal))).into_strong()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(raw_data: RawServoStyleSetBorrowed,
                                                                  element: RawGeckoElementBorrowed,
-                                                                 computed_values: ServoComputedValuesBorrowed,
+                                                                 computed_values: ServoStyleContextBorrowed,
                                                                  snapshots: *const ServoElementSnapshotTable,
                                                                  pseudo_type: CSSPseudoElementType)
-                                                                 -> ServoComputedValuesStrong
+                                                                 -> ServoStyleContextStrong
 {
     use style::style_resolver::StyleResolverForElement;
 
     debug_assert!(!snapshots.is_null());
     let computed_values = ComputedValues::as_arc(&computed_values);
 
     let rules = match computed_values.rules {
         None => return computed_values.clone().into_strong(),
@@ -725,17 +726,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)
 }
@@ -1495,91 +1495,97 @@ 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,
                                                           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 cascade_flags = 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();
@@ -1610,16 +1616,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
@@ -1631,17 +1639,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()
                 },
@@ -1662,105 +1672,125 @@ 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).clone_visited_style() {
+                                                       -> ServoStyleContextStrong {
+    match ComputedValuesInner::as_arc(&values).clone_visited_style() {
         Some(v) => v.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_GetStyleBits(values: ServoComputedValuesBorrowed) -> u64 {
     use style::properties::computed_value_flags::*;
-    let flags = ComputedValues::as_arc(&values).flags;
+    let flags = values.flags;
     let mut result = 0;
     if flags.contains(HAS_TEXT_DECORATION_LINES) {
         result |= structs::NS_STYLE_HAS_TEXT_DECORATION_LINES as u64;
     }
     if flags.contains(SHOULD_SUPPRESS_LINEBREAK) {
         result |= structs::NS_STYLE_SUPPRESS_LINEBREAK as u64;
     }
     result
 }
 
 #[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_EqualCustomProperties(
     first: ServoComputedValuesBorrowed,
     second: ServoComputedValuesBorrowed
 ) -> bool {
-    let first = ComputedValues::as_arc(&first);
-    let second = ComputedValues::as_arc(&second);
     first.get_custom_properties() == second.get_custom_properties()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(values: ServoComputedValuesBorrowed,
                                                         rules: RawGeckoServoStyleRuleListBorrowedMut) {
-    let values = ComputedValues::as_arc(&values);
     if let Some(ref rule_node) = values.rules {
         let mut result = vec![];
         for node in rule_node.self_and_ancestors() {
             if let &StyleSource::Style(ref rule) = node.style_source() {
                 result.push(rule);
             }
         }
         unsafe { rules.set_len(result.len() as u32) };
@@ -2748,39 +2778,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);
@@ -2791,16 +2825,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
@@ -2844,21 +2880,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,
@@ -2875,22 +2911,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() {
@@ -2955,23 +2990,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);
@@ -2984,23 +3018,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.
@@ -3234,34 +3267,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 {
@@ -3311,44 +3345,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,
     };