<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; }
#msg ul, pre { overflow: auto; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<title>[19968] trunk</title>
</head>
<body>

<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/19968">19968</a></dd>
<dt>Author</dt> <dd>ap</dd>
<dt>Date</dt> <dd>2007-03-05 12:39:41 -0800 (Mon, 05 Mar 2007)</dd>
</dl>

<h3>Log Message</h3>
<pre>        Reviewed by Darin.

        http://bugs.webkit.org/show_bug.cgi?id=12970
        Fix and import 4XPath test_core_functions.html test

WebCore:

        * xml/XPathExpression.cpp:
        (WebCore::XPathExpression::evaluate): Fully initialize the evaluation context.

        * xml/XPathFunctions.cpp:
        (WebCore::XPath::FunSubstring::doEvaluate): Fixed handling of edge cases.
        (WebCore::XPath::FunRound::round): Reimplemented to match the spec; exposed FunRound::round() to be used in
        other functions.

LayoutTests:
        * fast/xpath/4XPath/Core/test_core_functions-expected.txt: Added.
        * fast/xpath/4XPath/Core/test_core_functions.html: Added.
        The remaining failures with id() are caused by an XML DOM problem - ID attributes declared
        in an internal subset are not treated as such.

        * fast/xpath/4XPath/Core/test.js: Common data for XPath tests.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastxpath4XPathCoretest_core_functionsexpectedtxt">trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions-expected.txt</a></li>
<li><a href="#trunkWebCoreChangeLog">trunk/WebCore/ChangeLog</a></li>
<li><a href="#trunkWebCorexmlXPathExpressioncpp">trunk/WebCore/xml/XPathExpression.cpp</a></li>
<li><a href="#trunkWebCorexmlXPathFunctionscpp">trunk/WebCore/xml/XPathFunctions.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastxpath4XPathCoretestjs">trunk/LayoutTests/fast/xpath/4XPath/Core/test.js</a></li>
<li><a href="#trunkLayoutTestsfastxpath4XPathCoretest_core_functionshtml">trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (19967 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2007-03-05 20:29:11 UTC (rev 19967)
+++ trunk/LayoutTests/ChangeLog        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2007-03-05  Alexey Proskuryakov  &lt;ap@webkit.org&gt;
+
+        Reviewed by Darin.
+
+        http://bugs.webkit.org/show_bug.cgi?id=12970
+        Fix and import 4XPath test_core_functions.html test
+
+        * fast/xpath/4XPath/Core/test_core_functions-expected.txt: Added.
+        * fast/xpath/4XPath/Core/test_core_functions.html: Added.
+        The remaining failures with id() are caused by an XML DOM problem - ID attributes declared
+        in an internal subset are not treated as such.
+
+        * fast/xpath/4XPath/Core/test.js: Common data for XPath tests.
+
</ins><span class="cx"> 2007-03-05  Anders Carlsson  &lt;acarlsson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         * plugins/get-url-with-blank-target-expected.txt:
</span></span></pre></div>
<a id="trunkLayoutTestsfastxpath4XPathCoretestjsfromrev19963trunkLayoutTestsfastxpath4XPathCoretestjs"></a>
<div class="copfile"><h4>Copied: trunk/LayoutTests/fast/xpath/4XPath/Core/test.js (from rev 19963, trunk/LayoutTests/fast/xpath/4XPath/Core/test.js) (0 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/xpath/4XPath/Core/test.js                                (rev 0)
+++ trunk/LayoutTests/fast/xpath/4XPath/Core/test.js        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+DOM = (new DOMParser).parseFromString(
+    '&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;' +
+    '&lt;!DOCTYPE ROOT [' +
+    '  &lt;!ELEMENT CHILD2 (#PCDATA|GCHILD)*&gt;' +
+    '  &lt;!ATTLIST CHILD2 attr1 CDATA #IMPLIED' +
+    '                   CODE ID #REQUIRED&gt;' +
+    ']&gt;' +
+    '&lt;?xml-stylesheet &quot;Data&quot; ?&gt;' +
+    '&lt;ROOT&gt;' +
+    '  &lt;!-- Test Comment --&gt;' +
+    '  &lt;CHILD1 attr1=&quot;val1&quot; attr31=&quot;31&quot;&gt;' +
+    '    &lt;GCHILD name=&quot;GCHILD11&quot;/&gt;' +
+    '    &lt;GCHILD name=&quot;GCHILD12&quot;/&gt;' +
+    '    Text1' +
+    '  &lt;/CHILD1&gt;' +
+    '  &lt;CHILD2 attr1=&quot;val2&quot; CODE=&quot;1&quot;&gt;' +
+    '    &lt;GCHILD name=&quot;GCHILD21&quot;/&gt;' +
+    '    &lt;GCHILD name=&quot;GCHILD22&quot;/&gt;' +
+    '  &lt;/CHILD2&gt;' +
+    '  &lt;foo:CHILD3 xmlns:foo=&quot;http://foo.com&quot; foo:name=&quot;mike&quot;/&gt;' +
+    '  &lt;lang xml:lang=&quot;en&quot;&gt;' +
+    '    &lt;foo xml:lang=&quot;&quot;/&gt;' +
+    '    &lt;foo/&gt;' +
+    '    &lt;f\xf6\xf8/&gt;' +
+    '  &lt;/lang&gt;' +
+    '&lt;/ROOT&gt;' +
+    '&lt;?no-data ?&gt;',
+    'application/xml');
+
+DOM = DOM;
+ROOT = DOM.documentElement;
+
+PI = DOM.firstChild;
+while (PI.nodeType != Node.PROCESSING_INSTRUCTION_NODE)
+    PI = PI.nextSibling;
+PI2 = DOM.lastChild;
+COMMENT = ROOT.firstChild
+while (COMMENT.nodeType != Node.COMMENT_NODE)
+    COMMENT = COMMENT.nextSibling;
+
+CHILD1 = DOM.getElementsByTagName(&quot;CHILD1&quot;)[0];
+ATTR1 = CHILD1.getAttributeNode(&quot;attr1&quot;);
+ATTR31 = CHILD1.getAttributeNode(&quot;attr31&quot;);
+CHILD2 = DOM.getElementsByTagName(&quot;CHILD2&quot;)[0];
+ATTR2 = CHILD2.getAttributeNode(&quot;attr1&quot;);
+IDATTR2 = CHILD2.getAttributeNode('CODE')
+CHILD3 = DOM.getElementsByTagName(&quot;CHILD3&quot;)[0];
+text = CHILD1.lastChild;
+LANG = DOM.getElementsByTagName(&quot;lang&quot;)[0];
+NONASCIIQNAME = DOM.getElementsByTagName(&quot;f\xf6\xf8&quot;)[0];
+
+CHILDREN = [CHILD1, CHILD2, CHILD3, LANG];
+GCHILDREN1 = [CHILD1.getElementsByTagName(&quot;GCHILD&quot;)[0], CHILD1.getElementsByTagName(&quot;GCHILD&quot;)[1]];
+GCHILD11 = GCHILDREN1[0];
+GCHILD12 = GCHILDREN1[1];
+TEXT1 = CHILD1.lastChild;
+GCHILDREN2 = [CHILD2.getElementsByTagName(&quot;GCHILD&quot;)[0], CHILD2.getElementsByTagName(&quot;GCHILD&quot;)[1]];
+GCHILD21 = GCHILDREN2[0];
+GCHILD22 = GCHILDREN2[1];
+LCHILDREN = [LANG.getElementsByTagName(&quot;foo&quot;)[0], LANG.getElementsByTagName(&quot;foo&quot;)[1], LANG.getElementsByTagName(&quot;f\xf6\xf8&quot;)[0]];
+LCHILD1 = LCHILDREN[0];
+LCHILD2 = LCHILDREN[1];
+
+function checkSnapshot(comment, actual, expected) {
+    if (actual.snapshotLength != expected.length) {
+        testFailed(comment + &quot; incorrect length (expected &quot; + expected.length + &quot;, actual &quot; + actual.snapshotLength + &quot;)&quot;);
+        return;
+    }
+    
+    for (i = 0; i &lt; actual.snapshotLength; ++i) {
+        if (actual.snapshotItem(i) != expected[i]) {
+            testFailed(comment + &quot; item &quot; + i + &quot; incorrect (expected &quot; + expected[i].nodeName + &quot;, actual &quot; + actual.snapshotItem(i).nodeName + &quot;)&quot;);
+            return;
+        }
+    }
+    
+    testPassed(comment);
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsfastxpath4XPathCoretest_core_functionsexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions-expected.txt (19967 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions-expected.txt        2007-03-05 20:29:11 UTC (rev 19967)
+++ trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions-expected.txt        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-FAIL DOM.evaluate(&quot;last()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue should be 1 (of type number). Was 0 (of type number).
</del><ins>+PASS DOM.evaluate(&quot;last()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 1
</ins><span class="cx"> PASS DOM.evaluate(&quot;position()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 1
</span><span class="cx"> PASS DOM.evaluate(&quot;count(/ROOT | /ROOT/CHILD1)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 2
</span><span class="cx"> FAIL id(1) incorrect length (expected 1, actual 0)
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx"> PASS DOM.evaluate(&quot;substring('12345', 1.5, 2.6)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue is &quot;234&quot;
</span><span class="cx"> PASS DOM.evaluate(&quot;substring('12345', 0, 3)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue is &quot;12&quot;
</span><span class="cx"> PASS DOM.evaluate(&quot;substring('12345', number('NaN'), 3)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue is &quot;&quot;
</span><del>-FAIL DOM.evaluate(&quot;substring('12345', 1, number('NaN'))&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue should be  (of type string). Was 12345 (of type string).
</del><ins>+PASS DOM.evaluate(&quot;substring('12345', 1, number('NaN'))&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue is &quot;&quot;
</ins><span class="cx"> PASS DOM.evaluate(&quot;substring('12345', -42, 1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue is &quot;12345&quot;
</span><span class="cx"> PASS DOM.evaluate(&quot;substring('12345', -1 div 0, 1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue is &quot;&quot;
</span><span class="cx"> PASS DOM.evaluate(&quot;string-length('3.14Hi')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 6
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx"> PASS DOM.evaluate(&quot;ceiling(0.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 1
</span><span class="cx"> PASS DOM.evaluate(&quot;ceiling(-0.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 0
</span><span class="cx"> PASS DOM.evaluate(&quot;round(3.14)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is 3
</span><del>-FAIL DOM.evaluate(&quot;round(-4.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue should be -4 (of type number). Was -5 (of type number).
</del><ins>+PASS DOM.evaluate(&quot;round(-4.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is -4
</ins><span class="cx"> PASS DOM.evaluate(&quot;round(number('NaN'))&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is NaN
</span><span class="cx"> PASS DOM.evaluate(&quot;round(1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is Infinity
</span><span class="cx"> PASS DOM.evaluate(&quot;round(-1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue is -Infinity
</span></span></pre></div>
<a id="trunkLayoutTestsfastxpath4XPathCoretest_core_functionshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions.html (0 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions.html                                (rev 0)
+++ trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions.html        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -0,0 +1,115 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;link rel=&quot;stylesheet&quot; href=&quot;../../../js/resources/js-test-style.css&quot;&gt;
+&lt;script src=&quot;../../../js/resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;test.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;div id=&quot;console&quot;&gt;&lt;/div&gt;
+
+&lt;script&gt;
+    function nsResolver(prefix) {
+        if (prefix == 'f')
+            return 'http://foo.com';
+        return null;
+    }
+
+    shouldBe('DOM.evaluate(&quot;last()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '1');
+    shouldBe('DOM.evaluate(&quot;position()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '1');
+    shouldBe('DOM.evaluate(&quot;count(/ROOT | /ROOT/CHILD1)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '2');
+
+    result = DOM.evaluate(&quot;id(1)&quot;, CHILD1, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    checkSnapshot(&quot;id(1)&quot;, result, [CHILD2]);
+
+    result = DOM.evaluate(&quot;id('1 1')&quot;, CHILD1, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    checkSnapshot(&quot;id('1 1')&quot;, result, [CHILD2]);
+
+    result = DOM.evaluate(&quot;id('0')&quot;, CHILD1, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    checkSnapshot(&quot;id('0')&quot;, result, []);
+
+    result = DOM.evaluate(&quot;id('0 1')&quot;, CHILD1, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    checkSnapshot(&quot;id('0 1')&quot;, result, [CHILD2]);
+
+    result = DOM.evaluate(&quot;id('0 1 1')&quot;, CHILD1, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    checkSnapshot(&quot;id('0 1 1')&quot;, result, [CHILD2]);
+
+    result = DOM.evaluate(&quot;id('0 0 1 1')&quot;, CHILD1, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    checkSnapshot(&quot;id('0 0 1 1')&quot;, result, [CHILD2]);
+
+    shouldBe('DOM.evaluate(&quot;local-name(/empty)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;local-name(//f:CHILD3)&quot;, CHILD1, nsResolver, XPathResult.ANY_TYPE, null).stringValue', '&quot;CHILD3&quot;');
+    shouldBe('DOM.evaluate(&quot;namespace-uri(/empty)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;namespace-uri(//f:CHILD3)&quot;, CHILD1, nsResolver, XPathResult.ANY_TYPE, null).stringValue', '&quot;http://foo.com&quot;');
+    shouldBe('DOM.evaluate(&quot;name(//f:CHILD3)&quot;, CHILD1, nsResolver, XPathResult.ANY_TYPE, null).stringValue', '&quot;foo:CHILD3&quot;');
+
+    strNodeset3 = &quot;            Text1  &quot;;
+
+    shouldBe('DOM.evaluate(&quot;string(//CHILD1)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', 'strNodeset3');
+    shouldBe('DOM.evaluate(&quot;concat(//CHILD1, \'3.14\', \'Hi\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', 'strNodeset3 + &quot;3.14Hi&quot;');
+    shouldBe('DOM.evaluate(&quot;starts-with(//CHILD1, \'3.14\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+    shouldBe('DOM.evaluate(&quot;starts-with(//CHILD1, //CHILD1)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;starts-with(//CHILD1, \'\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;contains(//CHILD1, \'3.14\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+    shouldBe('DOM.evaluate(&quot;contains(//CHILD1, //CHILD1)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;contains(//CHILD1, \'\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;substring-before(\'3.14Hi\', \'Hi\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;3.14&quot;');
+    shouldBe('DOM.evaluate(&quot;substring-before(\'3.14Hi\', \'\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;substring-after(\'3.14Hi\', \'3.14\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;Hi&quot;');
+    shouldBe('DOM.evaluate(&quot;substring-after(\'3.14Hi\', \'\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'3.14Hi\', \'3.14\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;14Hi&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'3.14Hi\', \'3.14\', 1)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;1&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', 2, 3)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;234&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', 2)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;2345&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', 1.5, 2.6)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;234&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', 0, 3)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;12&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', number(\'NaN\'), 3)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', 1, number(\'NaN\'))&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', -42, 1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;12345&quot;');
+    shouldBe('DOM.evaluate(&quot;substring(\'12345\', -1 div 0, 1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;&quot;');
+    shouldBe('DOM.evaluate(&quot;string-length(\'3.14Hi\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '6');
+    shouldBe('DOM.evaluate(&quot;normalize-space(\'Ht    \t There\t   Mike\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;Ht There Mike&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'Ht    \t There\t   Mike\', \'abcdefg\', \'ABCDEFG\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;Ht    \t ThErE\t   MikE&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'hello world\', \'e\', \'a\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;hallo world&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'hello world\', \'e\', \'abc\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;hallo world&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'hello world\', \'el\', \'a\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;hao word&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'hello world\', \'abcdefgabc\', \'ABCDEFG123\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;hEllo worlD&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'hello world\', \'abcdefghhe\', \'ABCDEFGH\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;HEllo worlD&quot;');
+    shouldBe('DOM.evaluate(&quot;translate(\'hello world\', \'abcdefgh\', \'\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).stringValue', '&quot;llo worl&quot;');
+
+    shouldBe('DOM.evaluate(&quot;boolean(\'3.14\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;not(\'3.14Hi\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+    shouldBe('DOM.evaluate(&quot;true()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;false()&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+
+    shouldBe('DOM.evaluate(&quot;number(\'NaN\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'NaN');
+    shouldBe('DOM.evaluate(&quot;floor(3.14)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '3');
+    shouldBe('DOM.evaluate(&quot;floor(number())&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'NaN');
+    shouldBe('DOM.evaluate(&quot;floor(1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'Infinity');
+    shouldBe('DOM.evaluate(&quot;floor(-1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '-Infinity');
+    shouldBe('DOM.evaluate(&quot;floor(0.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '0');
+    shouldBe('DOM.evaluate(&quot;floor(-0.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '-1');
+    shouldBe('DOM.evaluate(&quot;ceiling(3.14)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '4');
+    shouldBe('DOM.evaluate(&quot;ceiling(number(\'NaN\'))&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'NaN');
+    shouldBe('DOM.evaluate(&quot;ceiling(1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'Infinity');
+    shouldBe('DOM.evaluate(&quot;ceiling(0.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '1');
+    shouldBe('DOM.evaluate(&quot;ceiling(-0.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '0'); // actually should be negative zero
+    shouldBe('DOM.evaluate(&quot;round(3.14)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '3');
+    shouldBe('DOM.evaluate(&quot;round(-4.5)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '-4');
+    shouldBe('DOM.evaluate(&quot;round(number(\'NaN\'))&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'NaN');
+    shouldBe('DOM.evaluate(&quot;round(1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', 'Infinity');
+    shouldBe('DOM.evaluate(&quot;round(-1 div 0)&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '-Infinity');
+    shouldBe('DOM.evaluate(&quot;round(\'12345\')&quot;, CHILD1, null, XPathResult.ANY_TYPE, null).numberValue', '12345');
+    shouldBe('DOM.evaluate(&quot;lang(\'en\')&quot;, LCHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+    shouldBe('DOM.evaluate(&quot;lang(\'en\')&quot;, LCHILD2, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;lang(\'\')&quot;, LCHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'true');
+    shouldBe('DOM.evaluate(&quot;lang(\'\')&quot;, LCHILD2, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+    shouldBe('DOM.evaluate(&quot;lang(\'foo\')&quot;, LCHILD1, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+    shouldBe('DOM.evaluate(&quot;lang(\'foo\')&quot;, LCHILD2, null, XPathResult.ANY_TYPE, null).booleanValue', 'false');
+
+    var successfullyParsed = true;
+
+&lt;/script&gt;
+&lt;script src=&quot;../../../js/resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">Property changes on: trunk/LayoutTests/fast/xpath/4XPath/Core/test_core_functions.html
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:mime-type
</span><span class="cx">   + text/html
</span></span></pre></div>
<a id="trunkWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/ChangeLog (19967 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/ChangeLog        2007-03-05 20:29:11 UTC (rev 19967)
+++ trunk/WebCore/ChangeLog        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -2,6 +2,21 @@
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Darin.
</span><span class="cx"> 
</span><ins>+        http://bugs.webkit.org/show_bug.cgi?id=12970
+        Fix and import 4XPath test_core_functions.html test
+
+        * xml/XPathExpression.cpp:
+        (WebCore::XPathExpression::evaluate): Fully initialize the evaluation context.
+
+        * xml/XPathFunctions.cpp:
+        (WebCore::XPath::FunSubstring::doEvaluate): Fixed handling of edge cases.
+        (WebCore::XPath::FunRound::round): Reimplemented to match the spec; exposed FunRound::round() to be used in
+        other functions.
+
+2007-03-05  Alexey Proskuryakov  &lt;ap@webkit.org&gt;
+
+        Reviewed by Darin.
+
</ins><span class="cx">         http://bugs.webkit.org/show_bug.cgi?id=12954
</span><span class="cx">         XPath relative operations are implemented incorrectly
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebCorexmlXPathExpressioncpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/xml/XPathExpression.cpp (19967 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/xml/XPathExpression.cpp        2007-03-05 20:29:11 UTC (rev 19967)
+++ trunk/WebCore/xml/XPathExpression.cpp        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -71,7 +71,9 @@
</span><span class="cx">         ? contextNode-&gt;ownerDocument()
</span><span class="cx">         : static_cast&lt;EventTargetNode*&gt;(contextNode);
</span><span class="cx"> 
</span><del>-    Expression::evaluationContext().node = contextNode;    
</del><ins>+    Expression::evaluationContext().node = contextNode;
+    Expression::evaluationContext().size = 1;
+    Expression::evaluationContext().position = 1;
</ins><span class="cx">     m_topExpression-&gt;optimize();
</span><span class="cx">     RefPtr&lt;XPathResult&gt; result = new XPathResult(eventTarget, m_topExpression-&gt;evaluate());
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebCorexmlXPathFunctionscpp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/xml/XPathFunctions.cpp (19967 => 19968)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/xml/XPathFunctions.cpp        2007-03-05 20:29:11 UTC (rev 19967)
+++ trunk/WebCore/xml/XPathFunctions.cpp        2007-03-05 20:39:41 UTC (rev 19968)
</span><span class="lines">@@ -186,6 +186,8 @@
</span><span class="cx"> 
</span><span class="cx"> class FunRound : public Function {
</span><span class="cx">     virtual Value doEvaluate() const;
</span><ins>+public:
+    static double round(double);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> DEFINE_FUNCTION_CREATOR(FunLast)
</span><span class="lines">@@ -511,11 +513,15 @@
</span><span class="cx"> Value FunSubstring::doEvaluate() const
</span><span class="cx"> {
</span><span class="cx">     String s = arg(0)-&gt;evaluate().toString();
</span><del>-    long pos = lround(arg(1)-&gt;evaluate().toNumber());
</del><ins>+    long pos = static_cast&lt;long&gt;(FunRound::round(arg(1)-&gt;evaluate().toNumber()));
</ins><span class="cx">     bool haveLength = argCount() == 3;
</span><span class="cx">     long len = -1;
</span><del>-    if (haveLength)
-        len = lround(arg(2)-&gt;evaluate().toNumber());
</del><ins>+    if (haveLength) {
+        double doubleLen = arg(2)-&gt;evaluate().toNumber();
+        if (isnan(doubleLen))
+            return &quot;&quot;;
+        len = static_cast&lt;long&gt;(FunRound::round(doubleLen));
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (pos &gt; long(s.length())) 
</span><span class="cx">         return &quot;&quot;;
</span><span class="lines">@@ -671,6 +677,17 @@
</span><span class="cx">     return ceil(arg(0)-&gt;evaluate().toNumber());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+double FunRound::round(double val)
+{
+    if (!isnan(val) &amp;&amp; !isinf(val)) {
+        if (signbit(val) &amp;&amp; val &gt;= -0.5)
+            val *= 0; // negative zero
+        else
+            val = floor(val + 0.5);
+    }
+    return val;
+}
+
</ins><span class="cx"> Value FunRound::doEvaluate() const
</span><span class="cx"> {
</span><span class="cx">     return round(arg(0)-&gt;evaluate().toNumber());
</span></span></pre>
</div>
</div>

</body>
</html>