From 9a0a3578e210425b2d56ac35921c2f5d90206983 Mon Sep 17 00:00:00 2001 From: William Chen Date: Mon, 9 Feb 2015 10:01:23 -0800 Subject: [PATCH] Bug 1087460 - Part 1: Make GetComposedDoc() work in UnbindFromTree. r=smaug --- dom/base/Element.cpp | 10 ++++++++-- dom/base/ShadowRoot.cpp | 2 +- dom/base/ShadowRoot.h | 12 ++++++++++++ dom/base/nsGenericDOMDataNode.cpp | 7 +++++-- dom/base/nsINode.cpp | 11 +---------- dom/base/nsINode.h | 8 +++----- dom/html/HTMLShadowElement.cpp | 4 ++++ dom/html/HTMLStyleElement.cpp | 9 ++++----- 8 files changed, 38 insertions(+), 25 deletions(-) diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 0acc25de202..beeb3697447 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -992,6 +992,8 @@ Element::CreateShadowRoot(ErrorResult& aError) nsRefPtr shadowRoot = new ShadowRoot(this, nodeInfo.forget(), protoBinding); + shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc()); + // Replace the old ShadowRoot with the new one and let the old // ShadowRoot know about the younger ShadowRoot because the old // ShadowRoot is projected into the younger ShadowRoot's shadow @@ -1007,6 +1009,8 @@ Element::CreateShadowRoot(ErrorResult& aError) child = child->GetNextSibling()) { child->UnbindFromTree(true, false); } + + olderShadow->SetIsComposedDocParticipant(false); } // xblBinding takes ownership of docInfo. @@ -1578,6 +1582,7 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // Call BindToTree on shadow root children. ShadowRoot* shadowRoot = GetShadowRoot(); if (shadowRoot) { + shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc()); for (nsIContent* child = shadowRoot->GetFirstChild(); child; child = child->GetNextSibling()) { rv = child->BindToTree(nullptr, shadowRoot, @@ -1635,8 +1640,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) // Make sure to unbind this node before doing the kids nsIDocument* document = - HasFlag(NODE_FORCE_XBL_BINDINGS) || IsInShadowTree() ? - OwnerDoc() : GetUncomposedDoc(); + HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc(); if (aNullParent) { if (IsFullScreenAncestor()) { @@ -1756,6 +1760,8 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent) child = child->GetNextSibling()) { child->UnbindFromTree(true, false); } + + shadowRoot->SetIsComposedDocParticipant(false); } } diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp index 7d95d772f4b..1fbdd58f77b 100644 --- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -67,7 +67,7 @@ ShadowRoot::ShadowRoot(nsIContent* aContent, nsXBLPrototypeBinding* aProtoBinding) : DocumentFragment(aNodeInfo), mPoolHost(aContent), mProtoBinding(aProtoBinding), mShadowElement(nullptr), - mInsertionPointChanged(false) + mInsertionPointChanged(false), mIsComposedDocParticipant(false) { SetHost(aContent); diff --git a/dom/base/ShadowRoot.h b/dom/base/ShadowRoot.h index 888aef3a9bf..fd2f807f47e 100644 --- a/dom/base/ShadowRoot.h +++ b/dom/base/ShadowRoot.h @@ -127,6 +127,12 @@ public: Element* Host(); ShadowRoot* GetOlderShadowRoot() { return mOlderShadow; } void StyleSheetChanged(); + + bool IsComposedDocParticipant() { return mIsComposedDocParticipant; } + void SetIsComposedDocParticipant(bool aIsComposedDocParticipant) + { + mIsComposedDocParticipant = aIsComposedDocParticipant; + } protected: virtual ~ShadowRoot(); @@ -171,6 +177,12 @@ protected: // the insertion points. After this flag is set, nodes will be distributed // on the next mutation event. bool mInsertionPointChanged; + + // Flag to indicate whether the descendants of this shadow root are part of the + // composed document. Ideally, we would use a node flag on nodes to + // mark whether it is in the composed document, but we have run out of flags + // so instead we track it here. + bool mIsComposedDocParticipant; }; class ShadowRootStyleSheetList : public StyleSheetList diff --git a/dom/base/nsGenericDOMDataNode.cpp b/dom/base/nsGenericDOMDataNode.cpp index 8dfe9bd6101..53951f11181 100644 --- a/dom/base/nsGenericDOMDataNode.cpp +++ b/dom/base/nsGenericDOMDataNode.cpp @@ -113,6 +113,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode) nsINode::Unlink(tmp); + // Clear flag here because unlinking slots will clear the + // containing shadow root pointer. + tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE); + nsDataSlots *slots = tmp->GetExistingDataSlots(); if (slots) { slots->Unlink(); @@ -562,8 +566,7 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent) NS_REFRAME_IF_WHITESPACE); nsIDocument* document = - HasFlag(NODE_FORCE_XBL_BINDINGS) || IsInShadowTree() ? - OwnerDoc() : GetUncomposedDoc(); + HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetComposedDoc(); if (aNullParent) { if (GetParent()) { diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 3069cc2689d..efa1cd50fb2 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -390,17 +390,8 @@ nsINode::GetComposedDocInternal() const MOZ_ASSERT(HasFlag(NODE_IS_IN_SHADOW_TREE) && IsContent(), "Should only be caled on nodes in the shadow tree."); - // Cross ShadowRoot boundary. ShadowRoot* containingShadow = AsContent()->GetContainingShadow(); - - nsIContent* poolHost = containingShadow->GetPoolHost(); - if (!poolHost) { - // This node is in an older shadow root that does not get projected into - // an insertion point, thus this node can not be in the composed document. - return nullptr; - } - - return poolHost->GetComposedDoc(); + return containingShadow->IsComposedDocParticipant() ? OwnerDoc() : nullptr; } #ifdef DEBUG diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index d38bfc04234..9fd89ef35a5 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -520,11 +520,9 @@ public: } /** - * This method gets the current doc of the node hosting this content - * or the current doc of this content if it is not being hosted. This - * method walks through ShadowRoot boundaries until it reach the host - * that is located in the root of the "tree of trees" (see Shadow DOM - * spec) and returns the current doc for that host. + * This method returns the owner doc if the node is in the + * composed document (as defined in the Shadow DOM spec), otherwise + * it returns null. */ nsIDocument* GetComposedDoc() const { diff --git a/dom/html/HTMLShadowElement.cpp b/dom/html/HTMLShadowElement.cpp index 9084c86eb07..4ae42212c2c 100644 --- a/dom/html/HTMLShadowElement.cpp +++ b/dom/html/HTMLShadowElement.cpp @@ -146,6 +146,8 @@ HTMLShadowElement::BindToTree(nsIDocument* aDocument, // Propagate BindToTree calls to projected shadow root children. ShadowRoot* projectedShadow = containingShadow->GetOlderShadowRoot(); if (projectedShadow) { + projectedShadow->SetIsComposedDocParticipant(IsInComposedDoc()); + for (nsIContent* child = projectedShadow->GetFirstChild(); child; child = child->GetNextSibling()) { rv = child->BindToTree(nullptr, projectedShadow, @@ -173,6 +175,8 @@ HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent) child = child->GetNextSibling()) { child->UnbindFromTree(true, false); } + + projectedShadow->SetIsComposedDocParticipant(false); } } diff --git a/dom/html/HTMLStyleElement.cpp b/dom/html/HTMLStyleElement.cpp index 27e0bf4ccca..605d3896dfd 100644 --- a/dom/html/HTMLStyleElement.cpp +++ b/dom/html/HTMLStyleElement.cpp @@ -157,15 +157,14 @@ void HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent) { nsCOMPtr oldDoc = GetUncomposedDoc(); - nsCOMPtr oldComposedDoc = GetComposedDoc(); ShadowRoot* oldShadow = GetContainingShadow(); nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); - if (GetContainingShadow() && !oldComposedDoc) { - // The style is in a shadow tree and was already not - // in the composed document. Thus the sheet does not - // need to be updated. + if (oldShadow && GetContainingShadow()) { + // The style is in a shadow tree and is still in the + // shadow tree. Thus the sheets in the shadow DOM + // do not need to be updated. return; }