Changeset 79510 in webkit


Ignore:
Timestamp:
Feb 23, 2011, 5:45:06 PM (14 years ago)
Author:
mitz@apple.com
Message:

Minimize calls to ubrk_setText()
https://bugs.webkit.org/show_bug.cgi?id=54912
<rdar://problem/9032774>

Patch by Ned Holbrook <nholbrook@apple.com> on 2011-02-23
Reviewed by Dan Bernstein.

Avoid calling ubrk_setText() once per call to isBreakable() by using a LazyLineBreakIterator, which defers
break iterator creation until needed. This requires replacing the global line break iterator primitive with a
version that can be nested, since in some cases two iterators may need to be outstanding. In particular,
layoutInlineChildren() may indirectly call computePreferredLogicalWidths() and each may need an iterator.
In a test with a paragraph of Japanese text, this reduced the number of ubrk_setText() calls from 164 to 1.

  • platform/text/TextBreakIterator.h: Add LazyLineBreakIterator.

(WebCore::LazyLineBreakIterator::LazyLineBreakIterator):
(WebCore::LazyLineBreakIterator::~LazyLineBreakIterator):
(WebCore::LazyLineBreakIterator::string):
(WebCore::LazyLineBreakIterator::length):
(WebCore::LazyLineBreakIterator::get):
(WebCore::LazyLineBreakIterator::reset):

  • platform/text/TextBreakIteratorICU.cpp: Replace lineBreakIterator() primitive with acquireLineBreakIterator()/releaseLineBreakIterator().

(WebCore::acquireLineBreakIterator):
(WebCore::releaseLineBreakIterator):

  • platform/text/qt/TextBreakIteratorQt.cpp: Ditto TextBreakIteratorICU.cpp.

(WebCore::acquireLineBreakIterator):
(WebCore::releaseLineBreakIterator):

  • rendering/RenderBlock.h:
  • rendering/RenderBlockLineLayout.cpp:

(WebCore::RenderBlock::layoutInlineChildren): Pass a mapping of RenderText to LazyLineBreakIterator from one call of findNextLineBreak() to the next.
(WebCore::RenderBlock::findNextLineBreak): Use said mapping, resetting LazyLineBreakIterator for any newly-encountered RenderText.

  • rendering/RenderText.cpp: Use a local LazyLineBreakIterator.

(WebCore::RenderText::computePreferredLogicalWidths):

  • rendering/break_lines.cpp: Accept LazyLineBreakIterator rather than TextBreakIterator.

(WebCore::nextBreakablePosition):

  • rendering/break_lines.h: Accept LazyLineBreakIterator rather than TextBreakIterator.

(WebCore::isBreakable):

Location:
trunk/Source/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r79508 r79510  
     12011-02-23  Ned Holbrook  <nholbrook@apple.com>
     2
     3        Reviewed by Dan Bernstein.
     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/qt/TextBreakIteratorQt.cpp: Ditto TextBreakIteratorICU.cpp.
     26        (WebCore::acquireLineBreakIterator):
     27        (WebCore::releaseLineBreakIterator):
     28        * rendering/RenderBlock.h:
     29        * rendering/RenderBlockLineLayout.cpp:
     30        (WebCore::RenderBlock::layoutInlineChildren): Pass a mapping of RenderText to LazyLineBreakIterator from one call of findNextLineBreak() to the next.
     31        (WebCore::RenderBlock::findNextLineBreak): Use said mapping, resetting LazyLineBreakIterator for any newly-encountered RenderText.
     32        * rendering/RenderText.cpp: Use a local LazyLineBreakIterator.
     33        (WebCore::RenderText::computePreferredLogicalWidths):
     34        * rendering/break_lines.cpp: Accept LazyLineBreakIterator rather than TextBreakIterator.
     35        (WebCore::nextBreakablePosition):
     36        * rendering/break_lines.h: Accept LazyLineBreakIterator rather than TextBreakIterator.
     37        (WebCore::isBreakable):
     38
    1392011-02-23  Anders Carlsson  <andersca@apple.com>
    240
  • trunk/Source/WebCore/platform/text/TextBreakIterator.h

    r50977 r79510  
    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.
     
    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
     
    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
  • trunk/Source/WebCore/platform/text/TextBreakIteratorICU.cpp

    r56345 r79510  
    2727#include <unicode/ubrk.h>
    2828#include <wtf/Assertions.h>
     29
     30using namespace std;
    2931
    3032namespace WebCore {
     
    6971}
    7072
    71 TextBreakIterator* lineBreakIterator(const UChar* string, int length)
    72 {
    73     static bool createdLineBreakIterator = false;
    74     static TextBreakIterator* staticLineBreakIterator;
    75     return setUpIterator(createdLineBreakIterator,
    76         staticLineBreakIterator, UBRK_LINE, string, 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)
     93{
     94    ASSERT(createdLineBreakIterator);
     95    ASSERT(iterator);
     96
     97    if (!staticLineBreakIterator)
     98        staticLineBreakIterator = iterator;
     99    else
     100        ubrk_close(reinterpret_cast<UBreakIterator*>(iterator));
    77101}
    78102
  • trunk/Source/WebCore/platform/text/qt/TextBreakIteratorQt.cpp

    r69773 r79510  
    3131#define DEBUG if (1) {} else qDebug
    3232#endif
     33
     34using namespace std;
    3335
    3436namespace WebCore {
     
    9092    }
    9193
    92     TextBreakIterator* lineBreakIterator(const UChar* string, int length)
     94    static TextBreakIterator* staticLineBreakIterator;
     95
     96    TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length)
    9397    {
    94         static TextBreakIterator staticLineBreakIterator;
    95         return setUpIterator(staticLineBreakIterator, QTextBoundaryFinder::Line, string, length);
     98        TextBreakIterator* lineBreakIterator = 0;
     99        if (staticLineBreakIterator) {
     100            setUpIterator(*staticLineBreakIterator, QTextBoundaryFinder::Line, string, length);
     101            swap(staticLineBreakIterator, lineBreakIterator);
     102        }
     103
     104        if (!lineBreakIterator && string && length)
     105            lineBreakIterator = new TextBreakIterator(QTextBoundaryFinder::Line, string, length);
     106
     107        return lineBreakIterator;
     108    }
     109
     110    void releaseLineBreakIterator(TextBreakIterator* iterator)
     111    {
     112        ASSERT(iterator);
     113
     114        if (!staticLineBreakIterator)
     115            staticLineBreakIterator = iterator;
     116        else
     117            delete iterator;
    96118    }
    97119
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r78846 r79510  
    3636class InlineIterator;
    3737class LayoutStateMaintainer;
     38class LazyLineBreakIterator;
    3839class RenderInline;
    3940
     
    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);
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r79286 r79510  
    3535#include "RenderView.h"
    3636#include "Settings.h"
     37#include "TextBreakIterator.h"
    3738#include "TextRun.h"
    3839#include "TrailingFloatsRootInlineBox.h"
     
    663664        bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
    664665
     666        LineBreakIteratorInfo lineBreakIteratorInfo;
    665667        VerticalPositionCache verticalPositionCache;
    666668
     
    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();
     
    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{
     
    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) {
  • trunk/Source/WebCore/rendering/RenderText.cpp

    r78846 r79510  
    749749    int len = textLength();
    750750    const UChar* txt = characters();
     751    LazyLineBreakIterator breakIterator(txt, len);
    751752    bool needsWordSpacing = false;
    752753    bool ignoringSpaces = false;
     
    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;
     
    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) {
  • trunk/Source/WebCore/rendering/break_lines.cpp

    r77062 r79510  
    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
     
    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);
  • trunk/Source/WebCore/rendering/break_lines.h

    r50583 r79510  
    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
Note: See TracChangeset for help on using the changeset viewer.