diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp index d7fb12340250..ae3ad4e08af9 100644 --- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -154,9 +154,7 @@ ServoRestyleManager::RecreateStyleContexts(Element* aElement, bool recreateContext = primaryFrame && changeHint; if (recreateContext) { RefPtr 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 diff --git a/layout/style/ServoBindingList.h b/layout/style/ServoBindingList.h index b89fcef67b5b..09280f6d1675 100644 --- a/layout/style/ServoBindingList.h +++ b/layout/style/ServoBindingList.h @@ -161,12 +161,24 @@ SERVO_BINDING_FUNC(Servo_NoteExplicitHints, void, RawGeckoElementBorrowed elemen 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, diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index 40e0c8a445da..0d4915fdd6f5 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -109,8 +109,15 @@ ServoStyleSet::GetContext(nsIContent* aContent, { MOZ_ASSERT(aContent->IsElement()); Element* element = aContent->AsElement(); - RefPtr computedValues = - Servo_ResolveStyle(element, mRawSet.get(), aConsume, aMayCompute).Consume(); + + RefPtr 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); } @@ -205,6 +212,21 @@ ServoStyleSet::ResolvePseudoElementStyle(Element* aOriginatingElement, return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType); } +already_AddRefed +ServoStyleSet::ResolveTransientStyle(Element* aElement, CSSPseudoElementType aType) +{ + nsIAtom* pseudoTag = nullptr; + if (aType != CSSPseudoElementType::NotPseudo) { + pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType); + } + + RefPtr 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 ServoStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index 53f23872e269..1a8068053a85 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -80,6 +80,13 @@ public: 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 + ResolveTransientStyle(dom::Element* aElement, + mozilla::CSSPseudoElementType aPseudoType); + // aFlags is an nsStyleSet flags bitfield already_AddRefed ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext, diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 6b619a084e54..318c5ad0f244 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -492,13 +492,6 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement, // No frame has been created, or we have a pseudo, or we're looking // for the default style, so resolve the style ourselves. - RefPtr 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) @@ -506,13 +499,35 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement, StyleSetHandle styleSet = presShell->StyleSet(); - RefPtr sc; + auto type = CSSPseudoElementType::NotPseudo; if (aPseudo) { CSSPseudoElementType 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 sc; + RefPtr 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; @@ -524,11 +539,6 @@ nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement, } 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 > rules; for (nsRuleNode* ruleNode = sc->RuleNode();