Source/WebCore/ChangeLog

 12011-02-24 Ned Holbrook <nholbrook@apple.com>
 2
 3 Reviewed by NOBODY (OOPS!).
 4
 5 Minimize calls to ubrk_setText()
 6 https://bugs.webkit.org/show_bug.cgi?id=54912
 7 <rdar://problem/9032774>
 8
 9 Avoid calling ubrk_setText() once per call to isBreakable() by using a LazyLineBreakIterator, which defers
 10 break iterator creation until needed. This requires replacing the global line break iterator primitive with a
 11 version that can be nested, since in some cases two iterators may need to be outstanding. In particular,
 12 layoutInlineChildren() may indirectly call computePreferredLogicalWidths() and each may need an iterator.
 13 In a test with a paragraph of Japanese text, this reduced the number of ubrk_setText() calls from 164 to 1.
 14
 15 * platform/text/TextBreakIterator.h: Add LazyLineBreakIterator.
 16 (WebCore::LazyLineBreakIterator::LazyLineBreakIterator):
 17 (WebCore::LazyLineBreakIterator::~LazyLineBreakIterator):
 18 (WebCore::LazyLineBreakIterator::string):
 19 (WebCore::LazyLineBreakIterator::length):
 20 (WebCore::LazyLineBreakIterator::get):
 21 (WebCore::LazyLineBreakIterator::reset):
 22 * platform/text/TextBreakIteratorICU.cpp: Replace lineBreakIterator() primitive with acquireLineBreakIterator()/releaseLineBreakIterator().
 23 (WebCore::acquireLineBreakIterator):
 24 (WebCore::releaseLineBreakIterator):
 25 * platform/text/brew/TextBreakIteratorBrew.cpp: Ditto.
 26 (WebCore::acquireLineBreakIterator):
 27 (WebCore::releaseLineBreakIterator):
 28 * platform/text/gtk/TextBreakIteratorGtk.cpp: Ditto.
 29 (WebCore::acquireLineBreakIterator):
 30 (WebCore::releaseLineBreakIterator):
 31 * platform/text/qt/TextBreakIteratorQt.cpp: Ditto.
 32 (WebCore::acquireLineBreakIterator):
 33 (WebCore::releaseLineBreakIterator):
 34 * platform/text/wince/TextBreakIteratorWinCE.cpp: Ditto.
 35 (WebCore::acquireLineBreakIterator):
 36 (WebCore::releaseLineBreakIterator):
 37 * rendering/RenderBlock.h:
 38 * rendering/RenderBlockLineLayout.cpp:
 39 (WebCore::RenderBlock::layoutInlineChildren): Pass a mapping of RenderText to LazyLineBreakIterator from one call of findNextLineBreak() to the next.
 40 (WebCore::RenderBlock::findNextLineBreak): Use said mapping, resetting LazyLineBreakIterator for any newly-encountered RenderText.
 41 * rendering/RenderText.cpp: Use a local LazyLineBreakIterator.
 42 (WebCore::RenderText::computePreferredLogicalWidths):
 43 * rendering/break_lines.cpp: Accept LazyLineBreakIterator rather than UniChar buffer.
 44 (WebCore::nextBreakablePosition):
 45 * rendering/break_lines.h: Accept LazyLineBreakIterator rather than UniChar buffer.
 46 (WebCore::isBreakable):
 47
1482011-02-24 Simon Fraser <simon.fraser@apple.com>
249
350 Reviewed by Dan Bernstein.
79647

Source/WebCore/platform/text/TextBreakIterator.h

@@namespace WebCore {
2828
2929 class TextBreakIterator;
3030
31  // Note: The returned iterator is good only until you get another iterator.
 31 // Note: The returned iterator is good only until you get another iterator, with the exception of acquireLineBreakIterator.
3232
3333 // Iterates over "extended grapheme clusters", as defined in UAX #29.
3434 // Note that platform implementations may be less sophisticated - e.g. ICU prior to

@@namespace WebCore {
4343 TextBreakIterator* cursorMovementIterator(const UChar*, int length);
4444
4545 TextBreakIterator* wordBreakIterator(const UChar*, int length);
46  TextBreakIterator* lineBreakIterator(const UChar*, int length);
 46 TextBreakIterator* acquireLineBreakIterator(const UChar*, int length);
 47 void releaseLineBreakIterator(TextBreakIterator*);
4748 TextBreakIterator* sentenceBreakIterator(const UChar*, int length);
4849
4950 int textBreakFirst(TextBreakIterator*);

@@namespace WebCore {
5758
5859 const int TextBreakDone = -1;
5960
 61class LazyLineBreakIterator {
 62public:
 63 LazyLineBreakIterator(const UChar* string = 0, int length = 0)
 64 : m_string(string)
 65 , m_length(length)
 66 , m_iterator(0)
 67 {
 68 }
 69
 70 ~LazyLineBreakIterator()
 71 {
 72 if (m_iterator)
 73 releaseLineBreakIterator(m_iterator);
 74 }
 75
 76 const UChar* string() const { return m_string; }
 77 int length() const { return m_length; }
 78
 79 TextBreakIterator* get()
 80 {
 81 if (!m_iterator)
 82 m_iterator = acquireLineBreakIterator(m_string, m_length);
 83 return m_iterator;
 84 }
 85
 86 void reset(const UChar* string, int length)
 87 {
 88 if (m_iterator)
 89 releaseLineBreakIterator(m_iterator);
 90
 91 m_string = string;
 92 m_length = length;
 93 m_iterator = 0;
 94 }
 95
 96private:
 97 const UChar* m_string;
 98 int m_length;
 99 TextBreakIterator* m_iterator;
 100};
 101
60102}
61103
62104#endif
79574

Source/WebCore/platform/text/TextBreakIteratorICU.cpp

2727#include <unicode/ubrk.h>
2828#include <wtf/Assertions.h>
2929
 30using namespace std;
 31
3032namespace WebCore {
3133
3234static TextBreakIterator* setUpIterator(bool& createdIterator, TextBreakIterator*& iterator,

@@TextBreakIterator* wordBreakIterator(con
6870 staticWordBreakIterator, UBRK_WORD, string, length);
6971}
7072
71 TextBreakIterator* lineBreakIterator(const UChar* string, int length)
 73static bool createdLineBreakIterator = false;
 74static TextBreakIterator* staticLineBreakIterator;
 75
 76TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length)
 77{
 78 TextBreakIterator* lineBreakIterator = 0;
 79 if (!createdLineBreakIterator || staticLineBreakIterator) {
 80 setUpIterator(createdLineBreakIterator, staticLineBreakIterator, UBRK_LINE, string, length);
 81 swap(staticLineBreakIterator, lineBreakIterator);
 82 }
 83
 84 if (!lineBreakIterator) {
 85 bool createdNewLineBreakIterator = false;
 86 setUpIterator(createdNewLineBreakIterator, lineBreakIterator, UBRK_LINE, string, length);
 87 }
 88
 89 return lineBreakIterator;
 90}
 91
 92void releaseLineBreakIterator(TextBreakIterator* iterator)
7293{
73  static bool createdLineBreakIterator = false;
74  static TextBreakIterator* staticLineBreakIterator;
75  return setUpIterator(createdLineBreakIterator,
76  staticLineBreakIterator, UBRK_LINE, string, length);
 94 ASSERT(createdLineBreakIterator);
 95 ASSERT(iterator);
 96
 97 if (!staticLineBreakIterator)
 98 staticLineBreakIterator = iterator;
 99 else
 100 ubrk_close(reinterpret_cast<UBreakIterator*>(iterator));
77101}
78102
79103TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
79574

Source/WebCore/platform/text/brew/TextBreakIteratorBrew.cpp

2626#include <wtf/StdLibExtras.h>
2727#include <wtf/unicode/Unicode.h>
2828
 29using namespace std;
2930using namespace WTF::Unicode;
3031
3132namespace WebCore {

@@TextBreakIterator* characterBreakIterato
260261 return &iterator;
261262}
262263
263 TextBreakIterator* lineBreakIterator(const UChar* string, int length)
 264static TextBreakIterator* staticLineBreakIterator;
 265
 266TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length)
264267{
265  DEFINE_STATIC_LOCAL(LineBreakIterator , iterator, ());
266  iterator.reset(string, length);
267  return &iterator;
 268 TextBreakIterator* lineBreakIterator = 0;
 269 if (staticLineBreakIterator) {
 270 staticLineBreakIterator->reset(string, length);
 271 swap(staticLineBreakIterator, lineBreakIterator);
 272 }
 273
 274 if (!lineBreakIterator && string && length)
 275 lineBreakIterator = new LineBreakIterator(string, length);
 276
 277 return lineBreakIterator;
 278}
 279
 280void releaseLineBreakIterator(TextBreakIterator* iterator)
 281{
 282 ASSERT(iterator);
 283
 284 if (!staticLineBreakIterator)
 285 staticLineBreakIterator = iterator;
 286 else
 287 delete iterator;
268288}
269289
270290TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
79574

Source/WebCore/platform/text/gtk/TextBreakIteratorGtk.cpp

@@TextBreakIterator* wordBreakIterator(con
239239 return setUpIterator(createdWordBreakIterator, staticWordBreakIterator, UBRK_WORD, string, length);
240240}
241241
242 TextBreakIterator* lineBreakIterator(const UChar* string, int length)
 242static bool createdLineBreakIterator = false;
 243static TextBreakIterator* staticLineBreakIterator;
 244
 245TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length)
243246{
244  static bool createdLineBreakIterator = false;
245  static TextBreakIterator* staticLineBreakIterator;
246  return setUpIterator(createdLineBreakIterator, staticLineBreakIterator, UBRK_LINE, string, length);
 247 TextBreakIterator* lineBreakIterator = 0;
 248 if (!createdLineBreakIterator || staticLineBreakIterator) {
 249 setUpIterator(createdLineBreakIterator, staticLineBreakIterator, UBRK_LINE, string, length);
 250 swap(staticLineBreakIterator, lineBreakIterator);
 251 }
 252
 253 if (!lineBreakIterator) {
 254 bool createdNewLineBreakIterator = false;
 255 setUpIterator(createdNewLineBreakIterator, lineBreakIterator, UBRK_LINE, string, length);
 256 }
 257
 258 return lineBreakIterator;
 259}
 260
 261void releaseLineBreakIterator(TextBreakIterator* iterator)
 262{
 263 ASSERT(createdLineBreakIterator);
 264 ASSERT(iterator);
 265
 266 if (!staticLineBreakIterator)
 267 staticLineBreakIterator = iterator;
 268 else
 269 delete iterator;
247270}
248271
249272TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
79574

Source/WebCore/platform/text/qt/TextBreakIteratorQt.cpp

3131#define DEBUG if (1) {} else qDebug
3232#endif
3333
 34using namespace std;
 35
3436namespace WebCore {
3537
3638#if USE(QT_ICU_TEXT_BREAKING)

@@const char* currentTextBreakLocaleID()
8082 return characterBreakIterator(string, length);
8183 }
8284
83  TextBreakIterator* lineBreakIterator(const UChar* string, int length)
 85 static TextBreakIterator* staticLineBreakIterator;
 86
 87 TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length)
8488 {
85  static TextBreakIterator staticLineBreakIterator;
86  return setUpIterator(staticLineBreakIterator, QTextBoundaryFinder::Line, string, length);
 89 TextBreakIterator* lineBreakIterator = 0;
 90 if (staticLineBreakIterator) {
 91 setUpIterator(*staticLineBreakIterator, QTextBoundaryFinder::Line, string, length);
 92 swap(staticLineBreakIterator, lineBreakIterator);
 93 }
 94
 95 if (!lineBreakIterator && string && length)
 96 lineBreakIterator = new TextBreakIterator(QTextBoundaryFinder::Line, QString(reinterpret_cast<const QChar*>(string), length));
 97
 98 return lineBreakIterator;
 99 }
 100
 101 void releaseLineBreakIterator(TextBreakIterator* iterator)
 102 {
 103 ASSERT(iterator);
 104
 105 if (!staticLineBreakIterator)
 106 staticLineBreakIterator = iterator;
 107 else
 108 delete iterator;
87109 }
88110
89111 TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
79574

Source/WebCore/platform/text/wince/TextBreakIteratorWinCE.cpp

2626#include <wtf/StdLibExtras.h>
2727#include <wtf/unicode/Unicode.h>
2828
 29using namespace std;
2930using namespace WTF::Unicode;
3031
3132namespace WebCore {

@@TextBreakIterator* characterBreakIterato
241242 return &iterator;
242243}
243244
244 TextBreakIterator* lineBreakIterator(const UChar* string, int length)
 245static TextBreakIterator* staticLineBreakIterator;
 246
 247TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length)
245248{
246  DEFINE_STATIC_LOCAL(LineBreakIterator , iterator, ());
247  iterator.reset(string, length);
248  return &iterator;
 249 TextBreakIterator* lineBreakIterator = 0;
 250 if (staticLineBreakIterator) {
 251 staticLineBreakIterator->reset(string, length);
 252 swap(staticLineBreakIterator, lineBreakIterator);
 253 }
 254
 255 if (!lineBreakIterator && string && length)
 256 lineBreakIterator = new LineBreakIterator(string, length);
 257
 258 return lineBreakIterator;
 259}
 260
 261void releaseLineBreakIterator(TextBreakIterator* iterator)
 262{
 263 ASSERT(iterator);
 264
 265 if (!staticLineBreakIterator)
 266 staticLineBreakIterator = iterator;
 267 else
 268 delete iterator;
249269}
250270
251271TextBreakIterator* sentenceBreakIterator(const UChar* string, int length)
79574

Source/WebCore/rendering/RenderBlock.h

@@namespace WebCore {
3535class ColumnInfo;
3636class InlineIterator;
3737class LayoutStateMaintainer;
 38class LazyLineBreakIterator;
3839class RenderInline;
3940
4041struct BidiRun;

@@private:
486487 void skipTrailingWhitespace(InlineIterator&, bool isLineEmpty, bool previousLineBrokeCleanly);
487488 int skipLeadingWhitespace(InlineBidiResolver&, bool firstLine, bool isLineEmpty, bool previousLineBrokeCleanly, FloatingObject* lastFloatFromPreviousLine);
488489 void fitBelowFloats(float widthToFit, bool firstLine, float& availableWidth);
489  InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine);
 490 typedef std::pair<RenderText*, LazyLineBreakIterator> LineBreakIteratorInfo;
 491 InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo&, bool& previousLineBrokeCleanly, bool& hyphenated, EClear*, FloatingObject* lastFloatFromPreviousLine);
490492 RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject);
491493 InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine);
492494 void computeInlineDirectionPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&);
79574

Source/WebCore/rendering/RenderBlockLineLayout.cpp

3434#include "RenderListMarker.h"
3535#include "RenderView.h"
3636#include "Settings.h"
 37#include "TextBreakIterator.h"
3738#include "TextRun.h"
3839#include "TrailingFloatsRootInlineBox.h"
3940#include "VerticalPositionCache.h"

@@void RenderBlock::layoutInlineChildren(b
662663 bool isLineEmpty = true;
663664 bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
664665
 666 LineBreakIteratorInfo lineBreakIteratorInfo;
665667 VerticalPositionCache verticalPositionCache;
666668
667669 while (!end.atEnd()) {

@@void RenderBlock::layoutInlineChildren(b
678680
679681 InlineIterator oldEnd = end;
680682 FloatingObject* lastFloatFromPreviousLine = m_floatingObjects ? m_floatingObjects->last() : 0;
681  end = findNextLineBreak(resolver, firstLine, isLineEmpty, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine);
 683 end = findNextLineBreak(resolver, firstLine, isLineEmpty, lineBreakIteratorInfo, previousLineBrokeCleanly, hyphenated, &clear, lastFloatFromPreviousLine);
682684 if (resolver.position().atEnd()) {
683685 resolver.deleteRuns();
684686 checkForFloatsFromLastLine = true;

@@static void tryHyphenating(RenderText* t
14321434 hyphenated = true;
14331435}
14341436
1435 InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly,
 1437InlineIterator RenderBlock::findNextLineBreak(InlineBidiResolver& resolver, bool firstLine, bool& isLineEmpty, LineBreakIteratorInfo& lineBreakIteratorInfo, bool& previousLineBrokeCleanly,
14361438 bool& hyphenated, EClear* clear, FloatingObject* lastFloatFromPreviousLine)
14371439{
14381440 ASSERT(resolver.position().block == this);

@@InlineIterator RenderBlock::findNextLine
17231725 midWordBreak = w + wrapW + charWidth > width;
17241726 }
17251727
1726  bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(str, pos, strlen, nextBreakable, breakNBSP) && (style->hyphens() != HyphensNone || (pos && str[pos - 1] != softHyphen)));
 1728 if (lineBreakIteratorInfo.first != t) {
 1729 lineBreakIteratorInfo.first = t;
 1730 lineBreakIteratorInfo.second.reset(str, strlen);
 1731 }
 1732
 1733 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(lineBreakIteratorInfo.second, pos, nextBreakable, breakNBSP) && (style->hyphens() != HyphensNone || (pos && str[pos - 1] != softHyphen)));
17271734
17281735 if (betweenWords || midWordBreak) {
17291736 bool stoppedIgnoringSpaces = false;
79574

Source/WebCore/rendering/RenderText.cpp

@@void RenderText::computePreferredLogical
748748 float wordSpacing = style()->wordSpacing();
749749 int len = textLength();
750750 const UChar* txt = characters();
 751 LazyLineBreakIterator breakIterator(txt, len);
751752 bool needsWordSpacing = false;
752753 bool ignoringSpaces = false;
753754 bool isSpace = false;

@@void RenderText::computePreferredLogical
807808 continue;
808809 }
809810
810  bool hasBreak = breakAll || isBreakable(txt, i, len, nextBreakable, breakNBSP);
 811 bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP);
811812 bool betweenWords = true;
812813 int j = i;
813814 while (c != '\n' && !isSpaceAccordingToStyle(c, style()) && c != '\t' && c != softHyphen) {

@@void RenderText::computePreferredLogical
815816 if (j == len)
816817 break;
817818 c = txt[j];
818  if (isBreakable(txt, j, len, nextBreakable, breakNBSP))
 819 if (isBreakable(breakIterator, j, nextBreakable, breakNBSP))
819820 break;
820821 if (breakAll) {
821822 betweenWords = false;
79574

Source/WebCore/rendering/break_lines.cpp

@@static inline TextBreakLocatorRef lineBr
154154}
155155#endif
156156
157 int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakSpaceAsBreak)
 157int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, bool treatNoBreakSpaceAsBreak)
158158{
159 #if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER)
160  TextBreakIterator* breakIterator = 0;
161 #endif
 159 const UChar* str = lazyBreakIterator.string();
 160 int len = lazyBreakIterator.length();
162161 int nextBreak = -1;
163162
164163 UChar lastCh = pos > 0 ? str[pos - 1] : 0;

@@int nextBreakablePosition(const UChar* s
171170 if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) {
172171 if (nextBreak < i && i) {
173172#if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER)
174  if (!breakIterator)
175  breakIterator = lineBreakIterator(str, len);
 173 TextBreakIterator* breakIterator = lazyBreakIterator.get();
176174 if (breakIterator)
177175 nextBreak = textBreakFollowing(breakIterator, i - 1);
178176#else
79574

Source/WebCore/rendering/break_lines.h

2525
2626namespace WebCore {
2727
28  int nextBreakablePosition(const UChar*, int pos, int len, bool breakNBSP = false);
 28class LazyLineBreakIterator;
2929
30  inline bool isBreakable(const UChar* str, int pos, int len, int& nextBreakable, bool breakNBSP = false)
31  {
32  if (pos > nextBreakable)
33  nextBreakable = nextBreakablePosition(str, pos, len, breakNBSP);
34  return pos == nextBreakable;
35  }
 30int nextBreakablePosition(LazyLineBreakIterator&, int pos, bool breakNBSP = false);
 31
 32inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP = false)
 33{
 34 if (pos > nextBreakable)
 35 nextBreakable = nextBreakablePosition(lazyBreakIterator, pos, breakNBSP);
 36 return pos == nextBreakable;
 37}
3638
3739} // namespace WebCore
3840
79574