Bug 1324627 - Add a special, explicit path for lazy style resolution and use it for GetComputedStyle. r=heycam draft
authorBobby Holley <bobbyholley@gmail.com>
Wed, 28 Dec 2016 11:21:19 +0800
changeset 454381 425eb849f57a0e0eabc3b64624e197b4264272d0
parent 454380 94459122fed6b6fbfa5c73c6b1eed0e75d09e357
child 454382 ec49ff55dce7a0bc95e6918e7a5bf3947459d241
push id39910
push userbmo:cam@mcc.id.au
push dateThu, 29 Dec 2016 07:06:54 +0000
reviewersheycam
bugs1324627
milestone53.0a1
Bug 1324627 - Add a special, explicit path for lazy style resolution and use it for GetComputedStyle. r=heycam MozReview-Commit-ID: ECnoeHYkpT
layout/base/ServoRestyleManager.cpp
layout/style/ServoBindingList.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/nsComputedDOMStyle.cpp
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -149,19 +149,17 @@ ServoRestyleManager::RecreateStyleContex
     return;
   }
 
   // If we have a frame and a non-zero + non-reconstruct change hint, we need to
   // attach a new style context.
   bool recreateContext = primaryFrame && changeHint;
   if (recreateContext) {
     RefPtr<ServoComputedValues> computedValues
-      = Servo_ResolveStyle(aElement, aStyleSet->mRawSet.get(),
-                           ConsumeStyleBehavior::Consume,
-                           LazyComputeBehavior::Assert).Consume();
+      = Servo_ResolveStyle(aElement, ConsumeStyleBehavior::Consume).Consume();
 
     // Hold the old style context alive, because it could become a dangling
     // pointer during the replacement. In practice it's not a huge deal (on
     // GetNextContinuationWithSameStyle the pointer is not dereferenced, only
     // compared), but better not playing with dangling pointers if not needed.
     RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
     MOZ_ASSERT(oldStyleContext);
 
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -156,22 +156,34 @@ SERVO_BINDING_FUNC(Servo_Shutdown, void)
 SERVO_BINDING_FUNC(Servo_Element_GetSnapshot, ServoElementSnapshot*,
                    RawGeckoElementBorrowed element)
 
 // Restyle and change hints.
 SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed element,
                    nsRestyleHint restyle_hint, nsChangeHint change_hint)
 SERVO_BINDING_FUNC(Servo_CheckChangeHint, nsChangeHint, RawGeckoElementBorrowed element)
 SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoComputedValuesStrong,
-                   RawGeckoElementBorrowed element, RawServoStyleSetBorrowed set,
-                   mozilla::ConsumeStyleBehavior consume, mozilla::LazyComputeBehavior compute)
+                   RawGeckoElementBorrowed element, mozilla::ConsumeStyleBehavior consume)
 SERVO_BINDING_FUNC(Servo_ResolvePseudoStyle, ServoComputedValuesStrong,
                    RawGeckoElementBorrowed element, nsIAtom* pseudo_tag,
                    bool is_probe, RawServoStyleSetBorrowed set)
 
+// 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,
+                   RawGeckoElementBorrowed element, nsIAtom* pseudo_tag,
+                   mozilla::ConsumeStyleBehavior consume,
+                   RawServoStyleSetBorrowed set)
+
 // Restyle the given subtree.
 SERVO_BINDING_FUNC(Servo_TraverseSubtree, void,
                    RawGeckoElementBorrowed root, RawServoStyleSetBorrowed set,
                    mozilla::TraversalRootBehavior root_behavior)
 
 // Assert that the tree has no pending or unconsumed restyles.
 SERVO_BINDING_FUNC(Servo_AssertTreeIsClean, void, RawGeckoElementBorrowed root)
 
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -104,18 +104,25 @@ ServoStyleSet::GetContext(nsIContent* aC
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
                           CSSPseudoElementType aPseudoType,
                           ConsumeStyleBehavior aConsume,
                           LazyComputeBehavior aMayCompute)
 {
   MOZ_ASSERT(aContent->IsElement());
   Element* element = aContent->AsElement();
-  RefPtr<ServoComputedValues> computedValues =
-    Servo_ResolveStyle(element, mRawSet.get(), aConsume, aMayCompute).Consume();
+
+  RefPtr<ServoComputedValues> computedValues;
+  if (aMayCompute == LazyComputeBehavior::Allow) {
+    computedValues =
+      Servo_ResolveStyleLazily(element, nullptr, aConsume, mRawSet.get()).Consume();
+  } else {
+    computedValues = Servo_ResolveStyle(element, aConsume).Consume();
+  }
+
   MOZ_ASSERT(computedValues);
   return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType);
 }
 
 already_AddRefed<nsStyleContext>
 ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
                           nsStyleContext* aParentContext,
                           nsIAtom* aPseudoTag,
@@ -200,16 +207,31 @@ ServoStyleSet::ResolvePseudoElementStyle
   RefPtr<ServoComputedValues> computedValues =
     Servo_ResolvePseudoStyle(aOriginatingElement, pseudoTag,
                              /* is_probe = */ false, mRawSet.get()).Consume();
   MOZ_ASSERT(computedValues);
 
   return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
 }
 
+already_AddRefed<nsStyleContext>
+ServoStyleSet::ResolveTransientStyle(Element* aElement, CSSPseudoElementType aType)
+{
+  nsIAtom* pseudoTag = nullptr;
+  if (aType != CSSPseudoElementType::NotPseudo) {
+    pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
+  }
+
+  RefPtr<ServoComputedValues> computedValues =
+    Servo_ResolveStyleLazily(aElement, pseudoTag, ConsumeStyleBehavior::DontConsume,
+                             mRawSet.get()).Consume();
+
+  return GetContext(computedValues.forget(), nullptr, pseudoTag, aType);
+}
+
 // aFlags is an nsStyleSet flags bitfield
 already_AddRefed<nsStyleContext>
 ServoStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
                                         nsStyleContext* aParentContext,
                                         uint32_t aFlags)
 {
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag));
 
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -75,16 +75,23 @@ public:
   ResolveStyleForOtherNonElement(nsStyleContext* aParentContext);
 
   already_AddRefed<nsStyleContext>
   ResolvePseudoElementStyle(dom::Element* aOriginatingElement,
                             mozilla::CSSPseudoElementType aType,
                             nsStyleContext* aParentContext,
                             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).
+  already_AddRefed<nsStyleContext>
+  ResolveTransientStyle(dom::Element* aElement,
+                        mozilla::CSSPseudoElementType aPseudoType);
+
   // aFlags is an nsStyleSet flags bitfield
   already_AddRefed<nsStyleContext>
   ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext,
                            uint32_t aFlags = 0);
 
   // manage the set of style sheets in the style set
   nsresult AppendStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
   nsresult PrependStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -487,53 +487,63 @@ nsComputedDOMStyle::GetStyleContextForEl
         RefPtr<nsStyleContext> ret = result;
         return ret.forget();
       }
     }
   }
 
   // No frame has been created, or we have a pseudo, or we're looking
   // for the default style, so resolve the style ourselves.
-  RefPtr<nsStyleContext> parentContext;
-  nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
-  // Don't resolve parent context for document fragments.
-  if (parent && parent->IsElement())
-    parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
-                                                     nullptr, presShell,
-                                                     aStyleType);
 
   nsPresContext *presContext = presShell->GetPresContext();
   if (!presContext)
     return nullptr;
 
   StyleSetHandle styleSet = presShell->StyleSet();
 
-  RefPtr<nsStyleContext> sc;
+  auto type = CSSPseudoElementType::NotPseudo;
   if (aPseudo) {
-    CSSPseudoElementType type = nsCSSPseudoElements::
+    type = nsCSSPseudoElements::
       GetPseudoType(aPseudo, CSSEnabledState::eIgnoreEnabledState);
     if (type >= CSSPseudoElementType::Count) {
       return nullptr;
     }
+  }
+
+  // For Servo, compute the result directly without recursively building up
+  // a throwaway style context chain.
+  if (ServoStyleSet* servoSet = styleSet->GetAsServo()) {
+    if (aStyleType == eDefaultOnly) {
+      NS_ERROR("stylo: ServoStyleSets cannot supply UA-only styles yet");
+      return nullptr;
+    }
+    return servoSet->ResolveTransientStyle(aElement, type);
+  }
+
+  RefPtr<nsStyleContext> sc;
+  RefPtr<nsStyleContext> parentContext;
+  nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
+  // Don't resolve parent context for document fragments.
+  if (parent && parent->IsElement())
+    parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
+                                                     nullptr, aPresShell,
+                                                     aStyleType);
+
+  if (type != CSSPseudoElementType::NotPseudo) {
     nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
     Element* pseudoElement =
       frame && inDocWithShell ? frame->GetPseudoElement(type) : nullptr;
     sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
                                              pseudoElement);
   } else {
     sc = styleSet->ResolveStyleFor(aElement, parentContext, ConsumeStyleBehavior::DontConsume,
                                    LazyComputeBehavior::Allow);
   }
 
   if (aStyleType == eDefaultOnly) {
-    if (styleSet->IsServo()) {
-      NS_ERROR("stylo: ServoStyleSets cannot supply UA-only styles yet");
-      return nullptr;
-    }
-
     // We really only want the user and UA rules.  Filter out the other ones.
     nsTArray< nsCOMPtr<nsIStyleRule> > rules;
     for (nsRuleNode* ruleNode = sc->RuleNode();
          !ruleNode->IsRoot();
          ruleNode = ruleNode->GetParent()) {
       if (ruleNode->GetLevel() == SheetType::Agent ||
           ruleNode->GetLevel() == SheetType::User) {
         rules.AppendElement(ruleNode->GetRule());