1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "nsIDOMCSSStyleDeclaration.h"
9 #include "nsIDOMDocumentXBL.h"
10 #include "nsIObserver.h"
11 #include "nsIXSLTProcessor.h"
12 #include "nsSyncLoadService.h"
13 #include "nsPIDOMWindow.h"
14 #include "nsIDOMElement.h"
15 #include "nsIDOMDocument.h"
16 #include "nsIServiceManager.h"
17 #include "nsNetUtil.h"
18 #include "mozilla/dom/Element.h"
19 #include "nsIDOMDocumentFragment.h"
20 #include "nsBindingManager.h"
21 #include "nsXBLService.h"
22 #include "nsIScriptSecurityManager.h"
23 #include "mozilla/Preferences.h"
24 #include "nsIDocument.h"
25 #include "nsVariant.h"
26 #include "nsIDOMCustomEvent.h"
28 using namespace mozilla
;
29 using namespace mozilla::dom
;
31 NS_IMPL_ISUPPORTS(nsXMLPrettyPrinter
,
35 nsXMLPrettyPrinter::nsXMLPrettyPrinter() : mDocument(nullptr),
40 nsXMLPrettyPrinter::~nsXMLPrettyPrinter()
42 NS_ASSERTION(!mDocument
, "we shouldn't be referencing the document still");
46 nsXMLPrettyPrinter::PrettyPrint(nsIDocument
* aDocument
,
47 bool* aDidPrettyPrint
)
49 *aDidPrettyPrint
= false;
51 // Check for iframe with display:none. Such iframes don't have presshells
52 if (!aDocument
->GetShell()) {
56 // check if we're in an invisible iframe
57 nsPIDOMWindow
*internalWin
= aDocument
->GetWindow();
58 nsCOMPtr
<nsIDOMElement
> frameElem
;
60 internalWin
->GetFrameElement(getter_AddRefs(frameElem
));
64 nsCOMPtr
<nsIDOMCSSStyleDeclaration
> computedStyle
;
65 nsCOMPtr
<nsIDOMDocument
> frameOwnerDoc
;
66 frameElem
->GetOwnerDocument(getter_AddRefs(frameOwnerDoc
));
68 nsCOMPtr
<nsIDOMWindow
> window
;
69 frameOwnerDoc
->GetDefaultView(getter_AddRefs(window
));
71 window
->GetComputedStyle(frameElem
,
73 getter_AddRefs(computedStyle
));
78 nsAutoString visibility
;
79 computedStyle
->GetPropertyValue(NS_LITERAL_STRING("visibility"),
81 if (!visibility
.EqualsLiteral("visible")) {
89 if (!Preferences::GetBool("layout.xml.prettyprint", true)) {
93 // Ok, we should prettyprint. Let's do it!
94 *aDidPrettyPrint
= true;
98 nsCOMPtr
<nsIURI
> xslUri
;
99 rv
= NS_NewURI(getter_AddRefs(xslUri
),
100 NS_LITERAL_CSTRING("chrome://global/content/xml/XMLPrettyPrint.xsl"));
101 NS_ENSURE_SUCCESS(rv
, rv
);
103 nsCOMPtr
<nsIDOMDocument
> xslDocument
;
104 rv
= nsSyncLoadService::LoadDocument(xslUri
, nullptr, nullptr, true,
105 getter_AddRefs(xslDocument
));
106 NS_ENSURE_SUCCESS(rv
, rv
);
108 // Transform the document
109 nsCOMPtr
<nsIXSLTProcessor
> transformer
=
110 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt", &rv
);
111 NS_ENSURE_SUCCESS(rv
, rv
);
113 rv
= transformer
->ImportStylesheet(xslDocument
);
114 NS_ENSURE_SUCCESS(rv
, rv
);
116 nsCOMPtr
<nsIDOMDocumentFragment
> resultFragment
;
117 nsCOMPtr
<nsIDOMDocument
> sourceDocument
= do_QueryInterface(aDocument
);
118 rv
= transformer
->TransformToFragment(sourceDocument
, sourceDocument
,
119 getter_AddRefs(resultFragment
));
120 NS_ENSURE_SUCCESS(rv
, rv
);
123 // Apply the prettprint XBL binding.
125 // We take some shortcuts here. In particular, we don't bother invoking the
126 // contstructor (since the binding has no constructor), and we don't bother
127 // calling LoadBindingDocument because it's a chrome:// URI and thus will get
128 // sync loaded no matter what.
131 // Grab the XBL service.
132 nsXBLService
* xblService
= nsXBLService::GetInstance();
133 NS_ENSURE_TRUE(xblService
, NS_ERROR_NOT_AVAILABLE
);
135 // Compute the binding URI.
136 nsCOMPtr
<nsIURI
> bindingUri
;
137 rv
= NS_NewURI(getter_AddRefs(bindingUri
),
138 NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint"));
139 NS_ENSURE_SUCCESS(rv
, rv
);
141 // Compute the bound element.
142 nsCOMPtr
<nsIContent
> rootCont
= aDocument
->GetRootElement();
143 NS_ENSURE_TRUE(rootCont
, NS_ERROR_UNEXPECTED
);
145 // Grab the system principal.
146 nsCOMPtr
<nsIPrincipal
> sysPrincipal
;
147 nsContentUtils::GetSecurityManager()->
148 GetSystemPrincipal(getter_AddRefs(sysPrincipal
));
150 // Load the bindings.
151 nsRefPtr
<nsXBLBinding
> unused
;
153 rv
= xblService
->LoadBindings(rootCont
, bindingUri
, sysPrincipal
,
154 getter_AddRefs(unused
), &ignored
);
155 NS_ENSURE_SUCCESS(rv
, rv
);
157 // Fire an event at the bound element to pass it |resultFragment|.
158 nsCOMPtr
<nsIDOMEvent
> domEvent
;
159 rv
= NS_NewDOMCustomEvent(getter_AddRefs(domEvent
), rootCont
,
161 NS_ENSURE_SUCCESS(rv
, rv
);
162 nsCOMPtr
<nsIDOMCustomEvent
> customEvent
= do_QueryInterface(domEvent
);
163 MOZ_ASSERT(customEvent
);
164 nsCOMPtr
<nsIWritableVariant
> resultFragmentVariant
= new nsVariant();
165 rv
= resultFragmentVariant
->SetAsISupports(resultFragment
);
166 MOZ_ASSERT(NS_SUCCEEDED(rv
));
167 rv
= customEvent
->InitCustomEvent(NS_LITERAL_STRING("prettyprint-dom-created"),
168 /* bubbles = */ false, /* cancelable = */ false,
169 /* detail = */ resultFragmentVariant
);
170 NS_ENSURE_SUCCESS(rv
, rv
);
171 customEvent
->SetTrusted(true);
173 rv
= rootCont
->DispatchEvent(domEvent
, &dummy
);
174 NS_ENSURE_SUCCESS(rv
, rv
);
176 // Observe the document so we know when to switch to "normal" view
177 aDocument
->AddObserver(this);
178 mDocument
= aDocument
;
186 nsXMLPrettyPrinter::MaybeUnhook(nsIContent
* aContent
)
188 // If there either aContent is null (the document-node was modified) or
189 // there isn't a binding parent we know it's non-anonymous content.
190 if ((!aContent
|| !aContent
->GetBindingParent()) && !mUnhookPending
) {
191 // Can't blindly to mUnhookPending after AddScriptRunner,
192 // since AddScriptRunner _could_ in theory run us
194 mUnhookPending
= true;
195 nsContentUtils::AddScriptRunner(
196 NS_NewRunnableMethod(this, &nsXMLPrettyPrinter::Unhook
));
201 nsXMLPrettyPrinter::Unhook()
203 mDocument
->RemoveObserver(this);
204 nsCOMPtr
<Element
> element
= mDocument
->GetDocumentElement();
207 mDocument
->BindingManager()->ClearBinding(element
);
216 nsXMLPrettyPrinter::AttributeChanged(nsIDocument
* aDocument
,
218 int32_t aNameSpaceID
,
222 MaybeUnhook(aElement
);
226 nsXMLPrettyPrinter::ContentAppended(nsIDocument
* aDocument
,
227 nsIContent
* aContainer
,
228 nsIContent
* aFirstNewContent
,
229 int32_t aNewIndexInContainer
)
231 MaybeUnhook(aContainer
);
235 nsXMLPrettyPrinter::ContentInserted(nsIDocument
* aDocument
,
236 nsIContent
* aContainer
,
238 int32_t aIndexInContainer
)
240 MaybeUnhook(aContainer
);
244 nsXMLPrettyPrinter::ContentRemoved(nsIDocument
* aDocument
,
245 nsIContent
* aContainer
,
247 int32_t aIndexInContainer
,
248 nsIContent
* aPreviousSibling
)
250 MaybeUnhook(aContainer
);
254 nsXMLPrettyPrinter::NodeWillBeDestroyed(const nsINode
* aNode
)
261 nsresult
NS_NewXMLPrettyPrinter(nsXMLPrettyPrinter
** aPrinter
)
263 *aPrinter
= new nsXMLPrettyPrinter
;
264 NS_ADDREF(*aPrinter
);