<!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>[208963] 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/208963">208963</a></dd>
<dt>Author</dt> <dd>darin@apple.com</dd>
<dt>Date</dt> <dd>2016-11-22 09:16:02 -0800 (Tue, 22 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make normal case fast in the input element limitString function
https://bugs.webkit.org/show_bug.cgi?id=165023

Reviewed by Dan Bernstein.

Source/WebCore:

When running Speedometer, the limitLength function was showing up as hot.
Fixed a couple obvious problems with that function's performance.

* html/TextFieldInputType.cpp:
(WebCore::isASCIILineBreak): Deleted. The isHTMLLineBreak function does
the same thing, but faster.
(WebCore::limitLength): Added a FIXME comment explaining that the function
isn't really a good idea. Don't call through to numCharactersInGraphemeClusters
at all for 8-bit strings since we don't allow CR or LF characters in the string
anyway, so there are no grapheme clusters more than a single code unit. Removed
optimization when the length is the string's length that String::left already does.
(WebCore::TextFieldInputType::sanitizeValue): Use isHTMLLineBreak instead of
isASCIILineBreak.
(WebCore::TextFieldInputType::handleBeforeTextInsertedEvent): Ditto.

* platform/LocalizedStrings.cpp: Use auto a lot more rather than writing out
RetainPtr.
(WebCore::truncatedStringForLookupMenuItem): Removed unneeded special case for
empty strings. Removed unneeded string with the ellipsis character in it, since
the makeString function already knows how to append a character to a string.

* rendering/RenderText.cpp:
(WebCore::mapLineBreakToIteratorMode): Updated for change to LineBreakIteratorMode.
* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::nextBreakablePosition): Ditto.

Source/WTF:

* wtf/text/LineBreakIteratorPoolICU.h: Removed many unneeded includes.
Simplified the class a bit, removing some extra definitions.
(WTF::LineBreakIteratorPool::sharedPool): Use NeverDestroyed instead of new.
(WTF::LineBreakIteratorPool::makeLocaleWithBreakKeyword): Reimplemented in
a simpler way without using StringBuilder. Also updated for change to
LineBreakIteratorMode.
(WTF::LineBreakIteratorPool::put): Use uncheckedAppend since the code is
careful to only use the inline capacity in the vector.

* wtf/text/TextBreakIterator.cpp: Moved some includes in here from the header.
(WTF::mapLineIteratorModeToRules): Updated for change to LineBreakIteratorMode.
(WTF::openLineBreakIterator): Ditto.
(WTF::numGraphemeClusters): Added a fast path for all 8-bit strings; don't
use ICU for that case, even if there is a CR character in it.
(WTF::numCharactersInGraphemeClusters): Added a fast path for strings that are
short enough to entirely fit without even looking at the characters; that's a
case we likely hit all the time. Also added a fast path for all 8-bit strings.

* wtf/text/TextBreakIterator.h: Changed LineBreakIteratorMode to be an enum
class and not repeat UAX14 in the names of the modes. Initialize data members
in the class definition rather than the constructors.

Tools:

* TestWebKitAPI/CMakeLists.txt: Added TextBreakIterator.cpp.
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Ditto.
* TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp: Added.
Contains some tests for the numGraphemeClusters and
numCharactersInGraphemeClusters functions that I used to make sure
that the new fast paths I added work correctly.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtftextLineBreakIteratorPoolICUh">trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h</a></li>
<li><a href="#trunkSourceWTFwtftextTextBreakIteratorcpp">trunk/Source/WTF/wtf/text/TextBreakIterator.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextTextBreakIteratorh">trunk/Source/WTF/wtf/text/TextBreakIterator.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlTextFieldInputTypecpp">trunk/Source/WebCore/html/TextFieldInputType.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformLocalizedStringscpp">trunk/Source/WebCore/platform/LocalizedStrings.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderTextcpp">trunk/Source/WebCore/rendering/RenderText.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingSimpleLineLayoutTextFragmentIteratorcpp">trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPICMakeListstxt">trunk/Tools/TestWebKitAPI/CMakeLists.txt</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsTestWebKitAPITestsWTFTextBreakIteratorcpp">trunk/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WTF/ChangeLog        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2016-11-22  Darin Adler  &lt;darin@apple.com&gt;
+
+        Make normal case fast in the input element limitString function
+        https://bugs.webkit.org/show_bug.cgi?id=165023
+
+        Reviewed by Dan Bernstein.
+
+        * wtf/text/LineBreakIteratorPoolICU.h: Removed many unneeded includes.
+        Simplified the class a bit, removing some extra definitions.
+        (WTF::LineBreakIteratorPool::sharedPool): Use NeverDestroyed instead of new.
+        (WTF::LineBreakIteratorPool::makeLocaleWithBreakKeyword): Reimplemented in
+        a simpler way without using StringBuilder. Also updated for change to
+        LineBreakIteratorMode.
+        (WTF::LineBreakIteratorPool::put): Use uncheckedAppend since the code is
+        careful to only use the inline capacity in the vector.
+
+        * wtf/text/TextBreakIterator.cpp: Moved some includes in here from the header.
+        (WTF::mapLineIteratorModeToRules): Updated for change to LineBreakIteratorMode.
+        (WTF::openLineBreakIterator): Ditto.
+        (WTF::numGraphemeClusters): Added a fast path for all 8-bit strings; don't
+        use ICU for that case, even if there is a CR character in it.
+        (WTF::numCharactersInGraphemeClusters): Added a fast path for strings that are
+        short enough to entirely fit without even looking at the characters; that's a
+        case we likely hit all the time. Also added a fast path for all 8-bit strings.
+
+        * wtf/text/TextBreakIterator.h: Changed LineBreakIteratorMode to be an enum
+        class and not repeat UAX14 in the names of the modes. Initialize data members
+        in the class definition rather than the constructors.
+
</ins><span class="cx"> 2016-11-21  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Hasher::addCharacters() should be able to handle zero length strings.
</span></span></pre></div>
<a id="trunkSourceWTFwtftextLineBreakIteratorPoolICUh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WTF/wtf/text/LineBreakIteratorPoolICU.h        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -23,18 +23,13 @@
</span><span class="cx">  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#ifndef LineBreakIteratorPoolICU_h
-#define LineBreakIteratorPoolICU_h
</del><ins>+#pragma once
</ins><span class="cx"> 
</span><span class="cx"> #include &quot;TextBreakIterator.h&quot;
</span><del>-#include &quot;TextBreakIteratorInternalICU.h&quot;
-#include &lt;unicode/ubrk.h&gt;
-#include &lt;wtf/Assertions.h&gt;
</del><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><ins>+#include &lt;wtf/NeverDestroyed.h&gt;
</ins><span class="cx"> #include &lt;wtf/ThreadSpecific.h&gt;
</span><span class="cx"> #include &lt;wtf/text/AtomicString.h&gt;
</span><del>-#include &lt;wtf/text/CString.h&gt;
-#include &lt;wtf/text/StringBuilder.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><span class="lines">@@ -41,45 +36,35 @@
</span><span class="cx"> class LineBreakIteratorPool {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(LineBreakIteratorPool);
</span><span class="cx"> public:
</span><del>-    LineBreakIteratorPool() { }
</del><ins>+    LineBreakIteratorPool() = default;
</ins><span class="cx"> 
</span><span class="cx">     static LineBreakIteratorPool&amp; sharedPool()
</span><span class="cx">     {
</span><del>-        static WTF::ThreadSpecific&lt;LineBreakIteratorPool&gt;* pool = new WTF::ThreadSpecific&lt;LineBreakIteratorPool&gt;;
-        return **pool;
</del><ins>+        static NeverDestroyed&lt;WTF::ThreadSpecific&lt;LineBreakIteratorPool&gt;&gt; pool;
+        return *pool.get();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static String makeLocaleWithBreakKeyword(const AtomicString&amp; locale, LineBreakIteratorMode mode)
</del><ins>+    static AtomicString makeLocaleWithBreakKeyword(const AtomicString&amp; locale, LineBreakIteratorMode mode)
</ins><span class="cx">     {
</span><del>-        StringBuilder localeWithKeyword;
-        localeWithKeyword.append(locale);
-        localeWithKeyword.appendLiteral(&quot;@break=&quot;);
</del><span class="cx">         switch (mode) {
</span><del>-        case LineBreakIteratorModeUAX14:
-            ASSERT_NOT_REACHED();
-            break;
-        case LineBreakIteratorModeUAX14Loose:
-            localeWithKeyword.appendLiteral(&quot;loose&quot;);
-            break;
-        case LineBreakIteratorModeUAX14Normal:
-            localeWithKeyword.appendLiteral(&quot;normal&quot;);
-            break;
-        case LineBreakIteratorModeUAX14Strict:
-            localeWithKeyword.appendLiteral(&quot;strict&quot;);
-            break;
</del><ins>+        case LineBreakIteratorMode::Default:
+            return locale;
+        case LineBreakIteratorMode::Loose:
+            return makeString(locale, &quot;@break=loose&quot;);
+        case LineBreakIteratorMode::Normal:
+            return makeString(locale, &quot;@break=normal&quot;);
+        case LineBreakIteratorMode::Strict:
+            return makeString(locale, &quot;@break=strict&quot;);
</ins><span class="cx">         }
</span><del>-        return localeWithKeyword.toString();
</del><ins>+        ASSERT_NOT_REACHED();
+        return locale;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     TextBreakIterator* take(const AtomicString&amp; locale, LineBreakIteratorMode mode, bool isCJK)
</span><span class="cx">     {
</span><del>-        AtomicString localeWithOptionalBreakKeyword;
-        if (mode == LineBreakIteratorModeUAX14)
-            localeWithOptionalBreakKeyword = locale;
-        else
-            localeWithOptionalBreakKeyword = makeLocaleWithBreakKeyword(locale, mode);
</del><ins>+        auto localeWithOptionalBreakKeyword = makeLocaleWithBreakKeyword(locale, mode);
</ins><span class="cx"> 
</span><del>-        TextBreakIterator* iterator = 0;
</del><ins>+        TextBreakIterator* iterator = nullptr;
</ins><span class="cx">         for (size_t i = 0; i &lt; m_pool.size(); ++i) {
</span><span class="cx">             if (m_pool[i].first == localeWithOptionalBreakKeyword) {
</span><span class="cx">                 iterator = m_pool[i].second;
</span><span class="lines">@@ -91,32 +76,28 @@
</span><span class="cx">         if (!iterator) {
</span><span class="cx">             iterator = openLineBreakIterator(localeWithOptionalBreakKeyword, mode, isCJK);
</span><span class="cx">             if (!iterator)
</span><del>-                return 0;
</del><ins>+                return nullptr;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         ASSERT(!m_vendedIterators.contains(iterator));
</span><del>-        m_vendedIterators.set(iterator, localeWithOptionalBreakKeyword);
</del><ins>+        m_vendedIterators.add(iterator, localeWithOptionalBreakKeyword);
</ins><span class="cx">         return iterator;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void put(TextBreakIterator* iterator)
</span><span class="cx">     {
</span><del>-        ASSERT_ARG(iterator, m_vendedIterators.contains(iterator));
-
</del><ins>+        ASSERT(m_vendedIterators.contains(iterator));
</ins><span class="cx">         if (m_pool.size() == capacity) {
</span><span class="cx">             closeLineBreakIterator(m_pool[0].second);
</span><span class="cx">             m_pool.remove(0);
</span><span class="cx">         }
</span><del>-
-        m_pool.append(Entry(m_vendedIterators.take(iterator), iterator));
</del><ins>+        m_pool.uncheckedAppend({ m_vendedIterators.take(iterator), iterator });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    static const size_t capacity = 4;
</del><ins>+    static constexpr size_t capacity = 4;
</ins><span class="cx"> 
</span><del>-    typedef std::pair&lt;AtomicString, TextBreakIterator*&gt; Entry;
-    typedef Vector&lt;Entry, capacity&gt; Pool;
-    Pool m_pool;
</del><ins>+    Vector&lt;std::pair&lt;AtomicString, TextBreakIterator*&gt;, capacity&gt; m_pool;
</ins><span class="cx">     HashMap&lt;TextBreakIterator*, AtomicString&gt; m_vendedIterators;
</span><span class="cx"> 
</span><span class="cx">     friend WTF::ThreadSpecific&lt;LineBreakIteratorPool&gt;::operator LineBreakIteratorPool*();
</span><span class="lines">@@ -123,5 +104,3 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span><del>-
-#endif
</del></span></pre></div>
<a id="trunkSourceWTFwtftextTextBreakIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/TextBreakIterator.cpp (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/TextBreakIterator.cpp        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WTF/wtf/text/TextBreakIterator.cpp        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * (C) 1999 Lars Knoll (knoll@kde.org)
</span><del>- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2004-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007-2009 Torch Mobile, Inc.
</span><span class="cx">  *
</span><span class="cx">  * This library is free software; you can redistribute it and/or
</span><span class="lines">@@ -23,11 +23,13 @@
</span><span class="cx"> #include &quot;TextBreakIterator.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;LineBreakIteratorPoolICU.h&quot;
</span><ins>+#include &quot;TextBreakIteratorInternalICU.h&quot;
</ins><span class="cx"> #include &quot;UTextProviderLatin1.h&quot;
</span><span class="cx"> #include &quot;UTextProviderUTF16.h&quot;
</span><span class="cx"> #include &lt;atomic&gt;
</span><span class="cx"> #include &lt;mutex&gt;
</span><del>-#include &lt;wtf/text/StringView.h&gt;
</del><ins>+#include &lt;unicode/ubrk.h&gt;
+#include &lt;wtf/text/StringBuilder.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> // FIXME: This needs a better name
</span><span class="cx"> #define ADDITIONAL_EMOJI_SUPPORT (PLATFORM(IOS) || (PLATFORM(MAC) &amp;&amp; __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101100))
</span><span class="lines">@@ -734,16 +736,16 @@
</span><span class="cx">     rulesBuilder.append(uax14Prologue);
</span><span class="cx">     rulesBuilder.append(uax14AssignmentsBefore);
</span><span class="cx">     switch (mode) {
</span><del>-    case LineBreakIteratorModeUAX14:
</del><ins>+    case LineBreakIteratorMode::Default:
</ins><span class="cx">         rulesBuilder.append(isCJK ? uax14AssignmentsCustomDefaultCJK : uax14AssignmentsCustomDefaultNonCJK);
</span><span class="cx">         break;
</span><del>-    case LineBreakIteratorModeUAX14Loose:
</del><ins>+    case LineBreakIteratorMode::Loose:
</ins><span class="cx">         rulesBuilder.append(isCJK ? uax14AssignmentsCustomLooseCJK : uax14AssignmentsCustomLooseNonCJK);
</span><span class="cx">         break;
</span><del>-    case LineBreakIteratorModeUAX14Normal:
</del><ins>+    case LineBreakIteratorMode::Normal:
</ins><span class="cx">         rulesBuilder.append(isCJK ? uax14AssignmentsCustomNormalCJK : uax14AssignmentsCustomNormalNonCJK);
</span><span class="cx">         break;
</span><del>-    case LineBreakIteratorModeUAX14Strict:
</del><ins>+    case LineBreakIteratorMode::Strict:
</ins><span class="cx">         rulesBuilder.append(isCJK ? uax14AssignmentsCustomStrictCJK : uax14AssignmentsCustomStrictNonCJK);
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="lines">@@ -783,7 +785,7 @@
</span><span class="cx">     UBreakIterator* ubrkIter;
</span><span class="cx">     UErrorCode openStatus = U_ZERO_ERROR;
</span><span class="cx">     bool localeIsEmpty = locale.isEmpty();
</span><del>-    if (mode == LineBreakIteratorModeUAX14)
</del><ins>+    if (mode == LineBreakIteratorMode::Default)
</ins><span class="cx">         ubrkIter = ubrk_open(UBRK_LINE, localeIsEmpty ? currentTextBreakLocaleID() : locale.string().utf8().data(), 0, 0, &amp;openStatus);
</span><span class="cx">     else {
</span><span class="cx">         UParseError parseStatus;
</span><span class="lines">@@ -902,40 +904,56 @@
</span><span class="cx">     if (!stringLength)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    // The only Latin-1 Extended Grapheme Cluster is CR LF
-    if (string.is8Bit() &amp;&amp; !string.contains('\r'))
-        return stringLength;
</del><ins>+    // The only Latin-1 Extended Grapheme Cluster is CRLF.
+    if (string.is8Bit()) {
+        auto* characters = string.characters8();
+        unsigned numCRLF = 0;
+        for (unsigned i = 1; i &lt; stringLength; ++i)
+            numCRLF += characters[i - 1] == '\r' &amp;&amp; characters[i] == '\n';
+        return stringLength - numCRLF;
+    }
</ins><span class="cx"> 
</span><del>-    NonSharedCharacterBreakIterator it(string);
-    if (!it)
</del><ins>+    NonSharedCharacterBreakIterator iterator { string };
+    if (!iterator) {
+        ASSERT_NOT_REACHED();
</ins><span class="cx">         return stringLength;
</span><ins>+    }
</ins><span class="cx"> 
</span><del>-    unsigned num = 0;
-    while (textBreakNext(it) != TextBreakDone)
-        ++num;
-    return num;
</del><ins>+    unsigned numGraphemeClusters = 0;
+    while (textBreakNext(iterator) != TextBreakDone)
+        ++numGraphemeClusters;
+    return numGraphemeClusters;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned numCharactersInGraphemeClusters(const StringView&amp; s, unsigned numGraphemeClusters)
</del><ins>+unsigned numCharactersInGraphemeClusters(StringView string, unsigned numGraphemeClusters)
</ins><span class="cx"> {
</span><del>-    unsigned stringLength = s.length();
</del><ins>+    unsigned stringLength = string.length();
</ins><span class="cx"> 
</span><del>-    if (!stringLength)
-        return 0;
</del><ins>+    if (stringLength &lt;= numGraphemeClusters)
+        return stringLength;
</ins><span class="cx"> 
</span><del>-    // The only Latin-1 Extended Grapheme Cluster is CR LF
-    if (s.is8Bit() &amp;&amp; !s.contains('\r'))
-        return std::min(stringLength, numGraphemeClusters);
</del><ins>+    // The only Latin-1 Extended Grapheme Cluster is CRLF.
+    if (string.is8Bit()) {
+        auto* characters = string.characters8();
+        unsigned i, j;
+        for (i = 0, j = 0; i &lt; numGraphemeClusters &amp;&amp; j + 1 &lt; stringLength; ++i, ++j)
+            j += characters[j] == '\r' &amp;&amp; characters[j + 1] == '\n';
+        return j + (i &lt; numGraphemeClusters &amp;&amp; j &lt; stringLength);
+    }
</ins><span class="cx"> 
</span><del>-    NonSharedCharacterBreakIterator it(s);
-    if (!it)
-        return std::min(stringLength, numGraphemeClusters);
</del><ins>+    NonSharedCharacterBreakIterator iterator { string };
+    if (!iterator) {
+        ASSERT_NOT_REACHED();
+        return stringLength;
+    }
</ins><span class="cx"> 
</span><span class="cx">     for (unsigned i = 0; i &lt; numGraphemeClusters; ++i) {
</span><del>-        if (textBreakNext(it) == TextBreakDone)
</del><ins>+        if (textBreakNext(iterator) == TextBreakDone) {
+            ASSERT_NOT_REACHED();
</ins><span class="cx">             return stringLength;
</span><ins>+        }
</ins><span class="cx">     }
</span><del>-    return textBreakCurrent(it);
</del><ins>+    return textBreakCurrent(iterator);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTF
</span></span></pre></div>
<a id="trunkSourceWTFwtftextTextBreakIteratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/TextBreakIterator.h (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/TextBreakIterator.h        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WTF/wtf/text/TextBreakIterator.h        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2006 Lars Knoll &lt;lars@trolltech.com&gt;
</span><del>- * Copyright (C) 2007, 2011, 2012 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2007-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * This library is free software; you can redistribute it and/or
</span><span class="cx">  * modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -19,10 +19,8 @@
</span><span class="cx">  *
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#ifndef TextBreakIterator_h
-#define TextBreakIterator_h
</del><ins>+#pragma once
</ins><span class="cx"> 
</span><del>-#include &lt;wtf/text/AtomicString.h&gt;
</del><span class="cx"> #include &lt;wtf/text/StringView.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="lines">@@ -31,12 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> // Note: The returned iterator is good only until you get another iterator, with the exception of acquireLineBreakIterator.
</span><span class="cx"> 
</span><del>-enum LineBreakIteratorMode {
-    LineBreakIteratorModeUAX14,
-    LineBreakIteratorModeUAX14Loose,
-    LineBreakIteratorModeUAX14Normal,
-    LineBreakIteratorModeUAX14Strict,
-};
</del><ins>+enum class LineBreakIteratorMode { Default, Loose, Normal, Strict };
</ins><span class="cx"> 
</span><span class="cx"> // This is similar to character break iterator in most cases, but is subject to
</span><span class="cx"> // platform UI conventions. One notable example where this can be different
</span><span class="lines">@@ -62,7 +55,7 @@
</span><span class="cx"> WTF_EXPORT_PRIVATE bool isTextBreak(TextBreakIterator*, int);
</span><span class="cx"> WTF_EXPORT_PRIVATE bool isWordTextBreak(TextBreakIterator*);
</span><span class="cx"> 
</span><del>-const int TextBreakDone = -1;
</del><ins>+constexpr int TextBreakDone = -1;
</ins><span class="cx"> 
</span><span class="cx"> WTF_EXPORT_PRIVATE bool isCJKLocale(const AtomicString&amp;);
</span><span class="cx"> 
</span><span class="lines">@@ -69,25 +62,17 @@
</span><span class="cx"> class LazyLineBreakIterator {
</span><span class="cx"> public:
</span><span class="cx">     LazyLineBreakIterator()
</span><del>-        : m_iterator(nullptr)
-        , m_cachedPriorContext(nullptr)
-        , m_mode(LineBreakIteratorModeUAX14)
-        , m_cachedPriorContextLength(0)
-        , m_isCJK(false)
</del><span class="cx">     {
</span><span class="cx">         resetPriorContext();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LazyLineBreakIterator(StringView stringView, const AtomicString&amp; locale = AtomicString(), LineBreakIteratorMode mode = LineBreakIteratorModeUAX14)
</del><ins>+    explicit LazyLineBreakIterator(StringView stringView, const AtomicString&amp; locale = AtomicString(), LineBreakIteratorMode mode = LineBreakIteratorMode::Default)
</ins><span class="cx">         : m_stringView(stringView)
</span><span class="cx">         , m_locale(locale)
</span><del>-        , m_iterator(nullptr)
-        , m_cachedPriorContext(nullptr)
</del><span class="cx">         , m_mode(mode)
</span><del>-        , m_cachedPriorContextLength(0)
</del><ins>+        , m_isCJK(isCJKLocale(locale))
</ins><span class="cx">     {
</span><span class="cx">         resetPriorContext();
</span><del>-        m_isCJK = isCJKLocale(locale);
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ~LazyLineBreakIterator()
</span><span class="lines">@@ -97,7 +82,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     StringView stringView() const { return m_stringView; }
</span><del>-    bool isLooseCJKMode() const { return m_isCJK &amp;&amp; m_mode == LineBreakIteratorModeUAX14Loose; }
</del><ins>+    bool isLooseCJKMode() const { return m_isCJK &amp;&amp; m_mode == LineBreakIteratorMode::Loose; }
</ins><span class="cx"> 
</span><span class="cx">     UChar lastCharacter() const
</span><span class="cx">     {
</span><span class="lines">@@ -176,15 +161,15 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    static const unsigned priorContextCapacity = 2;
</del><ins>+    static constexpr unsigned priorContextCapacity = 2;
</ins><span class="cx">     StringView m_stringView;
</span><span class="cx">     AtomicString m_locale;
</span><del>-    TextBreakIterator* m_iterator;
-    const UChar* m_cachedPriorContext;
-    LineBreakIteratorMode m_mode;
-    unsigned m_cachedPriorContextLength;
</del><ins>+    TextBreakIterator* m_iterator { nullptr };
+    const UChar* m_cachedPriorContext { nullptr };
+    LineBreakIteratorMode m_mode { LineBreakIteratorMode::Default };
+    unsigned m_cachedPriorContextLength { 0 };
</ins><span class="cx">     UChar m_priorContext[priorContextCapacity];
</span><del>-    bool m_isCJK;
</del><ins>+    bool m_isCJK { false };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> // Iterates over &quot;extended grapheme clusters&quot;, as defined in UAX #29.
</span><span class="lines">@@ -210,17 +195,15 @@
</span><span class="cx"> // of a non-combining character and following combining characters is
</span><span class="cx"> // counted as 1 grapheme cluster.
</span><span class="cx"> WTF_EXPORT_PRIVATE unsigned numGraphemeClusters(StringView);
</span><ins>+
</ins><span class="cx"> // Returns the number of characters which will be less than or equal to
</span><span class="cx"> // the specified grapheme cluster length.
</span><del>-WTF_EXPORT_PRIVATE unsigned numCharactersInGraphemeClusters(const StringView&amp;, unsigned);
</del><ins>+WTF_EXPORT_PRIVATE unsigned numCharactersInGraphemeClusters(StringView, unsigned);
</ins><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+using WTF::LazyLineBreakIterator;
</ins><span class="cx"> using WTF::LineBreakIteratorMode;
</span><del>-using WTF::LineBreakIteratorModeUAX14;
-using WTF::LazyLineBreakIterator;
</del><span class="cx"> using WTF::NonSharedCharacterBreakIterator;
</span><span class="cx"> using WTF::TextBreakDone;
</span><span class="cx"> using WTF::TextBreakIterator;
</span><del>-
-#endif
</del></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WebCore/ChangeLog        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2016-11-22  Darin Adler  &lt;darin@apple.com&gt;
+
+        Make normal case fast in the input element limitString function
+        https://bugs.webkit.org/show_bug.cgi?id=165023
+
+        Reviewed by Dan Bernstein.
+
+        When running Speedometer, the limitLength function was showing up as hot.
+        Fixed a couple obvious problems with that function's performance.
+
+        * html/TextFieldInputType.cpp:
+        (WebCore::isASCIILineBreak): Deleted. The isHTMLLineBreak function does
+        the same thing, but faster.
+        (WebCore::limitLength): Added a FIXME comment explaining that the function
+        isn't really a good idea. Don't call through to numCharactersInGraphemeClusters
+        at all for 8-bit strings since we don't allow CR or LF characters in the string
+        anyway, so there are no grapheme clusters more than a single code unit. Removed
+        optimization when the length is the string's length that String::left already does.
+        (WebCore::TextFieldInputType::sanitizeValue): Use isHTMLLineBreak instead of
+        isASCIILineBreak.
+        (WebCore::TextFieldInputType::handleBeforeTextInsertedEvent): Ditto.
+
+        * platform/LocalizedStrings.cpp: Use auto a lot more rather than writing out
+        RetainPtr.
+        (WebCore::truncatedStringForLookupMenuItem): Removed unneeded special case for
+        empty strings. Removed unneeded string with the ellipsis character in it, since
+        the makeString function already knows how to append a character to a string.
+
+        * rendering/RenderText.cpp:
+        (WebCore::mapLineBreakToIteratorMode): Updated for change to LineBreakIteratorMode.
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::nextBreakablePosition): Ditto.
+
</ins><span class="cx"> 2016-11-21  Sergio Villar Senin  &lt;svillar@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [css-grid] Isolate size of internal representation from actual grid size
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlTextFieldInputTypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/TextFieldInputType.cpp (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/TextFieldInputType.cpp        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WebCore/html/TextFieldInputType.cpp        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> #include &quot;FrameSelection.h&quot;
</span><span class="cx"> #include &quot;HTMLInputElement.h&quot;
</span><span class="cx"> #include &quot;HTMLNames.h&quot;
</span><ins>+#include &quot;HTMLParserIdioms.h&quot;
</ins><span class="cx"> #include &quot;KeyboardEvent.h&quot;
</span><span class="cx"> #include &quot;LocalizedStrings.h&quot;
</span><span class="cx"> #include &quot;NodeRenderStyle.h&quot;
</span><span class="lines">@@ -378,24 +379,25 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static bool isASCIILineBreak(UChar c)
</del><ins>+// FIXME: The name of this function doesn't make clear the two jobs it does:
+// 1) Limits the string to a particular number of grapheme clusters.
+// 2) Truncates the string at the first character which is a control character other than tab.
+// FIXME: TextFieldInputType::sanitizeValue doesn't need a limit on grapheme clusters. A limit on code units would do.
+// FIXME: Where does the &quot;truncate at first control character&quot; rule come from?
+static String limitLength(const String&amp; string, unsigned maxNumGraphemeClusters)
</ins><span class="cx"> {
</span><del>-    return c == '\r' || c == '\n';
</del><ins>+    StringView stringView { string };
+    unsigned firstNonTabControlCharacterIndex = stringView.find([] (UChar character) {
+        return character &lt; ' ' &amp;&amp; character != '\t';
+    });
+    unsigned limitedLength;
+    if (stringView.is8Bit())
+        limitedLength = std::min(firstNonTabControlCharacterIndex, maxNumGraphemeClusters);
+    else
+        limitedLength = numCharactersInGraphemeClusters(stringView.substring(0, firstNonTabControlCharacterIndex), maxNumGraphemeClusters);
+    return string.left(limitedLength);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static String limitLength(const String&amp; string, int maxLength)
-{
-    unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
-    for (unsigned i = 0; i &lt; newLength; ++i) {
-        const UChar current = string[i];
-        if (current &lt; ' ' &amp;&amp; current != '\t') {
-            newLength = i;
-            break;
-        }
-    }
-    return newLength &lt; string.length() ? string.left(newLength) : string;
-}
-
</del><span class="cx"> static String autoFillButtonTypeToAccessibilityLabel(AutoFillButtonType autoFillButtonType)
</span><span class="cx"> {
</span><span class="cx">     switch (autoFillButtonType) {
</span><span class="lines">@@ -441,7 +443,7 @@
</span><span class="cx"> 
</span><span class="cx"> String TextFieldInputType::sanitizeValue(const String&amp; proposedValue) const
</span><span class="cx"> {
</span><del>-    return limitLength(proposedValue.removeCharacters(isASCIILineBreak), HTMLInputElement::maxEffectiveLength);
</del><ins>+    return limitLength(proposedValue.removeCharacters(isHTMLLineBreak), HTMLInputElement::maxEffectiveLength);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void TextFieldInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent&amp; event)
</span><span class="lines">@@ -477,13 +479,12 @@
</span><span class="cx">     // Truncate the inserted text to avoid violating the maxLength and other constraints.
</span><span class="cx">     String eventText = event.text();
</span><span class="cx">     unsigned textLength = eventText.length();
</span><del>-    while (textLength &gt; 0 &amp;&amp; isASCIILineBreak(eventText[textLength - 1]))
</del><ins>+    while (textLength &gt; 0 &amp;&amp; isHTMLLineBreak(eventText[textLength - 1]))
</ins><span class="cx">         textLength--;
</span><span class="cx">     eventText.truncate(textLength);
</span><span class="cx">     eventText.replace(&quot;\r\n&quot;, &quot; &quot;);
</span><span class="cx">     eventText.replace('\r', ' ');
</span><span class="cx">     eventText.replace('\n', ' ');
</span><del>-
</del><span class="cx">     event.setText(limitLength(eventText, appendableLength));
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformLocalizedStringscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/LocalizedStrings.cpp (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/LocalizedStrings.cpp        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WebCore/platform/LocalizedStrings.cpp        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx"> #pragma clang diagnostic push
</span><span class="cx"> #pragma clang diagnostic ignored &quot;-Wformat-nonliteral&quot;
</span><span class="cx"> #endif
</span><del>-    RetainPtr&lt;CFStringRef&gt; result = adoptCF(CFStringCreateWithFormatAndArguments(0, 0, format.createCFString().get(), arguments));
</del><ins>+    auto result = adoptCF(CFStringCreateWithFormatAndArguments(0, 0, format.createCFString().get(), arguments));
</ins><span class="cx"> #if COMPILER(CLANG)
</span><span class="cx"> #pragma clang diagnostic pop
</span><span class="cx"> #endif
</span><span class="lines">@@ -73,19 +73,17 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTEXT_MENUS)
</span><ins>+
</ins><span class="cx"> static String truncatedStringForLookupMenuItem(const String&amp; original)
</span><span class="cx"> {
</span><del>-    if (original.isEmpty())
-        return original;
-
-    // Truncate the string if it's too long. This is in consistency with AppKit.
</del><ins>+    // Truncate the string if it's too long. This number is roughly the same as the one used by AppKit.
</ins><span class="cx">     unsigned maxNumberOfGraphemeClustersInLookupMenuItem = 24;
</span><del>-    static NeverDestroyed&lt;String&gt; ellipsis(&amp;horizontalEllipsis, 1);
</del><span class="cx"> 
</span><span class="cx">     String trimmed = original.stripWhiteSpace();
</span><span class="cx">     unsigned numberOfCharacters = numCharactersInGraphemeClusters(trimmed, maxNumberOfGraphemeClustersInLookupMenuItem);
</span><del>-    return numberOfCharacters == trimmed.length() ? trimmed : trimmed.left(numberOfCharacters) + ellipsis.get();
</del><ins>+    return numberOfCharacters == trimmed.length() ? trimmed : makeString(trimmed.left(numberOfCharacters), horizontalEllipsis);
</ins><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> String inputElementAltText()
</span><span class="lines">@@ -135,13 +133,16 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(COCOA)
</span><ins>+
</ins><span class="cx"> String copyImageUnknownFileLabel()
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;unknown&quot;, &quot;Unknown filename&quot;);
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTEXT_MENUS)
</span><ins>+
</ins><span class="cx"> String contextMenuItemTagOpenLinkInNewWindow()
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Open Link in New Window&quot;, &quot;Open in New Window context menu item&quot;);
</span><span class="lines">@@ -237,7 +238,7 @@
</span><span class="cx"> String contextMenuItemTagSearchWeb()
</span><span class="cx"> {
</span><span class="cx"> #if PLATFORM(COCOA)
</span><del>-    RetainPtr&lt;CFStringRef&gt; searchProviderName = adoptCF(wkCopyDefaultSearchProviderDisplayName());
</del><ins>+    auto searchProviderName = adoptCF(wkCopyDefaultSearchProviderDisplayName());
</ins><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;Search with %@&quot;, &quot;Search with search provider context menu item with provider name inserted&quot;), searchProviderName.get());
</span><span class="cx"> #else
</span><span class="cx">     return WEB_UI_STRING(&quot;Search with Google&quot;, &quot;Search with Google context menu item&quot;);
</span><span class="lines">@@ -247,7 +248,7 @@
</span><span class="cx"> String contextMenuItemTagLookUpInDictionary(const String&amp; selectedString)
</span><span class="cx"> {
</span><span class="cx"> #if USE(CF)
</span><del>-    RetainPtr&lt;CFStringRef&gt; selectedCFString = truncatedStringForLookupMenuItem(selectedString).createCFString();
</del><ins>+    auto selectedCFString = truncatedStringForLookupMenuItem(selectedString).createCFString();
</ins><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;Look Up “%@”&quot;, &quot;Look Up context menu item with selected word&quot;), selectedCFString.get());
</span><span class="cx"> #else
</span><span class="cx">     return WEB_UI_STRING(&quot;Look Up “&lt;selection&gt;”&quot;, &quot;Look Up context menu item with selected word&quot;).replace(&quot;&lt;selection&gt;&quot;, truncatedStringForLookupMenuItem(selectedString));
</span><span class="lines">@@ -324,6 +325,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(COCOA)
</span><ins>+
</ins><span class="cx"> String contextMenuItemTagStyles()
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Styles...&quot;, &quot;Styles context menu item&quot;);
</span><span class="lines">@@ -348,6 +350,7 @@
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Stop Speaking&quot;, &quot;Stop speaking context menu item&quot;);
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> String contextMenuItemTagWritingDirectionMenu()
</span><span class="lines">@@ -544,6 +547,7 @@
</span><span class="cx"> #endif // ENABLE(CONTEXT_MENUS)
</span><span class="cx"> 
</span><span class="cx"> #if !PLATFORM(IOS)
</span><ins>+
</ins><span class="cx"> String searchMenuNoRecentSearchesText()
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;No recent searches&quot;, &quot;Label for only item in menu that appears when clicking on the search field image, when no searches have been performed&quot;);
</span><span class="lines">@@ -558,6 +562,7 @@
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Clear Recent Searches&quot;, &quot;menu item in Recent Searches menu that empties menu's contents&quot;);
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif // !PLATFORM(IOS)
</span><span class="cx"> 
</span><span class="cx"> String AXWebAreaText()
</span><span class="lines">@@ -880,6 +885,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><ins>+
</ins><span class="cx"> String htmlSelectMultipleItems(size_t count)
</span><span class="cx"> {
</span><span class="cx">     switch (count) {
</span><span class="lines">@@ -911,21 +917,22 @@
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;no media selected (multiple)&quot;, &quot;Text to display in file button used in HTML forms for media files when no media files are selected and the button allows multiple files to be selected&quot;);
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> String imageTitle(const String&amp; filename, const IntSize&amp; size)
</span><span class="cx"> {
</span><span class="cx"> #if USE(CF)
</span><del>-    RetainPtr&lt;CFLocaleRef&gt; locale = adoptCF(CFLocaleCopyCurrent());
-    RetainPtr&lt;CFNumberFormatterRef&gt; formatter = adoptCF(CFNumberFormatterCreate(0, locale.get(), kCFNumberFormatterDecimalStyle));
</del><ins>+    auto locale = adoptCF(CFLocaleCopyCurrent());
+    auto formatter = adoptCF(CFNumberFormatterCreate(0, locale.get(), kCFNumberFormatterDecimalStyle));
</ins><span class="cx"> 
</span><span class="cx">     int widthInt = size.width();
</span><del>-    RetainPtr&lt;CFNumberRef&gt; width = adoptCF(CFNumberCreate(0, kCFNumberIntType, &amp;widthInt));
-    RetainPtr&lt;CFStringRef&gt; widthString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), width.get()));
</del><ins>+    auto width = adoptCF(CFNumberCreate(0, kCFNumberIntType, &amp;widthInt));
+    auto widthString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), width.get()));
</ins><span class="cx"> 
</span><span class="cx">     int heightInt = size.height();
</span><del>-    RetainPtr&lt;CFNumberRef&gt; height = adoptCF(CFNumberCreate(0, kCFNumberIntType, &amp;heightInt));
-    RetainPtr&lt;CFStringRef&gt; heightString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), height.get()));
</del><ins>+    auto height = adoptCF(CFNumberCreate(0, kCFNumberIntType, &amp;heightInt));
+    auto heightString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), height.get()));
</ins><span class="cx"> 
</span><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;%@ %@×%@ pixels&quot;, &quot;window title for a standalone image (uses multiplication symbol, not x)&quot;), filename.createCFString().get(), widthString.get(), heightString.get());
</span><span class="cx"> #else
</span><span class="lines">@@ -1126,7 +1133,7 @@
</span><span class="cx"> 
</span><span class="cx"> String validationMessageRangeUnderflowText(const String&amp; minimum)
</span><span class="cx"> {
</span><del>-#if PLATFORM(COCOA)
</del><ins>+#if USE(CF)
</ins><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;Value must be greater than or equal to %@&quot;, &quot;Validation message for input form controls with value lower than allowed minimum&quot;), minimum.createCFString().get());
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(minimum);
</span><span class="lines">@@ -1136,7 +1143,7 @@
</span><span class="cx"> 
</span><span class="cx"> String validationMessageRangeOverflowText(const String&amp; maximum)
</span><span class="cx"> {
</span><del>-#if PLATFORM(COCOA)
</del><ins>+#if USE(CF)
</ins><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;Value must be less than or equal to %@&quot;, &quot;Validation message for input form controls with value higher than allowed maximum&quot;), maximum.createCFString().get());
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(maximum);
</span><span class="lines">@@ -1160,6 +1167,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><ins>+
</ins><span class="cx"> String textTrackSubtitlesText()
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Subtitles&quot;, &quot;Menu section heading for subtitles&quot;);
</span><span class="lines">@@ -1185,7 +1193,10 @@
</span><span class="cx">     return WEB_UI_STRING_KEY(&quot;Unknown&quot;, &quot;Unknown (audio track)&quot;, &quot;Menu item label for an audio track that has no other name&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if PLATFORM(COCOA) || PLATFORM(WIN)
</del><ins>+#endif
+
+#if ENABLE(VIDEO_TRACK) &amp;&amp; USE(CF)
+
</ins><span class="cx"> String textTrackCountryAndLanguageMenuItemText(const String&amp; title, const String&amp; country, const String&amp; language)
</span><span class="cx"> {
</span><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;%@ (%@-%@)&quot;, &quot;Text track display name format that includes the country and language of the subtitle, in the form of 'Title (Language-Country)'&quot;), title.createCFString().get(), language.createCFString().get(), country.createCFString().get());
</span><span class="lines">@@ -1220,7 +1231,6 @@
</span><span class="cx"> {
</span><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;%@ AD&quot;, &quot;Text track contains Audio Descriptions&quot;), title.createCFString().get());
</span><span class="cx"> }
</span><del>-#endif
</del><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -1240,6 +1250,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(SUBTLE_CRYPTO)
</span><ins>+
</ins><span class="cx"> String webCryptoMasterKeyKeychainLabel(const String&amp; localizedApplicationName)
</span><span class="cx"> {
</span><span class="cx">     return formatLocalizedString(WEB_UI_STRING(&quot;%@ WebCrypto Master Key&quot;, &quot;Name of application's single WebCrypto master key in Keychain&quot;), localizedApplicationName.createCFString().get());
</span><span class="lines">@@ -1249,9 +1260,11 @@
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Used to encrypt WebCrypto keys in persistent storage, such as IndexedDB&quot;, &quot;Description of WebCrypto master keys in Keychain&quot;);
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC)
</span><ins>+
</ins><span class="cx"> String insertListTypeNone()
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;None&quot;, &quot;Option in segmented control for choosing list type in text editing&quot;);
</span><span class="lines">@@ -1281,6 +1294,7 @@
</span><span class="cx"> {
</span><span class="cx">     return WEB_UI_STRING(&quot;Exit Fullscreen&quot;, &quot;Button for exiting fullscreen when in fullscreen media playback&quot;);
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif // PLATFORM(MAC)
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderTextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderText.cpp (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderText.cpp        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WebCore/rendering/RenderText.cpp        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -705,15 +705,16 @@
</span><span class="cx">     switch (lineBreak) {
</span><span class="cx">     case LineBreakAuto:
</span><span class="cx">     case LineBreakAfterWhiteSpace:
</span><del>-        return LineBreakIteratorModeUAX14;
</del><ins>+        return LineBreakIteratorMode::Default;
</ins><span class="cx">     case LineBreakLoose:
</span><del>-        return LineBreakIteratorModeUAX14Loose;
</del><ins>+        return LineBreakIteratorMode::Loose;
</ins><span class="cx">     case LineBreakNormal:
</span><del>-        return LineBreakIteratorModeUAX14Normal;
</del><ins>+        return LineBreakIteratorMode::Normal;
</ins><span class="cx">     case LineBreakStrict:
</span><del>-        return LineBreakIteratorModeUAX14Strict;
</del><ins>+        return LineBreakIteratorMode::Strict;
</ins><span class="cx">     }
</span><del>-    return LineBreakIteratorModeUAX14;
</del><ins>+    ASSERT_NOT_REACHED();
+    return LineBreakIteratorMode::Default;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderText::computePreferredLogicalWidths(float leadWidth)
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingSimpleLineLayoutTextFragmentIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -121,7 +121,7 @@
</span><span class="cx">         UChar lastCharacter = textLength &gt; 0 ? currentText[textLength - 1] : 0;
</span><span class="cx">         UChar secondToLastCharacter = textLength &gt; 1 ? currentText[textLength - 2] : 0;
</span><span class="cx">         m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
</span><del>-        m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14);
</del><ins>+        m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorMode::Default);
</ins><span class="cx">     }
</span><span class="cx">     const auto* characters = segment.text.characters&lt;CharacterType&gt;();
</span><span class="cx">     unsigned segmentLength = segment.end - segment.start;
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Tools/ChangeLog        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2016-11-22  Darin Adler  &lt;darin@apple.com&gt;
+
+        Make normal case fast in the input element limitString function
+        https://bugs.webkit.org/show_bug.cgi?id=165023
+
+        Reviewed by Dan Bernstein.
+
+        * TestWebKitAPI/CMakeLists.txt: Added TextBreakIterator.cpp.
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Ditto.
+        * TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp: Added.
+        Contains some tests for the numGraphemeClusters and
+        numCharactersInGraphemeClusters functions that I used to make sure
+        that the new fast paths I added work correctly.
+
</ins><span class="cx"> 2016-11-22  Tomas Popela  &lt;tpopela@redhat.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, add myself as a WebKit committer.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPICMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/CMakeLists.txt        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -80,6 +80,7 @@
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/StringImpl.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/StringOperators.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/StringView.cpp
</span><ins>+    ${TESTWEBKITAPI_DIR}/Tests/WTF/TextBreakIterator.cpp
</ins><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/Time.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/UniqueRef.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/Variant.cpp
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (208962 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-11-22 14:34:55 UTC (rev 208962)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -420,6 +420,7 @@
</span><span class="cx">                 837A35F11D9A1E7D00663C57 /* DownloadRequestBlobURL.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 837A35F01D9A1E6400663C57 /* DownloadRequestBlobURL.html */; };
</span><span class="cx">                 83CF1C301C4F1B8B00688447 /* StringUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83CF1C2C1C4F19AE00688447 /* StringUtilities.mm */; };
</span><span class="cx">                 930AD402150698D00067970F /* lots-of-text.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 930AD401150698B30067970F /* lots-of-text.html */; };
</span><ins>+                9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */; };
</ins><span class="cx">                 932AE53D1D371047005DFFAF /* focus-inputs.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93575C551D30366E000D604D /* focus-inputs.html */; };
</span><span class="cx">                 9361002914DC95A70061379D /* lots-of-iframes.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9361002814DC957B0061379D /* lots-of-iframes.html */; };
</span><span class="cx">                 93625D271CD9741C006DC1F1 /* large-video-without-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93625D261CD973AF006DC1F1 /* large-video-without-audio.html */; };
</span><span class="lines">@@ -1047,6 +1048,7 @@
</span><span class="cx">                 8AA28C1916D2FA7B002FF4DB /* LoadPageOnCrash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadPageOnCrash.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 8DD76FA10486AA7600D96B5E /* TestWebKitAPI */ = {isa = PBXFileReference; explicitFileType = &quot;compiled.mach-o.executable&quot;; includeInIndex = 0; path = TestWebKitAPI; sourceTree = BUILT_PRODUCTS_DIR; };
</span><span class="cx">                 930AD401150698B30067970F /* lots-of-text.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;lots-of-text.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBreakIterator.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 9331407B17B4419000F083B1 /* DidNotHandleKeyDown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidNotHandleKeyDown.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 93575C551D30366E000D604D /* focus-inputs.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;focus-inputs.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 9361002814DC957B0061379D /* lots-of-iframes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;lots-of-iframes.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -1852,6 +1854,7 @@
</span><span class="cx">                                 7C74D42D188228F300E5ED57 /* StringView.cpp */,
</span><span class="cx">                                 5597F8341D9596C80066BC21 /* SynchronizedFixedQueue.cpp */,
</span><span class="cx">                                 0BCD85691485C98B00EA2003 /* SetForScope.cpp */,
</span><ins>+                                9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */,
</ins><span class="cx">                                 0F2C20B71DCD544800542D9E /* Time.cpp */,
</span><span class="cx">                                 5C5E633D1D0B67940085A025 /* UniqueRef.cpp */,
</span><span class="cx">                                 7CD0D5AA1D5534DE000CC9E1 /* Variant.cpp */,
</span><span class="lines">@@ -2327,6 +2330,7 @@
</span><span class="cx">                                 7C83DED21D0A590C00FEBCF3 /* HashMap.cpp in Sources */,
</span><span class="cx">                                 7C83DED41D0A590C00FEBCF3 /* HashSet.cpp in Sources */,
</span><span class="cx">                                 7C83DEE01D0A590C00FEBCF3 /* IntegerToStringConversion.cpp in Sources */,
</span><ins>+                                9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */,
</ins><span class="cx">                                 1ADAD1501D77A9F600212586 /* BlockPtr.mm in Sources */,
</span><span class="cx">                                 7C83DEE81D0A590C00FEBCF3 /* ListHashSet.cpp in Sources */,
</span><span class="cx">                                 7C83DF1D1D0A590C00FEBCF3 /* Lock.cpp in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWTFTextBreakIteratorcpp"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp (0 => 208963)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp        2016-11-22 17:16:02 UTC (rev 208963)
</span><span class="lines">@@ -0,0 +1,146 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+
+#include &lt;wtf/text/TextBreakIterator.h&gt;
+
+namespace TestWebKitAPI {
+
+static String makeUTF16(std::vector&lt;UChar&gt; input)
+{
+    return { input.data(), static_cast&lt;unsigned&gt;(input.size()) };
+}
+
+TEST(WTF, TextBreakIteratorNumGraphemeClusters)
+{
+    EXPECT_EQ(0U, numGraphemeClusters(StringView { }));
+    EXPECT_EQ(0U, numGraphemeClusters(StringView { &quot;&quot; }));
+    EXPECT_EQ(0U, numGraphemeClusters(makeUTF16({ })));
+
+    EXPECT_EQ(1U, numGraphemeClusters(StringView { &quot;a&quot; }));
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 'a' })));
+    EXPECT_EQ(1U, numGraphemeClusters(StringView { &quot;\r\n&quot; }));
+    EXPECT_EQ(1U, numGraphemeClusters(StringView { &quot;\n&quot; }));
+    EXPECT_EQ(1U, numGraphemeClusters(StringView { &quot;\r&quot; }));
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\r', '\n' })));
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\n' })));
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\r' })));
+
+    EXPECT_EQ(2U, numGraphemeClusters(StringView { &quot;\n\r&quot; }));
+    EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ '\n', '\r' })));
+
+    EXPECT_EQ(2U, numGraphemeClusters(StringView { &quot;\r\n\r&quot; }));
+    EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ '\r', '\n', '\r' })));
+
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 'g', 0x308 })));
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 0x1100, 0x1161, 0x11A8 })));
+    EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 0x0BA8, 0x0BBF })));
+
+    EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ 0x308, 'g' })));
+
+    EXPECT_EQ(3U, numGraphemeClusters(StringView { &quot;\r\nbc&quot; }));
+    EXPECT_EQ(3U, numGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' })));
+}
+
+TEST(WTF, TextBreakIteratorNumCharactersInGraphemeClusters)
+{
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { }, 0));
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { }, 1));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;&quot; }, 0));
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;&quot; }, 1));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ }), 0));
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ }), 1));
+
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { &quot;a&quot; }, 1));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 'a' }), 1));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { &quot;\n&quot; }, 1));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { &quot;\r&quot; }, 1));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\n' }), 1));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\r' }), 1));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;abc&quot; }, 0));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { &quot;abc&quot; }, 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;abc&quot; }, 2));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { &quot;abc&quot; }, 3));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { &quot;abc&quot; }, 4));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 0));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 2));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 3));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 'a', 'b', 'c' }), 4));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;\r\n&quot; }, 0));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;\r\n&quot; }, 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;\r\n&quot; }, 2));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;\r\n&quot; }, 3));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 0));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 2));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n' }), 3));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;\n\r&quot; }, 0));
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { &quot;\n\r&quot; }, 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;\n\r&quot; }, 2));
+
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\n', '\r' }), 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\n', '\r' }), 2));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;\r\n\r&quot; }, 0));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;\r\n\r&quot; }, 1));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { &quot;\r\n\r&quot; }, 2));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { &quot;\r\n\r&quot; }, 3));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 0));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 1));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 2));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ '\r', '\n', '\r' }), 3));
+
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308 }), 1));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 0x1100, 0x1161, 0x11A8 }), 1));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 0x0BA8, 0x0BBF }), 1));
+
+    EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 0x308, 'g' }), 1));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { &quot;\r\nbc&quot; }, 0));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { &quot;\r\nbc&quot; }, 1));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { &quot;\r\nbc&quot; }, 2));
+    EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { &quot;\r\nbc&quot; }, 3));
+    EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { &quot;\r\nbc&quot; }, 4));
+    EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { &quot;\r\nbc&quot; }, 5));
+
+    EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 0));
+    EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 1));
+    EXPECT_EQ(3U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 2));
+    EXPECT_EQ(4U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 3));
+    EXPECT_EQ(4U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 4));
+    EXPECT_EQ(4U, numCharactersInGraphemeClusters(makeUTF16({ 'g', 0x308, 'b', 'c' }), 5));
+}
+
+} // namespace TestWebKitAPI
</ins><span class="cx">Property changes on: trunk/Tools/TestWebKitAPI/Tests/WTF/TextBreakIterator.cpp
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<ins>+native
</ins><span class="cx">\ No newline at end of property
</span></div>

</body>
</html>