Changeset 126763 in webkit


Ignore:
Timestamp:
Aug 27, 2012, 8:31:56 AM (12 years ago)
Author:
mitz@apple.com
Message:

Improve line breaking performance for complex text
https://bugs.webkit.org/show_bug.cgi?id=83045

Patch by Ned Holbrook <nholbrook@apple.com> on 2012-08-27
Reviewed by Darin Adler.

Currently RenderBlock::LineBreaker::nextLineBreak assumes that measuring individual words is as cheap
as free. This is not the case when dealing with complex text, which benefits from laying out as much
text as possible and by reusing that layout when feasible: by doing so this patch improves line
breaking by 25% as measured with a simple test app.

The bulk of this change is modifying ComplexTextController::advance, which previously required the
text offset to be strictly increasing and assumed unidirectional text; now it supports random seeking
in a naive fashion (by restarting to the beginning) and traverses glyphs in logical order. In the
latter case, the presence of any non-LTR runs triggers the population of a mapping from logical to
visual run indices. Finally, a new flag has been added which inhibits glyph advances from being split
across ligatures (thus causing spurious line breaks).

A ComplexTextController and its associated TextRun and Font are encapsulated in a TextLayout object,
which is instantiated as an opaque object via functions that are no-ops unless building for Mac. A
static member function (isNeeded) checks to see whether a TextRun is complex, in order to avoid
needless instantiation. It also bails if tabs would be enabled since positional effects are not yet
handled in this mode.

No behavioral changes are expected due to this change, so no new tests.

  • platform/graphics/Font.cpp:

(WTF): Define deleteOwnedPtr for TextLayout as calling through destroyLayout; relying on operator delete is not workable as the class does not exist on all platforms.
(WTF::WebCore::TextLayout):
(WebCore): Implement no-op TextLayout wrappers for non-Mac platforms.
(WebCore::Font::createLayout):
(WebCore::Font::deleteLayout):
(WebCore::Font::width):

  • platform/graphics/Font.h:

(WebCore): Add forward declarations for RenderText and TextLayout.
(Font): Add functions for dealing with pointer to TextLayout implementation.
(WTF): Declare deleteOwnedPtr for TextLayout.

  • platform/graphics/mac/ComplexTextController.cpp:

(TextLayout): An instance of this class corresponds to a ComplexTextController for a particular TextRun.
(WebCore::TextLayout::isNeeded): Used by wrapper to avoid instantiation when complex layout is not required.
(WebCore::TextLayout::TextLayout):
(WebCore::TextLayout::width):
(WebCore::TextLayout::fontWithNoWordSpacing): Helper function to allow initialization of member variable.
(WebCore::TextLayout::constructTextRun): Ditto.
(WebCore): Implement real TextLayout wrappers for Mac.
(WebCore::Font::createLayout):
(WebCore::Font::deleteLayout):
(WebCore::Font::width):
(WebCore::ComplexTextController::ComplexTextController): Initialize m_ltrOnly and reserve initial capacity for m_runIndices.
(WebCore::ComplexTextController::indexOfCurrentRun): Return (visual) m_complexTextRuns index corresponding to (logical) m_currentRun, lazily constructing m_runIndices if needed.
(WebCore::ComplexTextController::incrementCurrentRun): Return next m_complexTextRuns index in logical order.
(WebCore::ComplexTextController::advance): Allow restarting, support for bidi reordering, and option to measure only whole glyphs rather than dividing advances.
(WebCore::ComplexTextController::adjustGlyphsAndAdvances): Clear m_ltrOnly on detecting a RTL run.

  • platform/graphics/mac/ComplexTextController.h:

(ComplexTextController): Add m_ltrOnly indicating no bidi reordering, and m_runIndices mapping from runs (logical order) to m_complexTextRuns (visual order).
(WebCore::ComplexTextController::ComplexTextRun::indexBegin):
(WebCore::ComplexTextController::ComplexTextRun::isLTR):
(ComplexTextRun): Add helper functions returning values pertinent to individual runs as opposed to the entire containing line.
(WebCore::ComplexTextController::stringBegin): Return first string index.
(WebCore::ComplexTextController::stringEnd): Return one past last string index.

  • platform/graphics/mac/ComplexTextControllerCoreText.mm: Initialize m_indexBegin and m_ltr.

(WebCore::ComplexTextController::ComplexTextRun::ComplexTextRun): Initialize m_indexBegin and m_ltr.

  • rendering/RenderBlock.h:

(RenderTextInfo): Add single mapping from RenderText to LazyLineBreakIterator and (possibly null) TextLayout since they are recreated under the same circumstances.

  • rendering/RenderBlockLineLayout.cpp:

(WebCore::RenderBlock::RenderTextInfo::RenderTextInfo): Make non-inline to avoid compilation errors.
(WebCore::RenderBlock::RenderTextInfo::~RenderTextInfo): Ditto.
(WebCore::RenderBlock::layoutRunsAndFloatsInRange): Allow RenderTextInfo to be reused across calls to nextLineBreak.
(WebCore::textWidth): Use TextLayout when supplied for measuring.
(WebCore::RenderBlock::LineBreaker::nextLineBreak):

Location:
trunk/Source/WebCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r126762 r126763  
     12012-08-27  Ned Holbrook  <nholbrook@apple.com>
     2
     3        Improve line breaking performance for complex text
     4        https://bugs.webkit.org/show_bug.cgi?id=83045
     5
     6        Reviewed by Darin Adler.
     7
     8        Currently RenderBlock::LineBreaker::nextLineBreak assumes that measuring individual words is as cheap
     9        as free. This is not the case when dealing with complex text, which benefits from laying out as much
     10        text as possible and by reusing that layout when feasible: by doing so this patch improves line
     11        breaking by 25% as measured with a simple test app.
     12
     13        The bulk of this change is modifying ComplexTextController::advance, which previously required the
     14        text offset to be strictly increasing and assumed unidirectional text; now it supports random seeking
     15        in a naive fashion (by restarting to the beginning) and traverses glyphs in logical order. In the
     16        latter case, the presence of any non-LTR runs triggers the population of a mapping from logical to
     17        visual run indices. Finally, a new flag has been added which inhibits glyph advances from being split
     18        across ligatures (thus causing spurious line breaks).
     19
     20        A ComplexTextController and its associated TextRun and Font are encapsulated in a TextLayout object,
     21        which is instantiated as an opaque object via functions that are no-ops unless building for Mac. A
     22        static member function (isNeeded) checks to see whether a TextRun is complex, in order to avoid
     23        needless instantiation. It also bails if tabs would be enabled since positional effects are not yet
     24        handled in this mode.
     25
     26        No behavioral changes are expected due to this change, so no new tests.
     27
     28        * platform/graphics/Font.cpp:
     29        (WTF): Define deleteOwnedPtr for TextLayout as calling through destroyLayout; relying on operator delete is not workable as the class does not exist on all platforms.
     30        (WTF::WebCore::TextLayout):
     31        (WebCore): Implement no-op TextLayout wrappers for non-Mac platforms.
     32        (WebCore::Font::createLayout):
     33        (WebCore::Font::deleteLayout):
     34        (WebCore::Font::width):
     35        * platform/graphics/Font.h:
     36        (WebCore): Add forward declarations for RenderText and TextLayout.
     37        (Font): Add functions for dealing with pointer to TextLayout implementation.
     38        (WTF): Declare deleteOwnedPtr for TextLayout.
     39        * platform/graphics/mac/ComplexTextController.cpp:
     40        (TextLayout): An instance of this class corresponds to a ComplexTextController for a particular TextRun.
     41        (WebCore::TextLayout::isNeeded): Used by wrapper to avoid instantiation when complex layout is not required.
     42        (WebCore::TextLayout::TextLayout):
     43        (WebCore::TextLayout::width):
     44        (WebCore::TextLayout::fontWithNoWordSpacing): Helper function to allow initialization of member variable.
     45        (WebCore::TextLayout::constructTextRun): Ditto.
     46        (WebCore): Implement real TextLayout wrappers for Mac.
     47        (WebCore::Font::createLayout):
     48        (WebCore::Font::deleteLayout):
     49        (WebCore::Font::width):
     50        (WebCore::ComplexTextController::ComplexTextController): Initialize m_ltrOnly and reserve initial capacity for m_runIndices.
     51        (WebCore::ComplexTextController::indexOfCurrentRun): Return (visual) m_complexTextRuns index corresponding to (logical) m_currentRun, lazily constructing m_runIndices if needed.
     52        (WebCore::ComplexTextController::incrementCurrentRun): Return next m_complexTextRuns index in logical order.
     53        (WebCore::ComplexTextController::advance): Allow restarting, support for bidi reordering, and option to measure only whole glyphs rather than dividing advances.
     54        (WebCore::ComplexTextController::adjustGlyphsAndAdvances): Clear m_ltrOnly on detecting a RTL run.
     55        * platform/graphics/mac/ComplexTextController.h:
     56        (ComplexTextController): Add m_ltrOnly indicating no bidi reordering, and m_runIndices mapping from runs (logical order) to m_complexTextRuns (visual order).
     57        (WebCore::ComplexTextController::ComplexTextRun::indexBegin):
     58        (WebCore::ComplexTextController::ComplexTextRun::isLTR):
     59        (ComplexTextRun): Add helper functions returning values pertinent to individual runs as opposed to the entire containing line.
     60        (WebCore::ComplexTextController::stringBegin): Return first string index.
     61        (WebCore::ComplexTextController::stringEnd): Return one past last string index.
     62        * platform/graphics/mac/ComplexTextControllerCoreText.mm: Initialize m_indexBegin and m_ltr.
     63        (WebCore::ComplexTextController::ComplexTextRun::ComplexTextRun): Initialize m_indexBegin and m_ltr.
     64        * rendering/RenderBlock.h:
     65        (RenderTextInfo): Add single mapping from RenderText to LazyLineBreakIterator and (possibly null) TextLayout since they are recreated under the same circumstances.
     66        * rendering/RenderBlockLineLayout.cpp:
     67        (WebCore::RenderBlock::RenderTextInfo::RenderTextInfo): Make non-inline to avoid compilation errors.
     68        (WebCore::RenderBlock::RenderTextInfo::~RenderTextInfo): Ditto.
     69        (WebCore::RenderBlock::layoutRunsAndFloatsInRange): Allow RenderTextInfo to be reused across calls to nextLineBreak.
     70        (WebCore::textWidth): Use TextLayout when supplied for measuring.
     71        (WebCore::RenderBlock::LineBreaker::nextLineBreak):
     72
    1732012-08-27  Nico Weber  <thakis@chromium.org>
    274
  • trunk/Source/WebCore/platform/graphics/Font.cpp

    r125766 r126763  
    4040using namespace Unicode;
    4141
     42namespace WTF {
     43
     44// allow compilation of OwnPtr<TextLayout> in source files that don't have access to the TextLayout class definition
     45template <> void deleteOwnedPtr<WebCore::TextLayout>(WebCore::TextLayout* ptr)
     46{
     47    WebCore::Font::deleteLayout(ptr);
     48}
     49
     50}
     51
    4252namespace WebCore {
    4353
     
    198208}
    199209
     210#if !PLATFORM(MAC)
     211
     212PassOwnPtr<TextLayout> Font::createLayout(RenderText*, float, bool) const
     213{
     214    return nullptr;
     215}
     216
     217void Font::deleteLayout(TextLayout*)
     218{
     219}
     220
     221float Font::width(TextLayout&, unsigned, unsigned)
     222{
     223    ASSERT_NOT_REACHED();
     224    return 0;
     225}
     226
     227#endif
     228
    200229FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
    201230{
  • trunk/Source/WebCore/platform/graphics/Font.h

    r125766 r126763  
    5454class GlyphPageTreeNode;
    5555class GraphicsContext;
     56class RenderText;
     57class TextLayout;
    5658class TextRun;
    5759
     
    102104    float width(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const;
    103105    float width(const TextRun&, int& charsConsumed, String& glyphName) const;
     106
     107    PassOwnPtr<TextLayout> createLayout(RenderText*, float xPos, bool collapseWhiteSpace) const;
     108    static void deleteLayout(TextLayout*);
     109    static float width(TextLayout&, unsigned from, unsigned len);
    104110
    105111    int offsetForPosition(const TextRun&, float position, bool includePartialGlyphs) const;
     
    311317}
    312318
    313 #endif
     319namespace WTF {
     320
     321template <> void deleteOwnedPtr<WebCore::TextLayout>(WebCore::TextLayout*);
     322
     323}
     324
     325#endif
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.cpp

    r125437 r126763  
    2828#include "FloatSize.h"
    2929#include "Font.h"
     30#include "RenderBlock.h"
     31#include "RenderText.h"
    3032#include "TextBreakIterator.h"
    3133#include "TextRun.h"
     
    3840namespace WebCore {
    3941
     42class TextLayout {
     43public:
     44    static bool isNeeded(RenderText* text, const Font& font)
     45    {
     46        TextRun run = RenderBlock::constructTextRun(text, font, text->characters(), text->textLength(), text->style());
     47        return font.codePath(run) == Font::Complex;
     48    }
     49
     50    TextLayout(RenderText* text, const Font& font, float xPos)
     51        : m_font(fontWithNoWordSpacing(font))
     52        , m_run(constructTextRun(text, font, xPos))
     53        , m_controller(adoptPtr(new ComplexTextController(&m_font, m_run, true)))
     54    {
     55    }
     56
     57    float width(unsigned from, unsigned len)
     58    {
     59        m_controller->advance(from, 0, ByWholeGlyphs);
     60        float beforeWidth = m_controller->runWidthSoFar();
     61        m_controller->advance(from + len, 0, ByWholeGlyphs);
     62        float afterWidth = m_controller->runWidthSoFar();
     63        return afterWidth - beforeWidth;
     64    }
     65
     66private:
     67    static Font fontWithNoWordSpacing(const Font& originalFont)
     68    {
     69        Font font(originalFont);
     70        font.setWordSpacing(0);
     71        return font;
     72    }
     73
     74    static TextRun constructTextRun(RenderText* text, const Font& font, float xPos)
     75    {
     76        TextRun run = RenderBlock::constructTextRun(text, font, text->characters(), text->textLength(), text->style());
     77        run.setCharactersLength(text->textLength());
     78        ASSERT(run.charactersLength() >= run.length());
     79
     80        run.setXPos(xPos);
     81        return run;
     82    }
     83
     84    // ComplexTextController has only references to its Font and TextRun so they must be kept alive here.
     85    Font m_font;
     86    TextRun m_run;
     87    OwnPtr<ComplexTextController> m_controller;
     88};
     89
     90PassOwnPtr<TextLayout> Font::createLayout(RenderText* text, float xPos, bool collapseWhiteSpace) const
     91{
     92    if (!collapseWhiteSpace || !TextLayout::isNeeded(text, *this))
     93        return nullptr;
     94    return adoptPtr(new TextLayout(text, *this, xPos));
     95}
     96
     97void Font::deleteLayout(TextLayout* layout)
     98{
     99    delete layout;
     100}
     101
     102float Font::width(TextLayout& layout, unsigned from, unsigned len)
     103{
     104    return layout.width(from, len);
     105}
     106
    40107static inline CGFloat roundCGFloat(CGFloat f)
    41108{
     
    55122    : m_font(*font)
    56123    , m_run(run)
     124    , m_isLTROnly(true)
    57125    , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
    58126    , m_forTextEmphasis(forTextEmphasis)
     
    92160    collectComplexTextRuns();
    93161    adjustGlyphsAndAdvances();
     162
     163    if (!m_isLTROnly)
     164        m_runIndices.reserveInitialCapacity(m_complexTextRuns.size());
    94165
    95166    m_runWidthSoFar = m_leadingExpansion;
     
    341412}
    342413
    343 void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
     414unsigned ComplexTextController::indexOfCurrentRun(unsigned& leftmostGlyph)
     415{
     416    leftmostGlyph = 0;
     417   
     418    size_t runCount = m_complexTextRuns.size();
     419    if (m_currentRun >= runCount)
     420        return runCount;
     421
     422    if (m_isLTROnly) {
     423        for (unsigned i = 0; i < m_currentRun; ++i)
     424            leftmostGlyph += m_complexTextRuns[i]->glyphCount();
     425        return m_currentRun;
     426    }
     427
     428    while (m_runIndices.size() <= m_currentRun) {
     429        unsigned offset = m_runIndices.isEmpty() ? 0 : stringEnd(*m_complexTextRuns[m_runIndices.last()]);
     430
     431        for (unsigned i = 0; i < runCount; ++i) {
     432            if (offset == stringBegin(*m_complexTextRuns[i])) {
     433                m_runIndices.uncheckedAppend(i);
     434                break;
     435            }
     436        }
     437    }
     438
     439    unsigned currentRunIndex = m_runIndices[m_currentRun];
     440    for (unsigned i = 0; i < currentRunIndex; ++i)
     441        leftmostGlyph += m_complexTextRuns[i]->glyphCount();
     442    return currentRunIndex;
     443}
     444
     445unsigned ComplexTextController::incrementCurrentRun(unsigned& leftmostGlyph)
     446{
     447    if (m_isLTROnly) {
     448        leftmostGlyph += m_complexTextRuns[m_currentRun++]->glyphCount();
     449        return m_currentRun;
     450    }
     451
     452    m_currentRun++;
     453    leftmostGlyph = 0;
     454    return indexOfCurrentRun(leftmostGlyph);
     455}
     456
     457void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, GlyphIterationStyle iterationStyle)
    344458{
    345459    if (static_cast<int>(offset) > m_end)
    346460        offset = m_end;
    347461
    348     if (offset <= m_currentCharacter)
    349         return;
     462    if (offset <= m_currentCharacter) {
     463        m_runWidthSoFar = m_leadingExpansion;
     464        m_numGlyphsSoFar = 0;
     465        m_currentRun = 0;
     466        m_glyphInCurrentRun = 0;
     467        m_characterInCurrentGlyph = 0;
     468    }
    350469
    351470    m_currentCharacter = offset;
     
    353472    size_t runCount = m_complexTextRuns.size();
    354473
    355     bool ltr = m_run.ltr();
    356 
    357     unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar;
     474    unsigned leftmostGlyph = 0;
     475    unsigned currentRunIndex = indexOfCurrentRun(leftmostGlyph);
    358476    while (m_currentRun < runCount) {
    359         const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun];
     477        const ComplexTextRun& complexTextRun = *m_complexTextRuns[currentRunIndex];
     478        bool ltr = complexTextRun.isLTR();
    360479        size_t glyphCount = complexTextRun.glyphCount();
    361480        unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
     481        unsigned k = leftmostGlyph + g;
     482
    362483        while (m_glyphInCurrentRun < glyphCount) {
    363484            unsigned glyphStartOffset = complexTextRun.indexAt(g);
     
    388509                ASSERT(m_characterInCurrentGlyph == oldCharacterInCurrentGlyph);
    389510                m_runWidthSoFar += adjustedAdvance.width;
     511            } else if (iterationStyle == ByWholeGlyphs) {
     512                if (!oldCharacterInCurrentGlyph)
     513                    m_runWidthSoFar += adjustedAdvance.width;
    390514            } else
    391515                m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
     
    405529            }
    406530        }
    407         m_currentRun++;
     531        currentRunIndex = incrementCurrentRun(leftmostGlyph);
    408532        m_glyphInCurrentRun = 0;
    409533    }
    410     if (!ltr && m_numGlyphsSoFar == m_adjustedAdvances.size())
     534    if (!m_run.ltr() && m_numGlyphsSoFar == m_adjustedAdvances.size())
    411535        m_runWidthSoFar += m_finalRoundingWidth;
    412536}
     
    421545        unsigned glyphCount = complexTextRun.glyphCount();
    422546        const SimpleFontData* fontData = complexTextRun.fontData();
     547
     548        if (!complexTextRun.isLTR())
     549            m_isLTROnly = false;
    423550
    424551        const CGGlyph* glyphs = complexTextRun.glyphs();
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextController.h

    r123181 r126763  
    4545class TextRun;
    4646
     47enum GlyphIterationStyle { IncludePartialGlyphs, ByWholeGlyphs };
     48
    4749// ComplexTextController is responsible for rendering and measuring glyphs for
    4850// complex scripts on OS X.
     
    5254
    5355    // Advance and emit glyphs up to the specified character.
    54     void advance(unsigned to, GlyphBuffer* = 0);
     56    void advance(unsigned to, GlyphBuffer* = 0, GlyphIterationStyle = IncludePartialGlyphs);
    5557
    5658    // Compute the character offset for a given x coordinate.
     
    9092        size_t stringLength() const { return m_stringLength; }
    9193        ALWAYS_INLINE CFIndex indexAt(size_t i) const;
     94        CFIndex indexBegin() const { return m_indexBegin; }
    9295        CFIndex indexEnd() const { return m_indexEnd; }
    9396        CFIndex endOffsetAt(size_t i) const { ASSERT(!m_isMonotonic); return m_glyphEndOffsets[i]; }
    9497        const CGGlyph* glyphs() const { return m_glyphs; }
    9598        const CGSize* advances() const { return m_advances; }
     99        bool isLTR() const { return m_isLTR; }
    96100        bool isMonotonic() const { return m_isMonotonic; }
    97101        void setIsNonMonotonic();
     
    108112        Vector<CFIndex, 64> m_coreTextIndicesVector;
    109113        const CFIndex* m_coreTextIndices;
     114        CFIndex m_indexBegin;
    110115        CFIndex m_indexEnd;
    111116        Vector<CFIndex, 64> m_glyphEndOffsets;
     
    114119        Vector<CGSize, 64> m_advancesVector;
    115120        const CGSize* m_advances;
     121        bool m_isLTR;
    116122        bool m_isMonotonic;
    117123    };
     124   
     125    static unsigned stringBegin(const ComplexTextRun& run) { return run.stringLocation() + run.indexBegin(); }
     126    static unsigned stringEnd(const ComplexTextRun& run) { return run.stringLocation() + run.indexEnd(); }
    118127
    119128    void collectComplexTextRuns();
     
    122131    void adjustGlyphsAndAdvances();
    123132
     133    unsigned indexOfCurrentRun(unsigned& leftmostGlyph);
     134    unsigned incrementCurrentRun(unsigned& leftmostGlyph);
     135
     136    // The default size of this vector was selected as being the smallest power of two greater than
     137    // the average (3.5) plus one standard deviation (7.5) of nonzero sizes used on Arabic Wikipedia.
     138    Vector<unsigned, 16> m_runIndices;
     139
    124140    const Font& m_font;
    125141    const TextRun& m_run;
     142    bool m_isLTROnly;
    126143    bool m_mayUseNaturalWritingDirection;
    127144    bool m_forTextEmphasis;
  • trunk/Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.mm

    r123181 r126763  
    106106    , m_stringLocation(stringLocation)
    107107    , m_stringLength(stringLength)
     108    , m_indexBegin(runRange.location)
    108109    , m_indexEnd(runRange.location + runRange.length)
     110    , m_isLTR(!(CTRunGetStatus(ctRun) & kCTRunStatusRightToLeft))
    109111    , m_isMonotonic(true)
    110112{
     
    139141    , m_stringLocation(stringLocation)
    140142    , m_stringLength(stringLength)
     143    , m_indexBegin(0)
    141144    , m_indexEnd(stringLength)
     145    , m_isLTR(ltr)
    142146    , m_isMonotonic(true)
    143147{
  • trunk/Source/WebCore/rendering/RenderBlock.h

    r126605 r126763  
    3030#include "RenderLineBoxList.h"
    3131#include "RootInlineBox.h"
     32#include "TextBreakIterator.h"
    3233#include "TextRun.h"
    3334#include <wtf/OwnPtr.h>
     
    4344class InlineIterator;
    4445class LayoutStateMaintainer;
    45 class LazyLineBreakIterator;
    4646class LineLayoutState;
    4747class LineWidth;
     
    5353class LineInfo;
    5454class RenderRubyRun;
     55class TextLayout;
    5556
    5657template <class Iterator, class Run> class BidiResolver;
     
    707708
    708709    // The following functions' implementations are in RenderBlockLineLayout.cpp.
    709     typedef std::pair<RenderText*, LazyLineBreakIterator> LineBreakIteratorInfo;
     710    struct RenderTextInfo {
     711        // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors.
     712        RenderTextInfo();
     713        ~RenderTextInfo();
     714
     715        RenderText* m_text;
     716        OwnPtr<TextLayout> m_layout;
     717        LazyLineBreakIterator m_lineBreakIterator;
     718    };
     719
    710720    class LineBreaker {
    711721    public:
     
    716726        }
    717727
    718         InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, LineBreakIteratorInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines);
     728        InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines);
    719729
    720730        bool lineWasHyphenated() { return m_hyphenated; }
  • trunk/Source/WebCore/rendering/RenderBlockLineLayout.cpp

    r126605 r126763  
    3737#include "RenderView.h"
    3838#include "Settings.h"
    39 #include "TextBreakIterator.h"
    4039#include "TrailingFloatsRootInlineBox.h"
    4140#include "VerticalPositionCache.h"
     
    12751274}
    12761275
     1276RenderBlock::RenderTextInfo::RenderTextInfo()
     1277    : m_text(0)
     1278{
     1279}
     1280
     1281RenderBlock::RenderTextInfo::~RenderTextInfo()
     1282{
     1283}
     1284
    12771285void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines)
    12781286{
     
    12821290    InlineIterator end = resolver.position();
    12831291    bool checkForEndLineMatch = layoutState.endLine();
    1284     LineBreakIteratorInfo lineBreakIteratorInfo;
     1292    RenderTextInfo renderTextInfo;
    12851293    VerticalPositionCache verticalPositionCache;
    12861294
     
    13181326            wrapShapeInfo->computeSegmentsForLine(logicalHeight());
    13191327#endif
    1320         end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), lineBreakIteratorInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines);
     1328        end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines);
    13211329        if (resolver.position().atEnd()) {
    13221330            // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
     
    20182026}
    20192027
    2020 static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace)
     2028static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, TextLayout* layout = 0)
    20212029{
    20222030    if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine())
    20232031        return text->width(from, len, font, xPos);
     2032
     2033    if (layout)
     2034        return Font::width(*layout, from, len);
    20242035
    20252036    TextRun run = RenderBlock::constructTextRun(text, font, text->characters() + from, len, text->style());
     
    21842195}
    21852196
    2186 InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo,
    2187     LineBreakIteratorInfo& lineBreakIteratorInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines)
     2197InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines)
    21882198{
    21892199    reset();
     
    24242434            }
    24252435
     2436            if (renderTextInfo.m_text != t || renderTextInfo.m_lineBreakIterator.string() != t->characters()) {
     2437                renderTextInfo.m_text = t;
     2438                renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace);
     2439                renderTextInfo.m_lineBreakIterator.reset(t->characters(), t->textLength(), style->locale());
     2440            }
     2441            TextLayout* textLayout = renderTextInfo.m_layout.get();
     2442
    24262443            for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) {
    24272444                bool previousCharacterIsSpace = currentCharacterIsSpace;
     
    24452462                    wrapW += charWidth;
    24462463                    bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL(t->characters()[current.m_pos + 1]);
    2447                     charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace);
     2464                    charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, textLayout);
    24482465                    midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth();
    24492466                }
    24502467
    2451                 if ((lineBreakIteratorInfo.first != t) || (lineBreakIteratorInfo.second.string() != t->characters())) {
    2452                     lineBreakIteratorInfo.first = t;
    2453                     lineBreakIteratorInfo.second.reset(t->characters(), t->textLength(), style->locale());
    2454                 }
    2455 
    2456                 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(lineBreakIteratorInfo.second, current.m_pos, current.m_nextBreakablePosition, breakNBSP)
     2468                bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(renderTextInfo.m_lineBreakIterator, current.m_pos, current.m_nextBreakablePosition, breakNBSP)
    24572469                    && (style->hyphens() != HyphensNone || (current.previousInSameNode() != softHyphen)));
    24582470
     
    24762488                    float additionalTmpW;
    24772489                    if (wordTrailingSpaceWidth && currentCharacterIsSpace)
    2478                         additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
     2490                        additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) - wordTrailingSpaceWidth + lastSpaceWordSpacing;
    24792491                    else
    2480                         additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
     2492                        additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + lastSpaceWordSpacing;
    24812493                    width.addUncommittedWidth(additionalTmpW);
    24822494                    if (!appliedStartWidth) {
     
    24952507                        bool lineWasTooWide = false;
    24962508                        if (width.fitsOnLine() && currentCharacterIsWS && currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
    2497                             float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0);
     2509                            float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + (applyWordSpacing ? wordSpacing : 0);
    24982510                            // Check if line is too big even without the extra space
    24992511                            // at the end of the line. If it is not, do nothing.
     
    26212633
    26222634            // IMPORTANT: current.m_pos is > length here!
    2623             float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing;
     2635            float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + lastSpaceWordSpacing;
    26242636            width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth));
    26252637            includeEndWidth = false;
Note: See TracChangeset for help on using the changeset viewer.