Title: [176510] trunk/Source/WebCore
Revision
176510
Author
[email protected]
Date
2014-11-23 10:46:18 -0800 (Sun, 23 Nov 2014)

Log Message

Use segment vector for FlowContents
https://bugs.webkit.org/show_bug.cgi?id=139015

Reviewed by Zalan Bujtas.

And FlowContents::Segment struct and use it.

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::removeTrailingWhitespace):
(WebCore::SimpleLineLayout::createLineRuns):
(WebCore::SimpleLineLayout::splitRunsAtRendererBoundary):

    Use segments.
    If there is only one segment there is nothing to do. Bail out.

* rendering/SimpleLineLayoutFlowContents.cpp:
(WebCore::SimpleLineLayout::initializeSegments):

    Move initialization to a function so m_segments can be const.
    Don't add empty end segment, handle the end case in code.

(WebCore::SimpleLineLayout::FlowContents::FlowContents):
(WebCore::SimpleLineLayout::FlowContents::textWidth):

    Simplify and use segments.

(WebCore::SimpleLineLayout::FlowContents::segmentForPositionSlow):

    Replace hand-rolled binary search with std::lower_bounds.

(WebCore::SimpleLineLayout::FlowContents::segmentForRenderer):
(WebCore::SimpleLineLayout::FlowContents::appendNextRendererContentIfNeeded):
(WebCore::SimpleLineLayout::FlowContents::renderer): Deleted.
(WebCore::SimpleLineLayout::FlowContents::resolveRendererPositions): Deleted.
* rendering/SimpleLineLayoutFlowContents.h:
(WebCore::SimpleLineLayout::FlowContents::hasOneSegment):
(WebCore::SimpleLineLayout::FlowContents::length):
(WebCore::SimpleLineLayout::FlowContents::isEnd):
(WebCore::SimpleLineLayout::FlowContents::isEndOfContent): Deleted.

    Renamed.

(WebCore::SimpleLineLayout::FlowContents::segmentForPosition):

    Inline the fast path.

* rendering/SimpleLineLayoutResolver.cpp:
(WebCore::SimpleLineLayout::RunResolver::Run::text):
(WebCore::SimpleLineLayout::RunResolver::rangeForRenderer):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (176509 => 176510)


--- trunk/Source/WebCore/ChangeLog	2014-11-23 18:00:52 UTC (rev 176509)
+++ trunk/Source/WebCore/ChangeLog	2014-11-23 18:46:18 UTC (rev 176510)
@@ -1,3 +1,55 @@
+2014-11-23  Antti Koivisto  <[email protected]>
+
+        Use segment vector for FlowContents
+        https://bugs.webkit.org/show_bug.cgi?id=139015
+
+        Reviewed by Zalan Bujtas.
+
+        And FlowContents::Segment struct and use it.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::removeTrailingWhitespace):
+        (WebCore::SimpleLineLayout::createLineRuns):
+        (WebCore::SimpleLineLayout::splitRunsAtRendererBoundary):
+
+            Use segments.
+            If there is only one segment there is nothing to do. Bail out.
+
+        * rendering/SimpleLineLayoutFlowContents.cpp:
+        (WebCore::SimpleLineLayout::initializeSegments):
+
+            Move initialization to a function so m_segments can be const.
+            Don't add empty end segment, handle the end case in code.
+
+        (WebCore::SimpleLineLayout::FlowContents::FlowContents):
+        (WebCore::SimpleLineLayout::FlowContents::textWidth):
+
+            Simplify and use segments.
+
+        (WebCore::SimpleLineLayout::FlowContents::segmentForPositionSlow):
+
+            Replace hand-rolled binary search with std::lower_bounds.
+
+        (WebCore::SimpleLineLayout::FlowContents::segmentForRenderer):
+        (WebCore::SimpleLineLayout::FlowContents::appendNextRendererContentIfNeeded):
+        (WebCore::SimpleLineLayout::FlowContents::renderer): Deleted.
+        (WebCore::SimpleLineLayout::FlowContents::resolveRendererPositions): Deleted.
+        * rendering/SimpleLineLayoutFlowContents.h:
+        (WebCore::SimpleLineLayout::FlowContents::hasOneSegment):
+        (WebCore::SimpleLineLayout::FlowContents::length):
+        (WebCore::SimpleLineLayout::FlowContents::isEnd):
+        (WebCore::SimpleLineLayout::FlowContents::isEndOfContent): Deleted.
+
+            Renamed.
+
+        (WebCore::SimpleLineLayout::FlowContents::segmentForPosition):
+
+            Inline the fast path.
+
+        * rendering/SimpleLineLayoutResolver.cpp:
+        (WebCore::SimpleLineLayout::RunResolver::Run::text):
+        (WebCore::SimpleLineLayout::RunResolver::rangeForRenderer):
+
 2014-11-22  Simon Fraser  <[email protected]>
 
         Extend WKRenderObject and WKRenderLayer with some more useful data

Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (176509 => 176510)


--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2014-11-23 18:00:52 UTC (rev 176509)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2014-11-23 18:46:18 UTC (rev 176510)
@@ -408,7 +408,7 @@
     }
 
     // If we skipped any whitespace and now the line end is a "preserved" newline, skip the newline too as we are wrapping the line here already.
-    if (lastPosition != lineState.position && style.preserveNewline && !flowContents.isEndOfContent(lineState.position) && flowContents.isNewlineCharacter(lineState.position))
+    if (lastPosition != lineState.position && style.preserveNewline && !flowContents.isEnd(lineState.position) && flowContents.isNewlineCharacter(lineState.position))
         ++lineState.position;
 }
 
@@ -513,7 +513,7 @@
 {
     const auto& style = flowContents.style();
     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
-    while (!flowContents.isEndOfContent(lineState.position)) {
+    while (!flowContents.isEnd(lineState.position)) {
         // Find the next text fragment. Start from the end of the previous fragment -current line end.
         TextFragment fragment = nextFragment(lineState.position, flowContents, lineState.width());
         if ((lineCanBeWrapped && !lineState.fits(fragment.width)) || fragment.mustBreak) {
@@ -562,7 +562,7 @@
             lineState.addUncommitted(fragment);
     }
     lineState.commitAndCreateRun(lineRuns);
-    return flowContents.isEndOfContent(lineState.position) && lineState.oveflowedFragment.isEmpty();
+    return flowContents.isEnd(lineState.position) && lineState.oveflowedFragment.isEmpty();
 }
 
 static void closeLineEndingAndAdjustRuns(LineState& lineState, Layout::RunVector& lineRuns, unsigned& lineCount, const FlowContents& flowContents)
@@ -587,28 +587,25 @@
 
 static void splitRunsAtRendererBoundary(Layout::RunVector& lineRuns, const FlowContents& flowContents)
 {
-    if (!lineRuns.size())
+    // FIXME: We should probably split during run construction instead of as a separate pass.
+    if (lineRuns.isEmpty())
         return;
+    if (flowContents.hasOneSegment())
+        return;
 
     unsigned runIndex = 0;
     do {
         const Run& run = lineRuns.at(runIndex);
         ASSERT(run.start != run.end);
-        const RenderText* startRenderer = flowContents.renderer(run.start);
-        const RenderText* endRenderer = flowContents.renderer(run.end - 1);
-        if (startRenderer == endRenderer)
+        auto& startSegment = flowContents.segmentForPosition(run.start);
+        if (run.end <= startSegment.end)
             continue;
         // This run overlaps multiple renderers. Split it up.
-        unsigned rendererStartPosition = 0;
-        unsigned rendererEndPosition = 0;
-        bool found = flowContents.resolveRendererPositions(*startRenderer, rendererStartPosition, rendererEndPosition);
-        ASSERT_UNUSED(found, found);
-
         // 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.
-        float logicalRightOfLeftRun = run.logicalLeft + flowContents.textWidth(run.start, rendererEndPosition, run.logicalLeft);
-        lineRuns.insert(runIndex, Run(run.start, rendererEndPosition, run.logicalLeft, logicalRightOfLeftRun, false));
+        float logicalRightOfLeftRun = run.logicalLeft + flowContents.textWidth(run.start, startSegment.end, run.logicalLeft);
+        lineRuns.insert(runIndex, Run(run.start, startSegment.end, run.logicalLeft, logicalRightOfLeftRun, false));
         Run& rightSideRun = lineRuns.at(runIndex + 1);
-        rightSideRun.start = rendererEndPosition;
+        rightSideRun.start = startSegment.end;
         rightSideRun.logicalLeft = logicalRightOfLeftRun;
     } while (++runIndex < lineRuns.size());
 }
@@ -638,8 +635,7 @@
         closeLineEndingAndAdjustRuns(lineState, runs, lineCount, flowContents);
     } while (!isEndOfContent);
 
-    if (flow.firstChild() != flow.lastChild())
-        splitRunsAtRendererBoundary(runs, flowContents);
+    splitRunsAtRendererBoundary(runs, flowContents);
     ASSERT(!lineState.uncommittedWidth);
 }
 

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp (176509 => 176510)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp	2014-11-23 18:00:52 UTC (rev 176509)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp	2014-11-23 18:46:18 UTC (rev 176510)
@@ -46,22 +46,26 @@
 {
 }
 
-FlowContents::FlowContents(const RenderBlockFlow& flow)
-    : m_style(flow.style())
-    , m_lineBreakIterator(downcast<RenderText>(*flow.firstChild()).text(), flow.style().locale())
-    , m_lastRendererIndex(0)
+static Vector<FlowContents::Segment> initializeSegments(const RenderBlockFlow& flow)
 {
+    Vector<FlowContents::Segment, 8> segments;
     unsigned startPosition = 0;
     for (auto& textChild : childrenOfType<RenderText>(flow)) {
-        unsigned contentLength = textChild.text()->length();
-        m_textRanges.append(std::make_pair(startPosition, &textChild));
-        startPosition += contentLength;
+        unsigned textLength = textChild.text()->length();
+        segments.append(FlowContents::Segment { startPosition, startPosition + textLength, textChild });
+        startPosition += textLength;
     }
-    // End item.
-    const RenderText* closingNullItem = nullptr;
-    m_textRanges.append(std::make_pair(startPosition, closingNullItem));
+    return segments;
 }
 
+FlowContents::FlowContents(const RenderBlockFlow& flow)
+    : m_style(flow.style())
+    , m_segments(initializeSegments(flow))
+    , m_lineBreakIterator(downcast<RenderText>(*flow.firstChild()).text(), flow.style().locale())
+    , m_lastSegmentIndex(0)
+{
+}
+
 unsigned FlowContents::findNextBreakablePosition(unsigned position) const
 {
     String string = m_lineBreakIterator.string();
@@ -83,93 +87,59 @@
 
 float FlowContents::textWidth(unsigned from, unsigned to, float xPosition) const
 {
-    unsigned rendererStart = 0;
-    const RenderText* textRenderer = renderer(from, &rendererStart);
-    ASSERT(textRenderer);
-    // Resolved positions are relative to the renderers.
-    unsigned absoluteStart = from - rendererStart;
-    unsigned absoluteEnd = to - rendererStart;
-    if ((m_style.font.isFixedPitch() && textRenderer == renderer(to)) || (!absoluteStart && absoluteEnd == textRenderer->text()->length()))
-        return textRenderer->width(absoluteStart, to - from, m_style.font, xPosition, nullptr, nullptr);
+    auto& fromSegment = segmentForPosition(from);
 
-    // We need to split up the text and measure renderers individually due to ligature.
+    if ((m_style.font.isFixedPitch() && fromSegment.end >= to) || (from == fromSegment.start && to == fromSegment.end))
+        return fromSegment.renderer.width(from - fromSegment.start, to - from, m_style.font, xPosition, nullptr, nullptr);
+
+    auto* segment = &fromSegment;
     float textWidth = 0;
     unsigned fragmentEnd = 0;
-    do {
-        fragmentEnd = std::min(to, rendererStart + textRenderer->text()->length());
-        unsigned absoluteFragmentEnd = fragmentEnd - rendererStart;
-        absoluteStart = from - rendererStart;
-        textWidth += runWidth(*textRenderer, absoluteStart, absoluteFragmentEnd, xPosition + textWidth);
+    while (true) {
+        fragmentEnd = std::min(to, segment->end);
+        textWidth += runWidth(segment->renderer, from - segment->start, fragmentEnd - segment->start, xPosition + textWidth);
+        if (fragmentEnd == to)
+            break;
         from = fragmentEnd;
-        if (fragmentEnd < to)
-            textRenderer = renderer(fragmentEnd, &rendererStart);
-    } while (fragmentEnd < to && textRenderer);
+        segment = &segmentForPosition(fragmentEnd);
+    };
+
     return textWidth;
 }
 
-const RenderText* FlowContents::renderer(unsigned position, unsigned* rendererStartPosition) const
+const FlowContents::Segment& FlowContents::segmentForPositionSlow(unsigned position) const
 {
-    unsigned arraySize = m_textRanges.size();
-    // Take advantage of the usage pattern.
-    if (position >= m_textRanges.at(m_lastRendererIndex).first && m_lastRendererIndex + 1 < arraySize && position < m_textRanges.at(m_lastRendererIndex + 1).first) {
-        if (rendererStartPosition)
-            *rendererStartPosition = m_textRanges.at(m_lastRendererIndex).first;
-        return m_textRanges.at(m_lastRendererIndex).second;
-    }
-    unsigned left = 0;
-    unsigned right = arraySize - 1;
-    ASSERT(arraySize);
-    ASSERT(position >= 0);
-    while (left < right) {
-        unsigned middle = (left + right) / 2;
-        unsigned endPosition = m_textRanges.at(middle + 1).first;
-        if (position > endPosition)
-            left = middle + 1;
-        else if (position < endPosition)
-            right = middle;
-        else {
-            right = middle + 1;
-            break;
-        }
-    }
-    if (rendererStartPosition)
-        *rendererStartPosition = m_textRanges.at(right).first;
-    return m_textRanges.at(right).second;
+    auto it = std::lower_bound(m_segments.begin(), m_segments.end(), position, [](const Segment& segment, unsigned position) {
+        return segment.end <= position;
+    });
+    ASSERT(it != m_segments.end());
+    m_lastSegmentIndex = it - m_segments.begin();
+    return *it;
 }
 
-bool FlowContents::resolveRendererPositions(const RenderText& renderer, unsigned& startPosition, unsigned& endPosition) const
+const FlowContents::Segment& FlowContents::segmentForRenderer(const RenderText& renderer) const
 {
-    unsigned arraySize = m_textRanges.size();
-    if (!arraySize)
-        return false;
-
-    unsigned index = 0;
-    do {
-        auto range = m_textRanges.at(index);
-        if (range.second == &renderer) {
-            startPosition = range.first;
-            ASSERT(index + 1 < arraySize);
-            endPosition = m_textRanges.at(index + 1).first;
-            return true;
-        }
-    } while (++index < arraySize);
-    return false;
+    for (auto& segment : m_segments) {
+        if (&segment.renderer == &renderer)
+            return segment;
+    }
+    ASSERT_NOT_REACHED();
+    return m_segments.last();
 }
 
 bool FlowContents::appendNextRendererContentIfNeeded(unsigned position) const
 {
+    if (isEnd(position))
+        return false;
     String string = m_lineBreakIterator.string();
     if (position < string.length())
         return false;
 
     // Content needs to be requested sequentially.
     ASSERT(position == string.length());
-    const RenderText* nextRenderer = renderer(position);
-    if (!nextRenderer)
-        return false;
+    auto& segment = segmentForPosition(position);
 
-    ++m_lastRendererIndex;
-    m_lineBreakIterator.resetStringAndReleaseIterator(string + String(nextRenderer->text()), m_style.locale, LineBreakIteratorModeUAX14);
+    m_lineBreakIterator.resetStringAndReleaseIterator(string + String(segment.renderer.text()), m_style.locale, LineBreakIteratorModeUAX14);
     return true;
 }
 

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h (176509 => 176510)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h	2014-11-23 18:00:52 UTC (rev 176509)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h	2014-11-23 18:46:18 UTC (rev 176510)
@@ -46,11 +46,19 @@
     float textWidth(unsigned from, unsigned to, float xPosition) const;
 
     bool isNewlineCharacter(unsigned position) const;
-    bool isEndOfContent(unsigned position) const;
+    bool isEnd(unsigned position) const;
 
-    bool resolveRendererPositions(const RenderText&, unsigned& startPosition, unsigned& endPosition) const;
-    const RenderText* renderer(unsigned position, unsigned* startPosition = nullptr) const;
+    struct Segment {
+        unsigned start;
+        unsigned end;
+        const RenderText& renderer;
+    };
+    const Segment& segmentForPosition(unsigned) const;
+    const Segment& segmentForRenderer(const RenderText&) const;
 
+    bool hasOneSegment() const { return m_segments.size() == 1; }
+    unsigned length() const { return m_segments.last().end; };
+
     struct Style {
         explicit Style(const RenderStyle&);
 
@@ -67,14 +75,16 @@
     const Style& style() const { return m_style; }
 
 private:
+    const Segment& segmentForPositionSlow(unsigned) const;
     bool appendNextRendererContentIfNeeded(unsigned position) const;
     unsigned nextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const;
     float runWidth(const RenderText&, unsigned from, unsigned to, float xPosition) const;
 
     const Style m_style;
+    const Vector<Segment, 8> m_segments;
+
     mutable LazyLineBreakIterator m_lineBreakIterator;
-    Vector<std::pair<unsigned, const RenderText*>> m_textRanges;
-    mutable unsigned m_lastRendererIndex;
+    mutable unsigned m_lastSegmentIndex;
 };
 
 inline bool FlowContents::isNewlineCharacter(unsigned position) const
@@ -84,12 +94,22 @@
     return m_lineBreakIterator.string().at(position) == '\n';
 }
 
-inline bool FlowContents::isEndOfContent(unsigned position) const
+inline bool FlowContents::isEnd(unsigned position) const
 {
-    return position >= m_lineBreakIterator.string().length() && !renderer(position);
+    return position >= length();
 }
 
+inline const FlowContents::Segment& FlowContents::segmentForPosition(unsigned position) const
+{
+    ASSERT(!isEnd(position));
+
+    auto& lastSegment = m_segments[m_lastSegmentIndex];
+    if (lastSegment.start <= position && position < lastSegment.end)
+        return lastSegment;
+    return segmentForPositionSlow(position);
 }
+
 }
+}
 
 #endif

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp (176509 => 176510)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp	2014-11-23 18:00:52 UTC (rev 176509)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutResolver.cpp	2014-11-23 18:46:18 UTC (rev 176510)
@@ -76,11 +76,11 @@
 {
     auto& resolver = m_iterator.resolver();
     auto& run = m_iterator.simpleRun();
-    unsigned rendererOffset = 0;
-    const auto* renderer = resolver.m_flowContents.renderer(run.start, &rendererOffset);
-    ASSERT(renderer);
-    ASSERT(renderer->is8Bit());
-    return StringView(renderer->characters8(), renderer->textLength()).substring(run.start - rendererOffset, run.end - run.start);
+    auto& segment = resolver.m_flowContents.segmentForPosition(run.start);
+    ASSERT(segment.renderer.is8Bit());
+    // We currently split runs on segment boundaries (different RenderText).
+    ASSERT(run.end <= segment.end);
+    return StringView(segment.renderer.characters8(), segment.renderer.textLength()).substring(run.start - segment.start, run.end - run.start);
 }
 
 RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex, unsigned lineIndex)
@@ -156,13 +156,14 @@
 
 Range<RunResolver::Iterator> RunResolver::rangeForRenderer(const RenderText& renderer) const
 {
-    unsigned startPosition = 0;
-    unsigned endPosition = 0;
-    m_flowContents.resolveRendererPositions(renderer, startPosition, endPosition);
+    auto& segment = m_flowContents.segmentForRenderer(renderer);
+
     auto rangeBegin = begin();
-    for (;(*rangeBegin).start() < startPosition && rangeBegin != end(); ++rangeBegin) { }
+    for (;(*rangeBegin).start() < segment.start && rangeBegin != end(); ++rangeBegin) { }
+
     auto rangeEnd = rangeBegin;
-    for (;(*rangeEnd).end() <= endPosition && rangeEnd != end(); ++rangeEnd) { }
+    for (;(*rangeEnd).end() <= segment.end && rangeEnd != end(); ++rangeEnd) { }
+
     return Range<Iterator>(rangeBegin, rangeEnd);
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to