summaryrefslogtreecommitdiffstats
path: root/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xslt/xslt/txMozillaStylesheetCompiler.cpp')
-rw-r--r--dom/xslt/xslt/txMozillaStylesheetCompiler.cpp622
1 files changed, 622 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
new file mode 100644
index 0000000000..252347492d
--- /dev/null
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -0,0 +1,622 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsIAuthPrompt.h"
+#include "mozilla/dom/Document.h"
+#include "nsIExpatSink.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsILoadGroup.h"
+#include "nsParser.h"
+#include "nsCharsetSource.h"
+#include "nsIRequestObserver.h"
+#include "nsContentPolicyUtils.h"
+#include "nsIStreamConverterService.h"
+#include "nsSyncLoadService.h"
+#include "nsIHttpChannel.h"
+#include "nsIURI.h"
+#include "nsIPrincipal.h"
+#include "nsIWindowWatcher.h"
+#include "nsIXMLContentSink.h"
+#include "nsMimeTypes.h"
+#include "nsNetUtil.h"
+#include "nsGkAtoms.h"
+#include "txLog.h"
+#include "txMozillaXSLTProcessor.h"
+#include "txStylesheetCompiler.h"
+#include "txXMLUtils.h"
+#include "nsAttrName.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIScriptError.h"
+#include "nsError.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/Text.h"
+#include "mozilla/Encoding.h"
+#include "mozilla/UniquePtr.h"
+#include "ReferrerInfo.h"
+
+using namespace mozilla;
+using mozilla::dom::Document;
+using mozilla::dom::ReferrerPolicy;
+
+static void getSpec(nsIChannel* aChannel, nsAString& aSpec) {
+ if (!aChannel) {
+ return;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ aChannel->GetOriginalURI(getter_AddRefs(uri));
+ if (!uri) {
+ return;
+ }
+
+ nsAutoCString spec;
+ uri->GetSpec(spec);
+ AppendUTF8toUTF16(spec, aSpec);
+}
+
+class txStylesheetSink final : public nsIXMLContentSink,
+ public nsIExpatSink,
+ public nsIStreamListener,
+ public nsIInterfaceRequestor {
+ public:
+ txStylesheetSink(txStylesheetCompiler* aCompiler, nsParser* aParser);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIEXPATSINK
+ NS_DECL_NSISTREAMLISTENER
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ // nsIContentSink
+ NS_IMETHOD WillParse(void) override { return NS_OK; }
+ NS_IMETHOD DidBuildModel(bool aTerminated) override;
+ NS_IMETHOD WillInterrupt(void) override { return NS_OK; }
+ void WillResume() override {}
+ NS_IMETHOD SetParser(nsParserBase* aParser) override { return NS_OK; }
+ virtual void FlushPendingNotifications(mozilla::FlushType aType) override {}
+ virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override {
+ }
+ virtual nsISupports* GetTarget() override { return nullptr; }
+
+ private:
+ RefPtr<txStylesheetCompiler> mCompiler;
+ nsCOMPtr<nsIStreamListener> mListener;
+ RefPtr<nsParser> mParser;
+ bool mCheckedForXML;
+
+ protected:
+ ~txStylesheetSink() = default;
+
+ // This exists solely to suppress a warning from nsDerivedSafe
+ txStylesheetSink();
+};
+
+txStylesheetSink::txStylesheetSink(txStylesheetCompiler* aCompiler,
+ nsParser* aParser)
+ : mCompiler(aCompiler),
+ mListener(aParser),
+ mParser(aParser),
+ mCheckedForXML(false) {}
+
+NS_IMPL_ISUPPORTS(txStylesheetSink, nsIXMLContentSink, nsIContentSink,
+ nsIExpatSink, nsIStreamListener, nsIRequestObserver,
+ nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+txStylesheetSink::HandleStartElement(const char16_t* aName,
+ const char16_t** aAtts,
+ uint32_t aAttsCount, uint32_t aLineNumber,
+ uint32_t aColumnNumber) {
+ MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
+
+ nsresult rv = mCompiler->startElement(aName, aAtts, aAttsCount / 2);
+ if (NS_FAILED(rv)) {
+ mCompiler->cancel(rv);
+
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::HandleEndElement(const char16_t* aName) {
+ nsresult rv = mCompiler->endElement();
+ if (NS_FAILED(rv)) {
+ mCompiler->cancel(rv);
+
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::HandleComment(const char16_t* aName) { return NS_OK; }
+
+NS_IMETHODIMP
+txStylesheetSink::HandleCDataSection(const char16_t* aData, uint32_t aLength) {
+ return HandleCharacterData(aData, aLength);
+}
+
+NS_IMETHODIMP
+txStylesheetSink::HandleDoctypeDecl(const nsAString& aSubset,
+ const nsAString& aName,
+ const nsAString& aSystemId,
+ const nsAString& aPublicId,
+ nsISupports* aCatalogData) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::HandleCharacterData(const char16_t* aData, uint32_t aLength) {
+ nsresult rv = mCompiler->characters(Substring(aData, aData + aLength));
+ if (NS_FAILED(rv)) {
+ mCompiler->cancel(rv);
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::HandleProcessingInstruction(const char16_t* aTarget,
+ const char16_t* aData) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::HandleXMLDeclaration(const char16_t* aVersion,
+ const char16_t* aEncoding,
+ int32_t aStandalone) {
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::ReportError(const char16_t* aErrorText,
+ const char16_t* aSourceText,
+ nsIScriptError* aError, bool* _retval) {
+ MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!");
+
+ // The expat driver should report the error.
+ *_retval = true;
+
+ mCompiler->cancel(NS_ERROR_FAILURE, aErrorText, aSourceText);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::DidBuildModel(bool aTerminated) {
+ return mCompiler->doneLoading();
+}
+
+NS_IMETHODIMP
+txStylesheetSink::OnDataAvailable(nsIRequest* aRequest,
+ nsIInputStream* aInputStream,
+ uint64_t aOffset, uint32_t aCount) {
+ if (!mCheckedForXML) {
+ Maybe<bool> isForXML = mParser->IsForParsingXML();
+ mCheckedForXML = isForXML.isSome();
+ if (mCheckedForXML && !isForXML.value()) {
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+ nsAutoString spec;
+ getSpec(channel, spec);
+ mCompiler->cancel(NS_ERROR_XSLT_WRONG_MIME_TYPE, nullptr, spec.get());
+
+ return NS_ERROR_XSLT_WRONG_MIME_TYPE;
+ }
+ }
+
+ return mListener->OnDataAvailable(aRequest, aInputStream, aOffset, aCount);
+}
+
+NS_IMETHODIMP
+txStylesheetSink::OnStartRequest(nsIRequest* aRequest) {
+ int32_t charsetSource = kCharsetFromDocTypeDefault;
+
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+
+ // check channel's charset...
+ const Encoding* encoding = nullptr;
+ nsAutoCString charsetVal;
+ if (NS_SUCCEEDED(channel->GetContentCharset(charsetVal))) {
+ encoding = Encoding::ForLabel(charsetVal);
+ if (encoding) {
+ charsetSource = kCharsetFromChannel;
+ }
+ }
+
+ if (!encoding) {
+ encoding = UTF_8_ENCODING;
+ }
+
+ mParser->SetDocumentCharset(WrapNotNull(encoding), charsetSource, false);
+
+ nsAutoCString contentType;
+ channel->GetContentType(contentType);
+
+ // Time to sniff! Note: this should go away once file channels do
+ // sniffing themselves.
+ nsCOMPtr<nsIURI> uri;
+ channel->GetURI(getter_AddRefs(uri));
+ if (uri->SchemeIs("file") &&
+ contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
+ nsresult rv;
+ nsCOMPtr<nsIStreamConverterService> serv =
+ do_GetService("@mozilla.org/streamConverters;1", &rv);
+ if (NS_SUCCEEDED(rv)) {
+ nsCOMPtr<nsIStreamListener> converter;
+ rv = serv->AsyncConvertData(UNKNOWN_CONTENT_TYPE, "*/*", mListener,
+ NS_ISUPPORTS_CAST(nsIParser*, mParser),
+ getter_AddRefs(converter));
+ if (NS_SUCCEEDED(rv)) {
+ mListener = converter;
+ }
+ }
+ }
+
+ return mListener->OnStartRequest(aRequest);
+}
+
+NS_IMETHODIMP
+txStylesheetSink::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
+ bool success = true;
+
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
+ if (httpChannel) {
+ Unused << httpChannel->GetRequestSucceeded(&success);
+ }
+
+ nsresult result = aStatusCode;
+ if (!success) {
+ // XXX We sometimes want to use aStatusCode here, but the parser resets
+ // it to NS_ERROR_NOINTERFACE because we don't implement
+ // nsIHTMLContentSink.
+ result = NS_ERROR_XSLT_NETWORK_ERROR;
+ } else if (!mCheckedForXML) {
+ Maybe<bool> isForXML = mParser->IsForParsingXML();
+ if (isForXML.isSome() && !isForXML.value()) {
+ result = NS_ERROR_XSLT_WRONG_MIME_TYPE;
+ }
+ }
+
+ if (NS_FAILED(result)) {
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
+ nsAutoString spec;
+ getSpec(channel, spec);
+ mCompiler->cancel(result, nullptr, spec.get());
+ }
+
+ nsresult rv = mListener->OnStopRequest(aRequest, aStatusCode);
+ mListener = nullptr;
+ mParser = nullptr;
+ return rv;
+}
+
+NS_IMETHODIMP
+txStylesheetSink::GetInterface(const nsIID& aIID, void** aResult) {
+ if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) {
+ NS_ENSURE_ARG(aResult);
+ *aResult = nullptr;
+
+ nsresult rv;
+ nsCOMPtr<nsIWindowWatcher> wwatcher =
+ do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIAuthPrompt> prompt;
+ rv = wwatcher->GetNewAuthPrompter(nullptr, getter_AddRefs(prompt));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ prompt.forget(aResult);
+
+ return NS_OK;
+ }
+
+ return NS_ERROR_NO_INTERFACE;
+}
+
+class txCompileObserver final : public txACompileObserver {
+ public:
+ txCompileObserver(txMozillaXSLTProcessor* aProcessor,
+ Document* aLoaderDocument);
+
+ TX_DECL_ACOMPILEOBSERVER
+ NS_INLINE_DECL_REFCOUNTING(txCompileObserver, override)
+
+ nsresult startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler,
+ nsIPrincipal* aSourcePrincipal,
+ ReferrerPolicy aReferrerPolicy);
+
+ private:
+ RefPtr<txMozillaXSLTProcessor> mProcessor;
+ nsCOMPtr<Document> mLoaderDocument;
+
+ // This exists solely to suppress a warning from nsDerivedSafe
+ txCompileObserver();
+
+ // Private destructor, to discourage deletion outside of Release():
+ ~txCompileObserver() = default;
+};
+
+txCompileObserver::txCompileObserver(txMozillaXSLTProcessor* aProcessor,
+ Document* aLoaderDocument)
+ : mProcessor(aProcessor), mLoaderDocument(aLoaderDocument) {}
+
+nsresult txCompileObserver::loadURI(const nsAString& aUri,
+ const nsAString& aReferrerUri,
+ ReferrerPolicy aReferrerPolicy,
+ txStylesheetCompiler* aCompiler) {
+ if (mProcessor->IsLoadDisabled()) {
+ return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURI> referrerUri;
+ rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ OriginAttributes attrs;
+ nsCOMPtr<nsIPrincipal> referrerPrincipal =
+ BasePrincipal::CreateContentPrincipal(referrerUri, attrs);
+ NS_ENSURE_TRUE(referrerPrincipal, NS_ERROR_FAILURE);
+
+ return startLoad(uri, aCompiler, referrerPrincipal, aReferrerPolicy);
+}
+
+void txCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
+ nsresult aResult,
+ const char16_t* aErrorText,
+ const char16_t* aParam) {
+ if (NS_SUCCEEDED(aResult)) {
+ mProcessor->setStylesheet(aCompiler->getStylesheet());
+ } else {
+ mProcessor->reportError(aResult, aErrorText, aParam);
+ }
+}
+
+nsresult txCompileObserver::startLoad(nsIURI* aUri,
+ txStylesheetCompiler* aCompiler,
+ nsIPrincipal* aReferrerPrincipal,
+ ReferrerPolicy aReferrerPolicy) {
+ nsCOMPtr<nsILoadGroup> loadGroup = mLoaderDocument->GetDocumentLoadGroup();
+ if (!loadGroup) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsIChannel> channel;
+ nsresult rv = NS_NewChannelWithTriggeringPrincipal(
+ getter_AddRefs(channel), aUri, mLoaderDocument,
+ aReferrerPrincipal, // triggeringPrincipal
+ nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT,
+ nsIContentPolicy::TYPE_XSLT,
+ nullptr, // aPerformanceStorage
+ loadGroup);
+
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ channel->SetContentType("text/xml"_ns);
+
+ nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
+ if (httpChannel) {
+ nsCOMPtr<nsIReferrerInfo> referrerInfo;
+ nsresult rv = aReferrerPrincipal->CreateReferrerInfo(
+ aReferrerPolicy, getter_AddRefs(referrerInfo));
+ if (NS_SUCCEEDED(rv)) {
+ rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ }
+ }
+
+ RefPtr<nsParser> parser = new nsParser();
+ RefPtr<txStylesheetSink> sink = new txStylesheetSink(aCompiler, parser);
+
+ channel->SetNotificationCallbacks(sink);
+
+ parser->SetCommand(kLoadAsData);
+ parser->SetContentSink(sink);
+ parser->Parse(aUri);
+
+ return channel->AsyncOpen(sink);
+}
+
+nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor,
+ Document* aLoaderDocument,
+ ReferrerPolicy aReferrerPolicy) {
+ nsIPrincipal* principal = aLoaderDocument->NodePrincipal();
+
+ nsAutoCString spec;
+ aUri->GetSpec(spec);
+ MOZ_LOG(txLog::xslt, LogLevel::Info, ("TX_LoadSheet: %s\n", spec.get()));
+
+ RefPtr<txCompileObserver> observer =
+ new txCompileObserver(aProcessor, aLoaderDocument);
+
+ RefPtr<txStylesheetCompiler> compiler = new txStylesheetCompiler(
+ NS_ConvertUTF8toUTF16(spec), aReferrerPolicy, observer);
+
+ return observer->startLoad(aUri, compiler, principal, aReferrerPolicy);
+}
+
+/**
+ * handling DOM->txStylesheet
+ * Observer needs to do synchronous loads.
+ */
+static nsresult handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) {
+ nsresult rv = NS_OK;
+
+ if (aNode->IsElement()) {
+ dom::Element* element = aNode->AsElement();
+
+ uint32_t attsCount = element->GetAttrCount();
+ UniquePtr<txStylesheetAttr[]> atts;
+ if (attsCount > 0) {
+ atts = MakeUnique<txStylesheetAttr[]>(attsCount);
+ uint32_t counter;
+ for (counter = 0; counter < attsCount; ++counter) {
+ txStylesheetAttr& att = atts[counter];
+ const nsAttrName* name = element->GetAttrNameAt(counter);
+ att.mNamespaceID = name->NamespaceID();
+ att.mLocalName = name->LocalName();
+ att.mPrefix = name->GetPrefix();
+ element->GetAttr(att.mNamespaceID, att.mLocalName, att.mValue);
+ }
+ }
+
+ mozilla::dom::NodeInfo* ni = element->NodeInfo();
+
+ rv = aCompiler->startElement(ni->NamespaceID(), ni->NameAtom(),
+ ni->GetPrefixAtom(), atts.get(), attsCount);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // explicitly destroy the attrs here since we no longer need it
+ atts = nullptr;
+
+ for (nsIContent* child = element->GetFirstChild(); child;
+ child = child->GetNextSibling()) {
+ rv = handleNode(child, aCompiler);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ rv = aCompiler->endElement();
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (dom::Text* text = aNode->GetAsText()) {
+ nsAutoString chars;
+ text->AppendTextTo(chars);
+ rv = aCompiler->characters(chars);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (aNode->IsDocument()) {
+ for (nsIContent* child = aNode->GetFirstChild(); child;
+ child = child->GetNextSibling()) {
+ rv = handleNode(child, aCompiler);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ return NS_OK;
+}
+
+class txSyncCompileObserver final : public txACompileObserver {
+ public:
+ explicit txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor);
+
+ TX_DECL_ACOMPILEOBSERVER
+ NS_INLINE_DECL_REFCOUNTING(txSyncCompileObserver, override)
+
+ private:
+ // Private destructor, to discourage deletion outside of Release():
+ ~txSyncCompileObserver() = default;
+
+ RefPtr<txMozillaXSLTProcessor> mProcessor;
+};
+
+txSyncCompileObserver::txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor)
+ : mProcessor(aProcessor) {}
+
+nsresult txSyncCompileObserver::loadURI(const nsAString& aUri,
+ const nsAString& aReferrerUri,
+ ReferrerPolicy aReferrerPolicy,
+ txStylesheetCompiler* aCompiler) {
+ if (mProcessor->IsLoadDisabled()) {
+ return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR;
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURI> referrerUri;
+ rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIPrincipal> referrerPrincipal =
+ BasePrincipal::CreateContentPrincipal(referrerUri, OriginAttributes());
+ NS_ENSURE_TRUE(referrerPrincipal, NS_ERROR_FAILURE);
+
+ // This is probably called by js, a loadGroup for the channel doesn't
+ // make sense.
+ nsCOMPtr<nsINode> source;
+ if (mProcessor) {
+ source = mProcessor->GetSourceContentModel();
+ }
+ dom::nsAutoSyncOperation sync(source ? source->OwnerDoc() : nullptr,
+ dom::SyncOperationBehavior::eSuspendInput);
+ nsCOMPtr<Document> document;
+
+ rv = nsSyncLoadService::LoadDocument(
+ uri, nsIContentPolicy::TYPE_XSLT, referrerPrincipal,
+ nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT, nullptr,
+ source ? source->OwnerDoc()->CookieJarSettings() : nullptr, false,
+ aReferrerPolicy, getter_AddRefs(document));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = handleNode(document, aCompiler);
+ if (NS_FAILED(rv)) {
+ nsAutoCString spec;
+ uri->GetSpec(spec);
+ aCompiler->cancel(rv, nullptr, NS_ConvertUTF8toUTF16(spec).get());
+ return rv;
+ }
+
+ rv = aCompiler->doneLoading();
+ return rv;
+}
+
+void txSyncCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler,
+ nsresult aResult,
+ const char16_t* aErrorText,
+ const char16_t* aParam) {}
+
+nsresult TX_CompileStylesheet(nsINode* aNode,
+ txMozillaXSLTProcessor* aProcessor,
+ txStylesheet** aStylesheet) {
+ // If we move GetBaseURI to nsINode this can be simplified.
+ nsCOMPtr<Document> doc = aNode->OwnerDoc();
+
+ nsIURI* nodeBaseURI = aNode->GetBaseURI();
+ NS_ENSURE_TRUE(nodeBaseURI, NS_ERROR_FAILURE);
+
+ nsAutoCString spec;
+ nodeBaseURI->GetSpec(spec);
+ NS_ConvertUTF8toUTF16 baseURI(spec);
+
+ nsIURI* docUri = doc->GetDocumentURI();
+ NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE);
+
+ // We need to remove the ref, a URI with a ref would mean that we have an
+ // embedded stylesheet.
+ nsCOMPtr<nsIURI> uri;
+ NS_GetURIWithoutRef(docUri, getter_AddRefs(uri));
+ NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
+
+ uri->GetSpec(spec);
+ NS_ConvertUTF8toUTF16 stylesheetURI(spec);
+
+ RefPtr<txSyncCompileObserver> obs = new txSyncCompileObserver(aProcessor);
+
+ RefPtr<txStylesheetCompiler> compiler =
+ new txStylesheetCompiler(stylesheetURI, doc->GetReferrerPolicy(), obs);
+
+ compiler->setBaseURI(baseURI);
+
+ nsresult rv = handleNode(aNode, compiler);
+ if (NS_FAILED(rv)) {
+ compiler->cancel(rv);
+ return rv;
+ }
+
+ rv = compiler->doneLoading();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *aStylesheet = compiler->getStylesheet();
+ NS_ADDREF(*aStylesheet);
+
+ return NS_OK;
+}