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 "txMozillaXSLTProcessor.h"
8 #include "mozilla/dom/Element.h"
9 #include "mozilla/dom/Document.h"
10 #include "nsIStringBundle.h"
12 #include "XPathResult.h"
13 #include "txExecutionState.h"
14 #include "txMozillaTextOutput.h"
15 #include "txMozillaXMLOutput.h"
16 #include "txURIUtils.h"
17 #include "txXMLUtils.h"
18 #include "txUnknownHandler.h"
19 #include "txXSLTMsgsURL.h"
20 #include "txXSLTProcessor.h"
21 #include "nsIPrincipal.h"
22 #include "nsThreadUtils.h"
24 #include "txExprParser.h"
25 #include "nsJSUtils.h"
26 #include "nsIXPConnect.h"
27 #include "nsNameSpaceManager.h"
28 #include "nsVariant.h"
29 #include "nsTextNode.h"
30 #include "mozilla/Components.h"
31 #include "mozilla/dom/DocumentFragment.h"
32 #include "mozilla/dom/XSLTProcessorBinding.h"
34 using namespace mozilla
;
35 using namespace mozilla::dom
;
38 * Output Handler Factories
40 class txToDocHandlerFactory
: public txAOutputHandlerFactory
{
42 txToDocHandlerFactory(txExecutionState
* aEs
, Document
* aSourceDocument
,
43 nsITransformObserver
* aObserver
, bool aDocumentIsData
)
45 mSourceDocument(aSourceDocument
),
47 mDocumentIsData(aDocumentIsData
) {}
49 TX_DECL_TXAOUTPUTHANDLERFACTORY
52 txExecutionState
* mEs
;
53 nsCOMPtr
<Document
> mSourceDocument
;
54 nsCOMPtr
<nsITransformObserver
> mObserver
;
58 class txToFragmentHandlerFactory
: public txAOutputHandlerFactory
{
60 explicit txToFragmentHandlerFactory(DocumentFragment
* aFragment
)
61 : mFragment(aFragment
) {}
63 TX_DECL_TXAOUTPUTHANDLERFACTORY
66 RefPtr
<DocumentFragment
> mFragment
;
69 nsresult
txToDocHandlerFactory::createHandlerWith(
70 txOutputFormat
* aFormat
, txAXMLEventHandler
** aHandler
) {
72 switch (aFormat
->mMethod
) {
75 *aHandler
= new txUnknownHandler(mEs
);
80 UniquePtr
<txMozillaXMLOutput
> handler(
81 new txMozillaXMLOutput(mSourceDocument
, aFormat
, mObserver
));
83 nsresult rv
= handler
->createResultDocument(
84 u
""_ns
, kNameSpaceID_None
, mSourceDocument
, mDocumentIsData
);
85 if (NS_SUCCEEDED(rv
)) {
86 *aHandler
= handler
.release();
93 UniquePtr
<txMozillaTextOutput
> handler(
94 new txMozillaTextOutput(mSourceDocument
, mObserver
));
96 nsresult rv
= handler
->createResultDocument(mDocumentIsData
);
97 if (NS_SUCCEEDED(rv
)) {
98 *aHandler
= handler
.release();
105 MOZ_CRASH("Unknown output method");
107 return NS_ERROR_FAILURE
;
110 nsresult
txToDocHandlerFactory::createHandlerWith(
111 txOutputFormat
* aFormat
, const nsAString
& aName
, int32_t aNsID
,
112 txAXMLEventHandler
** aHandler
) {
114 switch (aFormat
->mMethod
) {
115 case eMethodNotSet
: {
116 NS_ERROR("How can method not be known when root element is?");
117 return NS_ERROR_UNEXPECTED
;
122 UniquePtr
<txMozillaXMLOutput
> handler(
123 new txMozillaXMLOutput(mSourceDocument
, aFormat
, mObserver
));
125 nsresult rv
= handler
->createResultDocument(aName
, aNsID
, mSourceDocument
,
127 if (NS_SUCCEEDED(rv
)) {
128 *aHandler
= handler
.release();
135 UniquePtr
<txMozillaTextOutput
> handler(
136 new txMozillaTextOutput(mSourceDocument
, mObserver
));
138 nsresult rv
= handler
->createResultDocument(mDocumentIsData
);
139 if (NS_SUCCEEDED(rv
)) {
140 *aHandler
= handler
.release();
147 MOZ_CRASH("Unknown output method");
149 return NS_ERROR_FAILURE
;
152 nsresult
txToFragmentHandlerFactory::createHandlerWith(
153 txOutputFormat
* aFormat
, txAXMLEventHandler
** aHandler
) {
155 switch (aFormat
->mMethod
) {
156 case eMethodNotSet
: {
157 txOutputFormat format
;
158 format
.merge(*aFormat
);
159 nsCOMPtr
<Document
> doc
= mFragment
->OwnerDoc();
161 if (doc
->IsHTMLDocument()) {
162 format
.mMethod
= eHTMLOutput
;
164 format
.mMethod
= eXMLOutput
;
167 *aHandler
= new txMozillaXMLOutput(&format
, mFragment
, false);
173 *aHandler
= new txMozillaXMLOutput(aFormat
, mFragment
, false);
178 *aHandler
= new txMozillaTextOutput(mFragment
);
185 nsresult
txToFragmentHandlerFactory::createHandlerWith(
186 txOutputFormat
* aFormat
, const nsAString
& aName
, int32_t aNsID
,
187 txAXMLEventHandler
** aHandler
) {
189 NS_ASSERTION(aFormat
->mMethod
!= eMethodNotSet
,
190 "How can method not be known when root element is?");
191 NS_ENSURE_TRUE(aFormat
->mMethod
!= eMethodNotSet
, NS_ERROR_UNEXPECTED
);
192 return createHandlerWith(aFormat
, aHandler
);
195 class txVariable
: public txIGlobalParameter
{
196 using XSLTParameterValue
= txMozillaXSLTProcessor::XSLTParameterValue
;
197 using OwningXSLTParameterValue
=
198 txMozillaXSLTProcessor::OwningXSLTParameterValue
;
201 explicit txVariable(UniquePtr
<OwningXSLTParameterValue
>&& aValue
)
202 : mUnionValue(std::move(aValue
)) {}
203 nsresult
getValue(txAExprResult
** aValue
) override
{
205 nsresult rv
= convert(*mUnionValue
, getter_AddRefs(mValue
));
206 NS_ENSURE_SUCCESS(rv
, rv
);
209 NS_ADDREF(*aValue
= mValue
);
213 OwningXSLTParameterValue
getUnionValue() {
214 return OwningXSLTParameterValue(*mUnionValue
);
216 void setValue(UniquePtr
<OwningXSLTParameterValue
>&& aValue
) {
218 mUnionValue
= std::move(aValue
);
221 static UniquePtr
<OwningXSLTParameterValue
> convertToOwning(
222 const XSLTParameterValue
& aValue
, ErrorResult
& aError
);
224 friend void ImplCycleCollectionTraverse(
225 nsCycleCollectionTraversalCallback
& aCallback
, txVariable
& aVariable
,
226 const char* aName
, uint32_t aFlags
);
229 static nsresult
convert(const OwningXSLTParameterValue
& aUnionValue
,
230 txAExprResult
** aValue
);
232 UniquePtr
<OwningXSLTParameterValue
> mUnionValue
;
233 RefPtr
<txAExprResult
> mValue
;
236 inline void ImplCycleCollectionTraverse(
237 nsCycleCollectionTraversalCallback
& aCallback
, txVariable
& aVariable
,
238 const char* aName
, uint32_t aFlags
) {
239 ImplCycleCollectionTraverse(aCallback
, *aVariable
.mUnionValue
, aName
, aFlags
);
242 inline void ImplCycleCollectionUnlink(
243 txOwningExpandedNameMap
<txIGlobalParameter
>& aMap
) {
247 inline void ImplCycleCollectionTraverse(
248 nsCycleCollectionTraversalCallback
& aCallback
,
249 txOwningExpandedNameMap
<txIGlobalParameter
>& aMap
, const char* aName
,
250 uint32_t aFlags
= 0) {
251 aFlags
|= CycleCollectionEdgeNameArrayFlag
;
252 txOwningExpandedNameMap
<txIGlobalParameter
>::iterator
iter(aMap
);
253 while (iter
.next()) {
254 ImplCycleCollectionTraverse(
255 aCallback
, *static_cast<txVariable
*>(iter
.value()), aName
, aFlags
);
260 * txMozillaXSLTProcessor
263 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(txMozillaXSLTProcessor
, mOwner
,
264 mEmbeddedStylesheetRoot
, mSource
,
267 NS_IMPL_CYCLE_COLLECTING_ADDREF(txMozillaXSLTProcessor
)
268 NS_IMPL_CYCLE_COLLECTING_RELEASE(txMozillaXSLTProcessor
)
270 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(txMozillaXSLTProcessor
)
271 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
272 NS_INTERFACE_MAP_ENTRY(nsIDocumentTransformer
)
273 NS_INTERFACE_MAP_ENTRY(nsIMutationObserver
)
274 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDocumentTransformer
)
277 txMozillaXSLTProcessor::txMozillaXSLTProcessor()
279 mStylesheetDocument(nullptr),
280 mTransformResult(NS_OK
),
281 mCompileResult(NS_OK
),
284 txMozillaXSLTProcessor::txMozillaXSLTProcessor(nsISupports
* aOwner
)
286 mStylesheetDocument(nullptr),
287 mTransformResult(NS_OK
),
288 mCompileResult(NS_OK
),
291 txMozillaXSLTProcessor::~txMozillaXSLTProcessor() {
292 if (mStylesheetDocument
) {
293 mStylesheetDocument
->RemoveMutationObserver(this);
298 txMozillaXSLTProcessor::SetTransformObserver(nsITransformObserver
* aObserver
) {
299 mObserver
= aObserver
;
304 txMozillaXSLTProcessor::SetSourceContentModel(nsINode
* aSource
) {
307 if (NS_FAILED(mTransformResult
)) {
313 return DoTransform();
320 txMozillaXSLTProcessor::AddXSLTParamNamespace(const nsString
& aPrefix
,
321 const nsString
& aNamespace
) {
322 RefPtr
<nsAtom
> pre
= NS_Atomize(aPrefix
);
323 return mParamNamespaceMap
.mapNamespace(pre
, aNamespace
);
326 class txXSLTParamContext
: public txIParseContext
, public txIEvalContext
{
328 txXSLTParamContext(txNamespaceMap
* aResolver
, const txXPathNode
& aContext
,
329 txResultRecycler
* aRecycler
)
330 : mResolver(aResolver
), mContext(aContext
), mRecycler(aRecycler
) {}
333 nsresult
resolveNamespacePrefix(nsAtom
* aPrefix
, int32_t& aID
) override
{
334 aID
= mResolver
->lookupNamespace(aPrefix
);
335 return aID
== kNameSpaceID_Unknown
? NS_ERROR_DOM_NAMESPACE_ERR
: NS_OK
;
337 nsresult
resolveFunctionCall(nsAtom
* aName
, int32_t aID
,
338 FunctionCall
** aFunction
) override
{
339 return NS_ERROR_XPATH_UNKNOWN_FUNCTION
;
341 bool caseInsensitiveNameTests() override
{ return false; }
342 void SetErrorOffset(uint32_t aOffset
) override
{}
345 nsresult
getVariable(int32_t aNamespace
, nsAtom
* aLName
,
346 txAExprResult
*& aResult
) override
{
348 return NS_ERROR_INVALID_ARG
;
350 nsresult
isStripSpaceAllowed(const txXPathNode
& aNode
,
351 bool& aAllowed
) override
{
356 void* getPrivateContext() override
{ return nullptr; }
357 txResultRecycler
* recycler() override
{ return mRecycler
; }
358 void receiveError(const nsAString
& aMsg
, nsresult aRes
) override
{}
359 const txXPathNode
& getContextNode() override
{ return mContext
; }
360 uint32_t size() override
{ return 1; }
361 uint32_t position() override
{ return 1; }
364 txNamespaceMap
* mResolver
;
365 const txXPathNode
& mContext
;
366 txResultRecycler
* mRecycler
;
370 txMozillaXSLTProcessor::AddXSLTParam(const nsString
& aName
,
371 const nsString
& aNamespace
,
372 const nsString
& aSelect
,
373 const nsString
& aValue
,
377 if (aSelect
.IsVoid() == aValue
.IsVoid()) {
378 // Ignore if neither or both are specified
379 return NS_ERROR_FAILURE
;
382 RefPtr
<txAExprResult
> value
;
384 if (!aSelect
.IsVoid()) {
386 UniquePtr
<txXPathNode
> contextNode(
387 txXPathNativeNode::createXPathNode(aContext
));
388 NS_ENSURE_TRUE(contextNode
, NS_ERROR_OUT_OF_MEMORY
);
391 mRecycler
= new txResultRecycler
;
394 txXSLTParamContext
paramContext(&mParamNamespaceMap
, *contextNode
,
398 UniquePtr
<Expr
> expr
;
399 rv
= txExprParser::createExpr(aSelect
, ¶mContext
,
400 getter_Transfers(expr
));
401 NS_ENSURE_SUCCESS(rv
, rv
);
404 rv
= expr
->evaluate(¶mContext
, getter_AddRefs(value
));
405 NS_ENSURE_SUCCESS(rv
, rv
);
407 switch (value
->getResultType()) {
408 case txAExprResult::NUMBER
:
409 resultType
= XPathResult::NUMBER_TYPE
;
411 case txAExprResult::STRING
:
412 resultType
= XPathResult::STRING_TYPE
;
414 case txAExprResult::BOOLEAN
:
415 resultType
= XPathResult::BOOLEAN_TYPE
;
417 case txAExprResult::NODESET
:
418 resultType
= XPathResult::UNORDERED_NODE_ITERATOR_TYPE
;
421 MOZ_ASSERT_UNREACHABLE(
422 "We shouldn't have a txAExprResult::RESULT_TREE_FRAGMENT here.");
423 return NS_ERROR_FAILURE
;
426 value
= new StringResult(aValue
, nullptr);
427 resultType
= XPathResult::STRING_TYPE
;
430 RefPtr
<nsAtom
> name
= NS_Atomize(aName
);
431 int32_t nsId
= kNameSpaceID_Unknown
;
432 rv
= nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespace
, nsId
);
433 NS_ENSURE_SUCCESS(rv
, rv
);
435 RefPtr
<XPathResult
> xpathResult
= MakeRefPtr
<XPathResult
>(aContext
);
438 xpathResult
->SetExprResult(value
, resultType
, aContext
, error
);
439 if (error
.Failed()) {
440 return error
.StealNSResult();
443 UniquePtr
<OwningXSLTParameterValue
> varValue
=
444 MakeUnique
<OwningXSLTParameterValue
>();
445 varValue
->SetAsXPathResult() = xpathResult
.forget();
447 txExpandedName
varName(nsId
, name
);
448 txVariable
* var
= static_cast<txVariable
*>(mVariables
.get(varName
));
450 var
->setValue(std::move(varValue
));
455 var
= new txVariable(std::move(varValue
));
457 return mVariables
.add(varName
, var
);
460 class nsTransformBlockerEvent
: public mozilla::Runnable
{
462 RefPtr
<txMozillaXSLTProcessor
> mProcessor
;
464 explicit nsTransformBlockerEvent(txMozillaXSLTProcessor
* processor
)
465 : mozilla::Runnable("nsTransformBlockerEvent"), mProcessor(processor
) {}
467 ~nsTransformBlockerEvent() {
468 nsCOMPtr
<Document
> document
=
469 mProcessor
->GetSourceContentModel()->OwnerDoc();
470 document
->UnblockOnload(true);
473 NS_IMETHOD
Run() override
{
474 mProcessor
->TransformToDoc(nullptr, false);
479 nsresult
txMozillaXSLTProcessor::DoTransform() {
480 NS_ENSURE_TRUE(mSource
, NS_ERROR_UNEXPECTED
);
481 NS_ENSURE_TRUE(mStylesheet
, NS_ERROR_UNEXPECTED
);
482 NS_ASSERTION(mObserver
, "no observer");
483 NS_ASSERTION(NS_IsMainThread(), "should only be on main thread");
485 nsCOMPtr
<nsIRunnable
> event
= new nsTransformBlockerEvent(this);
486 mSource
->OwnerDoc()->BlockOnload();
487 nsresult rv
= NS_DispatchToCurrentThread(event
);
489 // XXX Maybe we should just display the source document in this case?
490 // Also, set up context information, see bug 204655.
491 reportError(rv
, nullptr, nullptr);
497 void txMozillaXSLTProcessor::ImportStylesheet(nsINode
& aStyle
,
498 mozilla::ErrorResult
& aRv
) {
499 // We don't support importing multiple stylesheets yet.
500 if (NS_WARN_IF(mStylesheetDocument
|| mStylesheet
)) {
501 aRv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
505 if (!nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller()->Subsumes(
506 aStyle
.NodePrincipal())) {
507 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
511 if (NS_WARN_IF(!aStyle
.IsElement() && !aStyle
.IsDocument())) {
512 aRv
.Throw(NS_ERROR_INVALID_ARG
);
517 TX_CompileStylesheet(&aStyle
, this, getter_AddRefs(mStylesheet
));
518 // XXX set up exception context, bug 204658
519 if (NS_WARN_IF(NS_FAILED(rv
))) {
524 mStylesheetDocument
= aStyle
.OwnerDoc();
525 if (aStyle
.IsElement()) {
526 mEmbeddedStylesheetRoot
= aStyle
.AsElement();
529 mStylesheetDocument
->AddMutationObserver(this);
532 already_AddRefed
<Document
> txMozillaXSLTProcessor::TransformToDocument(
533 nsINode
& aSource
, ErrorResult
& aRv
) {
534 if (NS_WARN_IF(NS_FAILED(mCompileResult
))) {
535 aRv
.Throw(mCompileResult
);
539 if (!nsContentUtils::CanCallerAccess(&aSource
)) {
540 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
544 nsresult rv
= ensureStylesheet();
545 if (NS_WARN_IF(NS_FAILED(rv
))) {
552 nsCOMPtr
<Document
> doc
;
553 rv
= TransformToDoc(getter_AddRefs(doc
), true);
561 class XSLTProcessRequest final
: public nsIRequest
{
563 explicit XSLTProcessRequest(txExecutionState
* aState
) : mState(aState
) {}
568 void Done() { mState
= nullptr; }
571 ~XSLTProcessRequest() {}
572 txExecutionState
* mState
;
574 NS_IMPL_ISUPPORTS(XSLTProcessRequest
, nsIRequest
)
577 XSLTProcessRequest::GetName(nsACString
& aResult
) {
578 aResult
.AssignLiteral("about:xslt-load-blocker");
583 XSLTProcessRequest::IsPending(bool* _retval
) {
589 XSLTProcessRequest::GetStatus(nsresult
* status
) {
594 NS_IMETHODIMP
XSLTProcessRequest::SetCanceledReason(const nsACString
& aReason
) {
595 return SetCanceledReasonImpl(aReason
);
598 NS_IMETHODIMP
XSLTProcessRequest::GetCanceledReason(nsACString
& aReason
) {
599 return GetCanceledReasonImpl(aReason
);
602 NS_IMETHODIMP
XSLTProcessRequest::CancelWithReason(nsresult aStatus
,
603 const nsACString
& aReason
) {
604 return CancelWithReasonImpl(aStatus
, aReason
);
608 XSLTProcessRequest::Cancel(nsresult status
) {
609 mState
->stopProcessing();
614 XSLTProcessRequest::Suspend(void) { return NS_OK
; }
617 XSLTProcessRequest::Resume(void) { return NS_OK
; }
620 XSLTProcessRequest::GetLoadGroup(nsILoadGroup
** aLoadGroup
) {
621 *aLoadGroup
= nullptr;
626 XSLTProcessRequest::SetLoadGroup(nsILoadGroup
* aLoadGroup
) { return NS_OK
; }
629 XSLTProcessRequest::GetLoadFlags(nsLoadFlags
* aLoadFlags
) {
630 *aLoadFlags
= nsIRequest::LOAD_NORMAL
;
635 XSLTProcessRequest::SetLoadFlags(nsLoadFlags aLoadFlags
) { return NS_OK
; }
638 XSLTProcessRequest::GetTRRMode(nsIRequest::TRRMode
* aTRRMode
) {
639 return GetTRRModeImpl(aTRRMode
);
643 XSLTProcessRequest::SetTRRMode(nsIRequest::TRRMode aTRRMode
) {
644 return SetTRRModeImpl(aTRRMode
);
647 nsresult
txMozillaXSLTProcessor::TransformToDoc(Document
** aResult
,
648 bool aCreateDataDocument
) {
649 UniquePtr
<txXPathNode
> sourceNode(
650 txXPathNativeNode::createXPathNode(mSource
));
652 return NS_ERROR_OUT_OF_MEMORY
;
655 txExecutionState
es(mStylesheet
, IsLoadDisabled());
657 Document
* sourceDoc
= mSource
->OwnerDoc();
658 nsCOMPtr
<nsILoadGroup
> loadGroup
= sourceDoc
->GetDocumentLoadGroup();
660 nsCOMPtr
<nsPIDOMWindowInner
> win
= do_QueryInterface(mOwner
);
661 if (win
&& win
->IsCurrentInnerWindow()) {
662 Document
* doc
= win
->GetDoc();
664 loadGroup
= doc
->GetDocumentLoadGroup();
669 return NS_ERROR_FAILURE
;
673 RefPtr
<XSLTProcessRequest
> xsltProcessRequest
= new XSLTProcessRequest(&es
);
674 loadGroup
->AddRequest(xsltProcessRequest
, nullptr);
676 // XXX Need to add error observers
678 // If aResult is non-null, we're a data document
679 txToDocHandlerFactory
handlerFactory(&es
, sourceDoc
, mObserver
,
680 aCreateDataDocument
);
681 es
.mOutputHandlerFactory
= &handlerFactory
;
683 nsresult rv
= es
.init(*sourceNode
, &mVariables
);
685 // Process root of XML source document
686 if (NS_SUCCEEDED(rv
)) {
687 rv
= txXSLTProcessor::execute(es
);
690 xsltProcessRequest
->Done();
691 loadGroup
->RemoveRequest(xsltProcessRequest
, nullptr, NS_OK
);
693 nsresult endRv
= es
.end(rv
);
694 if (NS_SUCCEEDED(rv
)) {
698 if (NS_SUCCEEDED(rv
)) {
700 txAOutputXMLEventHandler
* handler
=
701 static_cast<txAOutputXMLEventHandler
*>(es
.mOutputHandler
);
702 nsCOMPtr
<Document
> doc
;
703 handler
->getOutputDocument(getter_AddRefs(doc
));
704 MOZ_ASSERT(doc
->GetReadyStateEnum() == Document::READYSTATE_INTERACTIVE
,
706 doc
->SetReadyStateInternal(Document::READYSTATE_COMPLETE
);
709 } else if (mObserver
) {
710 // XXX set up context information, bug 204655
711 reportError(rv
, nullptr, nullptr);
717 already_AddRefed
<DocumentFragment
> txMozillaXSLTProcessor::TransformToFragment(
718 nsINode
& aSource
, Document
& aOutput
, ErrorResult
& aRv
) {
719 if (NS_WARN_IF(NS_FAILED(mCompileResult
))) {
720 aRv
.Throw(mCompileResult
);
724 nsIPrincipal
* subject
=
725 nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();
726 if (!subject
->Subsumes(aSource
.NodePrincipal()) ||
727 !subject
->Subsumes(aOutput
.NodePrincipal())) {
728 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
732 nsresult rv
= ensureStylesheet();
733 if (NS_WARN_IF(NS_FAILED(rv
))) {
738 UniquePtr
<txXPathNode
> sourceNode(
739 txXPathNativeNode::createXPathNode(&aSource
));
741 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
745 txExecutionState
es(mStylesheet
, IsLoadDisabled());
747 // XXX Need to add error observers
749 RefPtr
<DocumentFragment
> frag
= aOutput
.CreateDocumentFragment();
750 txToFragmentHandlerFactory
handlerFactory(frag
);
751 es
.mOutputHandlerFactory
= &handlerFactory
;
753 rv
= es
.init(*sourceNode
, &mVariables
);
755 // Process root of XML source document
756 if (NS_SUCCEEDED(rv
)) {
757 rv
= txXSLTProcessor::execute(es
);
759 // XXX setup exception context, bug 204658
760 nsresult endRv
= es
.end(rv
);
761 if (NS_SUCCEEDED(rv
)) {
770 return frag
.forget();
773 void txMozillaXSLTProcessor::SetParameter(const nsAString
& aNamespaceURI
,
774 const nsAString
& aLocalName
,
775 const XSLTParameterValue
& aValue
,
776 ErrorResult
& aError
) {
777 if (aValue
.IsNode()) {
778 if (!nsContentUtils::CanCallerAccess(&aValue
.GetAsNode())) {
779 aError
.ThrowSecurityError("Caller is not allowed to access node.");
782 } else if (aValue
.IsNodeSequence()) {
783 const Sequence
<OwningNonNull
<nsINode
>>& values
= aValue
.GetAsNodeSequence();
784 for (const auto& node
: values
) {
785 if (!nsContentUtils::CanCallerAccess(node
.get())) {
786 aError
.ThrowSecurityError(
787 "Caller is not allowed to access node in sequence.");
791 } else if (aValue
.IsXPathResult()) {
792 XPathResult
& xpathResult
= aValue
.GetAsXPathResult();
793 RefPtr
<txAExprResult
> result
;
794 aError
= xpathResult
.GetExprResult(getter_AddRefs(result
));
795 if (aError
.Failed()) {
799 if (result
->getResultType() == txAExprResult::NODESET
) {
801 static_cast<txNodeSet
*>(static_cast<txAExprResult
*>(result
));
803 int32_t i
, count
= nodeSet
->size();
804 for (i
= 0; i
< count
; ++i
) {
805 nsINode
* node
= txXPathNativeNode::getNode(nodeSet
->get(i
));
806 if (!nsContentUtils::CanCallerAccess(node
)) {
807 aError
.ThrowSecurityError(
808 "Caller is not allowed to access node in node-set.");
815 int32_t nsId
= kNameSpaceID_Unknown
;
817 nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI
, nsId
);
818 if (aError
.Failed()) {
822 RefPtr
<nsAtom
> localName
= NS_Atomize(aLocalName
);
823 txExpandedName
varName(nsId
, localName
);
825 UniquePtr
<OwningXSLTParameterValue
> value
=
826 txVariable::convertToOwning(aValue
, aError
);
827 if (aError
.Failed()) {
831 txVariable
* var
= static_cast<txVariable
*>(mVariables
.get(varName
));
833 var
->setValue(std::move(value
));
837 UniquePtr
<txVariable
> newVar
= MakeUnique
<txVariable
>(std::move(value
));
838 mVariables
.add(varName
, newVar
.release());
841 void txMozillaXSLTProcessor::GetParameter(
842 const nsAString
& aNamespaceURI
, const nsAString
& aLocalName
,
843 Nullable
<OwningXSLTParameterValue
>& aValue
, ErrorResult
& aRv
) {
844 int32_t nsId
= kNameSpaceID_Unknown
;
846 nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI
, nsId
);
847 if (NS_WARN_IF(NS_FAILED(rv
))) {
851 RefPtr
<nsAtom
> localName
= NS_Atomize(aLocalName
);
852 txExpandedName
varName(nsId
, localName
);
854 txVariable
* var
= static_cast<txVariable
*>(mVariables
.get(varName
));
859 aValue
.SetValue(var
->getUnionValue());
862 void txMozillaXSLTProcessor::RemoveParameter(const nsAString
& aNamespaceURI
,
863 const nsAString
& aLocalName
,
865 int32_t nsId
= kNameSpaceID_Unknown
;
867 nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI
, nsId
);
868 if (NS_WARN_IF(NS_FAILED(rv
))) {
872 RefPtr
<nsAtom
> localName
= NS_Atomize(aLocalName
);
873 txExpandedName
varName(nsId
, localName
);
875 mVariables
.remove(varName
);
878 void txMozillaXSLTProcessor::ClearParameters() { mVariables
.clear(); }
880 void txMozillaXSLTProcessor::Reset() {
881 if (mStylesheetDocument
) {
882 mStylesheetDocument
->RemoveMutationObserver(this);
884 mStylesheet
= nullptr;
885 mStylesheetDocument
= nullptr;
886 mEmbeddedStylesheetRoot
= nullptr;
887 mCompileResult
= NS_OK
;
891 void txMozillaXSLTProcessor::SetFlags(uint32_t aFlags
, SystemCallerGuarantee
) {
895 uint32_t txMozillaXSLTProcessor::Flags(SystemCallerGuarantee
) { return mFlags
; }
898 txMozillaXSLTProcessor::LoadStyleSheet(nsIURI
* aUri
,
899 Document
* aLoaderDocument
) {
900 mozilla::dom::ReferrerPolicy refpol
= mozilla::dom::ReferrerPolicy::_empty
;
901 if (mStylesheetDocument
) {
902 refpol
= mStylesheetDocument
->GetReferrerPolicy();
905 nsresult rv
= TX_LoadSheet(aUri
, this, aLoaderDocument
, refpol
);
906 if (NS_FAILED(rv
) && mObserver
) {
907 // This is most likely a network or security error, just
908 // use the uri as context.
911 CopyUTF8toUTF16(spec
, mSourceText
);
912 nsresult status
= NS_ERROR_GET_MODULE(rv
) == NS_ERROR_MODULE_XSLT
914 : NS_ERROR_XSLT_NETWORK_ERROR
;
915 reportError(status
, nullptr, nullptr);
920 nsresult
txMozillaXSLTProcessor::setStylesheet(txStylesheet
* aStylesheet
) {
921 mStylesheet
= aStylesheet
;
923 return DoTransform();
928 void txMozillaXSLTProcessor::reportError(nsresult aResult
,
929 const char16_t
* aErrorText
,
930 const char16_t
* aSourceText
) {
935 mTransformResult
= aResult
;
938 mErrorText
.Assign(aErrorText
);
940 nsCOMPtr
<nsIStringBundleService
> sbs
=
941 mozilla::components::StringBundle::Service();
944 sbs
->FormatStatusMessage(aResult
, u
"", errorText
);
946 nsAutoString errorMessage
;
947 nsCOMPtr
<nsIStringBundle
> bundle
;
948 sbs
->CreateBundle(XSLT_MSGS_URL
, getter_AddRefs(bundle
));
951 AutoTArray
<nsString
, 1> error
= {errorText
};
953 bundle
->FormatStringFromName("TransformError", error
, errorMessage
);
955 bundle
->FormatStringFromName("LoadingError", error
, errorMessage
);
958 mErrorText
.Assign(errorMessage
);
963 mSourceText
.Assign(aSourceText
);
971 void txMozillaXSLTProcessor::notifyError() {
972 nsCOMPtr
<Document
> document
;
974 nsresult rv
= NS_NewXMLDocument(getter_AddRefs(document
), nullptr, nullptr);
975 NS_ENSURE_SUCCESS_VOID(rv
);
978 URIUtils::ResetWithSource(document
, mSource
);
981 document
->GetReadyStateEnum() == Document::READYSTATE_UNINITIALIZED
,
983 document
->SetReadyStateInternal(Document::READYSTATE_LOADING
);
986 u
"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns
;
988 IgnoredErrorResult rv
;
989 ElementCreationOptionsOrString options
;
990 Unused
<< options
.SetAsString();
992 nsCOMPtr
<Element
> element
=
993 document
->CreateElementNS(ns
, u
"parsererror"_ns
, options
, rv
);
998 document
->AppendChild(*element
, rv
);
1003 RefPtr
<nsTextNode
> text
= document
->CreateTextNode(mErrorText
);
1005 element
->AppendChild(*text
, rv
);
1010 if (!mSourceText
.IsEmpty()) {
1011 ElementCreationOptionsOrString options
;
1012 Unused
<< options
.SetAsString();
1014 nsCOMPtr
<Element
> sourceElement
=
1015 document
->CreateElementNS(ns
, u
"sourcetext"_ns
, options
, rv
);
1020 element
->AppendChild(*sourceElement
, rv
);
1025 text
= document
->CreateTextNode(mSourceText
);
1027 sourceElement
->AppendChild(*text
, rv
);
1033 MOZ_ASSERT(document
->GetReadyStateEnum() == Document::READYSTATE_LOADING
,
1035 document
->SetReadyStateInternal(Document::READYSTATE_INTERACTIVE
);
1036 mObserver
->OnTransformDone(mSource
->OwnerDoc(), mTransformResult
, document
);
1039 nsresult
txMozillaXSLTProcessor::ensureStylesheet() {
1044 NS_ENSURE_TRUE(mStylesheetDocument
, NS_ERROR_NOT_INITIALIZED
);
1046 nsINode
* style
= mEmbeddedStylesheetRoot
;
1048 style
= mStylesheetDocument
;
1051 return TX_CompileStylesheet(style
, this, getter_AddRefs(mStylesheet
));
1054 void txMozillaXSLTProcessor::NodeWillBeDestroyed(nsINode
* aNode
) {
1055 nsCOMPtr
<nsIMutationObserver
> kungFuDeathGrip(this);
1056 if (NS_FAILED(mCompileResult
)) {
1060 mCompileResult
= ensureStylesheet();
1061 mStylesheetDocument
= nullptr;
1062 mEmbeddedStylesheetRoot
= nullptr;
1065 void txMozillaXSLTProcessor::CharacterDataChanged(
1066 nsIContent
* aContent
, const CharacterDataChangeInfo
&) {
1067 mStylesheet
= nullptr;
1070 void txMozillaXSLTProcessor::AttributeChanged(Element
* aElement
,
1071 int32_t aNameSpaceID
,
1074 const nsAttrValue
* aOldValue
) {
1075 mStylesheet
= nullptr;
1078 void txMozillaXSLTProcessor::ContentAppended(nsIContent
* aFirstNewContent
) {
1079 mStylesheet
= nullptr;
1082 void txMozillaXSLTProcessor::ContentInserted(nsIContent
* aChild
) {
1083 mStylesheet
= nullptr;
1086 void txMozillaXSLTProcessor::ContentRemoved(nsIContent
* aChild
,
1087 nsIContent
* aPreviousSibling
) {
1088 mStylesheet
= nullptr;
1092 JSObject
* txMozillaXSLTProcessor::WrapObject(
1093 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
1094 return XSLTProcessor_Binding::Wrap(aCx
, this, aGivenProto
);
1097 DocGroup
* txMozillaXSLTProcessor::GetDocGroup() const {
1098 return mStylesheetDocument
? mStylesheetDocument
->GetDocGroup() : nullptr;
1102 already_AddRefed
<txMozillaXSLTProcessor
> txMozillaXSLTProcessor::Constructor(
1103 const GlobalObject
& aGlobal
) {
1104 RefPtr
<txMozillaXSLTProcessor
> processor
=
1105 new txMozillaXSLTProcessor(aGlobal
.GetAsSupports());
1106 return processor
.forget();
1110 nsresult
txMozillaXSLTProcessor::Startup() {
1111 if (!txXSLTProcessor::init()) {
1112 return NS_ERROR_OUT_OF_MEMORY
;
1119 void txMozillaXSLTProcessor::Shutdown() { txXSLTProcessor::shutdown(); }
1122 UniquePtr
<txVariable::OwningXSLTParameterValue
> txVariable::convertToOwning(
1123 const XSLTParameterValue
& aValue
, ErrorResult
& aError
) {
1124 UniquePtr
<OwningXSLTParameterValue
> value
=
1125 MakeUnique
<OwningXSLTParameterValue
>();
1126 if (aValue
.IsUnrestrictedDouble()) {
1127 value
->SetAsUnrestrictedDouble() = aValue
.GetAsUnrestrictedDouble();
1128 } else if (aValue
.IsBoolean()) {
1129 value
->SetAsBoolean() = aValue
.GetAsBoolean();
1130 } else if (aValue
.IsString()) {
1131 value
->SetAsString() = aValue
.GetAsString();
1132 } else if (aValue
.IsNode()) {
1133 value
->SetAsNode() = aValue
.GetAsNode();
1134 } else if (aValue
.IsNodeSequence()) {
1135 value
->SetAsNodeSequence() = aValue
.GetAsNodeSequence();
1136 } else if (aValue
.IsXPathResult()) {
1137 // Clone the XPathResult so that mutations don't affect this variable.
1138 RefPtr
<XPathResult
> clone
= aValue
.GetAsXPathResult().Clone(aError
);
1139 if (aError
.Failed()) {
1142 value
->SetAsXPathResult() = *clone
;
1144 MOZ_ASSERT(false, "Unknown type?");
1150 nsresult
txVariable::convert(const OwningXSLTParameterValue
& aUnionValue
,
1151 txAExprResult
** aValue
) {
1152 if (aUnionValue
.IsUnrestrictedDouble()) {
1153 NS_ADDREF(*aValue
= new NumberResult(aUnionValue
.GetAsUnrestrictedDouble(),
1158 if (aUnionValue
.IsBoolean()) {
1159 NS_ADDREF(*aValue
= new BooleanResult(aUnionValue
.GetAsBoolean()));
1163 if (aUnionValue
.IsString()) {
1164 NS_ADDREF(*aValue
= new StringResult(aUnionValue
.GetAsString(), nullptr));
1168 if (aUnionValue
.IsNode()) {
1169 nsINode
& node
= aUnionValue
.GetAsNode();
1170 UniquePtr
<txXPathNode
> xpathNode(txXPathNativeNode::createXPathNode(&node
));
1172 return NS_ERROR_FAILURE
;
1175 NS_ADDREF(*aValue
= new txNodeSet(*xpathNode
, nullptr));
1179 if (aUnionValue
.IsNodeSequence()) {
1180 RefPtr
<txNodeSet
> nodeSet(new txNodeSet(nullptr));
1181 const Sequence
<OwningNonNull
<nsINode
>>& values
=
1182 aUnionValue
.GetAsNodeSequence();
1183 for (const auto& node
: values
) {
1184 UniquePtr
<txXPathNode
> xpathNode(
1185 txXPathNativeNode::createXPathNode(node
.get()));
1187 return NS_ERROR_FAILURE
;
1190 nodeSet
->append(*xpathNode
);
1192 nodeSet
.forget(aValue
);
1196 MOZ_ASSERT(aUnionValue
.IsXPathResult());
1198 XPathResult
& xpathResult
= aUnionValue
.GetAsXPathResult();
1199 if (xpathResult
.ResultType() == XPathResult::NUMBER_TYPE
) {
1200 IgnoredErrorResult rv
;
1202 new NumberResult(xpathResult
.GetNumberValue(rv
), nullptr));
1203 MOZ_ASSERT(!rv
.Failed());
1207 if (xpathResult
.ResultType() == XPathResult::BOOLEAN_TYPE
) {
1208 IgnoredErrorResult rv
;
1209 NS_ADDREF(*aValue
= new BooleanResult(xpathResult
.GetBooleanValue(rv
)));
1210 MOZ_ASSERT(!rv
.Failed());
1214 if (xpathResult
.ResultType() == XPathResult::STRING_TYPE
) {
1215 IgnoredErrorResult rv
;
1217 xpathResult
.GetStringValue(value
, rv
);
1218 NS_ADDREF(*aValue
= new StringResult(value
, nullptr));
1219 MOZ_ASSERT(!rv
.Failed());
1223 // If the XPathResult holds a nodeset, then it will keep the nodes alive and
1224 // we'll hold the XPathResult alive.
1225 return xpathResult
.GetExprResult(aValue
);