# HG changeset patch # User Emilio Cobos Alvarez # Date 1516112079 -3600 # Node ID eafefacbfaf926a479848e95e5b28d65f19af12f # Parent 869d8257d00150600658d791ef5d6af32b413410 Bug 1409672: Handle document state changes using the invalidation machinery. r=xidorn MozReview-Commit-ID: EoSMrYPS7dl diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp --- a/dom/xbl/nsBindingManager.cpp +++ b/dom/xbl/nsBindingManager.cpp @@ -1132,25 +1132,8 @@ nsBindingManager::FindNestedSingleInsert if (newParent == parent) { break; } parent = newParent; } return parent; } - -bool -nsBindingManager::AnyBindingHasDocumentStateDependency(EventStates aStateMask) -{ - MOZ_ASSERT(mDocument->IsStyledByServo()); - - bool result = false; - EnumerateBoundContentBindings([&](nsXBLBinding* aBinding) { - ServoStyleSet* styleSet = aBinding->PrototypeBinding()->GetServoStyleSet(); - if (styleSet && styleSet->HasDocumentStateDependency(aStateMask)) { - result = true; - return false; - } - return true; - }); - return result; -} diff --git a/dom/xbl/nsBindingManager.h b/dom/xbl/nsBindingManager.h --- a/dom/xbl/nsBindingManager.h +++ b/dom/xbl/nsBindingManager.h @@ -168,17 +168,21 @@ public: // points and their insertion parents. void ClearInsertionPointsRecursively(nsIContent* aContent); // Called when the document is going away void DropDocumentReference(); nsIContent* FindNestedSingleInsertionPoint(nsIContent* aContainer, bool* aMulti); - bool AnyBindingHasDocumentStateDependency(mozilla::EventStates aStateMask); + // Enumerate each bound content's bindings (including its base bindings) + // in mBoundContentSet. Return false from the callback to stop enumeration. + using BoundContentBindingCallback = std::function; + bool EnumerateBoundContentBindings( + const BoundContentBindingCallback& aCallback) const; protected: nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent); nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult); // Called by ContentAppended and ContentInserted to handle a single child // insertion. aChild must not be null. aContainer may be null. // aAppend is true if this child is being appended, not inserted. @@ -190,24 +194,17 @@ protected: void DoProcessAttachedQueue(); // Post an event to process the attached queue. void PostProcessAttachedQueueEvent(); // Call PostProcessAttachedQueueEvent() on a timer. static void PostPAQEventCallback(nsITimer* aTimer, void* aClosure); - // Enumerate each bound content's bindings (including its base bindings) - // in mBoundContentSet. Return false from the callback to stop enumeration. - using BoundContentBindingCallback = std::function; - bool EnumerateBoundContentBindings( - const BoundContentBindingCallback& aCallback) const; - // MEMBER VARIABLES -protected: // A set of nsIContent that currently have a binding installed. nsAutoPtr > > mBoundContentSet; // A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect // wrapper for JS objects). For XBL bindings that implement XPIDL // interfaces, and that get referred to from C++, this table caches // the XPConnect wrapper for the binding. By caching it, I control // its lifetime, and I prevent a re-wrap of the same script object diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -4268,45 +4268,40 @@ PresShell::ContentStateChanged(nsIDocume if (mDidInitialize) { nsAutoCauseReflowNotifier crNotifier(this); mPresContext->RestyleManager()->ContentStateChanged(aContent, aStateMask); VERIFY_STYLE_TREE; } } void -PresShell::DocumentStatesChanged(nsIDocument* aDocument, - EventStates aStateMask) +PresShell::DocumentStatesChanged(nsIDocument* aDocument, EventStates aStateMask) { NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged"); NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); + MOZ_ASSERT(!aStateMask.IsEmpty()); if (mDidInitialize) { - Element* rootElement = aDocument->GetRootElement(); - bool needRestyle = false; if (mStyleSet->IsServo()) { - needRestyle = rootElement && - (mStyleSet->AsServo()->HasDocumentStateDependency(aStateMask) || - aDocument->BindingManager()-> - AnyBindingHasDocumentStateDependency(aStateMask)); - } else { - needRestyle = mStyleSet->AsGecko()-> - HasDocumentStateDependentStyle(rootElement, aStateMask); - } - if (needRestyle) { - mPresContext->RestyleManager()->PostRestyleEvent(rootElement, - eRestyle_Subtree, - nsChangeHint(0)); - VERIFY_STYLE_TREE; + mStyleSet->AsServo()->InvalidateStyleForDocumentStateChanges(aStateMask); + } else if (Element* rootElement = aDocument->GetRootElement()) { + const bool needRestyle = + mStyleSet->AsGecko()->HasDocumentStateDependentStyle( + rootElement, aStateMask); + if (needRestyle) { + mPresContext->RestyleManager()->PostRestyleEvent(rootElement, + eRestyle_Subtree, + nsChangeHint(0)); + VERIFY_STYLE_TREE; + } } } if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) { - nsIFrame* root = mFrameConstructor->GetRootFrame(); - if (root) { + if (nsIFrame* root = mFrameConstructor->GetRootFrame()) { root->SchedulePaint(); } } } void PresShell::AttributeWillChange(nsIDocument* aDocument, Element* aElement, diff --git a/layout/style/ServoBindingList.h b/layout/style/ServoBindingList.h --- a/layout/style/ServoBindingList.h +++ b/layout/style/ServoBindingList.h @@ -35,16 +35,21 @@ SERVO_BINDING_FUNC(Servo_Element_GetPseu ServoStyleContextStrong, RawGeckoElementBorrowed node, size_t index) SERVO_BINDING_FUNC(Servo_Element_IsDisplayNone, bool, RawGeckoElementBorrowed element) SERVO_BINDING_FUNC(Servo_Element_IsPrimaryStyleReusedViaRuleNode, bool, RawGeckoElementBorrowed element) +SERVO_BINDING_FUNC(Servo_InvalidateStyleForDocStateChanges, + void, + RawGeckoElementBorrowed root, + const nsTArray* sets, + uint64_t aStatesChanged) // Styleset and Stylesheet management SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetContentsStrong, mozilla::css::Loader* loader, mozilla::ServoStyleSheet* gecko_stylesheet, const uint8_t* data, size_t data_len, diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -28,16 +28,17 @@ #include "nsDeviceContext.h" #include "nsHTMLStyleSheet.h" #include "nsIAnonymousContentCreator.h" #include "nsIDocumentInlines.h" #include "nsPrintfCString.h" #include "nsSMILAnimationController.h" #include "nsStyleContext.h" #include "nsStyleSet.h" +#include "nsXBLPrototypeBinding.h" #include "gfxUserFontSet.h" using namespace mozilla; using namespace mozilla::dom; ServoStyleSet* ServoStyleSet::sInServoTraversal = nullptr; #ifdef DEBUG @@ -218,16 +219,53 @@ ServoStyleSet::SetPresContext(nsPresCont if (rulesChanged != OriginFlags(0)) { MarkOriginsDirty(rulesChanged); return true; } return false; } +void +ServoStyleSet::InvalidateStyleForDocumentStateChanges(EventStates aStatesChanged) +{ + MOZ_ASSERT(IsMaster()); + MOZ_ASSERT(mDocument); + MOZ_ASSERT(!aStatesChanged.IsEmpty()); + + nsPresContext* pc = GetPresContext(); + if (!pc) { + return; + } + + Element* root = mDocument->GetRootElement(); + if (!root) { + return; + } + + // TODO(emilio): It may be nicer to just invalidate stuff in a given subtree + // for XBL sheets / shadow DOM. Consider just enumerating bound content + // instead and run invalidation individually, passing mRawSet for the UA / + // User sheets. + AutoTArray styleSets; + styleSets.AppendElement(mRawSet.get()); + // FIXME(emilio): When bug 1425759 is fixed we need to enumerate ShadowRoots + // too. + mDocument->BindingManager()->EnumerateBoundContentBindings( + [&](nsXBLBinding* aBinding) { + if (ServoStyleSet* set = aBinding->PrototypeBinding()->GetServoStyleSet()) { + styleSets.AppendElement(set->RawSet()); + } + return true; + }); + + Servo_InvalidateStyleForDocStateChanges( + root, &styleSets, aStatesChanged.ServoValue()); +} + nsRestyleHint ServoStyleSet::MediumFeaturesChanged(bool aViewportChanged) { bool viewportUnitsUsed = false; bool rulesChanged = MediumFeaturesChangedRules(&viewportUnitsUsed); if (nsPresContext* pc = GetPresContext()) { if (mDocument->BindingManager()->MediumFeaturesChanged(pc)) { diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -141,16 +141,19 @@ public: void RuleAdded(ServoStyleSheet&, css::Rule&); void RuleRemoved(ServoStyleSheet&, css::Rule&); void RuleChanged(ServoStyleSheet& aSheet, css::Rule* aRule); // All the relevant changes are handled in RuleAdded / RuleRemoved / etc, and // the relevant AppendSheet / RemoveSheet... void RecordStyleSheetChange(ServoStyleSheet*, StyleSheet::ChangeType) {} + // Runs style invalidation due to document state changes. + void InvalidateStyleForDocumentStateChanges(EventStates aStatesChanged); + void RecordShadowStyleChange(dom::ShadowRoot* aShadowRoot) { // FIXME(emilio): When we properly support shadow dom we'll need to do // better. MarkOriginsDirty(OriginFlags::All); } bool StyleSheetsHaveChanged() const {