⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 181685 in webkit


Ignore:
Timestamp:
Mar 17, 2015, 11:09:56 PM (11 years ago)
Author:
commit-queue@webkit.org
Message:

Unreviewed, rolling out r181667, r181682, and r181683.
https://bugs.webkit.org/show_bug.cgi?id=142812

Broke multiple tests with ASan, plus dependent commits
(Requested by ap on #webkit).

Reverted changesets:

"Simple line layout: Split fragments on renderer boundary on
the fly."
https://bugs.webkit.org/show_bug.cgi?id=142579
http://trac.webkit.org/changeset/181667

"Simple line layout: Change FlowContents::segmentForPosition()
to segmentForRun()."
https://bugs.webkit.org/show_bug.cgi?id=142785
http://trac.webkit.org/changeset/181682

"Simple line layout: Use Vector<>::const_iterator instead of
custom FlowContents::Iterator."
https://bugs.webkit.org/show_bug.cgi?id=142809
http://trac.webkit.org/changeset/181683

Location:
trunk
Files:
2 deleted
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r181684 r181685  
     12015-03-17  Commit Queue  <commit-queue@webkit.org>
     2
     3        Unreviewed, rolling out r181667, r181682, and r181683.
     4        https://bugs.webkit.org/show_bug.cgi?id=142812
     5
     6        Broke multiple tests with ASan, plus dependent commits
     7        (Requested by ap on #webkit).
     8
     9        Reverted changesets:
     10
     11        "Simple line layout: Split fragments on renderer boundary on
     12        the fly."
     13        https://bugs.webkit.org/show_bug.cgi?id=142579
     14        http://trac.webkit.org/changeset/181667
     15
     16        "Simple line layout: Change FlowContents::segmentForPosition()
     17        to segmentForRun()."
     18        https://bugs.webkit.org/show_bug.cgi?id=142785
     19        http://trac.webkit.org/changeset/181682
     20
     21        "Simple line layout: Use Vector<>::const_iterator instead of
     22        custom FlowContents::Iterator."
     23        https://bugs.webkit.org/show_bug.cgi?id=142809
     24        http://trac.webkit.org/changeset/181683
     25
    1262015-03-17  Alexey Proskuryakov  <ap@apple.com>
    227
  • trunk/Source/WebCore/ChangeLog

    r181683 r181685  
     12015-03-17  Commit Queue  <commit-queue@webkit.org>
     2
     3        Unreviewed, rolling out r181667, r181682, and r181683.
     4        https://bugs.webkit.org/show_bug.cgi?id=142812
     5
     6        Broke multiple tests with ASan, plus dependent commits
     7        (Requested by ap on #webkit).
     8
     9        Reverted changesets:
     10
     11        "Simple line layout: Split fragments on renderer boundary on
     12        the fly."
     13        https://bugs.webkit.org/show_bug.cgi?id=142579
     14        http://trac.webkit.org/changeset/181667
     15
     16        "Simple line layout: Change FlowContents::segmentForPosition()
     17        to segmentForRun()."
     18        https://bugs.webkit.org/show_bug.cgi?id=142785
     19        http://trac.webkit.org/changeset/181682
     20
     21        "Simple line layout: Use Vector<>::const_iterator instead of
     22        custom FlowContents::Iterator."
     23        https://bugs.webkit.org/show_bug.cgi?id=142809
     24        http://trac.webkit.org/changeset/181683
     25
    1262015-03-17  Zalan Bujtas  <zalan@apple.com>
    227
  • trunk/Source/WebCore/rendering/SimpleLineLayout.cpp

    r181667 r181685  
    232232}
    233233
    234 static void revertRuns(Layout::RunVector& runs, unsigned length, float width)
    235 {
    236     ASSERT(runs.size());
    237     while (length) {
    238         Run& lastRun = runs.last();
    239         unsigned lastRunLength = lastRun.end - lastRun.start;
    240         if (lastRunLength > length) {
    241             lastRun.logicalRight -= width;
    242             lastRun.end -= length;
    243             break;
    244         }
    245         runs.removeLast();
    246         length -= lastRunLength;
    247         width -= (lastRun.logicalRight - lastRun.logicalLeft);
    248     }
    249 }
    250 
    251234class LineState {
    252235public:
    253236    void setAvailableWidth(float width) { m_availableWidth = width; }
    254     void setCollapedWhitespaceWidth(float width) { m_collapsedWhitespaceWidth = width; }
    255237    void setLogicalLeftOffset(float offset) { m_logicalLeftOffset = offset; }
    256238    void setOverflowedFragment(const TextFragmentIterator::TextFragment& fragment) { m_overflowedFragment = fragment; }
     
    260242    const TextFragmentIterator::TextFragment& overflowedFragment() const { return m_overflowedFragment; }
    261243    bool hasTrailingWhitespace() const { return m_trailingWhitespaceLength; }
    262     TextFragmentIterator::TextFragment lastFragment() const { return m_fragments.last(); }
    263244    bool isWhitespaceOnly() const { return m_trailingWhitespaceWidth && m_runsWidth == m_trailingWhitespaceWidth; }
    264245    bool fits(float extra) const { return m_availableWidth >= m_runsWidth + extra; }
    265246    bool firstCharacterFits() const { return m_firstCharacterFits; }
    266247    float width() const { return m_runsWidth; }
    267     bool isEmpty() const
    268     {
    269         if (!m_fragments.size())
    270             return true;
    271         if (!m_lastCompleteFragment.isEmpty())
    272             return false;
    273         return m_fragments.last().overlapsToNextRenderer();
    274     }
    275 
    276     void appendFragmentAndCreateRunIfNeeded(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs)
     248
     249    void appendFragment(const TextFragmentIterator::TextFragment& fragment, Layout::RunVector& runs)
    277250    {
    278251        // Adjust end position while collapsing.
    279252        unsigned endPosition = fragment.isCollapsed() ? fragment.start() + 1 : fragment.end();
    280         // New line needs new run.
    281         if (!m_runsWidth)
     253
     254        if (m_createNewRun)
    282255            runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
    283256        else {
    284             const auto& lastFragment = m_fragments.last();
    285             // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers)
    286             if ((lastFragment.type() != fragment.type()) || !lastFragment.overlapsToNextRenderer())
    287                 m_lastCompleteFragment = lastFragment;
    288             // Collapse neighbouring whitespace, if they are across multiple renderers and are not collapsed yet.
    289             if (lastFragment.isCollapsible() && fragment.isCollapsible()) {
    290                 ASSERT(lastFragment.isLastInRenderer());
    291                 if (!lastFragment.isCollapsed()) {
    292                     // Line width needs to be reset so that now it takes collapsing into consideration.
    293                     m_runsWidth -= (lastFragment.width() - m_collapsedWhitespaceWidth);
    294                 }
    295                 // This fragment is collapsed completely. No run is needed.
    296                 return;
    297             }
    298             if (lastFragment.isLastInRenderer() || lastFragment.isCollapsed())
    299                 runs.append(Run(fragment.start(), endPosition, m_runsWidth, m_runsWidth + fragment.width(), false));
    300             else {
    301                 Run& lastRun = runs.last();
    302                 lastRun.end = endPosition;
    303                 lastRun.logicalRight += fragment.width();
    304             }
    305         }
    306         m_fragments.append(fragment);
     257            ASSERT(runs.size());
     258            Run& lastRun = runs.last();
     259            lastRun.end = endPosition;
     260            lastRun.logicalRight = m_runsWidth + fragment.width();
     261        }
     262        m_createNewRun = fragment.isCollapsed();
    307263        m_runsWidth += fragment.width();
    308264
     
    319275    }
    320276
    321     TextFragmentIterator::TextFragment revertToLastCompleteFragment(Layout::RunVector& runs)
    322     {
    323         ASSERT(m_fragments.size());
    324         unsigned revertLength = 0;
    325         float revertWidth = 0;
    326         while (m_fragments.size()) {
    327             const auto& current = m_fragments.last();
    328             if (current == m_lastCompleteFragment)
    329                 break;
    330             revertLength += current.end() - current.start();
    331             revertWidth += current.width();
    332             m_fragments.removeLast();
    333         }
    334         m_runsWidth -= revertWidth;
    335         if (revertLength)
    336             revertRuns(runs, revertLength, revertWidth);
    337         return m_lastCompleteFragment;
    338     }
    339 
    340277    void removeTrailingWhitespace(Layout::RunVector& runs)
    341278    {
    342         // FIXME: sync m_fragment, but it's ok for now as we don't use m_fragment anymore after removeTrailingWhitespace.
    343         if (!m_trailingWhitespaceLength)
    344             return;
    345         revertRuns(runs, m_trailingWhitespaceLength, m_trailingWhitespaceWidth);
     279        ASSERT(runs.size());
     280        Run& lastRun = runs.last();
     281        lastRun.logicalRight -= m_trailingWhitespaceWidth;
     282        lastRun.end -= m_trailingWhitespaceLength;
     283        if (lastRun.start == lastRun.end)
     284            runs.removeLast();
     285
    346286        m_runsWidth -= m_trailingWhitespaceWidth;
     287        m_trailingWhitespaceWidth = 0;
    347288        m_trailingWhitespaceLength = 0;
    348         m_trailingWhitespaceWidth = 0;
    349289    }
    350290
     
    354294    TextFragmentIterator::TextFragment m_overflowedFragment;
    355295    float m_runsWidth { 0 };
    356     TextFragmentIterator::TextFragment m_lastCompleteFragment;
     296    bool m_createNewRun { true };
    357297    float m_trailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
    358298    unsigned m_trailingWhitespaceLength { 0 };
    359     float m_collapsedWhitespaceWidth { 0 };
    360299    // Having one character on the line does not necessarily mean it actually fits.
    361300    // First character of the first fragment might be forced on to the current line even if it does not fit.
    362301    bool m_firstCharacterFits { false };
    363     Vector<TextFragmentIterator::TextFragment> m_fragments;
    364302};
    365303
     
    452390
    453391    // Check if we need to skip the leading whitespace.
    454     if (style.collapseWhitespace) {
    455         while (firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace)
    456             firstFragment = textFragmentIterator.nextTextFragment();
    457     }
     392    if (style.collapseWhitespace && firstFragment.type() == TextFragmentIterator::TextFragment::Whitespace)
     393        firstFragment = textFragmentIterator.nextTextFragment();
    458394    return firstFragment;
    459395}
    460396
    461 static void forceFragmentToLine(LineState& line, TextFragmentIterator& textFragmentIterator, Layout::RunVector& runs, const TextFragmentIterator::TextFragment& fragment)
    462 {
    463     line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
    464     // Check if there are more fragments to add to the current line.
    465     if (!fragment.overlapsToNextRenderer())
    466         return;
    467     auto nextFragment = textFragmentIterator.nextTextFragment();
    468     while (true) {
    469         if (nextFragment.type() != fragment.type())
    470             break;
    471         line.appendFragmentAndCreateRunIfNeeded(nextFragment, runs);
    472         // Does it overlap to the next segment?
    473         if (!nextFragment.overlapsToNextRenderer())
    474             return;
    475         nextFragment = textFragmentIterator.nextTextFragment();
    476     }
    477     line.setOverflowedFragment(nextFragment);
    478 }
    479 
    480397static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& runs, TextFragmentIterator& textFragmentIterator)
    481398{
    482399    const auto& style = textFragmentIterator.style();
    483     line.setCollapedWhitespaceWidth(style.spaceWidth);
    484400    bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
    485401    auto fragment = firstFragment(textFragmentIterator, previousLine);
     
    489405            // Add the new line fragment only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.)
    490406            if (!line.width())
    491                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
     407                line.appendFragment(fragment, runs);
    492408            break;
    493409        }
     
    498414            // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
    499415            // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
    500             bool emptyLine = line.isEmpty();
     416            bool emptyLine = !line.width();
    501417            // Whitespace fragment.
    502418            if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
     
    504420                    // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
    505421                    line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
    506                     line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
     422                    line.appendFragment(fragment, runs);
    507423                }
    508424                // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
     
    513429                // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
    514430                line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
    515                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
     431                line.appendFragment(fragment, runs);
    516432                break;
    517433            }
    518434            // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
    519             ASSERT(fragment.type() == TextFragmentIterator::TextFragment::NonWhitespace);
    520435            if (emptyLine) {
    521                 forceFragmentToLine(line, textFragmentIterator, runs, fragment);
     436                line.appendFragment(fragment, runs);
    522437                break;
    523438            }
    524439            // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
    525             if (line.lastFragment().overlapsToNextRenderer()) {
    526                 // Check if this fragment is a continuation of a previous segment. In such cases, we need to remove them all.
    527                 const auto& currentFragment = line.revertToLastCompleteFragment(runs);
    528                 textFragmentIterator.revertToFragment(currentFragment);
    529                 break;
    530             }
    531440            line.setOverflowedFragment(fragment);
    532441            break;
    533442        }
    534         line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
     443        line.appendFragment(fragment, runs);
    535444        // Find the next text fragment.
    536445        fragment = textFragmentIterator.nextTextFragment(line.width());
    537446    }
    538     return (fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty()) || line.overflowedFragment().type() == TextFragmentIterator::TextFragment::ContentEnd;
     447    return fragment.type() == TextFragmentIterator::TextFragment::ContentEnd && line.overflowedFragment().isEmpty();
    539448}
    540449
     
    558467}
    559468
     469static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const TextFragmentIterator& textFragmentIterator)
     470{
     471    // FIXME: We should probably split during run construction instead of as a separate pass.
     472    if (lineRuns.isEmpty())
     473        return;
     474    unsigned runIndex = 0;
     475    do {
     476        const Run& run = lineRuns.at(runIndex);
     477        ASSERT(run.start != run.end);
     478        auto& startSegment = textFragmentIterator.segmentForPosition(run.start);
     479        if (run.end <= startSegment.end)
     480            continue;
     481        // This run overlaps multiple renderers. Split it up.
     482        // Split run at the renderer's boundary and create a new run for the left side, while use the current run as the right side.
     483        float logicalRightOfLeftRun = run.logicalLeft + textFragmentIterator.textWidth(run.start, startSegment.end, run.logicalLeft);
     484        lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
     485        Run& rightSideRun = lineRuns.at(runIndex + 1);
     486        rightSideRun.start = startSegment.end;
     487        rightSideRun.logicalLeft = logicalRightOfLeftRun;
     488    } while (++runIndex < lineRuns.size());
     489}
     490
    560491static void createTextRuns(Layout::RunVector& runs, RenderBlockFlow& flow, unsigned& lineCount)
    561492{
     
    575506        closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, textFragmentIterator);
    576507    } while (!isEndOfContent);
     508
     509    if (flow.firstChild() != flow.lastChild())
     510        splitRunsAtRendererBoundary(runs, textFragmentIterator);
    577511}
    578512
  • trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp

    r181682 r181685  
    5252}
    5353
    54 unsigned FlowContents::segmentIndexForRunSlow(unsigned start, unsigned end) const
     54unsigned FlowContents::segmentIndexForPositionSlow(unsigned position) const
    5555{
    56     auto it = std::lower_bound(m_segments.begin(), m_segments.end(), start, [](const Segment& segment, unsigned start) {
    57         return segment.end <= start;
     56    auto it = std::lower_bound(m_segments.begin(), m_segments.end(), position, [](const Segment& segment, unsigned position) {
     57        return segment.end <= position;
    5858    });
    5959    ASSERT(it != m_segments.end());
    60     ASSERT_UNUSED(end, end <= it->end);
    6160    auto index = it - m_segments.begin();
    6261    m_lastSegmentIndex = index;
  • trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h

    r181683 r181685  
    4444        const RenderObject& renderer;
    4545    };
    46     const Segment& segmentForRun(unsigned start, unsigned end) const;
     46    const Segment& segmentForPosition(unsigned) const;
    4747    const Segment& segmentForRenderer(const RenderObject&) const;
    4848
    49     typedef Vector<Segment, 8>::const_iterator Iterator;
    50     Iterator begin() const { return m_segments.begin(); }
    51     Iterator end() const { return m_segments.end(); }
     49    class Iterator {
     50    public:
     51        Iterator(const FlowContents& flowContents, unsigned segmentIndex)
     52            : m_flowContents(flowContents)
     53            , m_segmentIndex(segmentIndex)
     54        {
     55        }
     56
     57        Iterator& operator++();
     58        bool operator==(const Iterator& other) const;
     59        bool operator!=(const Iterator& other) const;
     60        const Segment& operator*() const { return m_flowContents.m_segments[m_segmentIndex]; }
     61
     62    private:
     63        const FlowContents& m_flowContents;
     64        unsigned m_segmentIndex;
     65    };
     66
     67    Iterator begin() const { return Iterator(*this, 0); }
     68    Iterator end() const { return Iterator(*this, m_segments.size()); }
     69
     70    unsigned length() const { return m_segments.last().end; };
     71
     72    unsigned segmentIndexForPosition(unsigned position) const;
    5273
    5374private:
    54     unsigned segmentIndexForRunSlow(unsigned start, unsigned end) const;
     75    unsigned segmentIndexForPositionSlow(unsigned position) const;
     76
    5577    const Vector<Segment, 8> m_segments;
     78
    5679    mutable unsigned m_lastSegmentIndex;
    5780};
    5881
    59 inline const FlowContents::Segment& FlowContents::segmentForRun(unsigned start, unsigned end) const
     82inline FlowContents::Iterator& FlowContents::Iterator::operator++()
    6083{
    61     ASSERT(start < end);
     84    ++m_segmentIndex;
     85    return *this;
     86}
     87
     88inline bool FlowContents::Iterator::operator==(const FlowContents::Iterator& other) const
     89{
     90    return m_segmentIndex == other.m_segmentIndex;
     91}
     92
     93inline bool FlowContents::Iterator::operator!=(const FlowContents::Iterator& other) const
     94{
     95    return !(*this == other);
     96}
     97
     98inline unsigned FlowContents::segmentIndexForPosition(unsigned position) const
     99{
    62100    auto& lastSegment = m_segments[m_lastSegmentIndex];
    63     if (lastSegment.start <= start && end <= lastSegment.end)
    64         return m_segments[m_lastSegmentIndex];
    65     return m_segments[segmentIndexForRunSlow(start, end)];
     101    if (lastSegment.start <= position && position < lastSegment.end)
     102        return m_lastSegmentIndex;
     103    return segmentIndexForPositionSlow(position);
     104}
     105
     106inline const FlowContents::Segment& FlowContents::segmentForPosition(unsigned position) const
     107{
     108    return m_segments[segmentIndexForPosition(position)];
    66109}
    67110
  • trunk/Source/WebCore/rendering/SimpleLineLayoutFunctions.cpp

    r181667 r181685  
    8585        TextRun textRun(run.text());
    8686        textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
    87         textRun.setXPos(run.rect().x());
    8887        FloatPoint textOrigin = run.baseline() + paintOffset;
    8988        textOrigin.setY(roundToDevicePixel(LayoutUnit(textOrigin.y()), flow.document().deviceScaleFactor()));
  • trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp

    r181682 r181685  
    7777    auto& resolver = m_iterator.resolver();
    7878    auto& run = m_iterator.simpleRun();
    79     ASSERT(run.start < run.end);
    80     auto& segment = resolver.m_flowContents.segmentForRun(run.start, run.end);
     79    auto& segment = resolver.m_flowContents.segmentForPosition(run.start);
    8180    // We currently split runs on segment boundaries (different RenderObject).
    8281    ASSERT(run.end <= segment.end);
  • trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp

    r181683 r181685  
    4949TextFragmentIterator::TextFragmentIterator(const RenderBlockFlow& flow)
    5050    : m_flowContents(flow)
    51     , m_currentSegment(m_flowContents.begin())
    52     , m_lineBreakIterator(m_currentSegment->text, flow.style().locale())
     51    , m_lineBreakIterator((*m_flowContents.begin()).text, flow.style().locale())
    5352    , m_style(flow.style())
    5453{
     
    6261    // 3. non-whitespace characters.
    6362    // 4. empty, indicating content end.
    64     ASSERT(m_currentSegment != m_flowContents.end());
    65     if (m_position == m_currentSegment->end)
    66         ++m_currentSegment;
    67     // Is it content end?
    68     if (m_currentSegment == m_flowContents.end())
     63    if (isEnd(m_position))
    6964        return TextFragment(m_position, m_position, 0, TextFragment::ContentEnd);
    70     unsigned segmentEndPosition = m_currentSegment->end;
     65    if (isLineBreak(m_position)) {
     66        TextFragment fragment(m_position, m_position + 1, 0, TextFragment::LineBreak);
     67        ++m_position;
     68        return fragment;
     69    }
    7170    unsigned startPosition = m_position;
    72     if (isLineBreak(m_position)) {
    73         unsigned endPosition = ++m_position;
    74         return TextFragment(startPosition, endPosition, 0, TextFragment::LineBreak);
    75     }
    76     float width = 0;
    77     bool overlappingFragment = false;
    78     unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition, width, xPosition, overlappingFragment);
     71    unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition);
    7972    ASSERT(startPosition <= endPosition);
    80     if (startPosition < endPosition) {
     73    if (endPosition > startPosition) {
    8174        bool multipleWhitespace = startPosition + 1 < endPosition;
    8275        bool isCollapsed = multipleWhitespace && m_style.collapseWhitespace;
    8376        bool isBreakable = !isCollapsed && multipleWhitespace;
     77        float width = isCollapsed ? m_style.spaceWidth : textWidth(startPosition, endPosition, xPosition);
    8478        m_position = endPosition;
    85         return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, endPosition == segmentEndPosition, false, isCollapsed, m_style.collapseWhitespace, isBreakable);
     79        return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, isCollapsed, isBreakable);
    8680    }
    87     endPosition = skipToNextPosition(PositionType::Breakable, startPosition, width, xPosition, overlappingFragment);
     81    endPosition = skipToNextPosition(PositionType::Breakable, startPosition + 1);
    8882    m_position = endPosition;
    89     return TextFragment(startPosition, endPosition, width, TextFragment::NonWhitespace, endPosition == segmentEndPosition, overlappingFragment, false, false, m_style.breakWordOnOverflow);
     83    return TextFragment(startPosition, endPosition, textWidth(startPosition, endPosition, xPosition), TextFragment::NonWhitespace, false, m_style.breakWordOnOverflow);
    9084}
    9185
    92 void TextFragmentIterator::revertToFragment(const TextFragment& fragment)
     86float TextFragmentIterator::textWidth(unsigned from, unsigned to, float xPosition) const
    9387{
    94     ASSERT(m_position >= fragment.end());
    95     ASSERT(fragment.start() >= 0);
    96     // Revert segment first.
    97     while (m_currentSegment->start > fragment.start())
    98         --m_currentSegment;
    99     // TODO: It reverts to the last fragment on the same position, but that's ok for now as we don't need to
    100     // differentiate multiple renderers on the same position.
    101     m_position = fragment.start();
     88    const auto& fromSegment = m_flowContents.segmentForPosition(from);
     89    ASSERT(is<RenderText>(fromSegment.renderer));
     90    if ((m_style.font.isFixedPitch() && fromSegment.end >= to) || (from == fromSegment.start && to == fromSegment.end))
     91        return downcast<RenderText>(fromSegment.renderer).width(from - fromSegment.start, to - from, m_style.font, xPosition, nullptr, nullptr);
     92
     93    const auto* segment = &fromSegment;
     94    float textWidth = 0;
     95    unsigned fragmentEnd = 0;
     96    while (true) {
     97        fragmentEnd = std::min(to, segment->end);
     98        textWidth += segment->text.is8Bit() ? runWidth<LChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth) :
     99            runWidth<UChar>(segment->text, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth);
     100        if (fragmentEnd == to)
     101            break;
     102        from = fragmentEnd;
     103        segment = &m_flowContents.segmentForPosition(fragmentEnd);
     104    };
     105
     106    return textWidth;
    102107}
    103108
    104109template <typename CharacterType>
    105 unsigned TextFragmentIterator::nextBreakablePosition(const FlowContents::Segment& segment, unsigned startPosition)
     110static unsigned nextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, const FlowContents::Segment& segment, unsigned startPosition)
    106111{
    107     ASSERT(startPosition < segment.end);
    108     if (segment.text.impl() != m_lineBreakIterator.string().impl()) {
    109         const String& currentText = m_lineBreakIterator.string();
    110         unsigned textLength = currentText.length();
    111         UChar lastCharacter = textLength > 0 ? currentText[textLength - 1] : 0;
    112         UChar secondToLastCharacter = textLength > 1 ? currentText[textLength - 2] : 0;
    113         m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
    114         m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14);
    115     }
    116     const auto* characters = segment.text.characters<CharacterType>();
    117     unsigned segmentLength = segment.end - segment.start;
    118     unsigned segmentPosition = startPosition - segment.start;
    119     return segment.start + nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(m_lineBreakIterator, characters, segmentLength, segmentPosition);
     112    return nextBreakablePositionNonLoosely<CharacterType, NBSPBehavior::IgnoreNBSP>(lineBreakIterator, segment.text.characters<CharacterType>(), segment.end - segment.start, startPosition);
    120113}
    121114
    122115template <typename CharacterType>
    123 unsigned TextFragmentIterator::nextNonWhitespacePosition(const FlowContents::Segment& segment, unsigned startPosition)
     116static unsigned nextNonWhitespacePosition(const FlowContents::Segment& segment, unsigned startPosition, const TextFragmentIterator::Style& style)
    124117{
    125     ASSERT(startPosition < segment.end);
    126118    const auto* text = segment.text.characters<CharacterType>();
    127119    unsigned position = startPosition;
    128     for (; position < segment.end; ++position) {
    129         auto character = text[position - segment.start];
    130         bool isWhitespace = character == ' ' || character == '\t' || (!m_style.preserveNewline && character == '\n');
     120    unsigned length = segment.end - segment.start;
     121    for (; position < length; ++position) {
     122        auto character = text[position];
     123        bool isWhitespace = character == ' ' || character == '\t' || (!style.preserveNewline && character == '\n');
    131124        if (!isWhitespace)
    132125            return position;
     
    135128}
    136129
    137 float TextFragmentIterator::textWidth(unsigned from, unsigned to, float xPosition) const
     130unsigned TextFragmentIterator::skipToNextPosition(PositionType positionType, unsigned startPosition) const
    138131{
    139     auto& segment = *m_currentSegment;
    140     ASSERT(segment.start <= from && from <= segment.end && segment.start <= to && to <= segment.end);
    141     ASSERT(is<RenderText>(segment.renderer));
    142     if (m_style.font.isFixedPitch() || (from == segment.start && to == segment.end))
    143         return downcast<RenderText>(segment.renderer).width(from - segment.start, to - from, m_style.font, xPosition, nullptr, nullptr);
    144     return segment.text.is8Bit() ? runWidth<LChar>(segment, from, to, xPosition) : runWidth<UChar>(segment, from, to, xPosition);
    145 }
     132    if (isEnd(startPosition))
     133        return startPosition;
    146134
    147 unsigned TextFragmentIterator::skipToNextPosition(PositionType positionType, unsigned startPosition, float& width, float xPosition, bool& overlappingFragment)
    148 {
    149     overlappingFragment = false;
    150135    unsigned currentPosition = startPosition;
    151     unsigned nextPosition = currentPosition;
    152     // Collapsed whitespace has constant width. Do not measure it.
    153     if (positionType == NonWhitespace)
    154         nextPosition = m_currentSegment->text.is8Bit() ? nextNonWhitespacePosition<LChar>(*m_currentSegment, currentPosition) : nextNonWhitespacePosition<UChar>(*m_currentSegment, currentPosition);
    155     else if (positionType == Breakable) {
    156         // nextBreakablePosition returns the same position for certain characters such as hyphens. Call next again with modified position unless it's the end of the segment.
    157         nextPosition = m_currentSegment->text.is8Bit() ? nextBreakablePosition<LChar>(*m_currentSegment, currentPosition) : nextBreakablePosition<UChar>(*m_currentSegment, currentPosition);
    158         // We need to know whether the word actually finishes at the end of this renderer or not.
    159         if (nextPosition == m_currentSegment->end) {
    160             const auto nextSegment = m_currentSegment + 1;
    161             if (nextSegment != m_flowContents.end())
    162                 overlappingFragment = nextPosition < (nextSegment->text.is8Bit() ? nextBreakablePosition<LChar>(*nextSegment, nextPosition) : nextBreakablePosition<UChar>(*nextSegment, nextPosition));
    163         } else if (nextPosition == currentPosition) {
    164             if (++nextPosition < m_currentSegment->end)
    165                 nextPosition = m_currentSegment->text.is8Bit() ? nextBreakablePosition<LChar>(*m_currentSegment, currentPosition + 1) : nextBreakablePosition<UChar>(*m_currentSegment, currentPosition + 1);
    166         }
     136    FlowContents::Iterator it(m_flowContents, m_flowContents.segmentIndexForPosition(currentPosition));
     137    for (auto end = m_flowContents.end(); it != end; ++it) {
     138        auto& segment = *it;
     139        unsigned currentPositonRelativeToSegment = currentPosition - segment.start;
     140        unsigned nextPositionRelativeToSegment = 0;
     141        if (positionType == NonWhitespace) {
     142            nextPositionRelativeToSegment = segment.text.is8Bit() ? nextNonWhitespacePosition<LChar>(segment, currentPositonRelativeToSegment, m_style) :
     143                nextNonWhitespacePosition<UChar>(segment, currentPositonRelativeToSegment, m_style);
     144        } else if (positionType == Breakable) {
     145            if (segment.text.impl() != m_lineBreakIterator.string().impl()) {
     146                UChar lastCharacter = segment.start > 0 ? characterAt(segment.start - 1) : 0;
     147                UChar secondToLastCharacter = segment.start > 1 ? characterAt(segment.start - 2) : 0;
     148                m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
     149                m_lineBreakIterator.resetStringAndReleaseIterator(segment.text, m_style.locale, LineBreakIteratorModeUAX14);
     150            }
     151            nextPositionRelativeToSegment = segment.text.is8Bit() ? nextBreakablePosition<LChar>(m_lineBreakIterator, segment, currentPositonRelativeToSegment) :
     152                nextBreakablePosition<UChar>(m_lineBreakIterator, segment, currentPositonRelativeToSegment);
     153        } else
     154            ASSERT_NOT_REACHED();
     155        currentPosition = segment.start + nextPositionRelativeToSegment;
     156        if (currentPosition < segment.end)
     157            break;
    167158    }
    168     width = 0;
    169     if (nextPosition == currentPosition)
    170         return currentPosition;
    171     bool measureText = positionType != NonWhitespace || !m_style.collapseWhitespace;
    172     if (measureText) {
    173         float textWidth = this->textWidth(currentPosition, nextPosition, xPosition);
    174         xPosition += textWidth;
    175         width += textWidth;
    176     } else if (startPosition < nextPosition)
    177         width = m_style.spaceWidth;
    178     return nextPosition;
     159    return currentPosition;
    179160}
    180161
    181162template <typename CharacterType>
    182 float TextFragmentIterator::runWidth(const FlowContents::Segment& segment, unsigned startPosition, unsigned endPosition, float xPosition) const
     163float TextFragmentIterator::runWidth(const String& text, unsigned from, unsigned to, float xPosition) const
    183164{
    184     ASSERT(startPosition <= endPosition);
    185     if (startPosition == endPosition)
     165    ASSERT(from <= to);
     166    if (from == to)
    186167        return 0;
    187     unsigned segmentFrom = startPosition - segment.start;
    188     unsigned segmentTo = endPosition - segment.start;
    189     bool measureWithEndSpace = m_style.collapseWhitespace && segmentTo < segment.text.length() && segment.text[segmentTo] == ' ';
     168    bool measureWithEndSpace = m_style.collapseWhitespace && to < text.length() && text[to] == ' ';
    190169    if (measureWithEndSpace)
    191         ++segmentTo;
    192     TextRun run(segment.text.characters<CharacterType>() + segmentFrom, segmentTo - segmentFrom);
     170        ++to;
     171    TextRun run(text.characters<CharacterType>() + from, to - from);
    193172    run.setXPos(xPosition);
    194173    run.setTabSize(!!m_style.tabWidth, m_style.tabWidth);
  • trunk/Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h

    r181667 r181685  
    4444        enum Type { ContentEnd, LineBreak, Whitespace, NonWhitespace };
    4545        TextFragment() = default;
    46         TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false, bool isBreakable = false)
     46        TextFragment(unsigned start, unsigned end, float width, Type type, bool isCollapsed = false, bool isBreakable = false)
    4747            : m_start(start)
    4848            , m_end(end)
     49            , m_type(type)
    4950            , m_width(width)
    50             , m_type(type)
    51             , m_isLastInRenderer(isLastInRenderer)
    52             , m_overlapsToNextRenderer(overlapsToNextRenderer)
    5351            , m_isCollapsed(isCollapsed)
    54             , m_isCollapsible(isCollapsible)
    5552            , m_isBreakable(isBreakable)
    5653        {
     
    6158        float width() const { return m_width; }
    6259        Type type() const { return m_type; }
    63         bool isLastInRenderer() const { return m_isLastInRenderer; }
    64         bool overlapsToNextRenderer() const { return m_overlapsToNextRenderer; }
    6560        bool isCollapsed() const { return m_isCollapsed; }
    66         bool isCollapsible() const { return m_isCollapsible; }
    6761        bool isBreakable() const { return m_isBreakable; }
    6862
    6963        bool isEmpty() const { return start() == end(); }
    7064        TextFragment split(unsigned splitPosition, const TextFragmentIterator&);
    71         bool operator==(const TextFragment& other) const
    72         {
    73             return m_start == other.m_start
    74                 && m_end == other.m_end
    75                 && m_width == other.m_width
    76                 && m_type == other.m_type
    77                 && m_isLastInRenderer == other.m_isLastInRenderer
    78                 && m_overlapsToNextRenderer == other.m_overlapsToNextRenderer
    79                 && m_isCollapsed == other.m_isCollapsed
    80                 && m_isCollapsible == other.m_isCollapsible
    81                 && m_isBreakable == other.m_isBreakable;
    82         }
    8365
    8466    private:
    8567        unsigned m_start { 0 };
    8668        unsigned m_end { 0 };
     69        Type m_type { NonWhitespace };
    8770        float m_width { 0 };
    88         Type m_type { NonWhitespace };
    89         bool m_isLastInRenderer { false };
    90         bool m_overlapsToNextRenderer { false };
    9171        bool m_isCollapsed { false };
    92         bool m_isCollapsible { false };
    9372        bool m_isBreakable { false };
    9473    };
    9574    TextFragment nextTextFragment(float xPosition = 0);
    96     void revertToFragment(const TextFragment&);
    97     float textWidth(unsigned startPosition, unsigned endPosition, float xPosition) const;
     75    float textWidth(unsigned from, unsigned to, float xPosition) const;
    9876
    9977    struct Style {
     
    11189    };
    11290    const Style& style() const { return m_style; }
     91    // FIXME: remove splitRunsAtRendererBoundary()
     92    const FlowContents::Segment& segmentForPosition(unsigned position) const { return m_flowContents.segmentForPosition(position); };
    11393
    11494private:
    11595    enum PositionType { Breakable, NonWhitespace };
    116     unsigned skipToNextPosition(PositionType, unsigned startPosition, float& width, float xPosition, bool& overlappingFragment);
     96    unsigned skipToNextPosition(PositionType, unsigned startPosition) const;
     97    UChar characterAt(unsigned position) const;
    11798    bool isLineBreak(unsigned position) const;
    118     template <typename CharacterType> unsigned nextBreakablePosition(const FlowContents::Segment&, unsigned startPosition);
    119     template <typename CharacterType> unsigned nextNonWhitespacePosition(const FlowContents::Segment&, unsigned startPosition);
    120     template <typename CharacterType> float runWidth(const FlowContents::Segment&, unsigned startPosition, unsigned endPosition, float xPosition) const;
     99    bool isEnd(unsigned position) const;
     100    template <typename CharacterType> float runWidth(const String&, unsigned from, unsigned to, float xPosition) const;
    121101
    122102    FlowContents m_flowContents;
    123     FlowContents::Iterator m_currentSegment;
    124     LazyLineBreakIterator m_lineBreakIterator;
     103    mutable LazyLineBreakIterator m_lineBreakIterator;
    125104    const Style m_style;
    126105    unsigned m_position { 0 };
     
    149128}
    150129
     130inline UChar TextFragmentIterator::characterAt(unsigned position) const
     131{
     132    auto& segment = m_flowContents.segmentForPosition(position);
     133    return segment.text[position - segment.start];
     134}
     135
    151136inline bool TextFragmentIterator::isLineBreak(unsigned position) const
    152137{
    153     const auto& segment = *m_currentSegment;
    154     ASSERT(segment.start <= position && position < segment.end);
    155     return m_style.preserveNewline && segment.text[position - segment.start] == '\n';
     138    if (isEnd(position))
     139        return false;
     140    return m_style.preserveNewline && characterAt(position) == '\n';
     141}
     142
     143inline bool TextFragmentIterator::isEnd(unsigned position) const
     144{
     145    return position >= m_flowContents.length();
    156146}
    157147
Note: See TracChangeset for help on using the changeset viewer.