mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1062578 - Call BindToTree/UnbindFromTree on shadow root children when host is bound/unbound from tree. r=smaug
This commit is contained in:
parent
155b28578a
commit
4e2fd38b32
@ -834,6 +834,13 @@ Element::CreateShadowRoot(ErrorResult& aError)
|
||||
SetShadowRoot(shadowRoot);
|
||||
if (olderShadow) {
|
||||
olderShadow->SetYoungerShadow(shadowRoot);
|
||||
|
||||
// Unbind children of older shadow root because they
|
||||
// are no longer in the composed tree.
|
||||
for (nsIContent* child = olderShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
// xblBinding takes ownership of docInfo.
|
||||
@ -1384,6 +1391,18 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
// Call BindToTree on shadow root children.
|
||||
ShadowRoot* shadowRoot = GetShadowRoot();
|
||||
if (shadowRoot) {
|
||||
for (nsIContent* child = shadowRoot->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
rv = child->BindToTree(nullptr, shadowRoot,
|
||||
shadowRoot->GetBindingParent(),
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
// XXXbz script execution during binding can trigger some of these
|
||||
// postcondition asserts.... But we do want that, since things will
|
||||
// generally be quite broken when that happens.
|
||||
@ -1462,10 +1481,13 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
SetParentIsContent(false);
|
||||
}
|
||||
ClearInDocument();
|
||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// Begin keeping track of our subtree root.
|
||||
SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
|
||||
if (aNullParent || !mParent->IsInShadowTree()) {
|
||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// Begin keeping track of our subtree root.
|
||||
SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
|
||||
}
|
||||
|
||||
if (document) {
|
||||
// Notify XBL- & nsIAnonymousContentCreator-generated
|
||||
@ -1514,7 +1536,9 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
if (clearBindingParent) {
|
||||
slots->mBindingParent = nullptr;
|
||||
}
|
||||
slots->mContainingShadow = nullptr;
|
||||
if (aNullParent || !mParent->IsInShadowTree()) {
|
||||
slots->mContainingShadow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
|
||||
@ -1539,6 +1563,15 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
}
|
||||
|
||||
nsNodeUtils::ParentChainChanged(this);
|
||||
|
||||
// Unbind children of shadow root.
|
||||
ShadowRoot* shadowRoot = GetShadowRoot();
|
||||
if (shadowRoot) {
|
||||
for (nsIContent* child = shadowRoot->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsICSSDeclaration*
|
||||
|
@ -1393,6 +1393,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
|
||||
unbind the child nodes.
|
||||
} */
|
||||
|
||||
// Clear flag here because unlinking slots will clear the
|
||||
// containing shadow root pointer.
|
||||
tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// Unlink any DOM slots of interest.
|
||||
{
|
||||
nsDOMSlots *slots = tmp->GetExistingDOMSlots();
|
||||
|
@ -582,15 +582,20 @@ nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
SetParentIsContent(false);
|
||||
}
|
||||
ClearInDocument();
|
||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// Begin keeping track of our subtree root.
|
||||
SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
|
||||
if (aNullParent || !mParent->IsInShadowTree()) {
|
||||
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||
|
||||
// Begin keeping track of our subtree root.
|
||||
SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
|
||||
}
|
||||
|
||||
nsDataSlots *slots = GetExistingDataSlots();
|
||||
if (slots) {
|
||||
slots->mBindingParent = nullptr;
|
||||
slots->mContainingShadow = nullptr;
|
||||
if (aNullParent || !mParent->IsInShadowTree()) {
|
||||
slots->mContainingShadow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsNodeUtils::ParentChainChanged(this);
|
||||
|
@ -392,7 +392,15 @@ nsINode::GetComposedDocInternal() const
|
||||
|
||||
// Cross ShadowRoot boundary.
|
||||
ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
|
||||
return containingShadow->GetHost()->GetCrossShadowCurrentDoc();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -208,7 +208,8 @@ nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
|
||||
// We remove this stylesheet from the cache to load a new version.
|
||||
nsCOMPtr<nsIContent> thisContent;
|
||||
CallQueryInterface(this, getter_AddRefs(thisContent));
|
||||
nsIDocument* doc = thisContent->GetCrossShadowCurrentDoc();
|
||||
nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
|
||||
thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
|
||||
if (doc && doc->CSSLoader()->GetEnabled() &&
|
||||
mStyleSheet && mStyleSheet->GetOriginalURI()) {
|
||||
doc->CSSLoader()->ObsoleteSheet(mStyleSheet->GetOriginalURI());
|
||||
@ -344,7 +345,8 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = thisContent->GetCrossShadowCurrentDoc();
|
||||
nsCOMPtr<nsIDocument> doc = thisContent->IsInShadowTree() ?
|
||||
thisContent->OwnerDoc() : thisContent->GetUncomposedDoc();
|
||||
if (!doc || !doc->CSSLoader()->GetEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -55,13 +55,15 @@ HTMLContentElement::BindToTree(nsIDocument* aDocument,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow) {
|
||||
if (containingShadow && !oldContainingShadow) {
|
||||
nsINode* parentNode = nsINode::GetParentNode();
|
||||
while (parentNode && parentNode != containingShadow) {
|
||||
if (parentNode->IsElement() &&
|
||||
@ -85,23 +87,20 @@ HTMLContentElement::BindToTree(nsIDocument* aDocument,
|
||||
void
|
||||
HTMLContentElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
if (mIsInsertionPoint) {
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
// Make sure that containingShadow exists, it may have been nulled
|
||||
// during unlinking in which case the ShadowRoot is going away.
|
||||
if (containingShadow) {
|
||||
containingShadow->RemoveInsertionPoint(this);
|
||||
nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
// Remove all the matched nodes now that the
|
||||
// insertion point is no longer an insertion point.
|
||||
ClearMatchedNodes();
|
||||
containingShadow->SetInsertionPointChanged();
|
||||
}
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
|
||||
oldContainingShadow->RemoveInsertionPoint(this);
|
||||
|
||||
// Remove all the matched nodes now that the
|
||||
// insertion point is no longer an insertion point.
|
||||
ClearMatchedNodes();
|
||||
oldContainingShadow->SetInsertionPointChanged();
|
||||
|
||||
mIsInsertionPoint = false;
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -111,13 +111,15 @@ HTMLShadowElement::BindToTree(nsIDocument* aDocument,
|
||||
nsIContent* aBindingParent,
|
||||
bool aCompileEventHandlers)
|
||||
{
|
||||
nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
||||
aBindingParent,
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
if (containingShadow) {
|
||||
if (containingShadow && !oldContainingShadow) {
|
||||
// Keep track of all descendant <shadow> elements in tree order so
|
||||
// that when the current shadow insertion point is removed, the next
|
||||
// one can be found quickly.
|
||||
@ -141,35 +143,58 @@ HTMLShadowElement::BindToTree(nsIDocument* aDocument,
|
||||
containingShadow->SetInsertionPointChanged();
|
||||
}
|
||||
|
||||
if (mIsInsertionPoint && containingShadow) {
|
||||
// Propagate BindToTree calls to projected shadow root children.
|
||||
ShadowRoot* projectedShadow = containingShadow->GetOlderShadow();
|
||||
if (projectedShadow) {
|
||||
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
rv = child->BindToTree(nullptr, projectedShadow,
|
||||
projectedShadow->GetBindingParent(),
|
||||
aCompileEventHandlers);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLShadowElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
if (mIsInsertionPoint) {
|
||||
ShadowRoot* containingShadow = GetContainingShadow();
|
||||
// Make sure that containingShadow exists, it may have been nulled
|
||||
// during unlinking in which case the ShadowRoot is going away.
|
||||
if (containingShadow) {
|
||||
nsTArray<HTMLShadowElement*>& shadowDescendants =
|
||||
containingShadow->ShadowDescendants();
|
||||
shadowDescendants.RemoveElement(this);
|
||||
containingShadow->SetShadowElement(nullptr);
|
||||
nsRefPtr<ShadowRoot> oldContainingShadow = GetContainingShadow();
|
||||
|
||||
// Find the next shadow insertion point.
|
||||
if (shadowDescendants.Length() > 0 &&
|
||||
!IsInFallbackContent(shadowDescendants[0])) {
|
||||
containingShadow->SetShadowElement(shadowDescendants[0]);
|
||||
if (mIsInsertionPoint && oldContainingShadow) {
|
||||
// Propagate UnbindFromTree call to previous projected shadow
|
||||
// root children.
|
||||
ShadowRoot* projectedShadow = oldContainingShadow->GetOlderShadow();
|
||||
if (projectedShadow) {
|
||||
for (nsIContent* child = projectedShadow->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
child->UnbindFromTree(true, false);
|
||||
}
|
||||
|
||||
containingShadow->SetInsertionPointChanged();
|
||||
}
|
||||
|
||||
mIsInsertionPoint = false;
|
||||
}
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
if (oldContainingShadow && !GetContainingShadow() && mIsInsertionPoint) {
|
||||
nsTArray<HTMLShadowElement*>& shadowDescendants =
|
||||
oldContainingShadow->ShadowDescendants();
|
||||
shadowDescendants.RemoveElement(this);
|
||||
oldContainingShadow->SetShadowElement(nullptr);
|
||||
|
||||
// Find the next shadow insertion point.
|
||||
if (shadowDescendants.Length() > 0 &&
|
||||
!IsInFallbackContent(shadowDescendants[0])) {
|
||||
oldContainingShadow->SetShadowElement(shadowDescendants[0]);
|
||||
}
|
||||
|
||||
oldContainingShadow->SetInsertionPointChanged();
|
||||
|
||||
mIsInsertionPoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -156,9 +156,19 @@ HTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
void
|
||||
HTMLStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
|
||||
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.
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(oldDoc, oldShadow);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ support-files =
|
||||
[test_dest_insertion_points.html]
|
||||
[test_dest_insertion_points_shadow.html]
|
||||
[test_fallback_dest_insertion_points.html]
|
||||
[test_detached_style.html]
|
||||
[test_dynamic_content_element_matching.html]
|
||||
[test_document_register.html]
|
||||
[test_document_register_base_queue.html]
|
||||
|
25
dom/tests/mochitest/webcomponents/test_detached_style.html
Normal file
25
dom/tests/mochitest/webcomponents/test_detached_style.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1062578
|
||||
-->
|
||||
<head>
|
||||
<title>Test for creating style in shadow root of host not in document.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="grabme"></div>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1062578">Bug 1062578</a>
|
||||
<script>
|
||||
var host = document.createElement("div");
|
||||
var shadow = host.createShadowRoot();
|
||||
shadow.innerHTML = '<style> #inner { height: 200px; } </style><div id="inner">Hello</div>';
|
||||
|
||||
grabme.appendChild(host);
|
||||
|
||||
var inner = shadow.getElementById("inner");
|
||||
is(getComputedStyle(inner, null).getPropertyValue("height"), "200px", "Style in shadow root should take effect.");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -106,6 +106,7 @@ static const JSClass gPrototypeJSClass = {
|
||||
nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
|
||||
: mMarkedForDeath(false)
|
||||
, mUsingContentXBLScope(false)
|
||||
, mIsShadowRootBinding(false)
|
||||
, mPrototypeBinding(aBinding)
|
||||
{
|
||||
NS_ASSERTION(mPrototypeBinding, "Must have a prototype binding!");
|
||||
@ -117,6 +118,7 @@ nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
|
||||
nsXBLBinding::nsXBLBinding(ShadowRoot* aShadowRoot, nsXBLPrototypeBinding* aBinding)
|
||||
: mMarkedForDeath(false),
|
||||
mUsingContentXBLScope(false),
|
||||
mIsShadowRootBinding(true),
|
||||
mPrototypeBinding(aBinding),
|
||||
mContent(aShadowRoot)
|
||||
{
|
||||
@ -127,7 +129,10 @@ nsXBLBinding::nsXBLBinding(ShadowRoot* aShadowRoot, nsXBLPrototypeBinding* aBind
|
||||
|
||||
nsXBLBinding::~nsXBLBinding(void)
|
||||
{
|
||||
if (mContent) {
|
||||
if (mContent && !mIsShadowRootBinding) {
|
||||
// It is unnecessary to uninstall anonymous content in a shadow tree
|
||||
// because the ShadowRoot itself is a DocumentFragment and does not
|
||||
// need any additional cleanup.
|
||||
nsXBLBinding::UninstallAnonymousContent(mContent->OwnerDoc(), mContent);
|
||||
}
|
||||
nsXBLDocumentInfo* info = mPrototypeBinding->XBLDocumentInfo();
|
||||
@ -139,7 +144,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLBinding)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXBLBinding)
|
||||
// XXX Probably can't unlink mPrototypeBinding->XBLDocumentInfo(), because
|
||||
// mPrototypeBinding is weak.
|
||||
if (tmp->mContent) {
|
||||
if (tmp->mContent && !tmp->mIsShadowRootBinding) {
|
||||
nsXBLBinding::UninstallAnonymousContent(tmp->mContent->OwnerDoc(),
|
||||
tmp->mContent);
|
||||
}
|
||||
@ -234,13 +239,6 @@ void
|
||||
nsXBLBinding::UninstallAnonymousContent(nsIDocument* aDocument,
|
||||
nsIContent* aAnonParent)
|
||||
{
|
||||
if (aAnonParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
|
||||
// It is unnecessary to uninstall anonymous content in a shadow tree
|
||||
// because the ShadowRoot itself is a DocumentFragment and does not
|
||||
// need any additional cleanup.
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
// Hold a strong ref while doing this, just in case.
|
||||
nsCOMPtr<nsIContent> anonParent = aAnonParent;
|
||||
@ -811,7 +809,7 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen
|
||||
|
||||
// Update the anonymous content.
|
||||
// XXXbz why not only for style bindings?
|
||||
if (mContent) {
|
||||
if (mContent && !mIsShadowRootBinding) {
|
||||
nsXBLBinding::UninstallAnonymousContent(aOldDocument, mContent);
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,7 @@ protected:
|
||||
|
||||
bool mMarkedForDeath;
|
||||
bool mUsingContentXBLScope;
|
||||
bool mIsShadowRootBinding;
|
||||
|
||||
nsXBLPrototypeBinding* mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
|
||||
nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
|
||||
|
Loading…
Reference in New Issue
Block a user