Home | History | Annotate | Download | only in xml
      1 /*
      2  * Copyright (C) 2005 Frerich Raabe <raabe (at) kde.org>
      3  * Copyright (C) 2006, 2009 Apple Inc.
      4  * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org>
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "config.h"
     29 #include "core/xml/XPathFunctions.h"
     30 
     31 #include "core/XMLNames.h"
     32 #include "core/dom/Attr.h"
     33 #include "core/dom/Element.h"
     34 #include "core/dom/ProcessingInstruction.h"
     35 #include "core/dom/TreeScope.h"
     36 #include "core/xml/XPathUtil.h"
     37 #include "core/xml/XPathValue.h"
     38 #include "wtf/MathExtras.h"
     39 #include "wtf/text/StringBuilder.h"
     40 
     41 namespace WebCore {
     42 namespace XPath {
     43 
     44 static inline bool isWhitespace(UChar c)
     45 {
     46     return c == ' ' || c == '\n' || c == '\r' || c == '\t';
     47 }
     48 
     49 
     50 #define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
     51 
     52 class Interval {
     53 public:
     54     static const int Inf = -1;
     55 
     56     Interval();
     57     Interval(int value);
     58     Interval(int min, int max);
     59 
     60     bool contains(int value) const;
     61 
     62 private:
     63     int m_min;
     64     int m_max;
     65 };
     66 
     67 struct FunctionRec {
     68     typedef Function *(*FactoryFn)();
     69     FactoryFn factoryFn;
     70     Interval args;
     71 };
     72 
     73 static HashMap<String, FunctionRec>* functionMap;
     74 
     75 class FunLast FINAL : public Function {
     76     virtual Value evaluate() const OVERRIDE;
     77     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
     78 public:
     79     FunLast() { setIsContextSizeSensitive(true); }
     80 };
     81 
     82 class FunPosition FINAL : public Function {
     83     virtual Value evaluate() const OVERRIDE;
     84     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
     85 public:
     86     FunPosition() { setIsContextPositionSensitive(true); }
     87 };
     88 
     89 class FunCount FINAL : public Function {
     90     virtual Value evaluate() const OVERRIDE;
     91     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
     92 };
     93 
     94 class FunId FINAL : public Function {
     95     virtual Value evaluate() const OVERRIDE;
     96     virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
     97 };
     98 
     99 class FunLocalName FINAL : public Function {
    100     virtual Value evaluate() const OVERRIDE;
    101     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    102 public:
    103     FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node.
    104 };
    105 
    106 class FunNamespaceURI FINAL : public Function {
    107     virtual Value evaluate() const OVERRIDE;
    108     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    109 public:
    110     FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node.
    111 };
    112 
    113 class FunName FINAL : public Function {
    114     virtual Value evaluate() const OVERRIDE;
    115     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    116 public:
    117     FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node.
    118 };
    119 
    120 class FunString FINAL : public Function {
    121     virtual Value evaluate() const OVERRIDE;
    122     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    123 public:
    124     FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node.
    125 };
    126 
    127 class FunConcat FINAL : public Function {
    128     virtual Value evaluate() const OVERRIDE;
    129     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    130 };
    131 
    132 class FunStartsWith FINAL : public Function {
    133     virtual Value evaluate() const OVERRIDE;
    134     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    135 };
    136 
    137 class FunContains FINAL : public Function {
    138     virtual Value evaluate() const OVERRIDE;
    139     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    140 };
    141 
    142 class FunSubstringBefore FINAL : public Function {
    143     virtual Value evaluate() const OVERRIDE;
    144     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    145 };
    146 
    147 class FunSubstringAfter FINAL : public Function {
    148     virtual Value evaluate() const OVERRIDE;
    149     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    150 };
    151 
    152 class FunSubstring FINAL : public Function {
    153     virtual Value evaluate() const OVERRIDE;
    154     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    155 };
    156 
    157 class FunStringLength FINAL : public Function {
    158     virtual Value evaluate() const OVERRIDE;
    159     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
    160 public:
    161     FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node.
    162 };
    163 
    164 class FunNormalizeSpace FINAL : public Function {
    165     virtual Value evaluate() const OVERRIDE;
    166     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    167 public:
    168     FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node.
    169 };
    170 
    171 class FunTranslate FINAL : public Function {
    172     virtual Value evaluate() const OVERRIDE;
    173     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
    174 };
    175 
    176 class FunBoolean FINAL : public Function {
    177     virtual Value evaluate() const OVERRIDE;
    178     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    179 };
    180 
    181 class FunNot FINAL : public Function {
    182     virtual Value evaluate() const OVERRIDE;
    183     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    184 };
    185 
    186 class FunTrue FINAL : public Function {
    187     virtual Value evaluate() const OVERRIDE;
    188     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    189 };
    190 
    191 class FunFalse FINAL : public Function {
    192     virtual Value evaluate() const OVERRIDE;
    193     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    194 };
    195 
    196 class FunLang FINAL : public Function {
    197     virtual Value evaluate() const OVERRIDE;
    198     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
    199 public:
    200     FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node.
    201 };
    202 
    203 class FunNumber FINAL : public Function {
    204     virtual Value evaluate() const OVERRIDE;
    205     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
    206 public:
    207     FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node.
    208 };
    209 
    210 class FunSum FINAL : public Function {
    211     virtual Value evaluate() const OVERRIDE;
    212     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
    213 };
    214 
    215 class FunFloor FINAL : public Function {
    216     virtual Value evaluate() const OVERRIDE;
    217     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
    218 };
    219 
    220 class FunCeiling FINAL : public Function {
    221     virtual Value evaluate() const OVERRIDE;
    222     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
    223 };
    224 
    225 class FunRound FINAL : public Function {
    226     virtual Value evaluate() const OVERRIDE;
    227     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
    228 public:
    229     static double round(double);
    230 };
    231 
    232 DEFINE_FUNCTION_CREATOR(FunLast)
    233 DEFINE_FUNCTION_CREATOR(FunPosition)
    234 DEFINE_FUNCTION_CREATOR(FunCount)
    235 DEFINE_FUNCTION_CREATOR(FunId)
    236 DEFINE_FUNCTION_CREATOR(FunLocalName)
    237 DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
    238 DEFINE_FUNCTION_CREATOR(FunName)
    239 
    240 DEFINE_FUNCTION_CREATOR(FunString)
    241 DEFINE_FUNCTION_CREATOR(FunConcat)
    242 DEFINE_FUNCTION_CREATOR(FunStartsWith)
    243 DEFINE_FUNCTION_CREATOR(FunContains)
    244 DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
    245 DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
    246 DEFINE_FUNCTION_CREATOR(FunSubstring)
    247 DEFINE_FUNCTION_CREATOR(FunStringLength)
    248 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
    249 DEFINE_FUNCTION_CREATOR(FunTranslate)
    250 
    251 DEFINE_FUNCTION_CREATOR(FunBoolean)
    252 DEFINE_FUNCTION_CREATOR(FunNot)
    253 DEFINE_FUNCTION_CREATOR(FunTrue)
    254 DEFINE_FUNCTION_CREATOR(FunFalse)
    255 DEFINE_FUNCTION_CREATOR(FunLang)
    256 
    257 DEFINE_FUNCTION_CREATOR(FunNumber)
    258 DEFINE_FUNCTION_CREATOR(FunSum)
    259 DEFINE_FUNCTION_CREATOR(FunFloor)
    260 DEFINE_FUNCTION_CREATOR(FunCeiling)
    261 DEFINE_FUNCTION_CREATOR(FunRound)
    262 
    263 #undef DEFINE_FUNCTION_CREATOR
    264 
    265 inline Interval::Interval()
    266     : m_min(Inf), m_max(Inf)
    267 {
    268 }
    269 
    270 inline Interval::Interval(int value)
    271     : m_min(value), m_max(value)
    272 {
    273 }
    274 
    275 inline Interval::Interval(int min, int max)
    276     : m_min(min), m_max(max)
    277 {
    278 }
    279 
    280 inline bool Interval::contains(int value) const
    281 {
    282     if (m_min == Inf && m_max == Inf)
    283         return true;
    284 
    285     if (m_min == Inf)
    286         return value <= m_max;
    287 
    288     if (m_max == Inf)
    289         return value >= m_min;
    290 
    291     return value >= m_min && value <= m_max;
    292 }
    293 
    294 void Function::setArguments(WillBeHeapVector<OwnPtrWillBeMember<Expression> >& args)
    295 {
    296     ASSERT(!subExprCount());
    297 
    298     // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive.
    299     if (m_name != "lang" && !args.isEmpty())
    300         setIsContextNodeSensitive(false);
    301 
    302     WillBeHeapVector<OwnPtrWillBeMember<Expression> >::iterator end = args.end();
    303     for (WillBeHeapVector<OwnPtrWillBeMember<Expression> >::iterator it = args.begin(); it != end; ++it)
    304         addSubExpression(it->release());
    305 }
    306 
    307 Value FunLast::evaluate() const
    308 {
    309     return Expression::evaluationContext().size;
    310 }
    311 
    312 Value FunPosition::evaluate() const
    313 {
    314     return Expression::evaluationContext().position;
    315 }
    316 
    317 Value FunId::evaluate() const
    318 {
    319     Value a = arg(0)->evaluate();
    320     StringBuilder idList; // A whitespace-separated list of IDs
    321 
    322     if (a.isNodeSet()) {
    323         const NodeSet& nodes = a.toNodeSet();
    324         for (size_t i = 0; i < nodes.size(); ++i) {
    325             String str = stringValue(nodes[i]);
    326             idList.append(str);
    327             idList.append(' ');
    328         }
    329     } else {
    330         String str = a.toString();
    331         idList.append(str);
    332     }
    333 
    334     TreeScope& contextScope = evaluationContext().node->treeScope();
    335     OwnPtrWillBeRawPtr<NodeSet> result(NodeSet::create());
    336     HashSet<Node*> resultSet;
    337 
    338     unsigned startPos = 0;
    339     unsigned length = idList.length();
    340     while (true) {
    341         while (startPos < length && isWhitespace(idList[startPos]))
    342             ++startPos;
    343 
    344         if (startPos == length)
    345             break;
    346 
    347         size_t endPos = startPos;
    348         while (endPos < length && !isWhitespace(idList[endPos]))
    349             ++endPos;
    350 
    351         // If there are several nodes with the same id, id() should return the first one.
    352         // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
    353         Node* node = contextScope.getElementById(AtomicString(idList.substring(startPos, endPos - startPos)));
    354         if (node && resultSet.add(node).isNewEntry)
    355             result->append(node);
    356 
    357         startPos = endPos;
    358     }
    359 
    360     result->markSorted(false);
    361 
    362     return Value(result.release(), Value::adopt);
    363 }
    364 
    365 static inline String expandedNameLocalPart(Node* node)
    366 {
    367     // The local part of an XPath expanded-name matches DOM local name for most node types, except for namespace nodes and processing instruction nodes.
    368     // But note that Blink does not support namespace nodes.
    369     if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
    370         return toProcessingInstruction(node)->target();
    371     return node->localName().string();
    372 }
    373 
    374 static inline String expandedName(Node* node)
    375 {
    376     AtomicString prefix;
    377 
    378     switch (node->nodeType()) {
    379     case Node::ELEMENT_NODE:
    380         prefix = toElement(node)->prefix();
    381         break;
    382     case Node::ATTRIBUTE_NODE:
    383         prefix = toAttr(node)->prefix();
    384         break;
    385     default:
    386         break;
    387     }
    388 
    389     return prefix.isEmpty() ? expandedNameLocalPart(node) : prefix + ":" + expandedNameLocalPart(node);
    390 }
    391 
    392 Value FunLocalName::evaluate() const
    393 {
    394     if (argCount() > 0) {
    395         Value a = arg(0)->evaluate();
    396         if (!a.isNodeSet())
    397             return "";
    398 
    399         Node* node = a.toNodeSet().firstNode();
    400         return node ? expandedNameLocalPart(node) : "";
    401     }
    402 
    403     return expandedNameLocalPart(evaluationContext().node.get());
    404 }
    405 
    406 Value FunNamespaceURI::evaluate() const
    407 {
    408     if (argCount() > 0) {
    409         Value a = arg(0)->evaluate();
    410         if (!a.isNodeSet())
    411             return "";
    412 
    413         Node* node = a.toNodeSet().firstNode();
    414         return node ? node->namespaceURI().string() : "";
    415     }
    416 
    417     return evaluationContext().node->namespaceURI().string();
    418 }
    419 
    420 Value FunName::evaluate() const
    421 {
    422     if (argCount() > 0) {
    423         Value a = arg(0)->evaluate();
    424         if (!a.isNodeSet())
    425             return "";
    426 
    427         Node* node = a.toNodeSet().firstNode();
    428         return node ? expandedName(node) : "";
    429     }
    430 
    431     return expandedName(evaluationContext().node.get());
    432 }
    433 
    434 Value FunCount::evaluate() const
    435 {
    436     Value a = arg(0)->evaluate();
    437 
    438     return double(a.toNodeSet().size());
    439 }
    440 
    441 Value FunString::evaluate() const
    442 {
    443     if (!argCount())
    444         return Value(Expression::evaluationContext().node.get()).toString();
    445     return arg(0)->evaluate().toString();
    446 }
    447 
    448 Value FunConcat::evaluate() const
    449 {
    450     StringBuilder result;
    451     result.reserveCapacity(1024);
    452 
    453     unsigned count = argCount();
    454     for (unsigned i = 0; i < count; ++i) {
    455         String str(arg(i)->evaluate().toString());
    456         result.append(str);
    457     }
    458 
    459     return result.toString();
    460 }
    461 
    462 Value FunStartsWith::evaluate() const
    463 {
    464     String s1 = arg(0)->evaluate().toString();
    465     String s2 = arg(1)->evaluate().toString();
    466 
    467     if (s2.isEmpty())
    468         return true;
    469 
    470     return s1.startsWith(s2);
    471 }
    472 
    473 Value FunContains::evaluate() const
    474 {
    475     String s1 = arg(0)->evaluate().toString();
    476     String s2 = arg(1)->evaluate().toString();
    477 
    478     if (s2.isEmpty())
    479         return true;
    480 
    481     return s1.contains(s2) != 0;
    482 }
    483 
    484 Value FunSubstringBefore::evaluate() const
    485 {
    486     String s1 = arg(0)->evaluate().toString();
    487     String s2 = arg(1)->evaluate().toString();
    488 
    489     if (s2.isEmpty())
    490         return "";
    491 
    492     size_t i = s1.find(s2);
    493 
    494     if (i == kNotFound)
    495         return "";
    496 
    497     return s1.left(i);
    498 }
    499 
    500 Value FunSubstringAfter::evaluate() const
    501 {
    502     String s1 = arg(0)->evaluate().toString();
    503     String s2 = arg(1)->evaluate().toString();
    504 
    505     size_t i = s1.find(s2);
    506     if (i == kNotFound)
    507         return "";
    508 
    509     return s1.substring(i + s2.length());
    510 }
    511 
    512 Value FunSubstring::evaluate() const
    513 {
    514     String s = arg(0)->evaluate().toString();
    515     double doublePos = arg(1)->evaluate().toNumber();
    516     if (std::isnan(doublePos))
    517         return "";
    518     long pos = static_cast<long>(FunRound::round(doublePos));
    519     bool haveLength = argCount() == 3;
    520     long len = -1;
    521     if (haveLength) {
    522         double doubleLen = arg(2)->evaluate().toNumber();
    523         if (std::isnan(doubleLen))
    524             return "";
    525         len = static_cast<long>(FunRound::round(doubleLen));
    526     }
    527 
    528     if (pos > long(s.length()))
    529         return "";
    530 
    531     if (pos < 1) {
    532         if (haveLength) {
    533             len -= 1 - pos;
    534             if (len < 1)
    535                 return "";
    536         }
    537         pos = 1;
    538     }
    539 
    540     return s.substring(pos - 1, len);
    541 }
    542 
    543 Value FunStringLength::evaluate() const
    544 {
    545     if (!argCount())
    546         return Value(Expression::evaluationContext().node.get()).toString().length();
    547     return arg(0)->evaluate().toString().length();
    548 }
    549 
    550 Value FunNormalizeSpace::evaluate() const
    551 {
    552     if (!argCount()) {
    553         String s = Value(Expression::evaluationContext().node.get()).toString();
    554         return s.simplifyWhiteSpace();
    555     }
    556 
    557     String s = arg(0)->evaluate().toString();
    558     return s.simplifyWhiteSpace();
    559 }
    560 
    561 Value FunTranslate::evaluate() const
    562 {
    563     String s1 = arg(0)->evaluate().toString();
    564     String s2 = arg(1)->evaluate().toString();
    565     String s3 = arg(2)->evaluate().toString();
    566     StringBuilder result;
    567 
    568     for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
    569         UChar ch = s1[i1];
    570         size_t i2 = s2.find(ch);
    571 
    572         if (i2 == kNotFound)
    573             result.append(ch);
    574         else if (i2 < s3.length())
    575             result.append(s3[i2]);
    576     }
    577 
    578     return result.toString();
    579 }
    580 
    581 Value FunBoolean::evaluate() const
    582 {
    583     return arg(0)->evaluate().toBoolean();
    584 }
    585 
    586 Value FunNot::evaluate() const
    587 {
    588     return !arg(0)->evaluate().toBoolean();
    589 }
    590 
    591 Value FunTrue::evaluate() const
    592 {
    593     return true;
    594 }
    595 
    596 Value FunLang::evaluate() const
    597 {
    598     String lang = arg(0)->evaluate().toString();
    599 
    600     const Attribute* languageAttribute = 0;
    601     Node* node = evaluationContext().node.get();
    602     while (node) {
    603         if (node->isElementNode()) {
    604             Element* element = toElement(node);
    605             if (element->hasAttributes())
    606                 languageAttribute = element->findAttributeByName(XMLNames::langAttr);
    607         }
    608         if (languageAttribute)
    609             break;
    610         node = node->parentNode();
    611     }
    612 
    613     if (!languageAttribute)
    614         return false;
    615 
    616     String langValue = languageAttribute->value();
    617     while (true) {
    618         if (equalIgnoringCase(langValue, lang))
    619             return true;
    620 
    621         // Remove suffixes one by one.
    622         size_t index = langValue.reverseFind('-');
    623         if (index == kNotFound)
    624             break;
    625         langValue = langValue.left(index);
    626     }
    627 
    628     return false;
    629 }
    630 
    631 Value FunFalse::evaluate() const
    632 {
    633     return false;
    634 }
    635 
    636 Value FunNumber::evaluate() const
    637 {
    638     if (!argCount())
    639         return Value(Expression::evaluationContext().node.get()).toNumber();
    640     return arg(0)->evaluate().toNumber();
    641 }
    642 
    643 Value FunSum::evaluate() const
    644 {
    645     Value a = arg(0)->evaluate();
    646     if (!a.isNodeSet())
    647         return 0.0;
    648 
    649     double sum = 0.0;
    650     const NodeSet& nodes = a.toNodeSet();
    651     // To be really compliant, we should sort the node-set, as floating point addition is not associative.
    652     // However, this is unlikely to ever become a practical issue, and sorting is slow.
    653 
    654     for (unsigned i = 0; i < nodes.size(); i++)
    655         sum += Value(stringValue(nodes[i])).toNumber();
    656 
    657     return sum;
    658 }
    659 
    660 Value FunFloor::evaluate() const
    661 {
    662     return floor(arg(0)->evaluate().toNumber());
    663 }
    664 
    665 Value FunCeiling::evaluate() const
    666 {
    667     return ceil(arg(0)->evaluate().toNumber());
    668 }
    669 
    670 double FunRound::round(double val)
    671 {
    672     if (!std::isnan(val) && !std::isinf(val)) {
    673         if (std::signbit(val) && val >= -0.5)
    674             val *= 0; // negative zero
    675         else
    676             val = floor(val + 0.5);
    677     }
    678     return val;
    679 }
    680 
    681 Value FunRound::evaluate() const
    682 {
    683     return round(arg(0)->evaluate().toNumber());
    684 }
    685 
    686 struct FunctionMapping {
    687     const char* name;
    688     FunctionRec function;
    689 };
    690 
    691 static void createFunctionMap()
    692 {
    693     static const FunctionMapping functions[] = {
    694         { "boolean", { &createFunBoolean, 1 } },
    695         { "ceiling", { &createFunCeiling, 1 } },
    696         { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
    697         { "contains", { &createFunContains, 2 } },
    698         { "count", { &createFunCount, 1 } },
    699         { "false", { &createFunFalse, 0 } },
    700         { "floor", { &createFunFloor, 1 } },
    701         { "id", { &createFunId, 1 } },
    702         { "lang", { &createFunLang, 1 } },
    703         { "last", { &createFunLast, 0 } },
    704         { "local-name", { &createFunLocalName, Interval(0, 1) } },
    705         { "name", { &createFunName, Interval(0, 1) } },
    706         { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
    707         { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
    708         { "not", { &createFunNot, 1 } },
    709         { "number", { &createFunNumber, Interval(0, 1) } },
    710         { "position", { &createFunPosition, 0 } },
    711         { "round", { &createFunRound, 1 } },
    712         { "starts-with", { &createFunStartsWith, 2 } },
    713         { "string", { &createFunString, Interval(0, 1) } },
    714         { "string-length", { &createFunStringLength, Interval(0, 1) } },
    715         { "substring", { &createFunSubstring, Interval(2, 3) } },
    716         { "substring-after", { &createFunSubstringAfter, 2 } },
    717         { "substring-before", { &createFunSubstringBefore, 2 } },
    718         { "sum", { &createFunSum, 1 } },
    719         { "translate", { &createFunTranslate, 3 } },
    720         { "true", { &createFunTrue, 0 } },
    721     };
    722 
    723     functionMap = new HashMap<String, FunctionRec>;
    724     for (size_t i = 0; i < WTF_ARRAY_LENGTH(functions); ++i)
    725         functionMap->set(functions[i].name, functions[i].function);
    726 }
    727 
    728 
    729 Function* createFunction(const String& name)
    730 {
    731     WillBeHeapVector<OwnPtrWillBeMember<Expression> > args;
    732     return createFunction(name, args);
    733 }
    734 
    735 Function* createFunction(const String& name, WillBeHeapVector<OwnPtrWillBeMember<Expression> >& args)
    736 {
    737     if (!functionMap)
    738         createFunctionMap();
    739 
    740     HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name);
    741     FunctionRec* functionRec = 0;
    742 
    743     if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->value)->args.contains(args.size()))
    744         return 0;
    745 
    746     Function* function = functionRec->factoryFn();
    747     function->setArguments(args);
    748     function->setName(name);
    749     return function;
    750 }
    751 
    752 }
    753 }
    754