Bug 1719855 - Take over preventDefaulted infomation for long-tap events to the origin...
[gecko.git] / dom / xml / nsXMLPrettyPrinter.cpp
blob4a386e92fbecf8e48aef4882c449c071fc8b8f5a
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/DocumentL10n.h"
20 #include "mozilla/dom/ScriptSettings.h"
21 #include "mozilla/dom/ToJSValue.h"
22 #include "mozilla/dom/txMozillaXSLTProcessor.h"
24 using namespace mozilla;
25 using namespace mozilla::dom;
27 NS_IMPL_ISUPPORTS(nsXMLPrettyPrinter, nsIDocumentObserver, nsIMutationObserver)
29 nsXMLPrettyPrinter::nsXMLPrettyPrinter()
30 : mDocument(nullptr), mUnhookPending(false) {}
32 nsXMLPrettyPrinter::~nsXMLPrettyPrinter() {
33 NS_ASSERTION(!mDocument, "we shouldn't be referencing the document still");
36 nsresult nsXMLPrettyPrinter::PrettyPrint(Document* aDocument,
37 bool* aDidPrettyPrint) {
38 *aDidPrettyPrint = false;
40 // check the pref
41 if (!Preferences::GetBool("layout.xml.prettyprint", true)) {
42 return NS_OK;
45 // Find the root element
46 RefPtr<Element> rootElement = aDocument->GetRootElement();
47 NS_ENSURE_TRUE(rootElement, NS_ERROR_UNEXPECTED);
49 // nsXMLContentSink should not ask us to pretty print an XML doc that comes
50 // with a CanAttachShadowDOM() == true root element, but just in case:
51 if (rootElement->CanAttachShadowDOM()) {
52 MOZ_DIAGNOSTIC_ASSERT(false, "We shouldn't be getting this root element");
53 return NS_ERROR_UNEXPECTED;
56 // Ok, we should prettyprint. Let's do it!
57 *aDidPrettyPrint = true;
58 nsresult rv = NS_OK;
60 // Load the XSLT
61 nsCOMPtr<nsIURI> xslUri;
62 rv = NS_NewURI(getter_AddRefs(xslUri),
63 "chrome://global/content/xml/XMLPrettyPrint.xsl"_ns);
64 NS_ENSURE_SUCCESS(rv, rv);
66 nsCOMPtr<Document> xslDocument;
67 rv = nsSyncLoadService::LoadDocument(
68 xslUri, nsIContentPolicy::TYPE_XSLT, nsContentUtils::GetSystemPrincipal(),
69 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, nullptr,
70 aDocument->CookieJarSettings(), true, ReferrerPolicy::_empty,
71 getter_AddRefs(xslDocument));
72 NS_ENSURE_SUCCESS(rv, rv);
74 // Transform the document
75 RefPtr<txMozillaXSLTProcessor> transformer = new txMozillaXSLTProcessor();
76 ErrorResult err;
77 transformer->ImportStylesheet(*xslDocument, err);
78 if (NS_WARN_IF(err.Failed())) {
79 return err.StealNSResult();
82 RefPtr<DocumentFragment> resultFragment =
83 transformer->TransformToFragment(*aDocument, *aDocument, err);
84 if (NS_WARN_IF(err.Failed())) {
85 return err.StealNSResult();
88 // Attach an UA Widget Shadow Root on it.
89 rootElement->AttachAndSetUAShadowRoot(Element::NotifyUAWidgetSetup::No);
90 RefPtr<ShadowRoot> shadowRoot = rootElement->GetShadowRoot();
91 MOZ_RELEASE_ASSERT(shadowRoot && shadowRoot->IsUAWidget(),
92 "There should be a UA Shadow Root here.");
94 // Append the document fragment to the shadow dom.
95 shadowRoot->AppendChild(*resultFragment, err);
96 if (NS_WARN_IF(err.Failed())) {
97 return err.StealNSResult();
100 // Create a DocumentL10n, as the XML document is not allowed to have one.
101 // Make it sync so that the test for bug 590812 does not require a setTimeout.
102 RefPtr<DocumentL10n> l10n = DocumentL10n::Create(aDocument, true);
103 NS_ENSURE_TRUE(l10n, NS_ERROR_UNEXPECTED);
104 l10n->AddResourceId("dom/XMLPrettyPrint.ftl"_ns);
106 // Localize the shadow DOM header
107 Element* l10nRoot = shadowRoot->GetElementById(u"header"_ns);
108 NS_ENSURE_TRUE(l10nRoot, NS_ERROR_UNEXPECTED);
109 l10n->SetRootInfo(l10nRoot);
110 l10n->ConnectRoot(*l10nRoot, true, err);
111 if (NS_WARN_IF(err.Failed())) {
112 return err.StealNSResult();
114 RefPtr<Promise> promise = l10n->TranslateRoots(err);
115 if (NS_WARN_IF(err.Failed())) {
116 return err.StealNSResult();
119 // Observe the document so we know when to switch to "normal" view
120 aDocument->AddObserver(this);
121 mDocument = aDocument;
123 NS_ADDREF_THIS();
125 return NS_OK;
128 void nsXMLPrettyPrinter::MaybeUnhook(nsIContent* aContent) {
129 // If aContent is null, the document-node was modified.
130 // If it is not null but in the shadow tree or the <scrollbar> NACs,
131 // the change was in the generated content, and it should be ignored.
132 bool isGeneratedContent =
133 aContent &&
134 (aContent->IsInNativeAnonymousSubtree() || aContent->IsInShadowTree());
136 if (!isGeneratedContent && !mUnhookPending) {
137 // Can't blindly to mUnhookPending after AddScriptRunner,
138 // since AddScriptRunner _could_ in theory run us
139 // synchronously
140 mUnhookPending = true;
141 nsContentUtils::AddScriptRunner(NewRunnableMethod(
142 "nsXMLPrettyPrinter::Unhook", this, &nsXMLPrettyPrinter::Unhook));
146 void nsXMLPrettyPrinter::Unhook() {
147 mDocument->RemoveObserver(this);
148 nsCOMPtr<Element> element = mDocument->GetDocumentElement();
150 if (element) {
151 // Remove the shadow root
152 element->UnattachShadow();
155 mDocument = nullptr;
157 NS_RELEASE_THIS();
160 void nsXMLPrettyPrinter::AttributeChanged(Element* aElement,
161 int32_t aNameSpaceID,
162 nsAtom* aAttribute, int32_t aModType,
163 const nsAttrValue* aOldValue) {
164 MaybeUnhook(aElement);
167 void nsXMLPrettyPrinter::ContentAppended(nsIContent* aFirstNewContent) {
168 MaybeUnhook(aFirstNewContent->GetParent());
171 void nsXMLPrettyPrinter::ContentInserted(nsIContent* aChild) {
172 MaybeUnhook(aChild->GetParent());
175 void nsXMLPrettyPrinter::ContentRemoved(nsIContent* aChild,
176 nsIContent* aPreviousSibling) {
177 MaybeUnhook(aChild->GetParent());
180 void nsXMLPrettyPrinter::NodeWillBeDestroyed(nsINode* aNode) {
181 mDocument = nullptr;
182 NS_RELEASE_THIS();
185 nsresult NS_NewXMLPrettyPrinter(nsXMLPrettyPrinter** aPrinter) {
186 *aPrinter = new nsXMLPrettyPrinter;
187 NS_ADDREF(*aPrinter);
188 return NS_OK;