diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 68e3b4053b33..26b2cf888eac 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -264,9 +264,23 @@ nsComputedDOMStyle::nsComputedDOMStyle(dom::Element* aElement, nsComputedDOMStyle::~nsComputedDOMStyle() { + ClearStyleContext(); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsComputedDOMStyle, mContent) +NS_IMPL_CYCLE_COLLECTION_CLASS(nsComputedDOMStyle) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsComputedDOMStyle) + tmp->ClearStyleContext(); // remove observer before clearing mContent + NS_IMPL_CYCLE_COLLECTION_UNLINK(mContent) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsComputedDOMStyle) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsComputedDOMStyle) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle) return tmp->IsBlack(); @@ -283,6 +297,7 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END // QueryInterface implementation for nsComputedDOMStyle NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsComputedDOMStyle) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration) @@ -571,13 +586,39 @@ nsComputedDOMStyle::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv aCSSParseEnv.mPrincipal = nullptr; } +void +nsComputedDOMStyle::ClearStyleContext() +{ + if (mResolvedStyleContext) { + mResolvedStyleContext = false; + mContent->RemoveMutationObserver(this); + } + mStyleContext = nullptr; +} + +void +nsComputedDOMStyle::SetResolvedStyleContext(nsRefPtr&& aContext) +{ + if (!mResolvedStyleContext) { + mResolvedStyleContext = true; + mContent->AddMutationObserver(this); + } + mStyleContext = aContext; +} + +void +nsComputedDOMStyle::SetFrameStyleContext(nsStyleContext* aContext) +{ + ClearStyleContext(); + mStyleContext = aContext; +} + void nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) { nsCOMPtr document = do_QueryReferent(mDocumentWeak); if (!document) { - mResolvedStyleContext = false; - mStyleContext = nullptr; + ClearStyleContext(); return; } @@ -595,8 +636,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) mPresShell = document->GetShell(); if (!mPresShell || !mPresShell->GetPresContext()) { - mResolvedStyleContext = false; - mStyleContext = nullptr; + ClearStyleContext(); return; } @@ -632,8 +672,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) "the inner table"); } - mStyleContext = mInnerFrame->StyleContext(); - mResolvedStyleContext = false; + SetFrameStyleContext(mInnerFrame->StyleContext()); NS_ASSERTION(mStyleContext, "Frame without style context?"); } } @@ -661,13 +700,13 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) } #endif // Need to resolve a style context - mStyleContext = + nsRefPtr resolvedStyleContext = nsComputedDOMStyle::GetStyleContextForElement(mContent->AsElement(), mPseudo, mPresShell, mStyleType); - if (!mStyleContext) { - mResolvedStyleContext = false; + if (!resolvedStyleContext) { + ClearStyleContext(); return; } @@ -678,8 +717,7 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush) mPresShell->GetPresContext()->GetRestyleGeneration(), "why should we have flushed style again?"); - mResolvedStyleContext = true; - mStyleContextGeneration = currentGeneration; + SetResolvedStyleContext(Move(resolvedStyleContext)); NS_ASSERTION(mPseudo || !mStyleContext->HasPseudoElementData(), "should not have pseudo-element data"); } @@ -6018,6 +6056,17 @@ nsComputedDOMStyle::DoGetCustomProperty(const nsAString& aPropertyName) return val; } +void +nsComputedDOMStyle::ParentChainChanged(nsIContent* aContent) +{ + NS_ASSERTION(mContent == aContent, "didn't we register mContent?"); + NS_ASSERTION(mResolvedStyleContext, + "should have only registered an observer when " + "mResolvedStyleContext is true"); + + ClearStyleContext(); +} + /* static */ nsComputedStyleMap* nsComputedDOMStyle::GetComputedStyleMap() { diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index b8e40cfc8eec..7808cc5e6550 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -45,6 +45,7 @@ class nsStyleSides; struct nsTimingFunction; class nsComputedDOMStyle final : public nsDOMCSSDeclaration + , public nsStubMutationObserver { public: typedef nsCSSProps::KTableValue KTableValue; @@ -110,6 +111,9 @@ public: static void RegisterPrefChangeCallbacks(); static void UnregisterPrefChangeCallbacks(); + // nsIMutationObserver + NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED + private: virtual ~nsComputedDOMStyle(); @@ -128,6 +132,11 @@ private: void UpdateCurrentStyleSources(bool aNeedsLayoutFlush); void ClearCurrentStyleSources(); + // Helper functions called by UpdateCurrentStyleSources. + void ClearStyleContext(); + void SetResolvedStyleContext(nsRefPtr&& aContext); + void SetFrameStyleContext(nsStyleContext* aContext); + #define STYLE_STRUCT(name_, checkdata_cb_) \ const nsStyle##name_ * Style##name_() { \ return mStyleContext->Style##name_(); \