Bug 1769952 - Fix running raptor on a Win10-64 VM r=sparky
[gecko.git] / dom / xml / nsXMLPrettyPrinter.cpp
blobc8c941feebf0305ef439838dec02032a8040fafb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsXMLPrettyPrinter.h"
7 #include "nsContentUtils.h"
8 #include "nsICSSDeclaration.h"
9 #include "nsSyncLoadService.h"
10 #include "nsPIDOMWindow.h"
11 #include "nsNetUtil.h"
12 #include "mozilla/dom/Element.h"
13 #include "mozilla/dom/ShadowRoot.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/dom/Document.h"
16 #include "nsVariant.h"
17 #include "mozilla/dom/CustomEvent.h"
18 #include "mozilla/dom/DocumentFragment.h"
19 #include "mozilla/dom/ScriptSettings.h"
20 #include "mozilla/dom/ToJSValue.h"
21 #include "mozilla/dom/txMozillaXSLTProcessor.h"
23 using namespace mozilla;
24 using namespace mozilla::dom;
26 NS_IMPL_ISUPPORTS(nsXMLPrettyPrinter, nsIDocumentObserver, nsIMutationObserver)
28 nsXMLPrettyPrinter::nsXMLPrettyPrinter()
29 : mDocument(nullptr), mUnhookPending(false) {}
31 nsXMLPrettyPrinter::~nsXMLPrettyPrinter() {
32 NS_ASSERTION(!mDocument, "we shouldn't be referencing the document still");
35 nsresult nsXMLPrettyPrinter::PrettyPrint(Document* aDocument,
36 bool* aDidPrettyPrint) {
37 *aDidPrettyPrint = false;
39 // check the pref
40 if (!Preferences::GetBool("layout.xml.prettyprint", true)) {
41 return NS_OK;
44 // Find the root element
45 RefPtr<Element> rootElement = aDocument->GetRootElement();
46 NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED);
48 // nsXMLContentSink should not ask us to pretty print an XML doc that comes
49 // with a CanAttachShadowDOM() == true root element, but just in case:
50 if (rootElement->CanAttachShadowDOM()) {
51 MOZ_DIAGNOSTIC_ASSERT(false, "We shouldn't be getting this root element");
52 return NS_ERROR_UNEXPECTED;
55 // Ok, we should prettyprint. Let's do it!
56 *aDidPrettyPrint = true;
57 nsresult rv = NS_OK;
59 // Load the XSLT
60 nsCOMPtr<nsIURI> xslUri;
61 rv = NS_NewURI(getter_AddRefs(xslUri),
62 "chrome://global/content/xml/XMLPrettyPrint.xsl"_ns);
63 NS_ENSURE_SUCCESS(rv, rv);
65 nsCOMPtr<Document> xslDocument;
66 rv = nsSyncLoadService::LoadDocument(
67 xslUri, nsIContentPolicy::TYPE_XSLT, nsContentUtils::GetSystemPrincipal(),
68 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, nullptr,
69 aDocument->CookieJarSettings(), true, ReferrerPolicy::_empty,
70 getter_AddRefs(xslDocument));
71 NS_ENSURE_SUCCESS(rv, rv);
73 // Transform the document
74 RefPtr<txMozillaXSLTProcessor> transformer = new txMozillaXSLTProcessor();
75 ErrorResult err;
76 transformer->ImportStylesheet(*xslDocument, err);
77 if (NS_WARN_IF(err.Failed())) {
78 return err.StealNSResult();
81 RefPtr<DocumentFragment> resultFragment =
82 transformer->TransformToFragment(*aDocument, *aDocument, err);
83 if (NS_WARN_IF(err.Failed())) {
84 return err.StealNSResult();
87 // Attach an UA Widget Shadow Root on it.
88 rootElement->AttachAndSetUAShadowRoot(Element::NotifyUAWidgetSetup::No);
89 RefPtr<ShadowRoot> shadowRoot = rootElement->GetShadowRoot();
90 MOZ_RELEASE_ASSERT(shadowRoot && shadowRoot->IsUAWidget(),
91 "There should be a UA Shadow Root here.");
93 // Append the document fragment to the shadow dom.
94 shadowRoot->AppendChild(*resultFragment, err);
95 if (NS_WARN_IF(err.Failed())) {
96 return err.StealNSResult();
99 // Observe the document so we know when to switch to "normal" view
100 aDocument->AddObserver(this);
101 mDocument = aDocument;
103 NS_ADDREF_THIS();
105 return NS_OK;
108 void nsXMLPrettyPrinter::MaybeUnhook(nsIContent* aContent) {
109 // If aContent is null, the document-node was modified.
110 // If it is not null but in the shadow tree or the <scrollbar> NACs,
111 // the change was in the generated content, and it should be ignored.
112 bool isGeneratedContent =
113 aContent &&
114 (aContent->IsInNativeAnonymousSubtree() || aContent->IsInShadowTree());
116 if (!isGeneratedContent && !mUnhookPending) {
117 // Can't blindly to mUnhookPending after AddScriptRunner,
118 // since AddScriptRunner _could_ in theory run us
119 // synchronously
120 mUnhookPending = true;
121 nsContentUtils::AddScriptRunner(NewRunnableMethod(
122 "nsXMLPrettyPrinter::Unhook", this, &nsXMLPrettyPrinter::Unhook));
126 void nsXMLPrettyPrinter::Unhook() {
127 mDocument->RemoveObserver(this);
128 nsCOMPtr<Element> element = mDocument->GetDocumentElement();
130 if (element) {
131 // Remove the shadow root
132 element->UnattachShadow();
135 mDocument = nullptr;
137 NS_RELEASE_THIS();
140 void nsXMLPrettyPrinter::AttributeChanged(Element* aElement,
141 int32_t aNameSpaceID,
142 nsAtom* aAttribute, int32_t aModType,
143 const nsAttrValue* aOldValue) {
144 MaybeUnhook(aElement);
147 void nsXMLPrettyPrinter::ContentAppended(nsIContent* aFirstNewContent) {
148 MaybeUnhook(aFirstNewContent->GetParent());
151 void nsXMLPrettyPrinter::ContentInserted(nsIContent* aChild) {
152 MaybeUnhook(aChild->GetParent());
155 void nsXMLPrettyPrinter::ContentRemoved(nsIContent* aChild,
156 nsIContent* aPreviousSibling) {
157 MaybeUnhook(aChild->GetParent());
160 void nsXMLPrettyPrinter::NodeWillBeDestroyed(const nsINode* aNode) {
161 mDocument = nullptr;
162 NS_RELEASE_THIS();
165 nsresult NS_NewXMLPrettyPrinter(nsXMLPrettyPrinter** aPrinter) {
166 *aPrinter = new nsXMLPrettyPrinter;
167 NS_ADDREF(*aPrinter);
168 return NS_OK;