1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/xslt/xpath/txCoreFunctionCall.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,742 @@ 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 "mozilla/ArrayUtils.h" 1.10 +#include "mozilla/FloatingPoint.h" 1.11 + 1.12 +#include "txExpr.h" 1.13 +#include "nsAutoPtr.h" 1.14 +#include "txNodeSet.h" 1.15 +#include "nsGkAtoms.h" 1.16 +#include "txIXPathContext.h" 1.17 +#include "nsWhitespaceTokenizer.h" 1.18 +#include "txXPathTreeWalker.h" 1.19 +#include <math.h> 1.20 +#include "txStringUtils.h" 1.21 +#include "txXMLUtils.h" 1.22 + 1.23 +using namespace mozilla; 1.24 + 1.25 +struct txCoreFunctionDescriptor 1.26 +{ 1.27 + int8_t mMinParams; 1.28 + int8_t mMaxParams; 1.29 + Expr::ResultType mReturnType; 1.30 + nsIAtom** mName; 1.31 +}; 1.32 + 1.33 +// This must be ordered in the same order as txCoreFunctionCall::eType. 1.34 +// If you change one, change the other. 1.35 +static const txCoreFunctionDescriptor descriptTable[] = 1.36 +{ 1.37 + { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::count }, // COUNT 1.38 + { 1, 1, Expr::NODESET_RESULT, &nsGkAtoms::id }, // ID 1.39 + { 0, 0, Expr::NUMBER_RESULT, &nsGkAtoms::last }, // LAST 1.40 + { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::localName }, // LOCAL_NAME 1.41 + { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::namespaceUri }, // NAMESPACE_URI 1.42 + { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::name }, // NAME 1.43 + { 0, 0, Expr::NUMBER_RESULT, &nsGkAtoms::position }, // POSITION 1.44 + 1.45 + { 2, -1, Expr::STRING_RESULT, &nsGkAtoms::concat }, // CONCAT 1.46 + { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::contains }, // CONTAINS 1.47 + { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::normalizeSpace }, // NORMALIZE_SPACE 1.48 + { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::startsWith }, // STARTS_WITH 1.49 + { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::string }, // STRING 1.50 + { 0, 1, Expr::NUMBER_RESULT, &nsGkAtoms::stringLength }, // STRING_LENGTH 1.51 + { 2, 3, Expr::STRING_RESULT, &nsGkAtoms::substring }, // SUBSTRING 1.52 + { 2, 2, Expr::STRING_RESULT, &nsGkAtoms::substringAfter }, // SUBSTRING_AFTER 1.53 + { 2, 2, Expr::STRING_RESULT, &nsGkAtoms::substringBefore }, // SUBSTRING_BEFORE 1.54 + { 3, 3, Expr::STRING_RESULT, &nsGkAtoms::translate }, // TRANSLATE 1.55 + 1.56 + { 0, 1, Expr::NUMBER_RESULT, &nsGkAtoms::number }, // NUMBER 1.57 + { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::round }, // ROUND 1.58 + { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::floor }, // FLOOR 1.59 + { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::ceiling }, // CEILING 1.60 + { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::sum }, // SUM 1.61 + 1.62 + { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::boolean }, // BOOLEAN 1.63 + { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_false }, // _FALSE 1.64 + { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::lang }, // LANG 1.65 + { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::_not }, // _NOT 1.66 + { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_true } // _TRUE 1.67 +}; 1.68 + 1.69 + 1.70 +/* 1.71 + * Evaluates this Expr based on the given context node and processor state 1.72 + * @param context the context node for evaluation of this Expr 1.73 + * @param ps the ContextState containing the stack information needed 1.74 + * for evaluation 1.75 + * @return the result of the evaluation 1.76 + */ 1.77 +nsresult 1.78 +txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult) 1.79 +{ 1.80 + *aResult = nullptr; 1.81 + 1.82 + if (!requireParams(descriptTable[mType].mMinParams, 1.83 + descriptTable[mType].mMaxParams, 1.84 + aContext)) { 1.85 + return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT; 1.86 + } 1.87 + 1.88 + nsresult rv = NS_OK; 1.89 + switch (mType) { 1.90 + case COUNT: 1.91 + { 1.92 + nsRefPtr<txNodeSet> nodes; 1.93 + rv = evaluateToNodeSet(mParams[0], aContext, 1.94 + getter_AddRefs(nodes)); 1.95 + NS_ENSURE_SUCCESS(rv, rv); 1.96 + 1.97 + return aContext->recycler()->getNumberResult(nodes->size(), 1.98 + aResult); 1.99 + } 1.100 + case ID: 1.101 + { 1.102 + nsRefPtr<txAExprResult> exprResult; 1.103 + rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult)); 1.104 + NS_ENSURE_SUCCESS(rv, rv); 1.105 + 1.106 + nsRefPtr<txNodeSet> resultSet; 1.107 + rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet)); 1.108 + NS_ENSURE_SUCCESS(rv, rv); 1.109 + 1.110 + txXPathTreeWalker walker(aContext->getContextNode()); 1.111 + 1.112 + if (exprResult->getResultType() == txAExprResult::NODESET) { 1.113 + txNodeSet* nodes = static_cast<txNodeSet*> 1.114 + (static_cast<txAExprResult*> 1.115 + (exprResult)); 1.116 + int32_t i; 1.117 + for (i = 0; i < nodes->size(); ++i) { 1.118 + nsAutoString idList; 1.119 + txXPathNodeUtils::appendNodeValue(nodes->get(i), idList); 1.120 + nsWhitespaceTokenizer tokenizer(idList); 1.121 + while (tokenizer.hasMoreTokens()) { 1.122 + if (walker.moveToElementById(tokenizer.nextToken())) { 1.123 + resultSet->add(walker.getCurrentPosition()); 1.124 + } 1.125 + } 1.126 + } 1.127 + } 1.128 + else { 1.129 + nsAutoString idList; 1.130 + exprResult->stringValue(idList); 1.131 + nsWhitespaceTokenizer tokenizer(idList); 1.132 + while (tokenizer.hasMoreTokens()) { 1.133 + if (walker.moveToElementById(tokenizer.nextToken())) { 1.134 + resultSet->add(walker.getCurrentPosition()); 1.135 + } 1.136 + } 1.137 + } 1.138 + 1.139 + *aResult = resultSet; 1.140 + NS_ADDREF(*aResult); 1.141 + 1.142 + return NS_OK; 1.143 + } 1.144 + case LAST: 1.145 + { 1.146 + return aContext->recycler()->getNumberResult(aContext->size(), 1.147 + aResult); 1.148 + } 1.149 + case LOCAL_NAME: 1.150 + case NAME: 1.151 + case NAMESPACE_URI: 1.152 + { 1.153 + // Check for optional arg 1.154 + nsRefPtr<txNodeSet> nodes; 1.155 + if (!mParams.IsEmpty()) { 1.156 + rv = evaluateToNodeSet(mParams[0], aContext, 1.157 + getter_AddRefs(nodes)); 1.158 + NS_ENSURE_SUCCESS(rv, rv); 1.159 + 1.160 + if (nodes->isEmpty()) { 1.161 + aContext->recycler()->getEmptyStringResult(aResult); 1.162 + 1.163 + return NS_OK; 1.164 + } 1.165 + } 1.166 + 1.167 + const txXPathNode& node = nodes ? nodes->get(0) : 1.168 + aContext->getContextNode(); 1.169 + switch (mType) { 1.170 + case LOCAL_NAME: 1.171 + { 1.172 + StringResult* strRes = nullptr; 1.173 + rv = aContext->recycler()->getStringResult(&strRes); 1.174 + NS_ENSURE_SUCCESS(rv, rv); 1.175 + 1.176 + *aResult = strRes; 1.177 + txXPathNodeUtils::getLocalName(node, strRes->mValue); 1.178 + 1.179 + return NS_OK; 1.180 + } 1.181 + case NAMESPACE_URI: 1.182 + { 1.183 + StringResult* strRes = nullptr; 1.184 + rv = aContext->recycler()->getStringResult(&strRes); 1.185 + NS_ENSURE_SUCCESS(rv, rv); 1.186 + 1.187 + *aResult = strRes; 1.188 + txXPathNodeUtils::getNamespaceURI(node, strRes->mValue); 1.189 + 1.190 + return NS_OK; 1.191 + } 1.192 + case NAME: 1.193 + { 1.194 + // XXX Namespace: namespaces have a name 1.195 + if (txXPathNodeUtils::isAttribute(node) || 1.196 + txXPathNodeUtils::isElement(node) || 1.197 + txXPathNodeUtils::isProcessingInstruction(node)) { 1.198 + StringResult* strRes = nullptr; 1.199 + rv = aContext->recycler()->getStringResult(&strRes); 1.200 + NS_ENSURE_SUCCESS(rv, rv); 1.201 + 1.202 + *aResult = strRes; 1.203 + txXPathNodeUtils::getNodeName(node, strRes->mValue); 1.204 + } 1.205 + else { 1.206 + aContext->recycler()->getEmptyStringResult(aResult); 1.207 + } 1.208 + 1.209 + return NS_OK; 1.210 + } 1.211 + default: 1.212 + { 1.213 + break; 1.214 + } 1.215 + } 1.216 + } 1.217 + case POSITION: 1.218 + { 1.219 + return aContext->recycler()->getNumberResult(aContext->position(), 1.220 + aResult); 1.221 + } 1.222 + 1.223 + // String functions 1.224 + 1.225 + case CONCAT: 1.226 + { 1.227 + nsRefPtr<StringResult> strRes; 1.228 + rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); 1.229 + NS_ENSURE_SUCCESS(rv, rv); 1.230 + 1.231 + uint32_t i, len = mParams.Length(); 1.232 + for (i = 0; i < len; ++i) { 1.233 + rv = mParams[i]->evaluateToString(aContext, strRes->mValue); 1.234 + NS_ENSURE_SUCCESS(rv, rv); 1.235 + } 1.236 + 1.237 + NS_ADDREF(*aResult = strRes); 1.238 + 1.239 + return NS_OK; 1.240 + } 1.241 + case CONTAINS: 1.242 + { 1.243 + nsAutoString arg2; 1.244 + rv = mParams[1]->evaluateToString(aContext, arg2); 1.245 + NS_ENSURE_SUCCESS(rv, rv); 1.246 + 1.247 + if (arg2.IsEmpty()) { 1.248 + aContext->recycler()->getBoolResult(true, aResult); 1.249 + } 1.250 + else { 1.251 + nsAutoString arg1; 1.252 + rv = mParams[0]->evaluateToString(aContext, arg1); 1.253 + NS_ENSURE_SUCCESS(rv, rv); 1.254 + 1.255 + aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1), 1.256 + aResult); 1.257 + } 1.258 + 1.259 + return NS_OK; 1.260 + } 1.261 + case NORMALIZE_SPACE: 1.262 + { 1.263 + nsAutoString resultStr; 1.264 + if (!mParams.IsEmpty()) { 1.265 + rv = mParams[0]->evaluateToString(aContext, resultStr); 1.266 + NS_ENSURE_SUCCESS(rv, rv); 1.267 + } 1.268 + else { 1.269 + txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), 1.270 + resultStr); 1.271 + } 1.272 + 1.273 + nsRefPtr<StringResult> strRes; 1.274 + rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); 1.275 + NS_ENSURE_SUCCESS(rv, rv); 1.276 + 1.277 + bool addSpace = false; 1.278 + bool first = true; 1.279 + strRes->mValue.SetCapacity(resultStr.Length()); 1.280 + char16_t c; 1.281 + uint32_t src; 1.282 + for (src = 0; src < resultStr.Length(); src++) { 1.283 + c = resultStr.CharAt(src); 1.284 + if (XMLUtils::isWhitespace(c)) { 1.285 + addSpace = true; 1.286 + } 1.287 + else { 1.288 + if (addSpace && !first) 1.289 + strRes->mValue.Append(char16_t(' ')); 1.290 + 1.291 + strRes->mValue.Append(c); 1.292 + addSpace = false; 1.293 + first = false; 1.294 + } 1.295 + } 1.296 + *aResult = strRes; 1.297 + NS_ADDREF(*aResult); 1.298 + 1.299 + return NS_OK; 1.300 + } 1.301 + case STARTS_WITH: 1.302 + { 1.303 + nsAutoString arg2; 1.304 + rv = mParams[1]->evaluateToString(aContext, arg2); 1.305 + NS_ENSURE_SUCCESS(rv, rv); 1.306 + 1.307 + bool result = false; 1.308 + if (arg2.IsEmpty()) { 1.309 + result = true; 1.310 + } 1.311 + else { 1.312 + nsAutoString arg1; 1.313 + rv = mParams[0]->evaluateToString(aContext, arg1); 1.314 + NS_ENSURE_SUCCESS(rv, rv); 1.315 + 1.316 + result = StringBeginsWith(arg1, arg2); 1.317 + } 1.318 + 1.319 + aContext->recycler()->getBoolResult(result, aResult); 1.320 + 1.321 + return NS_OK; 1.322 + } 1.323 + case STRING: 1.324 + { 1.325 + nsRefPtr<StringResult> strRes; 1.326 + rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); 1.327 + NS_ENSURE_SUCCESS(rv, rv); 1.328 + 1.329 + if (!mParams.IsEmpty()) { 1.330 + rv = mParams[0]->evaluateToString(aContext, strRes->mValue); 1.331 + NS_ENSURE_SUCCESS(rv, rv); 1.332 + } 1.333 + else { 1.334 + txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), 1.335 + strRes->mValue); 1.336 + } 1.337 + 1.338 + NS_ADDREF(*aResult = strRes); 1.339 + 1.340 + return NS_OK; 1.341 + } 1.342 + case STRING_LENGTH: 1.343 + { 1.344 + nsAutoString resultStr; 1.345 + if (!mParams.IsEmpty()) { 1.346 + rv = mParams[0]->evaluateToString(aContext, resultStr); 1.347 + NS_ENSURE_SUCCESS(rv, rv); 1.348 + } 1.349 + else { 1.350 + txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), 1.351 + resultStr); 1.352 + } 1.353 + rv = aContext->recycler()->getNumberResult(resultStr.Length(), 1.354 + aResult); 1.355 + NS_ENSURE_SUCCESS(rv, rv); 1.356 + 1.357 + return NS_OK; 1.358 + } 1.359 + case SUBSTRING: 1.360 + { 1.361 + nsAutoString src; 1.362 + rv = mParams[0]->evaluateToString(aContext, src); 1.363 + NS_ENSURE_SUCCESS(rv, rv); 1.364 + 1.365 + double start; 1.366 + rv = evaluateToNumber(mParams[1], aContext, &start); 1.367 + NS_ENSURE_SUCCESS(rv, rv); 1.368 + 1.369 + // check for NaN or +/-Inf 1.370 + if (mozilla::IsNaN(start) || 1.371 + mozilla::IsInfinite(start) || 1.372 + start >= src.Length() + 0.5) { 1.373 + aContext->recycler()->getEmptyStringResult(aResult); 1.374 + 1.375 + return NS_OK; 1.376 + } 1.377 + 1.378 + start = floor(start + 0.5) - 1; 1.379 + 1.380 + double end; 1.381 + if (mParams.Length() == 3) { 1.382 + rv = evaluateToNumber(mParams[2], aContext, &end); 1.383 + NS_ENSURE_SUCCESS(rv, rv); 1.384 + 1.385 + end += start; 1.386 + if (mozilla::IsNaN(end) || end < 0) { 1.387 + aContext->recycler()->getEmptyStringResult(aResult); 1.388 + 1.389 + return NS_OK; 1.390 + } 1.391 + 1.392 + if (end > src.Length()) 1.393 + end = src.Length(); 1.394 + else 1.395 + end = floor(end + 0.5); 1.396 + } 1.397 + else { 1.398 + end = src.Length(); 1.399 + } 1.400 + 1.401 + if (start < 0) 1.402 + start = 0; 1.403 + 1.404 + if (start > end) { 1.405 + aContext->recycler()->getEmptyStringResult(aResult); 1.406 + 1.407 + return NS_OK; 1.408 + } 1.409 + 1.410 + return aContext->recycler()->getStringResult( 1.411 + Substring(src, (uint32_t)start, (uint32_t)(end - start)), 1.412 + aResult); 1.413 + } 1.414 + case SUBSTRING_AFTER: 1.415 + { 1.416 + nsAutoString arg1; 1.417 + rv = mParams[0]->evaluateToString(aContext, arg1); 1.418 + NS_ENSURE_SUCCESS(rv, rv); 1.419 + 1.420 + nsAutoString arg2; 1.421 + rv = mParams[1]->evaluateToString(aContext, arg2); 1.422 + NS_ENSURE_SUCCESS(rv, rv); 1.423 + 1.424 + if (arg2.IsEmpty()) { 1.425 + return aContext->recycler()->getStringResult(arg1, aResult); 1.426 + } 1.427 + 1.428 + int32_t idx = arg1.Find(arg2); 1.429 + if (idx == kNotFound) { 1.430 + aContext->recycler()->getEmptyStringResult(aResult); 1.431 + 1.432 + return NS_OK; 1.433 + } 1.434 + 1.435 + const nsSubstring& result = Substring(arg1, idx + arg2.Length()); 1.436 + return aContext->recycler()->getStringResult(result, aResult); 1.437 + } 1.438 + case SUBSTRING_BEFORE: 1.439 + { 1.440 + nsAutoString arg2; 1.441 + rv = mParams[1]->evaluateToString(aContext, arg2); 1.442 + NS_ENSURE_SUCCESS(rv, rv); 1.443 + 1.444 + if (arg2.IsEmpty()) { 1.445 + aContext->recycler()->getEmptyStringResult(aResult); 1.446 + 1.447 + return NS_OK; 1.448 + } 1.449 + 1.450 + nsAutoString arg1; 1.451 + rv = mParams[0]->evaluateToString(aContext, arg1); 1.452 + NS_ENSURE_SUCCESS(rv, rv); 1.453 + 1.454 + int32_t idx = arg1.Find(arg2); 1.455 + if (idx == kNotFound) { 1.456 + aContext->recycler()->getEmptyStringResult(aResult); 1.457 + 1.458 + return NS_OK; 1.459 + } 1.460 + 1.461 + return aContext->recycler()->getStringResult(StringHead(arg1, idx), 1.462 + aResult); 1.463 + } 1.464 + case TRANSLATE: 1.465 + { 1.466 + nsAutoString src; 1.467 + rv = mParams[0]->evaluateToString(aContext, src); 1.468 + NS_ENSURE_SUCCESS(rv, rv); 1.469 + 1.470 + if (src.IsEmpty()) { 1.471 + aContext->recycler()->getEmptyStringResult(aResult); 1.472 + 1.473 + return NS_OK; 1.474 + } 1.475 + 1.476 + nsRefPtr<StringResult> strRes; 1.477 + rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes)); 1.478 + NS_ENSURE_SUCCESS(rv, rv); 1.479 + 1.480 + strRes->mValue.SetCapacity(src.Length()); 1.481 + 1.482 + nsAutoString oldChars, newChars; 1.483 + rv = mParams[1]->evaluateToString(aContext, oldChars); 1.484 + NS_ENSURE_SUCCESS(rv, rv); 1.485 + 1.486 + rv = mParams[2]->evaluateToString(aContext, newChars); 1.487 + NS_ENSURE_SUCCESS(rv, rv); 1.488 + 1.489 + uint32_t i; 1.490 + int32_t newCharsLength = (int32_t)newChars.Length(); 1.491 + for (i = 0; i < src.Length(); i++) { 1.492 + int32_t idx = oldChars.FindChar(src.CharAt(i)); 1.493 + if (idx != kNotFound) { 1.494 + if (idx < newCharsLength) 1.495 + strRes->mValue.Append(newChars.CharAt((uint32_t)idx)); 1.496 + } 1.497 + else { 1.498 + strRes->mValue.Append(src.CharAt(i)); 1.499 + } 1.500 + } 1.501 + 1.502 + NS_ADDREF(*aResult = strRes); 1.503 + 1.504 + return NS_OK; 1.505 + } 1.506 + 1.507 + // Number functions 1.508 + 1.509 + case NUMBER: 1.510 + { 1.511 + double res; 1.512 + if (!mParams.IsEmpty()) { 1.513 + rv = evaluateToNumber(mParams[0], aContext, &res); 1.514 + NS_ENSURE_SUCCESS(rv, rv); 1.515 + } 1.516 + else { 1.517 + nsAutoString resultStr; 1.518 + txXPathNodeUtils::appendNodeValue(aContext->getContextNode(), 1.519 + resultStr); 1.520 + res = txDouble::toDouble(resultStr); 1.521 + } 1.522 + return aContext->recycler()->getNumberResult(res, aResult); 1.523 + } 1.524 + case ROUND: 1.525 + { 1.526 + double dbl; 1.527 + rv = evaluateToNumber(mParams[0], aContext, &dbl); 1.528 + NS_ENSURE_SUCCESS(rv, rv); 1.529 + 1.530 + if (mozilla::IsFinite(dbl)) { 1.531 + if (mozilla::IsNegative(dbl) && dbl >= -0.5) { 1.532 + dbl *= 0; 1.533 + } 1.534 + else { 1.535 + dbl = floor(dbl + 0.5); 1.536 + } 1.537 + } 1.538 + 1.539 + return aContext->recycler()->getNumberResult(dbl, aResult); 1.540 + } 1.541 + case FLOOR: 1.542 + { 1.543 + double dbl; 1.544 + rv = evaluateToNumber(mParams[0], aContext, &dbl); 1.545 + NS_ENSURE_SUCCESS(rv, rv); 1.546 + 1.547 + if (mozilla::IsFinite(dbl) && !mozilla::IsNegativeZero(dbl)) 1.548 + dbl = floor(dbl); 1.549 + 1.550 + return aContext->recycler()->getNumberResult(dbl, aResult); 1.551 + } 1.552 + case CEILING: 1.553 + { 1.554 + double dbl; 1.555 + rv = evaluateToNumber(mParams[0], aContext, &dbl); 1.556 + NS_ENSURE_SUCCESS(rv, rv); 1.557 + 1.558 + if (mozilla::IsFinite(dbl)) { 1.559 + if (mozilla::IsNegative(dbl) && dbl > -1) 1.560 + dbl *= 0; 1.561 + else 1.562 + dbl = ceil(dbl); 1.563 + } 1.564 + 1.565 + return aContext->recycler()->getNumberResult(dbl, aResult); 1.566 + } 1.567 + case SUM: 1.568 + { 1.569 + nsRefPtr<txNodeSet> nodes; 1.570 + nsresult rv = evaluateToNodeSet(mParams[0], aContext, 1.571 + getter_AddRefs(nodes)); 1.572 + NS_ENSURE_SUCCESS(rv, rv); 1.573 + 1.574 + double res = 0; 1.575 + int32_t i; 1.576 + for (i = 0; i < nodes->size(); ++i) { 1.577 + nsAutoString resultStr; 1.578 + txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr); 1.579 + res += txDouble::toDouble(resultStr); 1.580 + } 1.581 + return aContext->recycler()->getNumberResult(res, aResult); 1.582 + } 1.583 + 1.584 + // Boolean functions 1.585 + 1.586 + case BOOLEAN: 1.587 + { 1.588 + bool result; 1.589 + nsresult rv = mParams[0]->evaluateToBool(aContext, result); 1.590 + NS_ENSURE_SUCCESS(rv, rv); 1.591 + 1.592 + aContext->recycler()->getBoolResult(result, aResult); 1.593 + 1.594 + return NS_OK; 1.595 + } 1.596 + case _FALSE: 1.597 + { 1.598 + aContext->recycler()->getBoolResult(false, aResult); 1.599 + 1.600 + return NS_OK; 1.601 + } 1.602 + case LANG: 1.603 + { 1.604 + txXPathTreeWalker walker(aContext->getContextNode()); 1.605 + 1.606 + nsAutoString lang; 1.607 + bool found; 1.608 + do { 1.609 + found = walker.getAttr(nsGkAtoms::lang, kNameSpaceID_XML, 1.610 + lang); 1.611 + } while (!found && walker.moveToParent()); 1.612 + 1.613 + if (!found) { 1.614 + aContext->recycler()->getBoolResult(false, aResult); 1.615 + 1.616 + return NS_OK; 1.617 + } 1.618 + 1.619 + nsAutoString arg; 1.620 + rv = mParams[0]->evaluateToString(aContext, arg); 1.621 + NS_ENSURE_SUCCESS(rv, rv); 1.622 + 1.623 + bool result = 1.624 + StringBeginsWith(lang, arg, 1.625 + txCaseInsensitiveStringComparator()) && 1.626 + (lang.Length() == arg.Length() || 1.627 + lang.CharAt(arg.Length()) == '-'); 1.628 + 1.629 + aContext->recycler()->getBoolResult(result, aResult); 1.630 + 1.631 + return NS_OK; 1.632 + } 1.633 + case _NOT: 1.634 + { 1.635 + bool result; 1.636 + rv = mParams[0]->evaluateToBool(aContext, result); 1.637 + NS_ENSURE_SUCCESS(rv, rv); 1.638 + 1.639 + aContext->recycler()->getBoolResult(!result, aResult); 1.640 + 1.641 + return NS_OK; 1.642 + } 1.643 + case _TRUE: 1.644 + { 1.645 + aContext->recycler()->getBoolResult(true, aResult); 1.646 + 1.647 + return NS_OK; 1.648 + } 1.649 + } 1.650 + 1.651 + aContext->receiveError(NS_LITERAL_STRING("Internal error"), 1.652 + NS_ERROR_UNEXPECTED); 1.653 + return NS_ERROR_UNEXPECTED; 1.654 +} 1.655 + 1.656 +Expr::ResultType 1.657 +txCoreFunctionCall::getReturnType() 1.658 +{ 1.659 + return descriptTable[mType].mReturnType; 1.660 +} 1.661 + 1.662 +bool 1.663 +txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext) 1.664 +{ 1.665 + switch (mType) { 1.666 + case COUNT: 1.667 + case CONCAT: 1.668 + case CONTAINS: 1.669 + case STARTS_WITH: 1.670 + case SUBSTRING: 1.671 + case SUBSTRING_AFTER: 1.672 + case SUBSTRING_BEFORE: 1.673 + case TRANSLATE: 1.674 + case ROUND: 1.675 + case FLOOR: 1.676 + case CEILING: 1.677 + case SUM: 1.678 + case BOOLEAN: 1.679 + case _NOT: 1.680 + case _FALSE: 1.681 + case _TRUE: 1.682 + { 1.683 + return argsSensitiveTo(aContext); 1.684 + } 1.685 + case ID: 1.686 + { 1.687 + return (aContext & NODE_CONTEXT) || 1.688 + argsSensitiveTo(aContext); 1.689 + } 1.690 + case LAST: 1.691 + { 1.692 + return !!(aContext & SIZE_CONTEXT); 1.693 + } 1.694 + case LOCAL_NAME: 1.695 + case NAME: 1.696 + case NAMESPACE_URI: 1.697 + case NORMALIZE_SPACE: 1.698 + case STRING: 1.699 + case STRING_LENGTH: 1.700 + case NUMBER: 1.701 + { 1.702 + if (mParams.IsEmpty()) { 1.703 + return !!(aContext & NODE_CONTEXT); 1.704 + } 1.705 + return argsSensitiveTo(aContext); 1.706 + } 1.707 + case POSITION: 1.708 + { 1.709 + return !!(aContext & POSITION_CONTEXT); 1.710 + } 1.711 + case LANG: 1.712 + { 1.713 + return (aContext & NODE_CONTEXT) || 1.714 + argsSensitiveTo(aContext); 1.715 + } 1.716 + } 1.717 + 1.718 + NS_NOTREACHED("how'd we get here?"); 1.719 + return true; 1.720 +} 1.721 + 1.722 +// static 1.723 +bool 1.724 +txCoreFunctionCall::getTypeFromAtom(nsIAtom* aName, eType& aType) 1.725 +{ 1.726 + uint32_t i; 1.727 + for (i = 0; i < ArrayLength(descriptTable); ++i) { 1.728 + if (aName == *descriptTable[i].mName) { 1.729 + aType = static_cast<eType>(i); 1.730 + 1.731 + return true; 1.732 + } 1.733 + } 1.734 + 1.735 + return false; 1.736 +} 1.737 + 1.738 +#ifdef TX_TO_STRING 1.739 +nsresult 1.740 +txCoreFunctionCall::getNameAtom(nsIAtom** aAtom) 1.741 +{ 1.742 + NS_ADDREF(*aAtom = *descriptTable[mType].mName); 1.743 + return NS_OK; 1.744 +} 1.745 +#endif