<!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 <darin@apple.com>
+
+ 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 <mark.lam@apple.com>
</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 "TextBreakIterator.h"
</span><del>-#include "TextBreakIteratorInternalICU.h"
-#include <unicode/ubrk.h>
-#include <wtf/Assertions.h>
</del><span class="cx"> #include <wtf/HashMap.h>
</span><ins>+#include <wtf/NeverDestroyed.h>
</ins><span class="cx"> #include <wtf/ThreadSpecific.h>
</span><span class="cx"> #include <wtf/text/AtomicString.h>
</span><del>-#include <wtf/text/CString.h>
-#include <wtf/text/StringBuilder.h>
</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& sharedPool()
</span><span class="cx"> {
</span><del>- static WTF::ThreadSpecific<LineBreakIteratorPool>* pool = new WTF::ThreadSpecific<LineBreakIteratorPool>;
- return **pool;
</del><ins>+ static NeverDestroyed<WTF::ThreadSpecific<LineBreakIteratorPool>> pool;
+ return *pool.get();
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- static String makeLocaleWithBreakKeyword(const AtomicString& locale, LineBreakIteratorMode mode)
</del><ins>+ static AtomicString makeLocaleWithBreakKeyword(const AtomicString& locale, LineBreakIteratorMode mode)
</ins><span class="cx"> {
</span><del>- StringBuilder localeWithKeyword;
- localeWithKeyword.append(locale);
- localeWithKeyword.appendLiteral("@break=");
</del><span class="cx"> switch (mode) {
</span><del>- case LineBreakIteratorModeUAX14:
- ASSERT_NOT_REACHED();
- break;
- case LineBreakIteratorModeUAX14Loose:
- localeWithKeyword.appendLiteral("loose");
- break;
- case LineBreakIteratorModeUAX14Normal:
- localeWithKeyword.appendLiteral("normal");
- break;
- case LineBreakIteratorModeUAX14Strict:
- localeWithKeyword.appendLiteral("strict");
- break;
</del><ins>+ case LineBreakIteratorMode::Default:
+ return locale;
+ case LineBreakIteratorMode::Loose:
+ return makeString(locale, "@break=loose");
+ case LineBreakIteratorMode::Normal:
+ return makeString(locale, "@break=normal");
+ case LineBreakIteratorMode::Strict:
+ return makeString(locale, "@break=strict");
</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& 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 < 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<AtomicString, TextBreakIterator*> Entry;
- typedef Vector<Entry, capacity> Pool;
- Pool m_pool;
</del><ins>+ Vector<std::pair<AtomicString, TextBreakIterator*>, capacity> m_pool;
</ins><span class="cx"> HashMap<TextBreakIterator*, AtomicString> m_vendedIterators;
</span><span class="cx">
</span><span class="cx"> friend WTF::ThreadSpecific<LineBreakIteratorPool>::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 "TextBreakIterator.h"
</span><span class="cx">
</span><span class="cx"> #include "LineBreakIteratorPoolICU.h"
</span><ins>+#include "TextBreakIteratorInternalICU.h"
</ins><span class="cx"> #include "UTextProviderLatin1.h"
</span><span class="cx"> #include "UTextProviderUTF16.h"
</span><span class="cx"> #include <atomic>
</span><span class="cx"> #include <mutex>
</span><del>-#include <wtf/text/StringView.h>
</del><ins>+#include <unicode/ubrk.h>
+#include <wtf/text/StringBuilder.h>
</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) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 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, &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() && !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 < stringLength; ++i)
+ numCRLF += characters[i - 1] == '\r' && 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& 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 <= numGraphemeClusters)
+ return stringLength;
</ins><span class="cx">
</span><del>- // The only Latin-1 Extended Grapheme Cluster is CR LF
- if (s.is8Bit() && !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 < numGraphemeClusters && j + 1 < stringLength; ++i, ++j)
+ j += characters[j] == '\r' && characters[j + 1] == '\n';
+ return j + (i < numGraphemeClusters && j < 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 < 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 <lars@trolltech.com>
</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 <wtf/text/AtomicString.h>
</del><span class="cx"> #include <wtf/text/StringView.h>
</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&);
</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& locale = AtomicString(), LineBreakIteratorMode mode = LineBreakIteratorModeUAX14)
</del><ins>+ explicit LazyLineBreakIterator(StringView stringView, const AtomicString& 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 && m_mode == LineBreakIteratorModeUAX14Loose; }
</del><ins>+ bool isLooseCJKMode() const { return m_isCJK && 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 "extended grapheme clusters", 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&, 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 <darin@apple.com>
+
+ 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 <svillar@igalia.com>
</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 "FrameSelection.h"
</span><span class="cx"> #include "HTMLInputElement.h"
</span><span class="cx"> #include "HTMLNames.h"
</span><ins>+#include "HTMLParserIdioms.h"
</ins><span class="cx"> #include "KeyboardEvent.h"
</span><span class="cx"> #include "LocalizedStrings.h"
</span><span class="cx"> #include "NodeRenderStyle.h"
</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 "truncate at first control character" rule come from?
+static String limitLength(const String& 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 < ' ' && 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& string, int maxLength)
-{
- unsigned newLength = numCharactersInGraphemeClusters(string, maxLength);
- for (unsigned i = 0; i < newLength; ++i) {
- const UChar current = string[i];
- if (current < ' ' && current != '\t') {
- newLength = i;
- break;
- }
- }
- return newLength < 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& 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& 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 > 0 && isASCIILineBreak(eventText[textLength - 1]))
</del><ins>+ while (textLength > 0 && isHTMLLineBreak(eventText[textLength - 1]))
</ins><span class="cx"> textLength--;
</span><span class="cx"> eventText.truncate(textLength);
</span><span class="cx"> eventText.replace("\r\n", " ");
</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 "-Wformat-nonliteral"
</span><span class="cx"> #endif
</span><del>- RetainPtr<CFStringRef> 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& 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<String> ellipsis(&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("unknown", "Unknown filename");
</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("Open Link in New Window", "Open in New Window context menu item");
</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<CFStringRef> searchProviderName = adoptCF(wkCopyDefaultSearchProviderDisplayName());
</del><ins>+ auto searchProviderName = adoptCF(wkCopyDefaultSearchProviderDisplayName());
</ins><span class="cx"> return formatLocalizedString(WEB_UI_STRING("Search with %@", "Search with search provider context menu item with provider name inserted"), searchProviderName.get());
</span><span class="cx"> #else
</span><span class="cx"> return WEB_UI_STRING("Search with Google", "Search with Google context menu item");
</span><span class="lines">@@ -247,7 +248,7 @@
</span><span class="cx"> String contextMenuItemTagLookUpInDictionary(const String& selectedString)
</span><span class="cx"> {
</span><span class="cx"> #if USE(CF)
</span><del>- RetainPtr<CFStringRef> selectedCFString = truncatedStringForLookupMenuItem(selectedString).createCFString();
</del><ins>+ auto selectedCFString = truncatedStringForLookupMenuItem(selectedString).createCFString();
</ins><span class="cx"> return formatLocalizedString(WEB_UI_STRING("Look Up “%@”", "Look Up context menu item with selected word"), selectedCFString.get());
</span><span class="cx"> #else
</span><span class="cx"> return WEB_UI_STRING("Look Up “<selection>”", "Look Up context menu item with selected word").replace("<selection>", 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("Styles...", "Styles context menu item");
</span><span class="lines">@@ -348,6 +350,7 @@
</span><span class="cx"> {
</span><span class="cx"> return WEB_UI_STRING("Stop Speaking", "Stop speaking context menu item");
</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("No recent searches", "Label for only item in menu that appears when clicking on the search field image, when no searches have been performed");
</span><span class="lines">@@ -558,6 +562,7 @@
</span><span class="cx"> {
</span><span class="cx"> return WEB_UI_STRING("Clear Recent Searches", "menu item in Recent Searches menu that empties menu's contents");
</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("no media selected (multiple)", "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");
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> String imageTitle(const String& filename, const IntSize& size)
</span><span class="cx"> {
</span><span class="cx"> #if USE(CF)
</span><del>- RetainPtr<CFLocaleRef> locale = adoptCF(CFLocaleCopyCurrent());
- RetainPtr<CFNumberFormatterRef> 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<CFNumberRef> width = adoptCF(CFNumberCreate(0, kCFNumberIntType, &widthInt));
- RetainPtr<CFStringRef> widthString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), width.get()));
</del><ins>+ auto width = adoptCF(CFNumberCreate(0, kCFNumberIntType, &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<CFNumberRef> height = adoptCF(CFNumberCreate(0, kCFNumberIntType, &heightInt));
- RetainPtr<CFStringRef> heightString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), height.get()));
</del><ins>+ auto height = adoptCF(CFNumberCreate(0, kCFNumberIntType, &heightInt));
+ auto heightString = adoptCF(CFNumberFormatterCreateStringWithNumber(0, formatter.get(), height.get()));
</ins><span class="cx">
</span><span class="cx"> return formatLocalizedString(WEB_UI_STRING("%@ %@×%@ pixels", "window title for a standalone image (uses multiplication symbol, not x)"), 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& minimum)
</span><span class="cx"> {
</span><del>-#if PLATFORM(COCOA)
</del><ins>+#if USE(CF)
</ins><span class="cx"> return formatLocalizedString(WEB_UI_STRING("Value must be greater than or equal to %@", "Validation message for input form controls with value lower than allowed minimum"), 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& maximum)
</span><span class="cx"> {
</span><del>-#if PLATFORM(COCOA)
</del><ins>+#if USE(CF)
</ins><span class="cx"> return formatLocalizedString(WEB_UI_STRING("Value must be less than or equal to %@", "Validation message for input form controls with value higher than allowed maximum"), 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("Subtitles", "Menu section heading for subtitles");
</span><span class="lines">@@ -1185,7 +1193,10 @@
</span><span class="cx"> return WEB_UI_STRING_KEY("Unknown", "Unknown (audio track)", "Menu item label for an audio track that has no other name");
</span><span class="cx"> }
</span><span class="cx">
</span><del>-#if PLATFORM(COCOA) || PLATFORM(WIN)
</del><ins>+#endif
+
+#if ENABLE(VIDEO_TRACK) && USE(CF)
+
</ins><span class="cx"> String textTrackCountryAndLanguageMenuItemText(const String& title, const String& country, const String& language)
</span><span class="cx"> {
</span><span class="cx"> return formatLocalizedString(WEB_UI_STRING("%@ (%@-%@)", "Text track display name format that includes the country and language of the subtitle, in the form of 'Title (Language-Country)'"), 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("%@ AD", "Text track contains Audio Descriptions"), 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& localizedApplicationName)
</span><span class="cx"> {
</span><span class="cx"> return formatLocalizedString(WEB_UI_STRING("%@ WebCrypto Master Key", "Name of application's single WebCrypto master key in Keychain"), localizedApplicationName.createCFString().get());
</span><span class="lines">@@ -1249,9 +1260,11 @@
</span><span class="cx"> {
</span><span class="cx"> return WEB_UI_STRING("Used to encrypt WebCrypto keys in persistent storage, such as IndexedDB", "Description of WebCrypto master keys in Keychain");
</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("None", "Option in segmented control for choosing list type in text editing");
</span><span class="lines">@@ -1281,6 +1294,7 @@
</span><span class="cx"> {
</span><span class="cx"> return WEB_UI_STRING("Exit Fullscreen", "Button for exiting fullscreen when in fullscreen media playback");
</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 > 0 ? currentText[textLength - 1] : 0;
</span><span class="cx"> UChar secondToLastCharacter = textLength > 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<CharacterType>();
</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 <darin@apple.com>
+
+ 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 <tpopela@redhat.com>
</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 = "<group>"; };
</span><span class="cx">                 8DD76FA10486AA7600D96B5E /* TestWebKitAPI */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; 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 = "lots-of-text.html"; sourceTree = "<group>"; };
</span><ins>+                9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBreakIterator.cpp; sourceTree = "<group>"; };
</ins><span class="cx">                 9331407B17B4419000F083B1 /* DidNotHandleKeyDown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidNotHandleKeyDown.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 93575C551D30366E000D604D /* focus-inputs.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "focus-inputs.html"; sourceTree = "<group>"; };
</span><span class="cx">                 9361002814DC957B0061379D /* lots-of-iframes.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "lots-of-iframes.html"; sourceTree = "<group>"; };
</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 "config.h"
+
+#include <wtf/text/TextBreakIterator.h>
+
+namespace TestWebKitAPI {
+
+static String makeUTF16(std::vector<UChar> input)
+{
+ return { input.data(), static_cast<unsigned>(input.size()) };
+}
+
+TEST(WTF, TextBreakIteratorNumGraphemeClusters)
+{
+ EXPECT_EQ(0U, numGraphemeClusters(StringView { }));
+ EXPECT_EQ(0U, numGraphemeClusters(StringView { "" }));
+ EXPECT_EQ(0U, numGraphemeClusters(makeUTF16({ })));
+
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "a" }));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ 'a' })));
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "\r\n" }));
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "\n" }));
+ EXPECT_EQ(1U, numGraphemeClusters(StringView { "\r" }));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\r', '\n' })));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\n' })));
+ EXPECT_EQ(1U, numGraphemeClusters(makeUTF16({ '\r' })));
+
+ EXPECT_EQ(2U, numGraphemeClusters(StringView { "\n\r" }));
+ EXPECT_EQ(2U, numGraphemeClusters(makeUTF16({ '\n', '\r' })));
+
+ EXPECT_EQ(2U, numGraphemeClusters(StringView { "\r\n\r" }));
+ 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 { "\r\nbc" }));
+ 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 { "" }, 0));
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "" }, 1));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ }), 0));
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(makeUTF16({ }), 1));
+
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "a" }, 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ 'a' }), 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "\n" }, 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "\r" }, 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\n' }), 1));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\r' }), 1));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "abc" }, 0));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "abc" }, 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "abc" }, 2));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "abc" }, 3));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "abc" }, 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 { "\r\n" }, 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 2));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n" }, 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 { "\n\r" }, 0));
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(StringView { "\n\r" }, 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\n\r" }, 2));
+
+ EXPECT_EQ(1U, numCharactersInGraphemeClusters(makeUTF16({ '\n', '\r' }), 1));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(makeUTF16({ '\n', '\r' }), 2));
+
+ EXPECT_EQ(0U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 2));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "\r\n\r" }, 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 { "\r\nbc" }, 0));
+ EXPECT_EQ(2U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 1));
+ EXPECT_EQ(3U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 2));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 3));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 4));
+ EXPECT_EQ(4U, numCharactersInGraphemeClusters(StringView { "\r\nbc" }, 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>