diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 7069d3477b74..d82aaf4afcf1 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1224,6 +1224,16 @@ Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError) return nullptr; } + if (StaticPrefs::dom_webcomponents_shadowdom_report_usage()) { + OwnerDoc()->ReportShadowDOMUsage(); + } + + return AttachShadowWithoutNameChecks(aInit.mMode); +} + +already_AddRefed +Element::AttachShadowWithoutNameChecks(ShadowRootMode aMode) +{ nsAutoScriptBlocker scriptBlocker; RefPtr nodeInfo = @@ -1244,14 +1254,10 @@ Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError) * and mode is init’s mode. */ RefPtr shadowRoot = - new ShadowRoot(this, aInit.mMode, nodeInfo.forget()); + new ShadowRoot(this, aMode, nodeInfo.forget()); shadowRoot->SetIsComposedDocParticipant(IsInComposedDoc()); - if (StaticPrefs::dom_webcomponents_shadowdom_report_usage()) { - OwnerDoc()->ReportShadowDOMUsage(); - } - /** * 5. Set context object’s shadow root to shadow. */ @@ -1263,6 +1269,27 @@ Element::AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError) return shadowRoot.forget(); } +void +Element::UnattachShadow() +{ + if (!GetShadowRoot()) { + return; + } + + nsAutoScriptBlocker scriptBlocker; + + if (nsIDocument* doc = GetComposedDoc()) { + if (nsIPresShell* shell = doc->GetShell()) { + shell->DestroyFramesForAndRestyle(this); + } + } + MOZ_ASSERT(!GetPrimaryFrame()); + + // Simply unhook the shadow root from the element. + MOZ_ASSERT(!GetShadowRoot()->HasSlots(), "Won't work when shadow root has slots!"); + SetShadowRoot(nullptr); +} + void Element::GetAttribute(const nsAString& aName, DOMString& aReturn) { diff --git a/dom/base/Element.h b/dom/base/Element.h index 131965839624..2c443acbf780 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -1263,6 +1263,10 @@ public: // Shadow DOM v1 already_AddRefed AttachShadow(const ShadowRootInit& aInit, ErrorResult& aError); + + already_AddRefed AttachShadowWithoutNameChecks(ShadowRootMode aMode); + void UnattachShadow(); + ShadowRoot* GetShadowRootByMode() const; void SetSlot(const nsAString& aName, ErrorResult& aError); void GetSlot(nsAString& aName); diff --git a/dom/base/ShadowRoot.h b/dom/base/ShadowRoot.h index e3c4489cfee5..fdd9f2edfd3b 100644 --- a/dom/base/ShadowRoot.h +++ b/dom/base/ShadowRoot.h @@ -139,6 +139,7 @@ private: public: void AddSlot(HTMLSlotElement* aSlot); void RemoveSlot(HTMLSlotElement* aSlot); + bool HasSlots() const { return !mSlotMap.IsEmpty(); }; const RawServoAuthorStyles* ServoStyles() const { diff --git a/dom/xml/nsXMLPrettyPrinter.cpp b/dom/xml/nsXMLPrettyPrinter.cpp index 1d2bfd264275..68e4dcca836c 100644 --- a/dom/xml/nsXMLPrettyPrinter.cpp +++ b/dom/xml/nsXMLPrettyPrinter.cpp @@ -124,68 +124,80 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument, return err.StealNSResult(); } - // - // Apply the prettprint XBL binding. - // - // We take some shortcuts here. In particular, we don't bother invoking the - // contstructor (since the binding has no constructor), and we don't bother - // calling LoadBindingDocument because it's a chrome:// URI and thus will get - // sync loaded no matter what. - // - - // Grab the XBL service. - nsXBLService* xblService = nsXBLService::GetInstance(); - NS_ENSURE_TRUE(xblService, NS_ERROR_NOT_AVAILABLE); - - // Compute the binding URI. - nsCOMPtr bindingUri; - rv = NS_NewURI(getter_AddRefs(bindingUri), - NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint")); - NS_ENSURE_SUCCESS(rv, rv); - - // Compute the bound element. + // Find the root element RefPtr rootElement = aDocument->GetRootElement(); NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED); - // Grab the system principal. - nsCOMPtr sysPrincipal; - nsContentUtils::GetSecurityManager()-> - GetSystemPrincipal(getter_AddRefs(sysPrincipal)); + if (nsContentUtils::IsShadowDOMEnabled()) { + // Attach a closed shadow root on it. + RefPtr shadowRoot = + rootElement->AttachShadowWithoutNameChecks(ShadowRootMode::Closed); - // Destroy any existing frames before we unbind anonymous content. - // Note that the shell might be Destroy'ed by now (see bug 1415541). - if (!shell->IsDestroying()) { - shell->DestroyFramesForAndRestyle(rootElement); - } + // Append the document fragment to the shadow dom. + shadowRoot->AppendChild(*resultFragment, err); + if (NS_WARN_IF(err.Failed())) { + return err.StealNSResult(); + } + } else { + // + // Apply the prettprint XBL binding. + // + // We take some shortcuts here. In particular, we don't bother invoking the + // contstructor (since the binding has no constructor), and we don't bother + // calling LoadBindingDocument because it's a chrome:// URI and thus will get + // sync loaded no matter what. + // - // Load the bindings. - RefPtr unused; - bool ignored; - rv = xblService->LoadBindings(rootElement, bindingUri, sysPrincipal, - getter_AddRefs(unused), &ignored); - NS_ENSURE_SUCCESS(rv, rv); + // Grab the XBL service. + nsXBLService* xblService = nsXBLService::GetInstance(); + NS_ENSURE_TRUE(xblService, NS_ERROR_NOT_AVAILABLE); - // Fire an event at the bound element to pass it |resultFragment|. - RefPtr event = - NS_NewDOMCustomEvent(rootElement, nullptr, nullptr); - MOZ_ASSERT(event); - AutoJSAPI jsapi; - if (!jsapi.Init(event->GetParentObject())) { - return NS_ERROR_UNEXPECTED; - } - JSContext* cx = jsapi.cx(); - JS::Rooted detail(cx); - if (!ToJSValue(cx, resultFragment, &detail)) { - return NS_ERROR_UNEXPECTED; - } - event->InitCustomEvent(cx, NS_LITERAL_STRING("prettyprint-dom-created"), - /* bubbles = */ false, /* cancelable = */ false, - detail); + // Compute the binding URI. + nsCOMPtr bindingUri; + rv = NS_NewURI(getter_AddRefs(bindingUri), + NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint")); + NS_ENSURE_SUCCESS(rv, rv); - event->SetTrusted(true); - rootElement->DispatchEvent(*event, err); - if (NS_WARN_IF(err.Failed())) { - return err.StealNSResult(); + // Grab the system principal. + nsCOMPtr sysPrincipal; + nsContentUtils::GetSecurityManager()-> + GetSystemPrincipal(getter_AddRefs(sysPrincipal)); + + // Destroy any existing frames before we unbind anonymous content. + // Note that the shell might be Destroy'ed by now (see bug 1415541). + if (!shell->IsDestroying()) { + shell->DestroyFramesForAndRestyle(rootElement); + } + + // Load the bindings. + RefPtr unused; + bool ignored; + rv = xblService->LoadBindings(rootElement, bindingUri, sysPrincipal, + getter_AddRefs(unused), &ignored); + NS_ENSURE_SUCCESS(rv, rv); + + // Fire an event at the bound element to pass it |resultFragment|. + RefPtr event = + NS_NewDOMCustomEvent(rootElement, nullptr, nullptr); + MOZ_ASSERT(event); + AutoJSAPI jsapi; + if (!jsapi.Init(event->GetParentObject())) { + return NS_ERROR_UNEXPECTED; + } + JSContext* cx = jsapi.cx(); + JS::Rooted detail(cx); + if (!ToJSValue(cx, resultFragment, &detail)) { + return NS_ERROR_UNEXPECTED; + } + event->InitCustomEvent(cx, NS_LITERAL_STRING("prettyprint-dom-created"), + /* bubbles = */ false, /* cancelable = */ false, + detail); + + event->SetTrusted(true); + rootElement->DispatchEvent(*event, err); + if (NS_WARN_IF(err.Failed())) { + return err.StealNSResult(); + } } // Observe the document so we know when to switch to "normal" view @@ -200,9 +212,15 @@ nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument, void nsXMLPrettyPrinter::MaybeUnhook(nsIContent* aContent) { - // If there either aContent is null (the document-node was modified) or - // there isn't a binding parent we know it's non-anonymous content. - if ((!aContent || !aContent->GetBindingParent()) && !mUnhookPending) { + // If aContent is null, the document-node was modified. + // If it is not null but in the shadow tree, the NACs, + // or the XBL binding, the change was in the generated content, and + // it should be ignored. + bool isGeneratedContent = !aContent ? + false : + aContent->GetBindingParent() || aContent->IsInShadowTree(); + + if (!isGeneratedContent && !mUnhookPending) { // Can't blindly to mUnhookPending after AddScriptRunner, // since AddScriptRunner _could_ in theory run us // synchronously @@ -219,6 +237,10 @@ nsXMLPrettyPrinter::Unhook() nsCOMPtr element = mDocument->GetDocumentElement(); if (element) { + // Remove the shadow root + element->UnattachShadow(); + + // Remove the bound XBL binding mDocument->BindingManager()->ClearBinding(element); } diff --git a/dom/xml/nsXMLPrettyPrinter.h b/dom/xml/nsXMLPrettyPrinter.h index 0f1f2f23a8dc..33412bd30d17 100644 --- a/dom/xml/nsXMLPrettyPrinter.h +++ b/dom/xml/nsXMLPrettyPrinter.h @@ -44,7 +44,7 @@ private: /** * Signals for unhooking by setting mUnhookPending if the node changed is - * non-anonymous content. + * not in the shadow root tree nor in anonymous content. * * @param aContent content that has changed */ diff --git a/dom/xml/resources/XMLMonoPrint.css b/dom/xml/resources/XMLMonoPrint.css deleted file mode 100644 index 95875d0e5aa2..000000000000 --- a/dom/xml/resources/XMLMonoPrint.css +++ /dev/null @@ -1,10 +0,0 @@ -@charset "UTF-8"; -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#tree, -.expandable-opening::-moz-list-bullet { - font-family: monospace; - white-space: pre; -} diff --git a/dom/xml/resources/XMLPrettyPrint.xml b/dom/xml/resources/XMLPrettyPrint.xml index 9df399cb58c0..202cdf8343d5 100644 --- a/dom/xml/resources/XMLPrettyPrint.xml +++ b/dom/xml/resources/XMLPrettyPrint.xml @@ -15,7 +15,12 @@ + // and append them to our own. + for (let el of event.detail.childNodes) { + container.appendChild(el); + } ]]> diff --git a/dom/xml/resources/XMLPrettyPrint.xsl b/dom/xml/resources/XMLPrettyPrint.xsl index 9e8580f10f85..a78fe5e12a6a 100644 --- a/dom/xml/resources/XMLPrettyPrint.xsl +++ b/dom/xml/resources/XMLPrettyPrint.xsl @@ -17,16 +17,19 @@ - - -