Changeset 158196 in webkit


Ignore:
Timestamp:
Oct 29, 2013 10:00:42 AM (10 years ago)
Author:
Antti Koivisto
Message:

Multiple runs per line on simple line path
https://bugs.webkit.org/show_bug.cgi?id=123446

Reviewed by Andreas Kling.

By allowing multiple runs per line we can support text flows with consecutive whitespaces in the middle.

  • rendering/SimpleLineLayout.cpp:

(WebCore::SimpleLineLayout::canUseFor):

Remove space test.
The improved test coverage found a few more cases that we need to disallow.

(WebCore::SimpleLineLayout::adjustRunOffsets):

Round the run positions and widths so they match line boxes.
Adjust for text-align.

(WebCore::SimpleLineLayout::create):

Split lines with consecutive spaces into runs.

  • rendering/SimpleLineLayout.h:

(WebCore::SimpleLineLayout::Run::Run):

  • rendering/SimpleLineLayoutFunctions.cpp:

(WebCore::SimpleLineLayout::hitTestFlow):
(WebCore::SimpleLineLayout::collectFlowOverflow):
(WebCore::SimpleLineLayout::computeTextBoundingBox):

  • rendering/SimpleLineLayoutResolver.h:

(WebCore::SimpleLineLayout::RunResolver::Iterator::resolver):
(WebCore::SimpleLineLayout::RunResolver::Iterator::lineIndex):
(WebCore::SimpleLineLayout::RunResolver::Run::Run):
(WebCore::SimpleLineLayout::RunResolver::Run::rect):
(WebCore::SimpleLineLayout::RunResolver::Run::baseline):
(WebCore::SimpleLineLayout::RunResolver::Run::text):
(WebCore::SimpleLineLayout::RunResolver::Run::lineIndex):
(WebCore::SimpleLineLayout::RunResolver::Iterator::Iterator):
(WebCore::SimpleLineLayout::RunResolver::Iterator::operator++):

Removed unnecessary operators.

(WebCore::SimpleLineLayout::RunResolver::Iterator::operator==):
(WebCore::SimpleLineLayout::RunResolver::Iterator::operator!=):
(WebCore::SimpleLineLayout::RunResolver::Iterator::operator*):
(WebCore::SimpleLineLayout::RunResolver::Iterator::simpleRun):
(WebCore::SimpleLineLayout::RunResolver::RunResolver):
(WebCore::SimpleLineLayout::RunResolver::begin):
(WebCore::SimpleLineLayout::RunResolver::end):

Resolver -> RunResolver

(WebCore::SimpleLineLayout::LineResolver::Iterator::Iterator):
(WebCore::SimpleLineLayout::LineResolver::Iterator::operator++):
(WebCore::SimpleLineLayout::LineResolver::Iterator::operator==):
(WebCore::SimpleLineLayout::LineResolver::Iterator::operator!=):
(WebCore::SimpleLineLayout::LineResolver::Iterator::operator*):
(WebCore::SimpleLineLayout::LineResolver::LineResolver):
(WebCore::SimpleLineLayout::LineResolver::begin):
(WebCore::SimpleLineLayout::LineResolver::end):

Add LineResolver around RunResolver. It resolves the line rectangles.

(WebCore::SimpleLineLayout::runResolver):
(WebCore::SimpleLineLayout::lineResolver):

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r158195 r158196  
     12013-10-29  Antti Koivisto  <antti@apple.com>
     2
     3        Multiple runs per line on simple line path
     4        https://bugs.webkit.org/show_bug.cgi?id=123446
     5
     6        Reviewed by Andreas Kling.
     7
     8        By allowing multiple runs per line we can support text flows with consecutive whitespaces in the middle.
     9
     10        * rendering/SimpleLineLayout.cpp:
     11        (WebCore::SimpleLineLayout::canUseFor):
     12       
     13            Remove space test.
     14            The improved test coverage found a few more cases that we need to disallow.
     15
     16        (WebCore::SimpleLineLayout::adjustRunOffsets):
     17           
     18            Round the run positions and widths so they match line boxes.
     19            Adjust for text-align.
     20
     21        (WebCore::SimpleLineLayout::create):
     22       
     23            Split lines with consecutive spaces into runs.
     24
     25        * rendering/SimpleLineLayout.h:
     26        (WebCore::SimpleLineLayout::Run::Run):
     27        * rendering/SimpleLineLayoutFunctions.cpp:
     28        (WebCore::SimpleLineLayout::hitTestFlow):
     29        (WebCore::SimpleLineLayout::collectFlowOverflow):
     30        (WebCore::SimpleLineLayout::computeTextBoundingBox):
     31        * rendering/SimpleLineLayoutResolver.h:
     32        (WebCore::SimpleLineLayout::RunResolver::Iterator::resolver):
     33        (WebCore::SimpleLineLayout::RunResolver::Iterator::lineIndex):
     34        (WebCore::SimpleLineLayout::RunResolver::Run::Run):
     35        (WebCore::SimpleLineLayout::RunResolver::Run::rect):
     36        (WebCore::SimpleLineLayout::RunResolver::Run::baseline):
     37        (WebCore::SimpleLineLayout::RunResolver::Run::text):
     38        (WebCore::SimpleLineLayout::RunResolver::Run::lineIndex):
     39        (WebCore::SimpleLineLayout::RunResolver::Iterator::Iterator):
     40        (WebCore::SimpleLineLayout::RunResolver::Iterator::operator++):
     41       
     42            Removed unnecessary operators.
     43
     44        (WebCore::SimpleLineLayout::RunResolver::Iterator::operator==):
     45        (WebCore::SimpleLineLayout::RunResolver::Iterator::operator!=):
     46        (WebCore::SimpleLineLayout::RunResolver::Iterator::operator*):
     47        (WebCore::SimpleLineLayout::RunResolver::Iterator::simpleRun):
     48        (WebCore::SimpleLineLayout::RunResolver::RunResolver):
     49        (WebCore::SimpleLineLayout::RunResolver::begin):
     50        (WebCore::SimpleLineLayout::RunResolver::end):
     51       
     52            Resolver -> RunResolver
     53
     54        (WebCore::SimpleLineLayout::LineResolver::Iterator::Iterator):
     55        (WebCore::SimpleLineLayout::LineResolver::Iterator::operator++):
     56        (WebCore::SimpleLineLayout::LineResolver::Iterator::operator==):
     57        (WebCore::SimpleLineLayout::LineResolver::Iterator::operator!=):
     58        (WebCore::SimpleLineLayout::LineResolver::Iterator::operator*):
     59        (WebCore::SimpleLineLayout::LineResolver::LineResolver):
     60        (WebCore::SimpleLineLayout::LineResolver::begin):
     61        (WebCore::SimpleLineLayout::LineResolver::end):
     62       
     63            Add LineResolver around RunResolver. It resolves the line rectangles.
     64
     65        (WebCore::SimpleLineLayout::runResolver):
     66        (WebCore::SimpleLineLayout::lineResolver):
     67
    1682013-10-29  Chris Fleizach  <cfleizach@apple.com>
    269
  • trunk/Source/WebCore/rendering/SimpleLineLayout.cpp

    r158188 r158196  
    7979    if (flow.isRubyText() || flow.isRubyBase())
    8080        return false;
     81    if (flow.parent()->isDeprecatedFlexibleBox())
     82        return false;
    8183    // These tests only works during layout. Outside layout this function may give false positives.
    8284    if (flow.view().layoutState()) {
     
    155157
    156158    unsigned length = textRenderer.textLength();
    157     unsigned consecutiveSpaceCount = 0;
    158159    for (unsigned i = 0; i < length; ++i) {
    159         // This rejects anything with more than one consecutive whitespace, except at the beginning or end.
    160         // This is because we don't currently do subruns within lines. Fixing this would improve coverage significantly.
    161160        UChar character = textRenderer.characterAt(i);
    162         if (isWhitespace(character)) {
    163             ++consecutiveSpaceCount;
     161        if (character == ' ')
    164162            continue;
    165         }
    166         if (consecutiveSpaceCount != i && consecutiveSpaceCount > 1)
    167             return false;
    168         consecutiveSpaceCount = 0;
    169163
    170164        // These would be easy to support.
     
    174168            return false;
    175169
    176         static const UChar lowestRTLCharacter = 0x590;
    177         if (character >= lowestRTLCharacter) {
    178             UCharDirection direction = u_charDirection(character);
    179             if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC
    180                 || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE
    181                 || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE)
    182                 return false;
    183         }
     170        UCharDirection direction = u_charDirection(character);
     171        if (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC
     172            || direction == U_RIGHT_TO_LEFT_EMBEDDING || direction == U_RIGHT_TO_LEFT_OVERRIDE
     173            || direction == U_LEFT_TO_RIGHT_EMBEDDING || direction == U_LEFT_TO_RIGHT_OVERRIDE
     174            || direction == U_POP_DIRECTIONAL_FORMAT || direction == U_BOUNDARY_NEUTRAL)
     175            return false;
    184176
    185177        if (!primaryFontData.glyphForCharacter(character))
     
    232224}
    233225
     226static void adjustRunOffsets(Vector<Run, 4>& lineRuns, ETextAlign textAlign, float lineWidth, float availableWidth)
     227{
     228    float lineLeft = computeLineLeft(textAlign, availableWidth - lineWidth);
     229    for (unsigned i = 0; i < lineRuns.size(); ++i) {
     230        float adjustedLeft = floor(lineLeft + lineRuns[i].left);
     231        float adjustedRight = ceil(lineLeft + lineRuns[i].left + lineRuns[i].width);
     232        lineRuns[i].left = adjustedLeft;
     233        lineRuns[i].width = adjustedRight - adjustedLeft;
     234    }
     235}
     236
    234237std::unique_ptr<Layout> create(RenderBlockFlow& flow)
    235238{
     
    252255        lineEndOffset = skipWhitespaces(textRenderer, lineEndOffset, textLength);
    253256        unsigned lineStartOffset = lineEndOffset;
    254         unsigned runEndOffset = lineEndOffset;
     257        unsigned wordEndOffset = lineEndOffset;
    255258        LineWidth lineWidth(flow, false, DoNotIndentText);
    256         while (runEndOffset < textLength) {
    257             ASSERT(!isWhitespace(textRenderer.characterAt(runEndOffset)));
    258 
    259             bool previousWasSpaceBetweenRuns = runEndOffset > lineStartOffset && isWhitespace(textRenderer.characterAt(runEndOffset - 1));
    260             unsigned runStartOffset = previousWasSpaceBetweenRuns ? runEndOffset - 1 : runEndOffset;
    261 
    262             ++runEndOffset;
    263             while (runEndOffset < textLength) {
    264                 if (runEndOffset > lineStartOffset && isBreakable(lineBreakIterator, runEndOffset, nextBreakable, false))
     259
     260        Vector<Run, 4> lineRuns;
     261        lineRuns.uncheckedAppend(Run(lineStartOffset, 0));
     262
     263        while (wordEndOffset < textLength) {
     264            ASSERT(!isWhitespace(textRenderer.characterAt(wordEndOffset)));
     265
     266            bool previousWasSpaceBetweenWords = wordEndOffset > lineStartOffset && isWhitespace(textRenderer.characterAt(wordEndOffset - 1));
     267            unsigned wordStartOffset = previousWasSpaceBetweenWords ? wordEndOffset - 1 : wordEndOffset;
     268
     269            ++wordEndOffset;
     270            while (wordEndOffset < textLength) {
     271                if (wordEndOffset > lineStartOffset && isBreakable(lineBreakIterator, wordEndOffset, nextBreakable, false))
    265272                    break;
    266                 ++runEndOffset;
     273                ++wordEndOffset;
    267274            }
    268275
    269             unsigned runLength = runEndOffset - runStartOffset;
    270             bool includeEndSpace = runEndOffset < textLength && textRenderer.characterAt(runEndOffset) == ' ';
     276            unsigned wordLength = wordEndOffset - wordStartOffset;
     277            bool includeEndSpace = wordEndOffset < textLength && textRenderer.characterAt(wordEndOffset) == ' ';
    271278            float wordWidth;
    272279            if (includeEndSpace)
    273                 wordWidth = textWidth(textRenderer, runStartOffset, runLength + 1, lineWidth.committedWidth(), style) - wordTrailingSpaceWidth;
     280                wordWidth = textWidth(textRenderer, wordStartOffset, wordLength + 1, lineWidth.committedWidth(), style) - wordTrailingSpaceWidth;
    274281            else
    275                 wordWidth = textWidth(textRenderer, runStartOffset, runLength, lineWidth.committedWidth(), style);
     282                wordWidth = textWidth(textRenderer, wordStartOffset, wordLength, lineWidth.committedWidth(), style);
    276283
    277284            lineWidth.addUncommittedWidth(wordWidth);
     285
     286            // Move to the next line if the current one is full and we have something on it.
     287            if (!lineWidth.fitsOnLine() && lineWidth.committedWidth())
     288                break;
     289
     290            if (wordStartOffset > lineEndOffset) {
     291                // There were more than one consecutive whitespace.
     292                ASSERT(previousWasSpaceBetweenWords);
     293                // Include space to the end of the previous run.
     294                lineRuns.last().textLength++;
     295                lineRuns.last().width += wordTrailingSpaceWidth;
     296                // Start a new run on the same line.
     297                float previousRight = lineRuns.last().left + lineRuns.last().width;
     298                lineRuns.append(Run(wordStartOffset + 1, previousRight));
     299            }
     300
     301            lineWidth.commit();
     302
     303            lineRuns.last().width = lineWidth.committedWidth() - lineRuns.last().left;
     304            lineRuns.last().textLength = wordEndOffset - lineRuns.last().textOffset;
     305
     306            lineEndOffset = wordEndOffset;
     307            wordEndOffset = skipWhitespaces(textRenderer, wordEndOffset, textLength);
     308
    278309            if (!lineWidth.fitsOnLine()) {
    279                 if (!lineWidth.committedWidth()) {
    280                     lineWidth.commit();
    281                     lineEndOffset = runEndOffset;
    282                 }
     310                // The first run on the line overflows.
     311                ASSERT(lineRuns.size() == 1);
    283312                break;
    284313            }
    285             lineWidth.commit();
    286             lineEndOffset = runEndOffset;
    287             runEndOffset = skipWhitespaces(textRenderer, runEndOffset, textLength);
    288314        }
    289315        if (lineStartOffset == lineEndOffset)
    290316            continue;
    291317
    292         float alignedLeft = computeLineLeft(textAlign, lineWidth.availableWidth() - lineWidth.committedWidth());
    293         float alignedRight = alignedLeft + lineWidth.committedWidth();
    294 
    295         Run run;
    296         run.textOffset = lineStartOffset;
    297         run.textLength = lineEndOffset - lineStartOffset;
    298         run.left = floor(alignedLeft);
    299         run.width = ceil(alignedRight) - run.left;
    300 
    301         layout->runs.append(run);
     318        adjustRunOffsets(lineRuns, textAlign, lineWidth.committedWidth(), lineWidth.availableWidth());
     319
     320        for (unsigned i = 0; i < lineRuns.size(); ++i)
     321            layout->runs.append(lineRuns[i]);
     322
     323        layout->runs.last().isEndOfLine = true;
    302324        layout->lineCount++;
    303325    }
  • trunk/Source/WebCore/rendering/SimpleLineLayout.h

    r158107 r158196  
    3939
    4040struct Run {
     41    Run(unsigned textOffset, float left)
     42        : textOffset(textOffset)
     43        , textLength(0)
     44        , isEndOfLine(false)
     45        , left(left)
     46        , width(0)
     47    { }
     48
    4149    unsigned textOffset;
    42     unsigned textLength;
     50    unsigned textLength : 31;
     51    unsigned isEndOfLine : 1;
    4352    float left;
    4453    float width;
  • trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp

    r158163 r158196  
    8686    auto resolver = lineResolver(flow, layout);
    8787    for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
    88         auto line = *it;
    89         auto lineRect = line.rect();
     88        auto lineRect = *it;
    9089        lineRect.moveBy(accumulatedOffset);
    9190        if (!locationInContainer.intersects(lineRect))
     
    103102    auto resolver = lineResolver(flow, layout);
    104103    for (auto it = resolver.begin(), end = resolver.end(); it != end; ++it) {
    105         auto line = *it;
    106         auto rect = line.rect();
     104        auto rect = *it;
    107105        flow.addLayoutOverflow(rect);
    108106        flow.addVisualOverflow(rect);
     
    117115    if (it == end)
    118116        return IntRect();
    119     auto firstLineRect = (*it).rect();
     117    auto firstLineRect = *it;
    120118    float left = firstLineRect.x();
    121119    float right = firstLineRect.maxX();
     120    float bottom = firstLineRect.maxY();
    122121    for (++it; it != end; ++it) {
    123         auto line = *it;
    124         auto rect = line.rect();
     122        auto rect = *it;
    125123        if (rect.x() < left)
    126124            left = rect.x();
    127125        if (rect.maxX() > right)
    128126            right = rect.maxX();
     127        if (rect.maxY() > bottom)
     128            bottom = rect.maxY();
    129129    }
    130130    float x = firstLineRect.x();
    131131    float y = firstLineRect.y();
    132132    float width = right - left;
    133     float height = (*resolver.last()).rect().maxY() - y;
     133    float height = bottom - y;
    134134    return enclosingIntRect(FloatRect(x, y, width, height));
    135135}
  • trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.h

    r158163 r158196  
    3737namespace SimpleLineLayout {
    3838
    39 class Resolver {
     39class RunResolver {
    4040public:
    4141    class Iterator;
     
    4343    class Run {
    4444    public:
    45         Run(const Resolver&, unsigned lineIndex);
     45        explicit Run(const Iterator&);
    4646
    4747        LayoutRect rect() const;
     
    4949        String text() const;
    5050
     51        unsigned lineIndex() const;
     52
    5153    private:
    52         const Resolver& m_resolver;
     54        const Iterator& m_iterator;
     55    };
     56
     57    class Iterator {
     58    public:
     59        Iterator(const RunResolver&, unsigned lineIndex);
     60
     61        Iterator& operator++();
     62        bool operator==(const Iterator&) const;
     63        bool operator!=(const Iterator&) const;
     64
     65        Run operator*() const;
     66
     67        const RunResolver& resolver() const { return m_resolver; }
     68        const SimpleLineLayout::Run& simpleRun() const;
     69        unsigned lineIndex() const { return m_lineIndex; }
     70
     71    private:
     72        const RunResolver& m_resolver;
     73        unsigned m_runIndex;
    5374        unsigned m_lineIndex;
    5475    };
    5576
    56     class Iterator {
    57     public:
    58         Iterator(const Resolver&, unsigned lineIndex);
    59 
    60         Iterator& operator++();
    61         Iterator& operator--();
    62         bool operator==(const Iterator&) const;
    63         bool operator!=(const Iterator&) const;
    64 
    65         Run operator*() const;
    66 
    67     private:
    68         const Resolver& m_resolver;
    69         unsigned m_lineIndex;
    70     };
    71 
    72     Resolver(const RenderBlockFlow&, const Layout&);
    73 
    74     unsigned size() const;
     77    RunResolver(const RenderBlockFlow&, const Layout&);
    7578
    7679    Iterator begin() const;
    7780    Iterator end() const;
    78     Iterator last() const;
    79     Iterator operator[](unsigned) const;
    8081
    8182private:
     
    8990};
    9091
    91 Resolver runResolver(const RenderBlockFlow&, const Layout&);
    92 Resolver lineResolver(const RenderBlockFlow&, const Layout&);
    93 
    94 inline Resolver::Run::Run(const Resolver& resolver, unsigned lineIndex)
     92class LineResolver {
     93public:
     94    class Iterator;
     95
     96    class Iterator {
     97    public:
     98        explicit Iterator(RunResolver::Iterator);
     99
     100        Iterator& operator++();
     101        bool operator==(const Iterator&) const;
     102        bool operator!=(const Iterator&) const;
     103
     104        const LayoutRect operator*() const;
     105
     106    private:
     107        RunResolver::Iterator m_runIterator;
     108        LayoutRect m_rect;
     109    };
     110
     111    LineResolver(const RenderBlockFlow&, const Layout&);
     112
     113    Iterator begin() const;
     114    Iterator end() const;
     115
     116private:
     117    RunResolver m_runResolver;
     118};
     119
     120RunResolver runResolver(const RenderBlockFlow&, const Layout&);
     121LineResolver lineResolver(const RenderBlockFlow&, const Layout&);
     122
     123inline RunResolver::Run::Run(const Iterator& iterator)
     124    : m_iterator(iterator)
     125{
     126}
     127
     128inline LayoutRect RunResolver::Run::rect() const
     129{
     130    auto& resolver = m_iterator.resolver();
     131    auto& run = m_iterator.simpleRun();
     132
     133    LayoutPoint linePosition(run.left, resolver.m_lineHeight * m_iterator.lineIndex() + resolver.m_baseline - resolver.m_ascent);
     134    LayoutSize lineSize(run.width, resolver.m_ascent + resolver.m_descent);
     135    return LayoutRect(linePosition + resolver.m_contentOffset, lineSize);
     136}
     137
     138inline LayoutPoint RunResolver::Run::baseline() const
     139{
     140    auto& resolver = m_iterator.resolver();
     141    auto& run = m_iterator.simpleRun();
     142
     143    float baselineY = resolver.m_lineHeight * m_iterator.lineIndex() + resolver.m_baseline;
     144    return LayoutPoint(run.left, baselineY) + resolver.m_contentOffset;
     145}
     146
     147inline String RunResolver::Run::text() const
     148{
     149    auto& resolver = m_iterator.resolver();
     150    auto& run = m_iterator.simpleRun();
     151    return resolver.m_string.substringSharingImpl(run.textOffset, run.textLength);
     152}
     153
     154inline unsigned RunResolver::Run::lineIndex() const
     155{
     156    return m_iterator.lineIndex();
     157}
     158
     159inline RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex)
    95160    : m_resolver(resolver)
    96     , m_lineIndex(lineIndex)
    97 {
    98 }
    99 
    100 inline LayoutRect Resolver::Run::rect() const
    101 {
    102     auto& run = m_resolver.m_layout.runs[m_lineIndex];
    103 
    104     LayoutPoint linePosition(run.left, m_resolver.m_lineHeight * m_lineIndex + m_resolver.m_baseline - m_resolver.m_ascent);
    105     LayoutSize lineSize(run.width, m_resolver.m_ascent + m_resolver.m_descent);
    106     return LayoutRect(linePosition + m_resolver.m_contentOffset, lineSize);
    107 }
    108 
    109 inline LayoutPoint Resolver::Run::baseline() const
    110 {
    111     auto& run = m_resolver.m_layout.runs[m_lineIndex];
    112 
    113     float baselineY = m_resolver.m_lineHeight * m_lineIndex + m_resolver.m_baseline;
    114     return LayoutPoint(run.left, baselineY) + m_resolver.m_contentOffset;
    115 }
    116 
    117 inline String Resolver::Run::text() const
    118 {
    119     auto& run = m_resolver.m_layout.runs[m_lineIndex];
    120     return m_resolver.m_string.substringSharingImpl(run.textOffset, run.textLength);
    121 }
    122 
    123 inline Resolver::Iterator::Iterator(const Resolver& resolver, unsigned lineIndex)
    124     : m_resolver(resolver)
    125     , m_lineIndex(lineIndex)
    126 {
    127 }
    128 
    129 inline Resolver::Iterator& Resolver::Iterator::operator++()
    130 {
    131     ++m_lineIndex;
     161    , m_runIndex(runIndex)
     162    , m_lineIndex(0)
     163{
     164}
     165
     166inline RunResolver::Iterator& RunResolver::Iterator::operator++()
     167{
     168    if (simpleRun().isEndOfLine)
     169        ++m_lineIndex;
     170    ++m_runIndex;
    132171    return *this;
    133172}
    134173
    135 inline Resolver::Iterator& Resolver::Iterator::operator--()
    136 {
    137     --m_lineIndex;
    138     return *this;
    139 }
    140 
    141 inline bool Resolver::Iterator::operator==(const Iterator& other) const
     174inline bool RunResolver::Iterator::operator==(const Iterator& other) const
    142175{
    143176    ASSERT(&m_resolver == &other.m_resolver);
    144     return m_lineIndex == other.m_lineIndex;
    145 }
    146 
    147 inline bool Resolver::Iterator::operator!=(const Iterator& other) const
     177    return m_runIndex == other.m_runIndex;
     178}
     179
     180inline bool RunResolver::Iterator::operator!=(const Iterator& other) const
    148181{
    149182    return !(*this == other);
    150183}
    151184
    152 inline Resolver::Run Resolver::Iterator::operator*() const
    153 {
    154     return Run(m_resolver, m_lineIndex);
    155 }
    156 
    157 inline Resolver::Resolver(const RenderBlockFlow& flow, const Layout& layout)
     185inline RunResolver::Run RunResolver::Iterator::operator*() const
     186{
     187    return Run(*this);
     188}
     189
     190inline const SimpleLineLayout::Run& RunResolver::Iterator::simpleRun() const
     191{
     192    return m_resolver.m_layout.runs[m_runIndex];
     193}
     194
     195inline RunResolver::RunResolver(const RenderBlockFlow& flow, const Layout& layout)
    158196    : m_layout(layout)
    159197    , m_string(toRenderText(*flow.firstChild()).text())
     
    166204}
    167205
    168 inline unsigned Resolver::size() const
    169 {
    170     return m_layout.runs.size();
    171 }
    172 
    173 inline Resolver::Iterator Resolver::begin() const
     206inline RunResolver::Iterator RunResolver::begin() const
    174207{
    175208    return Iterator(*this, 0);
    176209}
    177210
    178 inline Resolver::Iterator Resolver::end() const
    179 {
    180     return Iterator(*this, size());
    181 }
    182 
    183 inline Resolver::Iterator Resolver::last() const
    184 {
    185     ASSERT(size());
    186     return Iterator(*this, size() - 1);
    187 }
    188 
    189 inline Resolver::Iterator Resolver::operator[](unsigned index) const
    190 {
    191     ASSERT(index < size());
    192     return Iterator(*this, index);
    193 }
    194 
    195 inline Resolver runResolver(const RenderBlockFlow& flow, const Layout& layout)
    196 {
    197     return Resolver(flow, layout);
    198 }
    199 
    200 inline Resolver lineResolver(const RenderBlockFlow& flow, const Layout& layout)
    201 {
    202     return Resolver(flow, layout);
     211inline RunResolver::Iterator RunResolver::end() const
     212{
     213    return Iterator(*this, m_layout.runs.size());
     214}
     215
     216inline LineResolver::Iterator::Iterator(RunResolver::Iterator runIterator)
     217    : m_runIterator(runIterator)
     218{
     219}
     220
     221inline LineResolver::Iterator& LineResolver::Iterator::operator++()
     222{
     223    unsigned previousLine = m_runIterator.lineIndex();
     224    while ((++m_runIterator).lineIndex() == previousLine) { }
     225
     226    return *this;
     227}
     228
     229inline bool LineResolver::Iterator::operator==(const Iterator& other) const
     230{
     231    return m_runIterator == other.m_runIterator;
     232}
     233
     234inline bool LineResolver::Iterator::operator!=(const Iterator& other) const
     235{
     236    return m_runIterator != other.m_runIterator;
     237}
     238
     239inline const LayoutRect LineResolver::Iterator::operator*() const
     240{
     241    unsigned currentLine = m_runIterator.lineIndex();
     242    auto it = m_runIterator;
     243    LayoutRect rect = (*it).rect();
     244    while ((++it).lineIndex() == currentLine)
     245        rect.unite((*it).rect());
     246
     247    return rect;
     248}
     249
     250inline LineResolver::LineResolver(const RenderBlockFlow& flow, const Layout& layout)
     251    : m_runResolver(flow, layout)
     252{
     253}
     254
     255inline LineResolver::Iterator LineResolver::begin() const
     256{
     257    return Iterator(m_runResolver.begin());
     258}
     259
     260inline LineResolver::Iterator LineResolver::end() const
     261{
     262    return Iterator(m_runResolver.end());
     263}
     264
     265inline RunResolver runResolver(const RenderBlockFlow& flow, const Layout& layout)
     266{
     267    return RunResolver(flow, layout);
     268}
     269
     270inline LineResolver lineResolver(const RenderBlockFlow& flow, const Layout& layout)
     271{
     272    return LineResolver(flow, layout);
    203273}
    204274
Note: See TracChangeset for help on using the changeset viewer.