Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / dom / xslt / xpath / XPathExpression.cpp
blob0706763d79f213d3b8157c8da11bb955e58ada58
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 "XPathExpression.h"
8 #include <utility>
10 #include "XPathResult.h"
11 #include "mozilla/dom/BindingUtils.h"
12 #include "mozilla/dom/Text.h"
13 #include "mozilla/dom/XPathResultBinding.h"
14 #include "nsError.h"
15 #include "nsINode.h"
16 #include "txExpr.h"
17 #include "txExprResult.h"
18 #include "txIXPathContext.h"
19 #include "txURIUtils.h"
20 #include "txXPathTreeWalker.h"
22 namespace mozilla::dom {
24 class EvalContextImpl : public txIEvalContext {
25 public:
26 EvalContextImpl(const txXPathNode& aContextNode, uint32_t aContextPosition,
27 uint32_t aContextSize, txResultRecycler* aRecycler)
28 : mContextNode(aContextNode),
29 mContextPosition(aContextPosition),
30 mContextSize(aContextSize),
31 mLastError(NS_OK),
32 mRecycler(aRecycler) {}
34 nsresult getError() { return mLastError; }
36 TX_DECL_EVAL_CONTEXT;
38 private:
39 const txXPathNode& mContextNode;
40 uint32_t mContextPosition;
41 uint32_t mContextSize;
42 nsresult mLastError;
43 RefPtr<txResultRecycler> mRecycler;
46 XPathExpression::XPathExpression(UniquePtr<Expr>&& aExpression,
47 txResultRecycler* aRecycler,
48 Document* aDocument)
49 : mExpression(std::move(aExpression)),
50 mRecycler(aRecycler),
51 mDocument(do_GetWeakReference(aDocument)),
52 mCheckDocument(aDocument != nullptr) {}
54 XPathExpression::~XPathExpression() = default;
56 already_AddRefed<XPathResult> XPathExpression::EvaluateWithContext(
57 JSContext* aCx, nsINode& aContextNode, uint32_t aContextPosition,
58 uint32_t aContextSize, uint16_t aType, JS::Handle<JSObject*> aInResult,
59 ErrorResult& aRv) {
60 RefPtr<XPathResult> inResult;
61 if (aInResult) {
62 nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult);
63 if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) {
64 aRv.Throw(rv);
65 return nullptr;
69 return EvaluateWithContext(aContextNode, aContextPosition, aContextSize,
70 aType, inResult, aRv);
73 already_AddRefed<XPathResult> XPathExpression::EvaluateWithContext(
74 nsINode& aContextNode, uint32_t aContextPosition, uint32_t aContextSize,
75 uint16_t aType, XPathResult* aInResult, ErrorResult& aRv) {
76 if (aContextPosition > aContextSize) {
77 aRv.Throw(NS_ERROR_FAILURE);
78 return nullptr;
81 if (aType > XPathResult_Binding::FIRST_ORDERED_NODE_TYPE) {
82 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
83 return nullptr;
86 if (!nsContentUtils::LegacyIsCallerNativeCode() &&
87 !nsContentUtils::CanCallerAccess(&aContextNode)) {
88 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
89 return nullptr;
92 if (mCheckDocument) {
93 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
94 if (doc != aContextNode.OwnerDoc()) {
95 aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
96 return nullptr;
100 uint16_t nodeType = aContextNode.NodeType();
102 if (nodeType == nsINode::TEXT_NODE ||
103 nodeType == nsINode::CDATA_SECTION_NODE) {
104 Text* textNode = aContextNode.GetAsText();
105 MOZ_ASSERT(textNode);
107 uint32_t textLength = textNode->Length();
108 if (textLength == 0) {
109 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
110 return nullptr;
113 // XXX Need to get logical XPath text node for CDATASection
114 // and Text nodes.
115 } else if (nodeType != nsINode::DOCUMENT_NODE &&
116 nodeType != nsINode::ELEMENT_NODE &&
117 nodeType != nsINode::ATTRIBUTE_NODE &&
118 nodeType != nsINode::COMMENT_NODE &&
119 nodeType != nsINode::PROCESSING_INSTRUCTION_NODE) {
120 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
121 return nullptr;
124 UniquePtr<txXPathNode> contextNode(
125 txXPathNativeNode::createXPathNode(&aContextNode));
126 if (!contextNode) {
127 aRv.Throw(NS_ERROR_FAILURE);
128 return nullptr;
131 EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize,
132 mRecycler);
133 RefPtr<txAExprResult> exprResult;
134 aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult));
135 if (aRv.Failed()) {
136 return nullptr;
139 uint16_t resultType = aType;
140 if (aType == XPathResult::ANY_TYPE) {
141 short exprResultType = exprResult->getResultType();
142 switch (exprResultType) {
143 case txAExprResult::NUMBER:
144 resultType = XPathResult::NUMBER_TYPE;
145 break;
146 case txAExprResult::STRING:
147 resultType = XPathResult::STRING_TYPE;
148 break;
149 case txAExprResult::BOOLEAN:
150 resultType = XPathResult::BOOLEAN_TYPE;
151 break;
152 case txAExprResult::NODESET:
153 resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE;
154 break;
155 case txAExprResult::RESULT_TREE_FRAGMENT:
156 aRv.Throw(NS_ERROR_FAILURE);
157 return nullptr;
161 RefPtr<XPathResult> xpathResult = aInResult;
162 if (!xpathResult) {
163 xpathResult = new XPathResult(&aContextNode);
166 xpathResult->SetExprResult(exprResult, resultType, &aContextNode, aRv);
167 if (aRv.Failed()) {
168 return nullptr;
171 return xpathResult.forget();
175 * Implementation of the txIEvalContext private to XPathExpression
176 * EvalContextImpl bases on only one context node and no variables
179 nsresult EvalContextImpl::getVariable(int32_t aNamespace, nsAtom* aLName,
180 txAExprResult*& aResult) {
181 aResult = 0;
182 return NS_ERROR_INVALID_ARG;
185 nsresult EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode,
186 bool& aAllowed) {
187 aAllowed = false;
189 return NS_OK;
192 void* EvalContextImpl::getPrivateContext() {
193 // we don't have a private context here.
194 return nullptr;
197 txResultRecycler* EvalContextImpl::recycler() { return mRecycler; }
199 void EvalContextImpl::receiveError(const nsAString& aMsg, nsresult aRes) {
200 mLastError = aRes;
201 // forward aMsg to console service?
204 const txXPathNode& EvalContextImpl::getContextNode() { return mContextNode; }
206 uint32_t EvalContextImpl::size() { return mContextSize; }
208 uint32_t EvalContextImpl::position() { return mContextPosition; }
210 } // namespace mozilla::dom