1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xml/document/src/nsXMLPrettyPrinter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,267 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsXMLPrettyPrinter.h" 1.10 +#include "nsContentUtils.h" 1.11 +#include "nsIDOMCSSStyleDeclaration.h" 1.12 +#include "nsIDOMDocumentXBL.h" 1.13 +#include "nsIObserver.h" 1.14 +#include "nsIXSLTProcessor.h" 1.15 +#include "nsSyncLoadService.h" 1.16 +#include "nsPIDOMWindow.h" 1.17 +#include "nsIDOMElement.h" 1.18 +#include "nsIDOMDocument.h" 1.19 +#include "nsIServiceManager.h" 1.20 +#include "nsNetUtil.h" 1.21 +#include "mozilla/dom/Element.h" 1.22 +#include "nsIDOMDocumentFragment.h" 1.23 +#include "nsBindingManager.h" 1.24 +#include "nsXBLService.h" 1.25 +#include "nsIScriptSecurityManager.h" 1.26 +#include "mozilla/Preferences.h" 1.27 +#include "nsIDocument.h" 1.28 +#include "nsVariant.h" 1.29 +#include "nsIDOMCustomEvent.h" 1.30 +#include "GeneratedEvents.h" 1.31 + 1.32 +using namespace mozilla; 1.33 +using namespace mozilla::dom; 1.34 + 1.35 +NS_IMPL_ISUPPORTS(nsXMLPrettyPrinter, 1.36 + nsIDocumentObserver, 1.37 + nsIMutationObserver) 1.38 + 1.39 +nsXMLPrettyPrinter::nsXMLPrettyPrinter() : mDocument(nullptr), 1.40 + mUnhookPending(false) 1.41 +{ 1.42 +} 1.43 + 1.44 +nsXMLPrettyPrinter::~nsXMLPrettyPrinter() 1.45 +{ 1.46 + NS_ASSERTION(!mDocument, "we shouldn't be referencing the document still"); 1.47 +} 1.48 + 1.49 +nsresult 1.50 +nsXMLPrettyPrinter::PrettyPrint(nsIDocument* aDocument, 1.51 + bool* aDidPrettyPrint) 1.52 +{ 1.53 + *aDidPrettyPrint = false; 1.54 + 1.55 + // Check for iframe with display:none. Such iframes don't have presshells 1.56 + if (!aDocument->GetShell()) { 1.57 + return NS_OK; 1.58 + } 1.59 + 1.60 + // check if we're in an invisible iframe 1.61 + nsPIDOMWindow *internalWin = aDocument->GetWindow(); 1.62 + nsCOMPtr<nsIDOMElement> frameElem; 1.63 + if (internalWin) { 1.64 + internalWin->GetFrameElement(getter_AddRefs(frameElem)); 1.65 + } 1.66 + 1.67 + if (frameElem) { 1.68 + nsCOMPtr<nsIDOMCSSStyleDeclaration> computedStyle; 1.69 + nsCOMPtr<nsIDOMDocument> frameOwnerDoc; 1.70 + frameElem->GetOwnerDocument(getter_AddRefs(frameOwnerDoc)); 1.71 + if (frameOwnerDoc) { 1.72 + nsCOMPtr<nsIDOMWindow> window; 1.73 + frameOwnerDoc->GetDefaultView(getter_AddRefs(window)); 1.74 + if (window) { 1.75 + window->GetComputedStyle(frameElem, 1.76 + EmptyString(), 1.77 + getter_AddRefs(computedStyle)); 1.78 + } 1.79 + } 1.80 + 1.81 + if (computedStyle) { 1.82 + nsAutoString visibility; 1.83 + computedStyle->GetPropertyValue(NS_LITERAL_STRING("visibility"), 1.84 + visibility); 1.85 + if (!visibility.EqualsLiteral("visible")) { 1.86 + 1.87 + return NS_OK; 1.88 + } 1.89 + } 1.90 + } 1.91 + 1.92 + // check the pref 1.93 + if (!Preferences::GetBool("layout.xml.prettyprint", true)) { 1.94 + return NS_OK; 1.95 + } 1.96 + 1.97 + // Ok, we should prettyprint. Let's do it! 1.98 + *aDidPrettyPrint = true; 1.99 + nsresult rv = NS_OK; 1.100 + 1.101 + // Load the XSLT 1.102 + nsCOMPtr<nsIURI> xslUri; 1.103 + rv = NS_NewURI(getter_AddRefs(xslUri), 1.104 + NS_LITERAL_CSTRING("chrome://global/content/xml/XMLPrettyPrint.xsl")); 1.105 + NS_ENSURE_SUCCESS(rv, rv); 1.106 + 1.107 + nsCOMPtr<nsIDOMDocument> xslDocument; 1.108 + rv = nsSyncLoadService::LoadDocument(xslUri, nullptr, nullptr, true, 1.109 + getter_AddRefs(xslDocument)); 1.110 + NS_ENSURE_SUCCESS(rv, rv); 1.111 + 1.112 + // Transform the document 1.113 + nsCOMPtr<nsIXSLTProcessor> transformer = 1.114 + do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt", &rv); 1.115 + NS_ENSURE_SUCCESS(rv, rv); 1.116 + 1.117 + rv = transformer->ImportStylesheet(xslDocument); 1.118 + NS_ENSURE_SUCCESS(rv, rv); 1.119 + 1.120 + nsCOMPtr<nsIDOMDocumentFragment> resultFragment; 1.121 + nsCOMPtr<nsIDOMDocument> sourceDocument = do_QueryInterface(aDocument); 1.122 + rv = transformer->TransformToFragment(sourceDocument, sourceDocument, 1.123 + getter_AddRefs(resultFragment)); 1.124 + NS_ENSURE_SUCCESS(rv, rv); 1.125 + 1.126 + // 1.127 + // Apply the prettprint XBL binding. 1.128 + // 1.129 + // We take some shortcuts here. In particular, we don't bother invoking the 1.130 + // contstructor (since the binding has no constructor), and we don't bother 1.131 + // calling LoadBindingDocument because it's a chrome:// URI and thus will get 1.132 + // sync loaded no matter what. 1.133 + // 1.134 + 1.135 + // Grab the XBL service. 1.136 + nsXBLService* xblService = nsXBLService::GetInstance(); 1.137 + NS_ENSURE_TRUE(xblService, NS_ERROR_NOT_AVAILABLE); 1.138 + 1.139 + // Compute the binding URI. 1.140 + nsCOMPtr<nsIURI> bindingUri; 1.141 + rv = NS_NewURI(getter_AddRefs(bindingUri), 1.142 + NS_LITERAL_STRING("chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint")); 1.143 + NS_ENSURE_SUCCESS(rv, rv); 1.144 + 1.145 + // Compute the bound element. 1.146 + nsCOMPtr<nsIContent> rootCont = aDocument->GetRootElement(); 1.147 + NS_ENSURE_TRUE(rootCont, NS_ERROR_UNEXPECTED); 1.148 + 1.149 + // Grab the system principal. 1.150 + nsCOMPtr<nsIPrincipal> sysPrincipal; 1.151 + nsContentUtils::GetSecurityManager()-> 1.152 + GetSystemPrincipal(getter_AddRefs(sysPrincipal)); 1.153 + 1.154 + // Load the bindings. 1.155 + nsRefPtr<nsXBLBinding> unused; 1.156 + bool ignored; 1.157 + rv = xblService->LoadBindings(rootCont, bindingUri, sysPrincipal, 1.158 + getter_AddRefs(unused), &ignored); 1.159 + NS_ENSURE_SUCCESS(rv, rv); 1.160 + 1.161 + // Fire an event at the bound element to pass it |resultFragment|. 1.162 + nsCOMPtr<nsIDOMEvent> domEvent; 1.163 + rv = NS_NewDOMCustomEvent(getter_AddRefs(domEvent), rootCont, 1.164 + nullptr, nullptr); 1.165 + NS_ENSURE_SUCCESS(rv, rv); 1.166 + nsCOMPtr<nsIDOMCustomEvent> customEvent = do_QueryInterface(domEvent); 1.167 + MOZ_ASSERT(customEvent); 1.168 + nsCOMPtr<nsIWritableVariant> resultFragmentVariant = new nsVariant(); 1.169 + rv = resultFragmentVariant->SetAsISupports(resultFragment); 1.170 + MOZ_ASSERT(NS_SUCCEEDED(rv)); 1.171 + rv = customEvent->InitCustomEvent(NS_LITERAL_STRING("prettyprint-dom-created"), 1.172 + /* bubbles = */ false, /* cancelable = */ false, 1.173 + /* detail = */ resultFragmentVariant); 1.174 + NS_ENSURE_SUCCESS(rv, rv); 1.175 + customEvent->SetTrusted(true); 1.176 + bool dummy; 1.177 + rv = rootCont->DispatchEvent(domEvent, &dummy); 1.178 + NS_ENSURE_SUCCESS(rv, rv); 1.179 + 1.180 + // Observe the document so we know when to switch to "normal" view 1.181 + aDocument->AddObserver(this); 1.182 + mDocument = aDocument; 1.183 + 1.184 + NS_ADDREF_THIS(); 1.185 + 1.186 + return NS_OK; 1.187 +} 1.188 + 1.189 +void 1.190 +nsXMLPrettyPrinter::MaybeUnhook(nsIContent* aContent) 1.191 +{ 1.192 + // If there either aContent is null (the document-node was modified) or 1.193 + // there isn't a binding parent we know it's non-anonymous content. 1.194 + if ((!aContent || !aContent->GetBindingParent()) && !mUnhookPending) { 1.195 + // Can't blindly to mUnhookPending after AddScriptRunner, 1.196 + // since AddScriptRunner _could_ in theory run us 1.197 + // synchronously 1.198 + mUnhookPending = true; 1.199 + nsContentUtils::AddScriptRunner( 1.200 + NS_NewRunnableMethod(this, &nsXMLPrettyPrinter::Unhook)); 1.201 + } 1.202 +} 1.203 + 1.204 +void 1.205 +nsXMLPrettyPrinter::Unhook() 1.206 +{ 1.207 + mDocument->RemoveObserver(this); 1.208 + nsCOMPtr<Element> element = mDocument->GetDocumentElement(); 1.209 + 1.210 + if (element) { 1.211 + mDocument->BindingManager()->ClearBinding(element); 1.212 + } 1.213 + 1.214 + mDocument = nullptr; 1.215 + 1.216 + NS_RELEASE_THIS(); 1.217 +} 1.218 + 1.219 +void 1.220 +nsXMLPrettyPrinter::AttributeChanged(nsIDocument* aDocument, 1.221 + Element* aElement, 1.222 + int32_t aNameSpaceID, 1.223 + nsIAtom* aAttribute, 1.224 + int32_t aModType) 1.225 +{ 1.226 + MaybeUnhook(aElement); 1.227 +} 1.228 + 1.229 +void 1.230 +nsXMLPrettyPrinter::ContentAppended(nsIDocument* aDocument, 1.231 + nsIContent* aContainer, 1.232 + nsIContent* aFirstNewContent, 1.233 + int32_t aNewIndexInContainer) 1.234 +{ 1.235 + MaybeUnhook(aContainer); 1.236 +} 1.237 + 1.238 +void 1.239 +nsXMLPrettyPrinter::ContentInserted(nsIDocument* aDocument, 1.240 + nsIContent* aContainer, 1.241 + nsIContent* aChild, 1.242 + int32_t aIndexInContainer) 1.243 +{ 1.244 + MaybeUnhook(aContainer); 1.245 +} 1.246 + 1.247 +void 1.248 +nsXMLPrettyPrinter::ContentRemoved(nsIDocument* aDocument, 1.249 + nsIContent* aContainer, 1.250 + nsIContent* aChild, 1.251 + int32_t aIndexInContainer, 1.252 + nsIContent* aPreviousSibling) 1.253 +{ 1.254 + MaybeUnhook(aContainer); 1.255 +} 1.256 + 1.257 +void 1.258 +nsXMLPrettyPrinter::NodeWillBeDestroyed(const nsINode* aNode) 1.259 +{ 1.260 + mDocument = nullptr; 1.261 + NS_RELEASE_THIS(); 1.262 +} 1.263 + 1.264 + 1.265 +nsresult NS_NewXMLPrettyPrinter(nsXMLPrettyPrinter** aPrinter) 1.266 +{ 1.267 + *aPrinter = new nsXMLPrettyPrinter; 1.268 + NS_ADDREF(*aPrinter); 1.269 + return NS_OK; 1.270 +}