dom/xslt/xpath/txCoreFunctionCall.cpp

changeset 0
6474c204b198
     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

mercurial