<!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" />
<title>[173761] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { 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 #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#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>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/173761">173761</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2014-09-19 10:47:50 -0700 (Fri, 19 Sep 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Simple ES6 feature:String prototype additions
https://bugs.webkit.org/show_bug.cgi?id=131704
Patch by Diego Pino Garcia <dpino@igalia.com> on 2014-09-19
Reviewed by Darin Adler.
Source/JavaScriptCore:
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):
(JSC::stringProtoFuncStartsWith): Added.
(JSC::stringProtoFuncEndsWith): Added.
(JSC::stringProtoFuncContains): Added.
Source/WTF:
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::find):
(WTF::equalInner): Added.
(WTF::StringImpl::startsWith): Add implementation that supports
'startOffset' parameter.
(WTF::StringImpl::endsWith): Add implementation that supports
'endOffset' parameter.
* wtf/text/StringImpl.h:
* wtf/text/WTFString.h:
(WTF::String::contains): Modify current implementation to allow
setting a startOffset, 0 by default.
(WTF::String::startsWith):
(WTF::String::endsWith):
LayoutTests:
Test ES6 functions: string.startsWith(), string.endsWith() and
string.contains().
* js/Object-getOwnPropertyNames-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/string-contains.js: Added.
(stringToSearchIn.toString):
(startOffset.valueOf):
(matchString.toString):
(endOffset.valueOf):
* js/string-contains-expected.txt: Added.
* js/string-contains.html: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsjsObjectgetOwnPropertyNamesexpectedtxt">trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsObjectgetOwnPropertyNamesjs">trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypecpp">trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextStringImplcpp">trunk/Source/WTF/wtf/text/StringImpl.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextStringImplh">trunk/Source/WTF/wtf/text/StringImpl.h</a></li>
<li><a href="#trunkSourceWTFwtftextWTFStringh">trunk/Source/WTF/wtf/text/WTFString.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsscripttestsstringcontainsjs">trunk/LayoutTests/js/script-tests/string-contains.js</a></li>
<li><a href="#trunkLayoutTestsjsstringcontainsexpectedtxt">trunk/LayoutTests/js/string-contains-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsstringcontainshtml">trunk/LayoutTests/js/string-contains.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/LayoutTests/ChangeLog        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2014-09-19 Diego Pino Garcia <dpino@igalia.com>
+
+ Simple ES6 feature:String prototype additions
+ https://bugs.webkit.org/show_bug.cgi?id=131704
+
+ Reviewed by Darin Adler.
+
+ Test ES6 functions: string.startsWith(), string.endsWith() and
+ string.contains().
+
+ * js/Object-getOwnPropertyNames-expected.txt:
+ * js/script-tests/Object-getOwnPropertyNames.js:
+ * js/script-tests/string-contains.js: Added.
+ (stringToSearchIn.toString):
+ (startOffset.valueOf):
+ (matchString.toString):
+ (endOffset.valueOf):
+ * js/string-contains-expected.txt: Added.
+ * js/string-contains.html: Added.
+
</ins><span class="cx"> 2014-09-19 Youenn Fablet <youenn.fablet@crf.canon.fr>
</span><span class="cx">
</span><span class="cx"> WTR and DRT didReceiveAuthenticationChallengeInFrame should print messages consistently
</span></span></pre></div>
<a id="trunkLayoutTestsjsObjectgetOwnPropertyNamesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -47,7 +47,7 @@
</span><span class="cx"> PASS getSortedOwnPropertyNames(Array) is ['isArray', 'length', 'name', 'prototype']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
</span><span class="cx"> PASS getSortedOwnPropertyNames(String) is ['fromCharCode', 'length', 'name', 'prototype']
</span><del>-PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
</del><ins>+PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'contains', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
</ins><span class="cx"> PASS getSortedOwnPropertyNames(Boolean) is ['length', 'name', 'prototype']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Boolean.prototype) is ['constructor', 'toString', 'valueOf']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Number) is ['MAX_VALUE', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'length', 'name', 'prototype']
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsObjectgetOwnPropertyNamesjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -55,7 +55,7 @@
</span><span class="cx"> "Array": "['isArray', 'length', 'name', 'prototype']",
</span><span class="cx"> "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']",
</span><span class="cx"> "String": "['fromCharCode', 'length', 'name', 'prototype']",
</span><del>- "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
</del><ins>+ "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'contains', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
</ins><span class="cx"> "Boolean": "['length', 'name', 'prototype']",
</span><span class="cx"> "Boolean.prototype": "['constructor', 'toString', 'valueOf']",
</span><span class="cx"> "Number": "['MAX_VALUE', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'length', 'name', 'prototype']",
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsstringcontainsjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/string-contains.js (0 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/string-contains.js         (rev 0)
+++ trunk/LayoutTests/js/script-tests/string-contains.js        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -0,0 +1,278 @@
</span><ins>+description("This test checks the ES6 string functions startsWith(), endsWith() and contains().");
+
+// Test contains
+shouldBe("'foo bar'.contains('bar')", "true");
+shouldBe("'foo bar'.contains('bar', 4)", "true");
+shouldBe("'foo bar'.contains('ar', 5)", "true");
+shouldBe("'foo bar'.contains('qux')", "false");
+shouldBe("'foo bar'.contains('foo')", "true");
+shouldBe("'foo bar'.contains('foo', 0)", "true");
+shouldBe("'foo bar'.contains('foo', -1)", "true");
+shouldBe("'foo bar'.contains('')", "true");
+shouldBe("'foo bar'.contains()", "false");
+shouldBe("'foo bar qux'.contains('qux', 7)", "true");
+shouldBe("'foo bar qux'.contains('bar', 7)", "false");
+shouldBe("'foo null bar'.contains()", "false");
+shouldBe("'foo null bar'.contains(null)", "true");
+shouldBe("'foo null bar'.contains(null)", "true");
+shouldBe("'foo undefined bar'.contains()", "true");
+shouldBe("'foo undefined bar'.contains(undefined)", "true");
+shouldBe("'foo undefined bar'.contains()", "true");
+shouldBe("'foo undefined bar'.contains()", "true");
+shouldBe("'foo true bar'.contains(true)", "true");
+shouldBe("'foo false bar'.contains(false)", "true");
+shouldBe("'foo 1 bar'.contains(1)", "true");
+shouldBe("'foo 1.1 bar'.contains(1.1)", "true");
+shouldBe("'foo NaN bar'.contains(NaN)", "true");
+shouldBe("'foo 1.0 bar'.contains(1.0)", "true");
+shouldBe("'foo 1e+100 bar'.contains(1e+100)", "true");
+shouldBe("'foo 1e100 bar'.contains(1e100)", "false");
+shouldBe("'フーバー'.contains('ーバ')", "true");
+shouldBe("'フーバー'.contains('クー')", "false");
+
+// Test startsWith
+shouldBe("'foo bar'.startsWith('foo')", "true");
+shouldBe("'foo bar'.startsWith('foo', 0)", "true");
+shouldBe("'foo bar'.startsWith('foo', -1)", "true");
+shouldBe("'foo bar'.startsWith('oo', 1)", "true");
+shouldBe("'foo bar'.startsWith('qux')", "false");
+shouldBe("'foo bar'.startsWith('')", "true");
+shouldBe("'foo bar'.startsWith()", "false");
+shouldBe("'null'.startsWith()", "false");
+shouldBe("'null'.startsWith(null)", "true");
+shouldBe("'null bar'.startsWith(null)", "true");
+shouldBe("'undefined'.startsWith()", "true");
+shouldBe("'undefined'.startsWith(undefined)", "true");
+shouldBe("'undefined bar'.startsWith()", "true");
+shouldBe("'undefined bar'.startsWith()", "true");
+shouldBe("'true bar'.startsWith(true)", "true");
+shouldBe("'false bar'.startsWith(false)", "true");
+shouldBe("'1 bar'.startsWith(1)", "true");
+shouldBe("'1.1 bar'.startsWith(1.1)", "true");
+shouldBe("'NaN bar'.startsWith(NaN)", "true");
+shouldBe("'1e+100 bar'.startsWith(1e+100)", "true");
+shouldBe("'1e100 bar'.startsWith(1e100)", "false");
+shouldBe("'フーバー'.startsWith('フー')", "true");
+shouldBe("'フーバー'.startsWith('バー')", "false");
+
+// Test endsWith
+shouldBe("'foo bar'.endsWith('bar')", "true");
+shouldBe("'foo bar'.endsWith('ba', 6)", "true");
+shouldBe("'foo bar'.endsWith(' ba', 6)", "true");
+shouldBe("'foo bar'.endsWith('foo bar')", "true");
+shouldBe("'foo bar'.endsWith('foo bar', 7)", "true");
+shouldBe("'foo bar'.endsWith('foo bar', 8)", "true");
+shouldBe("'foo bar'.endsWith('foo bar', -1)", "false");
+shouldBe("'foo bar'.endsWith('qux')", "false");
+shouldBe("'foo bar'.endsWith('')", "true");
+shouldBe("'foo bar'.endsWith()", "false");
+shouldBe("'foo null'.endsWith()", "false");
+shouldBe("'foo null'.endsWith(null)", "true");
+shouldBe("'foo null'.endsWith(null)", "true");
+shouldBe("'foo undefined'.endsWith()", "true");
+shouldBe("'foo undefined'.endsWith(undefined)", "true");
+shouldBe("'foo undefined'.endsWith()", "true");
+shouldBe("'foo undefined'.endsWith()", "true");
+shouldBe("'foo true'.endsWith(true)", "true");
+shouldBe("'foo false'.endsWith(false)", "true");
+shouldBe("'foo 1'.endsWith(1)", "true");
+shouldBe("'foo 1.1'.endsWith(1.1)", "true");
+shouldBe("'foo NaN'.endsWith(NaN)", "true");
+shouldBe("'foo 1e+100'.endsWith(1e+100)", "true");
+shouldBe("'foo 1e100'.endsWith(1e100)", "false");
+shouldBe("'フーバー'.endsWith('バー')", "true");
+shouldBe("'フーバー'.endsWith('フー')", "false");
+
+// Call functions with an environment record as 'this'.
+shouldThrow("(function() { var f = String.prototype.startsWith; (function() { f('a'); })(); })()");
+shouldThrow("(function() { var f = String.prototype.endsWith; (function() { f('a'); })(); })()");
+shouldThrow("(function() { var f = String.prototype.contains; (function() { f('a'); })(); })()");
+
+// ES6 spec says a regex as argument should throw an Exception.
+shouldThrow("'foo bar'.startsWith(/\w+/)");
+shouldThrow("'foo bar'.endsWith(/\w+/)");
+shouldThrow("'foo bar'.contains(/\w+/)");
+
+// Check side effects in startsWith.
+var sideEffect = "";
+var stringToSearchIn = new String("foo bar");
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+var startOffset = new Number(0);
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+var matchString = new String("foo");
+matchString.toString = function() {
+ sideEffect += "C";
+ return this;
+}
+// Calling stringToSearchIn.startsWith implicitly calls stringToSearchIn.toString(),
+// startOffset.valueOf() and matchString.toString(), in that respective order.
+shouldBe("stringToSearchIn.startsWith(matchString, startOffset)", "true");
+shouldBe("sideEffect == 'ABC'", "true");
+
+// If stringToSearchIn throws an exception startOffset.valueOf() and
+// matchString.toString() are not called.
+stringToSearchIn.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.startsWith(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == ''", "true");
+
+// If startOffset throws an exception stringToSearchIn.toString() is called but
+// matchString.toString() is not.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.startsWith(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'A'", "true");
+
+// If matchString.toString() throws an exception stringToSearchIn.toString() and
+// startOffset.valueOf() were called.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.startsWith(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'AB'", "true");
+
+// Check side effects in endsWith.
+sideEffect = "";
+stringToSearchIn = new String('foo bar');
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+var endOffset = new Number(stringToSearchIn.length);
+endOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString = new String('bar');
+matchString.toString = function() {
+ sideEffect += "C";
+ return this;
+}
+
+// Calling stringToSearchIn.endsWith implicitly calls stringToSearchIn.toString(),
+// endOffset.valueOf() and matchString.toString(), in that respective order.
+shouldBe("stringToSearchIn.endsWith(matchString, endOffset)", "true");
+shouldBe("sideEffect == 'ABC'", "true");
+
+// If stringToSearchIn throws an exception endOffset.valueOf() and
+// matchString.toString() are not called.
+stringToSearchIn.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.endsWith(matchString, endOffset)", "'error'");
+shouldBe("sideEffect == ''", "true");
+
+// If endOffset throws an exception stringToSearchIn.toString() is called but
+// matchString.toString() is not.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+endOffset.valueOf = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.endsWith(matchString, endOffset)", "'error'");
+shouldBe("sideEffect == 'A'", "true");
+
+// If matchString.toString() throws an exception stringToSearchIn.toString() and
+// endOffset.valueOf() were called.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+endOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.endsWith(matchString, endOffset)", "'error'");
+shouldBe("sideEffect == 'AB'", "true");
+
+// Check side effects in contains.
+var sideEffect = "";
+stringToSearchIn = new String("foo bar");
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+var startOffset = new Number(0);
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString = new String("foo");
+matchString.toString = function() {
+ sideEffect += "C";
+ return this;
+}
+// Calling stringToSearchIn.contains implicitly calls stringToSearchIn.toString(),
+// startOffset.valueOf() and matchString.toString(), in that respective order.
+shouldBe("stringToSearchIn.contains(matchString, startOffset)", "true");
+shouldBe("sideEffect == 'ABC'", "true");
+
+// If stringToSearchIn throws an exception startOffset.valueOf() and
+// matchString.toString() are not called.
+stringToSearchIn.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.contains(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == ''", "true");
+
+// If startOffset throws an exception stringToSearchIn.toString() is called but
+// matchString.toString() is not.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.contains(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'A'", "true");
+
+// If matchString.toString() throws an exception stringToSearchIn.toString() and
+// startOffset.valueOf() were called.
+stringToSearchIn.toString = function() {
+ sideEffect += "A";
+ return this;
+}
+startOffset.valueOf = function() {
+ sideEffect += "B";
+ return this;
+}
+matchString.toString = function() {
+ throw "error";
+}
+sideEffect = "";
+shouldThrow("stringToSearchIn.contains(matchString, startOffset)", "'error'");
+shouldBe("sideEffect == 'AB'", "true");
</ins></span></pre></div>
<a id="trunkLayoutTestsjsstringcontainsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/string-contains-expected.txt (0 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/string-contains-expected.txt         (rev 0)
+++ trunk/LayoutTests/js/string-contains-expected.txt        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -0,0 +1,116 @@
</span><ins>+This test checks the ES6 string functions startsWith(), endsWith() and contains().
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS 'foo bar'.contains('bar') is true
+PASS 'foo bar'.contains('bar', 4) is true
+PASS 'foo bar'.contains('ar', 5) is true
+PASS 'foo bar'.contains('qux') is false
+PASS 'foo bar'.contains('foo') is true
+PASS 'foo bar'.contains('foo', 0) is true
+PASS 'foo bar'.contains('foo', -1) is true
+PASS 'foo bar'.contains('') is true
+PASS 'foo bar'.contains() is false
+PASS 'foo bar qux'.contains('qux', 7) is true
+PASS 'foo bar qux'.contains('bar', 7) is false
+PASS 'foo null bar'.contains() is false
+PASS 'foo null bar'.contains(null) is true
+PASS 'foo null bar'.contains(null) is true
+PASS 'foo undefined bar'.contains() is true
+PASS 'foo undefined bar'.contains(undefined) is true
+PASS 'foo undefined bar'.contains() is true
+PASS 'foo undefined bar'.contains() is true
+PASS 'foo true bar'.contains(true) is true
+PASS 'foo false bar'.contains(false) is true
+PASS 'foo 1 bar'.contains(1) is true
+PASS 'foo 1.1 bar'.contains(1.1) is true
+PASS 'foo NaN bar'.contains(NaN) is true
+PASS 'foo 1.0 bar'.contains(1.0) is true
+PASS 'foo 1e+100 bar'.contains(1e+100) is true
+PASS 'foo 1e100 bar'.contains(1e100) is false
+PASS 'フーバー'.contains('ーバ') is true
+PASS 'フーバー'.contains('クー') is false
+PASS 'foo bar'.startsWith('foo') is true
+PASS 'foo bar'.startsWith('foo', 0) is true
+PASS 'foo bar'.startsWith('foo', -1) is true
+PASS 'foo bar'.startsWith('oo', 1) is true
+PASS 'foo bar'.startsWith('qux') is false
+PASS 'foo bar'.startsWith('') is true
+PASS 'foo bar'.startsWith() is false
+PASS 'null'.startsWith() is false
+PASS 'null'.startsWith(null) is true
+PASS 'null bar'.startsWith(null) is true
+PASS 'undefined'.startsWith() is true
+PASS 'undefined'.startsWith(undefined) is true
+PASS 'undefined bar'.startsWith() is true
+PASS 'undefined bar'.startsWith() is true
+PASS 'true bar'.startsWith(true) is true
+PASS 'false bar'.startsWith(false) is true
+PASS '1 bar'.startsWith(1) is true
+PASS '1.1 bar'.startsWith(1.1) is true
+PASS 'NaN bar'.startsWith(NaN) is true
+PASS '1e+100 bar'.startsWith(1e+100) is true
+PASS '1e100 bar'.startsWith(1e100) is false
+PASS 'フーバー'.startsWith('フー') is true
+PASS 'フーバー'.startsWith('バー') is false
+PASS 'foo bar'.endsWith('bar') is true
+PASS 'foo bar'.endsWith('ba', 6) is true
+PASS 'foo bar'.endsWith(' ba', 6) is true
+PASS 'foo bar'.endsWith('foo bar') is true
+PASS 'foo bar'.endsWith('foo bar', 7) is true
+PASS 'foo bar'.endsWith('foo bar', 8) is true
+PASS 'foo bar'.endsWith('foo bar', -1) is false
+PASS 'foo bar'.endsWith('qux') is false
+PASS 'foo bar'.endsWith('') is true
+PASS 'foo bar'.endsWith() is false
+PASS 'foo null'.endsWith() is false
+PASS 'foo null'.endsWith(null) is true
+PASS 'foo null'.endsWith(null) is true
+PASS 'foo undefined'.endsWith() is true
+PASS 'foo undefined'.endsWith(undefined) is true
+PASS 'foo undefined'.endsWith() is true
+PASS 'foo undefined'.endsWith() is true
+PASS 'foo true'.endsWith(true) is true
+PASS 'foo false'.endsWith(false) is true
+PASS 'foo 1'.endsWith(1) is true
+PASS 'foo 1.1'.endsWith(1.1) is true
+PASS 'foo NaN'.endsWith(NaN) is true
+PASS 'foo 1e+100'.endsWith(1e+100) is true
+PASS 'foo 1e100'.endsWith(1e100) is false
+PASS 'フーバー'.endsWith('バー') is true
+PASS 'フーバー'.endsWith('フー') is false
+PASS (function() { var f = String.prototype.startsWith; (function() { f('a'); })(); })() threw exception TypeError: Type error.
+PASS (function() { var f = String.prototype.endsWith; (function() { f('a'); })(); })() threw exception TypeError: Type error.
+PASS (function() { var f = String.prototype.contains; (function() { f('a'); })(); })() threw exception TypeError: Type error.
+PASS 'foo bar'.startsWith(/w+/) threw exception TypeError: Type error.
+PASS 'foo bar'.endsWith(/w+/) threw exception TypeError: Type error.
+PASS 'foo bar'.contains(/w+/) threw exception TypeError: Type error.
+PASS stringToSearchIn.startsWith(matchString, startOffset) is true
+PASS sideEffect == 'ABC' is true
+PASS stringToSearchIn.startsWith(matchString, startOffset) threw exception error.
+PASS sideEffect == '' is true
+PASS stringToSearchIn.startsWith(matchString, startOffset) threw exception error.
+PASS sideEffect == 'A' is true
+PASS stringToSearchIn.startsWith(matchString, startOffset) threw exception error.
+PASS sideEffect == 'AB' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) is true
+PASS sideEffect == 'ABC' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) threw exception error.
+PASS sideEffect == '' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) threw exception error.
+PASS sideEffect == 'A' is true
+PASS stringToSearchIn.endsWith(matchString, endOffset) threw exception error.
+PASS sideEffect == 'AB' is true
+PASS stringToSearchIn.contains(matchString, startOffset) is true
+PASS sideEffect == 'ABC' is true
+PASS stringToSearchIn.contains(matchString, startOffset) threw exception error.
+PASS sideEffect == '' is true
+PASS stringToSearchIn.contains(matchString, startOffset) threw exception error.
+PASS sideEffect == 'A' is true
+PASS stringToSearchIn.contains(matchString, startOffset) threw exception error.
+PASS sideEffect == 'AB' is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsstringcontainshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/string-contains.html (0 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/string-contains.html         (rev 0)
+++ trunk/LayoutTests/js/string-contains.html        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+ <script src="script-tests/string-contains.js"></script>
+ <script src="../resources/js-test-post.js"></script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2014-09-19 Diego Pino Garcia <dpino@igalia.com>
+
+ Simple ES6 feature:String prototype additions
+ https://bugs.webkit.org/show_bug.cgi?id=131704
+
+ Reviewed by Darin Adler.
+
+ * runtime/StringPrototype.cpp:
+ (JSC::StringPrototype::finishCreation):
+ (JSC::stringProtoFuncStartsWith): Added.
+ (JSC::stringProtoFuncEndsWith): Added.
+ (JSC::stringProtoFuncContains): Added.
+
</ins><span class="cx"> 2014-09-18 Joseph Pecoraro <pecoraro@apple.com>
</span><span class="cx">
</span><span class="cx"> Unreviewed rollout r173731. Broke multiple builds.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -82,6 +82,9 @@
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
</span><ins>+EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState*);
+EncodedJSValue JSC_HOST_CALL stringProtoFuncContains(ExecState*);
</ins><span class="cx">
</span><span class="cx"> const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, CREATE_METHOD_TABLE(StringPrototype) };
</span><span class="cx">
</span><span class="lines">@@ -131,6 +134,9 @@
</span><span class="cx"> JSC_NATIVE_FUNCTION("trim", stringProtoFuncTrim, DontEnum, 0);
</span><span class="cx"> JSC_NATIVE_FUNCTION("trimLeft", stringProtoFuncTrimLeft, DontEnum, 0);
</span><span class="cx"> JSC_NATIVE_FUNCTION("trimRight", stringProtoFuncTrimRight, DontEnum, 0);
</span><ins>+ JSC_NATIVE_FUNCTION("startsWith", stringProtoFuncStartsWith, DontEnum, 0);
+ JSC_NATIVE_FUNCTION("endsWith", stringProtoFuncEndsWith, DontEnum, 0);
+ JSC_NATIVE_FUNCTION("contains", stringProtoFuncContains, DontEnum, 0);
</ins><span class="cx">
</span><span class="cx"> // The constructor will be added later, after StringConstructor has been built
</span><span class="cx"> putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
</span><span class="lines">@@ -1546,6 +1552,77 @@
</span><span class="cx"> JSValue thisValue = exec->thisValue();
</span><span class="cx"> return JSValue::encode(trimString(exec, thisValue, TrimRight));
</span><span class="cx"> }
</span><ins>+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ unsigned start = std::max(0, exec->argument(1).toInt32(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ String matchString = a0.toString(exec)->value(exec);
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.startsWith(matchString, start, true)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncEndsWith(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ unsigned length = stringToSearchIn.length();
+ JSValue a1 = exec->argument(1);
+ int pos = a1.isUndefined() ? length : a1.toInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ unsigned end = std::min<unsigned>(std::max(pos, 0), length);
+
+ String matchString = a0.toString(exec)->value(exec);
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.endsWith(matchString, end, true)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncContains(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String stringToSearchIn = thisValue.toString(exec)->value(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue a0 = exec->argument(0);
+ if (jsDynamicCast<RegExpObject*>(a0))
+ return throwVMTypeError(exec);
+
+ unsigned start = std::max(0, exec->argument(1).toInt32(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ String matchString = a0.toString(exec)->value(exec);
+
+ return JSValue::encode(jsBoolean(stringToSearchIn.contains(matchString, true, start)));
+}
</ins><span class="cx">
</span><del>-
</del><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/ChangeLog        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+2014-09-19 Diego Pino Garcia <dpino@igalia.com>
+
+ Simple ES6 feature:String prototype additions
+ https://bugs.webkit.org/show_bug.cgi?id=131704
+
+ Reviewed by Darin Adler.
+
+ * wtf/text/StringImpl.cpp:
+ (WTF::StringImpl::find):
+ (WTF::equalInner): Added.
+ (WTF::StringImpl::startsWith): Add implementation that supports
+ 'startOffset' parameter.
+ (WTF::StringImpl::endsWith): Add implementation that supports
+ 'endOffset' parameter.
+ * wtf/text/StringImpl.h:
+ * wtf/text/WTFString.h:
+ (WTF::String::contains): Modify current implementation to allow
+ setting a startOffset, 0 by default.
+ (WTF::String::startsWith):
+ (WTF::String::endsWith):
+
</ins><span class="cx"> 2014-09-18 Carlos Garcia Campos <cgarcia@igalia.com>
</span><span class="cx">
</span><span class="cx"> [GTK] Dot not allow to create delete-on-destroy GMainLoopSources
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringImplcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringImpl.cpp (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringImpl.cpp        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/wtf/text/StringImpl.cpp        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -1368,6 +1368,25 @@
</span><span class="cx"> return equalIgnoringCase(stringImpl->characters16() + startOffset, reinterpret_cast<const LChar*>(matchString), matchLength);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ALWAYS_INLINE static bool equalInner(StringImpl& stringImpl, unsigned startOffset, StringImpl& matchString, bool caseSensitive)
+{
+ if (startOffset > stringImpl.length())
+ return false;
+ if (matchString.length() > stringImpl.length())
+ return false;
+ if (matchString.length() + startOffset > stringImpl.length())
+ return false;
+
+ if (caseSensitive) {
+ if (stringImpl.is8Bit())
+ return equal(stringImpl.characters8() + startOffset, matchString.characters8(), matchString.length());
+ return equal(stringImpl.characters16() + startOffset, matchString.characters16(), matchString.length());
+ }
+ if (stringImpl.is8Bit())
+ return equalIgnoringCase(stringImpl.characters8() + startOffset, matchString.characters8(), matchString.length());
+ return equalIgnoringCase(stringImpl.characters16() + startOffset, matchString.characters16(), matchString.length());
+}
+
</ins><span class="cx"> bool StringImpl::startsWith(const StringImpl* str) const
</span><span class="cx"> {
</span><span class="cx"> if (!str)
</span><span class="lines">@@ -1399,6 +1418,11 @@
</span><span class="cx"> return equalInner(this, 0, matchString, matchLength, caseSensitive);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool StringImpl::startsWith(StringImpl& matchString, unsigned startOffset, bool caseSensitive) const
+{
+ return equalInner(const_cast<StringImpl&>(*this), startOffset, matchString, caseSensitive);
+}
+
</ins><span class="cx"> bool StringImpl::endsWith(StringImpl* matchString, bool caseSensitive)
</span><span class="cx"> {
</span><span class="cx"> ASSERT(matchString);
</span><span class="lines">@@ -1423,6 +1447,13 @@
</span><span class="cx"> return equalInner(this, startOffset, matchString, matchLength, caseSensitive);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool StringImpl::endsWith(StringImpl& matchString, unsigned endOffset, bool caseSensitive) const
+{
+ if (endOffset < matchString.length())
+ return false;
+ return equalInner(const_cast<StringImpl&>(*this), endOffset - matchString.length(), matchString, caseSensitive);
+}
+
</ins><span class="cx"> PassRef<StringImpl> StringImpl::replace(UChar oldC, UChar newC)
</span><span class="cx"> {
</span><span class="cx"> if (oldC == newC)
</span></span></pre></div>
<a id="trunkSourceWTFwtftextStringImplh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/StringImpl.h (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/StringImpl.h        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/wtf/text/StringImpl.h        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -673,12 +673,14 @@
</span><span class="cx"> WTF_EXPORT_STRING_API bool startsWith(const char*, unsigned matchLength, bool caseSensitive) const;
</span><span class="cx"> template<unsigned matchLength>
</span><span class="cx"> bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const { return startsWith(prefix, matchLength - 1, caseSensitive); }
</span><ins>+ WTF_EXPORT_STRING_API bool startsWith(StringImpl&, unsigned startOffset, bool caseSensitive) const;
</ins><span class="cx">
</span><span class="cx"> WTF_EXPORT_STRING_API bool endsWith(StringImpl*, bool caseSensitive = true);
</span><span class="cx"> WTF_EXPORT_STRING_API bool endsWith(UChar) const;
</span><span class="cx"> WTF_EXPORT_STRING_API bool endsWith(const char*, unsigned matchLength, bool caseSensitive) const;
</span><span class="cx"> template<unsigned matchLength>
</span><span class="cx"> bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const { return endsWith(prefix, matchLength - 1, caseSensitive); }
</span><ins>+ WTF_EXPORT_STRING_API bool endsWith(StringImpl&, unsigned endOffset, bool caseSensitive) const;
</ins><span class="cx">
</span><span class="cx"> WTF_EXPORT_STRING_API PassRef<StringImpl> replace(UChar, UChar);
</span><span class="cx"> WTF_EXPORT_STRING_API PassRef<StringImpl> replace(UChar, StringImpl*);
</span></span></pre></div>
<a id="trunkSourceWTFwtftextWTFStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/WTFString.h (173760 => 173761)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/WTFString.h        2014-09-19 17:38:13 UTC (rev 173760)
+++ trunk/Source/WTF/wtf/text/WTFString.h        2014-09-19 17:47:50 UTC (rev 173761)
</span><span class="lines">@@ -256,8 +256,10 @@
</span><span class="cx"> WTF_EXPORT_STRING_API UChar32 characterStartingAt(unsigned) const; // Ditto.
</span><span class="cx">
</span><span class="cx"> bool contains(UChar c) const { return find(c) != notFound; }
</span><del>- bool contains(const LChar* str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
- bool contains(const String& str, bool caseSensitive = true) const { return find(str, 0, caseSensitive) != notFound; }
</del><ins>+ bool contains(const LChar* str, bool caseSensitive = true, unsigned startOffset = 0) const
+ { return find(str, startOffset, caseSensitive) != notFound; }
+ bool contains(const String& str, bool caseSensitive = true, unsigned startOffset = 0) const
+ { return find(str, startOffset, caseSensitive) != notFound; }
</ins><span class="cx">
</span><span class="cx"> bool startsWith(const String& s) const
</span><span class="cx"> { return m_impl ? m_impl->startsWith(s.impl()) : s.isEmpty(); }
</span><span class="lines">@@ -268,6 +270,8 @@
</span><span class="cx"> template<unsigned matchLength>
</span><span class="cx"> bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
</span><span class="cx"> { return m_impl ? m_impl->startsWith<matchLength>(prefix, caseSensitive) : !matchLength; }
</span><ins>+ bool startsWith(String& prefix, unsigned startOffset, bool caseSensitive) const
+ { return m_impl && prefix.impl() ? m_impl->startsWith(*prefix.impl(), startOffset, caseSensitive) : false; }
</ins><span class="cx">
</span><span class="cx"> bool endsWith(const String& s, bool caseSensitive = true) const
</span><span class="cx"> { return m_impl ? m_impl->endsWith(s.impl(), caseSensitive) : s.isEmpty(); }
</span><span class="lines">@@ -277,6 +281,8 @@
</span><span class="cx"> template<unsigned matchLength>
</span><span class="cx"> bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
</span><span class="cx"> { return m_impl ? m_impl->endsWith<matchLength>(prefix, caseSensitive) : !matchLength; }
</span><ins>+ bool endsWith(String& suffix, unsigned endOffset, bool caseSensitive) const
+ { return m_impl && suffix.impl() ? m_impl->endsWith(*suffix.impl(), endOffset, caseSensitive) : false; }
</ins><span class="cx">
</span><span class="cx"> WTF_EXPORT_STRING_API void append(const String&);
</span><span class="cx"> WTF_EXPORT_STRING_API void append(LChar);
</span></span></pre>
</div>
</div>
</body>
</html>