dom/xslt/xpath/txCoreFunctionCall.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     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 "mozilla/ArrayUtils.h"
     7 #include "mozilla/FloatingPoint.h"
     9 #include "txExpr.h"
    10 #include "nsAutoPtr.h"
    11 #include "txNodeSet.h"
    12 #include "nsGkAtoms.h"
    13 #include "txIXPathContext.h"
    14 #include "nsWhitespaceTokenizer.h"
    15 #include "txXPathTreeWalker.h"
    16 #include <math.h>
    17 #include "txStringUtils.h"
    18 #include "txXMLUtils.h"
    20 using namespace mozilla;
    22 struct txCoreFunctionDescriptor
    23 {
    24     int8_t mMinParams;
    25     int8_t mMaxParams;
    26     Expr::ResultType mReturnType;
    27     nsIAtom** mName;
    28 };
    30 // This must be ordered in the same order as txCoreFunctionCall::eType.
    31 // If you change one, change the other.
    32 static const txCoreFunctionDescriptor descriptTable[] =
    33 {
    34     { 1, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::count }, // COUNT
    35     { 1, 1, Expr::NODESET_RESULT, &nsGkAtoms::id }, // ID
    36     { 0, 0, Expr::NUMBER_RESULT,  &nsGkAtoms::last }, // LAST
    37     { 0, 1, Expr::STRING_RESULT,  &nsGkAtoms::localName }, // LOCAL_NAME
    38     { 0, 1, Expr::STRING_RESULT,  &nsGkAtoms::namespaceUri }, // NAMESPACE_URI
    39     { 0, 1, Expr::STRING_RESULT,  &nsGkAtoms::name }, // NAME
    40     { 0, 0, Expr::NUMBER_RESULT,  &nsGkAtoms::position }, // POSITION
    42     { 2, -1, Expr::STRING_RESULT, &nsGkAtoms::concat }, // CONCAT
    43     { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::contains }, // CONTAINS
    44     { 0, 1, Expr::STRING_RESULT,  &nsGkAtoms::normalizeSpace }, // NORMALIZE_SPACE
    45     { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::startsWith }, // STARTS_WITH
    46     { 0, 1, Expr::STRING_RESULT,  &nsGkAtoms::string }, // STRING
    47     { 0, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::stringLength }, // STRING_LENGTH
    48     { 2, 3, Expr::STRING_RESULT,  &nsGkAtoms::substring }, // SUBSTRING
    49     { 2, 2, Expr::STRING_RESULT,  &nsGkAtoms::substringAfter }, // SUBSTRING_AFTER
    50     { 2, 2, Expr::STRING_RESULT,  &nsGkAtoms::substringBefore }, // SUBSTRING_BEFORE
    51     { 3, 3, Expr::STRING_RESULT,  &nsGkAtoms::translate }, // TRANSLATE
    53     { 0, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::number }, // NUMBER
    54     { 1, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::round }, // ROUND
    55     { 1, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::floor }, // FLOOR
    56     { 1, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::ceiling }, // CEILING
    57     { 1, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::sum }, // SUM
    59     { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::boolean }, // BOOLEAN
    60     { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_false }, // _FALSE
    61     { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::lang }, // LANG
    62     { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::_not }, // _NOT
    63     { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_true } // _TRUE
    64 };
    67 /*
    68  * Evaluates this Expr based on the given context node and processor state
    69  * @param context the context node for evaluation of this Expr
    70  * @param ps the ContextState containing the stack information needed
    71  * for evaluation
    72  * @return the result of the evaluation
    73  */
    74 nsresult
    75 txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
    76 {
    77     *aResult = nullptr;
    79     if (!requireParams(descriptTable[mType].mMinParams,
    80                        descriptTable[mType].mMaxParams,
    81                        aContext)) {
    82         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
    83     }
    85     nsresult rv = NS_OK;
    86     switch (mType) {
    87         case COUNT:
    88         {
    89             nsRefPtr<txNodeSet> nodes;
    90             rv = evaluateToNodeSet(mParams[0], aContext,
    91                                    getter_AddRefs(nodes));
    92             NS_ENSURE_SUCCESS(rv, rv);
    94             return aContext->recycler()->getNumberResult(nodes->size(),
    95                                                          aResult);
    96         }
    97         case ID:
    98         {
    99             nsRefPtr<txAExprResult> exprResult;
   100             rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
   101             NS_ENSURE_SUCCESS(rv, rv);
   103             nsRefPtr<txNodeSet> resultSet;
   104             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
   105             NS_ENSURE_SUCCESS(rv, rv);
   107             txXPathTreeWalker walker(aContext->getContextNode());
   109             if (exprResult->getResultType() == txAExprResult::NODESET) {
   110                 txNodeSet* nodes = static_cast<txNodeSet*>
   111                                               (static_cast<txAExprResult*>
   112                                                           (exprResult));
   113                 int32_t i;
   114                 for (i = 0; i < nodes->size(); ++i) {
   115                     nsAutoString idList;
   116                     txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
   117                     nsWhitespaceTokenizer tokenizer(idList);
   118                     while (tokenizer.hasMoreTokens()) {
   119                         if (walker.moveToElementById(tokenizer.nextToken())) {
   120                             resultSet->add(walker.getCurrentPosition());
   121                         }
   122                     }
   123                 }
   124             }
   125             else {
   126                 nsAutoString idList;
   127                 exprResult->stringValue(idList);
   128                 nsWhitespaceTokenizer tokenizer(idList);
   129                 while (tokenizer.hasMoreTokens()) {
   130                     if (walker.moveToElementById(tokenizer.nextToken())) {
   131                         resultSet->add(walker.getCurrentPosition());
   132                     }
   133                 }
   134             }
   136             *aResult = resultSet;
   137             NS_ADDREF(*aResult);
   139             return NS_OK;
   140         }
   141         case LAST:
   142         {
   143             return aContext->recycler()->getNumberResult(aContext->size(),
   144                                                          aResult);
   145         }
   146         case LOCAL_NAME:
   147         case NAME:
   148         case NAMESPACE_URI:
   149         {
   150             // Check for optional arg
   151             nsRefPtr<txNodeSet> nodes;
   152             if (!mParams.IsEmpty()) {
   153                 rv = evaluateToNodeSet(mParams[0], aContext,
   154                                        getter_AddRefs(nodes));
   155                 NS_ENSURE_SUCCESS(rv, rv);
   157                 if (nodes->isEmpty()) {
   158                     aContext->recycler()->getEmptyStringResult(aResult);
   160                     return NS_OK;
   161                 }
   162             }
   164             const txXPathNode& node = nodes ? nodes->get(0) :
   165                                               aContext->getContextNode();
   166             switch (mType) {
   167                 case LOCAL_NAME:
   168                 {
   169                     StringResult* strRes = nullptr;
   170                     rv = aContext->recycler()->getStringResult(&strRes);
   171                     NS_ENSURE_SUCCESS(rv, rv);
   173                     *aResult = strRes;
   174                     txXPathNodeUtils::getLocalName(node, strRes->mValue);
   176                     return NS_OK;
   177                 }
   178                 case NAMESPACE_URI:
   179                 {
   180                     StringResult* strRes = nullptr;
   181                     rv = aContext->recycler()->getStringResult(&strRes);
   182                     NS_ENSURE_SUCCESS(rv, rv);
   184                     *aResult = strRes;
   185                     txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
   187                     return NS_OK;
   188                 }
   189                 case NAME:
   190                 {
   191                     // XXX Namespace: namespaces have a name
   192                     if (txXPathNodeUtils::isAttribute(node) ||
   193                         txXPathNodeUtils::isElement(node) ||
   194                         txXPathNodeUtils::isProcessingInstruction(node)) {
   195                         StringResult* strRes = nullptr;
   196                         rv = aContext->recycler()->getStringResult(&strRes);
   197                         NS_ENSURE_SUCCESS(rv, rv);
   199                         *aResult = strRes;
   200                         txXPathNodeUtils::getNodeName(node, strRes->mValue);
   201                     }
   202                     else {
   203                         aContext->recycler()->getEmptyStringResult(aResult);
   204                     }
   206                     return NS_OK;
   207                 }
   208                 default:
   209                 {
   210                     break;
   211                 }
   212             }
   213         }
   214         case POSITION:
   215         {
   216             return aContext->recycler()->getNumberResult(aContext->position(),
   217                                                          aResult);
   218         }
   220         // String functions
   222         case CONCAT:
   223         {
   224             nsRefPtr<StringResult> strRes;
   225             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
   226             NS_ENSURE_SUCCESS(rv, rv);
   228             uint32_t i, len = mParams.Length();
   229             for (i = 0; i < len; ++i) {
   230                 rv = mParams[i]->evaluateToString(aContext, strRes->mValue);
   231                 NS_ENSURE_SUCCESS(rv, rv);
   232             }
   234             NS_ADDREF(*aResult = strRes);
   236             return NS_OK;
   237         }
   238         case CONTAINS:
   239         {
   240             nsAutoString arg2;
   241             rv = mParams[1]->evaluateToString(aContext, arg2);
   242             NS_ENSURE_SUCCESS(rv, rv);
   244             if (arg2.IsEmpty()) {
   245                 aContext->recycler()->getBoolResult(true, aResult);
   246             }
   247             else {
   248                 nsAutoString arg1;
   249                 rv = mParams[0]->evaluateToString(aContext, arg1);
   250                 NS_ENSURE_SUCCESS(rv, rv);
   252                 aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1),
   253                                                     aResult);
   254             }
   256             return NS_OK;
   257         }
   258         case NORMALIZE_SPACE:
   259         {
   260             nsAutoString resultStr;
   261             if (!mParams.IsEmpty()) {
   262                 rv = mParams[0]->evaluateToString(aContext, resultStr);
   263                 NS_ENSURE_SUCCESS(rv, rv);
   264             }
   265             else {
   266                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
   267                                                   resultStr);
   268             }
   270             nsRefPtr<StringResult> strRes;
   271             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
   272             NS_ENSURE_SUCCESS(rv, rv);
   274             bool addSpace = false;
   275             bool first = true;
   276             strRes->mValue.SetCapacity(resultStr.Length());
   277             char16_t c;
   278             uint32_t src;
   279             for (src = 0; src < resultStr.Length(); src++) {
   280                 c = resultStr.CharAt(src);
   281                 if (XMLUtils::isWhitespace(c)) {
   282                     addSpace = true;
   283                 }
   284                 else {
   285                     if (addSpace && !first)
   286                         strRes->mValue.Append(char16_t(' '));
   288                     strRes->mValue.Append(c);
   289                     addSpace = false;
   290                     first = false;
   291                 }
   292             }
   293             *aResult = strRes;
   294             NS_ADDREF(*aResult);
   296             return NS_OK;
   297         }
   298         case STARTS_WITH:
   299         {
   300             nsAutoString arg2;
   301             rv = mParams[1]->evaluateToString(aContext, arg2);
   302             NS_ENSURE_SUCCESS(rv, rv);
   304             bool result = false;
   305             if (arg2.IsEmpty()) {
   306                 result = true;
   307             }
   308             else {
   309                 nsAutoString arg1;
   310                 rv = mParams[0]->evaluateToString(aContext, arg1);
   311                 NS_ENSURE_SUCCESS(rv, rv);
   313                 result = StringBeginsWith(arg1, arg2);
   314             }
   316             aContext->recycler()->getBoolResult(result, aResult);
   318             return NS_OK;
   319         }
   320         case STRING:
   321         {
   322             nsRefPtr<StringResult> strRes;
   323             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
   324             NS_ENSURE_SUCCESS(rv, rv);
   326             if (!mParams.IsEmpty()) {
   327                 rv = mParams[0]->evaluateToString(aContext, strRes->mValue);
   328                 NS_ENSURE_SUCCESS(rv, rv);
   329             }
   330             else {
   331                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
   332                                                   strRes->mValue);
   333             }
   335             NS_ADDREF(*aResult = strRes);
   337             return NS_OK;
   338         }
   339         case STRING_LENGTH:
   340         {
   341             nsAutoString resultStr;
   342             if (!mParams.IsEmpty()) {
   343                 rv = mParams[0]->evaluateToString(aContext, resultStr);
   344                 NS_ENSURE_SUCCESS(rv, rv);
   345             }
   346             else {
   347                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
   348                                                   resultStr);
   349             }
   350             rv = aContext->recycler()->getNumberResult(resultStr.Length(),
   351                                                        aResult);
   352             NS_ENSURE_SUCCESS(rv, rv);
   354             return NS_OK;
   355         }
   356         case SUBSTRING:
   357         {
   358             nsAutoString src;
   359             rv = mParams[0]->evaluateToString(aContext, src);
   360             NS_ENSURE_SUCCESS(rv, rv);
   362             double start;
   363             rv = evaluateToNumber(mParams[1], aContext, &start);
   364             NS_ENSURE_SUCCESS(rv, rv);
   366             // check for NaN or +/-Inf
   367             if (mozilla::IsNaN(start) ||
   368                 mozilla::IsInfinite(start) ||
   369                 start >= src.Length() + 0.5) {
   370                 aContext->recycler()->getEmptyStringResult(aResult);
   372                 return NS_OK;
   373             }
   375             start = floor(start + 0.5) - 1;
   377             double end;
   378             if (mParams.Length() == 3) {
   379                 rv = evaluateToNumber(mParams[2], aContext, &end);
   380                 NS_ENSURE_SUCCESS(rv, rv);
   382                 end += start;
   383                 if (mozilla::IsNaN(end) || end < 0) {
   384                     aContext->recycler()->getEmptyStringResult(aResult);
   386                     return NS_OK;
   387                 }
   389                 if (end > src.Length())
   390                     end = src.Length();
   391                 else
   392                     end = floor(end + 0.5);
   393             }
   394             else {
   395                 end = src.Length();
   396             }
   398             if (start < 0)
   399                 start = 0;
   401             if (start > end) {
   402                 aContext->recycler()->getEmptyStringResult(aResult);
   404                 return NS_OK;
   405             }
   407             return aContext->recycler()->getStringResult(
   408                   Substring(src, (uint32_t)start, (uint32_t)(end - start)),
   409                   aResult);
   410         }
   411         case SUBSTRING_AFTER:
   412         {
   413             nsAutoString arg1;
   414             rv = mParams[0]->evaluateToString(aContext, arg1);
   415             NS_ENSURE_SUCCESS(rv, rv);
   417             nsAutoString arg2;
   418             rv = mParams[1]->evaluateToString(aContext, arg2);
   419             NS_ENSURE_SUCCESS(rv, rv);
   421             if (arg2.IsEmpty()) {
   422                 return aContext->recycler()->getStringResult(arg1, aResult);
   423             }
   425             int32_t idx = arg1.Find(arg2);
   426             if (idx == kNotFound) {
   427                 aContext->recycler()->getEmptyStringResult(aResult);
   429                 return NS_OK;
   430             }
   432             const nsSubstring& result = Substring(arg1, idx + arg2.Length());
   433             return aContext->recycler()->getStringResult(result, aResult);
   434         }
   435         case SUBSTRING_BEFORE:
   436         {
   437             nsAutoString arg2;
   438             rv = mParams[1]->evaluateToString(aContext, arg2);
   439             NS_ENSURE_SUCCESS(rv, rv);
   441             if (arg2.IsEmpty()) {
   442                 aContext->recycler()->getEmptyStringResult(aResult);
   444                 return NS_OK;
   445             }
   447             nsAutoString arg1;
   448             rv = mParams[0]->evaluateToString(aContext, arg1);
   449             NS_ENSURE_SUCCESS(rv, rv);
   451             int32_t idx = arg1.Find(arg2);
   452             if (idx == kNotFound) {
   453                 aContext->recycler()->getEmptyStringResult(aResult);
   455                 return NS_OK;
   456             }
   458             return aContext->recycler()->getStringResult(StringHead(arg1, idx),
   459                                                          aResult);
   460         }
   461         case TRANSLATE:
   462         {
   463             nsAutoString src;
   464             rv = mParams[0]->evaluateToString(aContext, src);
   465             NS_ENSURE_SUCCESS(rv, rv);
   467             if (src.IsEmpty()) {
   468                 aContext->recycler()->getEmptyStringResult(aResult);
   470                 return NS_OK;
   471             }
   473             nsRefPtr<StringResult> strRes;
   474             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
   475             NS_ENSURE_SUCCESS(rv, rv);
   477             strRes->mValue.SetCapacity(src.Length());
   479             nsAutoString oldChars, newChars;
   480             rv = mParams[1]->evaluateToString(aContext, oldChars);
   481             NS_ENSURE_SUCCESS(rv, rv);
   483             rv = mParams[2]->evaluateToString(aContext, newChars);
   484             NS_ENSURE_SUCCESS(rv, rv);
   486             uint32_t i;
   487             int32_t newCharsLength = (int32_t)newChars.Length();
   488             for (i = 0; i < src.Length(); i++) {
   489                 int32_t idx = oldChars.FindChar(src.CharAt(i));
   490                 if (idx != kNotFound) {
   491                     if (idx < newCharsLength)
   492                         strRes->mValue.Append(newChars.CharAt((uint32_t)idx));
   493                 }
   494                 else {
   495                     strRes->mValue.Append(src.CharAt(i));
   496                 }
   497             }
   499             NS_ADDREF(*aResult = strRes);
   501             return NS_OK;
   502         }
   504         // Number functions
   506         case NUMBER:
   507         {
   508             double res;
   509             if (!mParams.IsEmpty()) {
   510                 rv = evaluateToNumber(mParams[0], aContext, &res);
   511                 NS_ENSURE_SUCCESS(rv, rv);
   512             }
   513             else {
   514                 nsAutoString resultStr;
   515                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
   516                                                   resultStr);
   517                 res = txDouble::toDouble(resultStr);
   518             }
   519             return aContext->recycler()->getNumberResult(res, aResult);
   520         }
   521         case ROUND:
   522         {
   523             double dbl;
   524             rv = evaluateToNumber(mParams[0], aContext, &dbl);
   525             NS_ENSURE_SUCCESS(rv, rv);
   527             if (mozilla::IsFinite(dbl)) {
   528                 if (mozilla::IsNegative(dbl) && dbl >= -0.5) {
   529                     dbl *= 0;
   530                 }
   531                 else {
   532                     dbl = floor(dbl + 0.5);
   533                 }
   534             }
   536             return aContext->recycler()->getNumberResult(dbl, aResult);
   537         }
   538         case FLOOR:
   539         {
   540             double dbl;
   541             rv = evaluateToNumber(mParams[0], aContext, &dbl);
   542             NS_ENSURE_SUCCESS(rv, rv);
   544             if (mozilla::IsFinite(dbl) && !mozilla::IsNegativeZero(dbl))
   545                 dbl = floor(dbl);
   547             return aContext->recycler()->getNumberResult(dbl, aResult);
   548         }
   549         case CEILING:
   550         {
   551             double dbl;
   552             rv = evaluateToNumber(mParams[0], aContext, &dbl);
   553             NS_ENSURE_SUCCESS(rv, rv);
   555             if (mozilla::IsFinite(dbl)) {
   556                 if (mozilla::IsNegative(dbl) && dbl > -1)
   557                     dbl *= 0;
   558                 else
   559                     dbl = ceil(dbl);
   560             }
   562             return aContext->recycler()->getNumberResult(dbl, aResult);
   563         }
   564         case SUM:
   565         {
   566             nsRefPtr<txNodeSet> nodes;
   567             nsresult rv = evaluateToNodeSet(mParams[0], aContext,
   568                                             getter_AddRefs(nodes));
   569             NS_ENSURE_SUCCESS(rv, rv);
   571             double res = 0;
   572             int32_t i;
   573             for (i = 0; i < nodes->size(); ++i) {
   574                 nsAutoString resultStr;
   575                 txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
   576                 res += txDouble::toDouble(resultStr);
   577             }
   578             return aContext->recycler()->getNumberResult(res, aResult);
   579         }
   581         // Boolean functions
   583         case BOOLEAN:
   584         {
   585             bool result;
   586             nsresult rv = mParams[0]->evaluateToBool(aContext, result);
   587             NS_ENSURE_SUCCESS(rv, rv);
   589             aContext->recycler()->getBoolResult(result, aResult);
   591             return NS_OK;
   592         }
   593         case _FALSE:
   594         {
   595             aContext->recycler()->getBoolResult(false, aResult);
   597             return NS_OK;
   598         }
   599         case LANG:
   600         {
   601             txXPathTreeWalker walker(aContext->getContextNode());
   603             nsAutoString lang;
   604             bool found;
   605             do {
   606                 found = walker.getAttr(nsGkAtoms::lang, kNameSpaceID_XML,
   607                                        lang);
   608             } while (!found && walker.moveToParent());
   610             if (!found) {
   611                 aContext->recycler()->getBoolResult(false, aResult);
   613                 return NS_OK;
   614             }
   616             nsAutoString arg;
   617             rv = mParams[0]->evaluateToString(aContext, arg);
   618             NS_ENSURE_SUCCESS(rv, rv);
   620             bool result =
   621                 StringBeginsWith(lang, arg,
   622                                  txCaseInsensitiveStringComparator()) &&
   623                 (lang.Length() == arg.Length() ||
   624                  lang.CharAt(arg.Length()) == '-');
   626             aContext->recycler()->getBoolResult(result, aResult);
   628             return NS_OK;
   629         }
   630         case _NOT:
   631         {
   632             bool result;
   633             rv = mParams[0]->evaluateToBool(aContext, result);
   634             NS_ENSURE_SUCCESS(rv, rv);
   636             aContext->recycler()->getBoolResult(!result, aResult);
   638             return NS_OK;
   639         }
   640         case _TRUE:
   641         {
   642             aContext->recycler()->getBoolResult(true, aResult);
   644             return NS_OK;
   645         }
   646     }
   648     aContext->receiveError(NS_LITERAL_STRING("Internal error"),
   649                            NS_ERROR_UNEXPECTED);
   650     return NS_ERROR_UNEXPECTED;
   651 }
   653 Expr::ResultType
   654 txCoreFunctionCall::getReturnType()
   655 {
   656     return descriptTable[mType].mReturnType;
   657 }
   659 bool
   660 txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext)
   661 {
   662     switch (mType) {
   663         case COUNT:
   664         case CONCAT:
   665         case CONTAINS:
   666         case STARTS_WITH:
   667         case SUBSTRING:
   668         case SUBSTRING_AFTER:
   669         case SUBSTRING_BEFORE:
   670         case TRANSLATE:
   671         case ROUND:
   672         case FLOOR:
   673         case CEILING:
   674         case SUM:
   675         case BOOLEAN:
   676         case _NOT:
   677         case _FALSE:
   678         case _TRUE:
   679         {
   680             return argsSensitiveTo(aContext);
   681         }
   682         case ID:
   683         {
   684             return (aContext & NODE_CONTEXT) ||
   685                    argsSensitiveTo(aContext);
   686         }
   687         case LAST:
   688         {
   689             return !!(aContext & SIZE_CONTEXT);
   690         }
   691         case LOCAL_NAME:
   692         case NAME:
   693         case NAMESPACE_URI:
   694         case NORMALIZE_SPACE:
   695         case STRING:
   696         case STRING_LENGTH:
   697         case NUMBER:
   698         {
   699             if (mParams.IsEmpty()) {
   700                 return !!(aContext & NODE_CONTEXT);
   701             }
   702             return argsSensitiveTo(aContext);
   703         }
   704         case POSITION:
   705         {
   706             return !!(aContext & POSITION_CONTEXT);
   707         }
   708         case LANG:
   709         {
   710             return (aContext & NODE_CONTEXT) ||
   711                    argsSensitiveTo(aContext);
   712         }
   713     }
   715     NS_NOTREACHED("how'd we get here?");
   716     return true;
   717 }
   719 // static
   720 bool
   721 txCoreFunctionCall::getTypeFromAtom(nsIAtom* aName, eType& aType)
   722 {
   723     uint32_t i;
   724     for (i = 0; i < ArrayLength(descriptTable); ++i) {
   725         if (aName == *descriptTable[i].mName) {
   726             aType = static_cast<eType>(i);
   728             return true;
   729         }
   730     }
   732     return false;
   733 }
   735 #ifdef TX_TO_STRING
   736 nsresult
   737 txCoreFunctionCall::getNameAtom(nsIAtom** aAtom)
   738 {
   739     NS_ADDREF(*aAtom = *descriptTable[mType].mName);
   740     return NS_OK;
   741 }
   742 #endif

mercurial