Bug 1087460 - Part 1: Make GetComposedDoc() work in UnbindFromTree. r=smaug

This commit is contained in:
William Chen 2015-02-09 10:01:23 -08:00
parent 44179aabe3
commit 9a0a3578e2
8 changed files with 38 additions and 25 deletions

View File

@ -992,6 +992,8 @@ Element::CreateShadowRoot(ErrorResult& aError)
nsRefPtr<ShadowRoot> 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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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()) {

View File

@ -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

View File

@ -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
{

View File

@ -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);
}
}

View File

@ -157,15 +157,14 @@ void
HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
nsCOMPtr<nsIDocument> 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;
}