Title: [179185] trunk/Source/WebCore
Revision
179185
Author
[email protected]
Date
2015-01-27 09:01:07 -0800 (Tue, 27 Jan 2015)

Log Message

Simple line layout: Make FlowContents an iterator class.
https://bugs.webkit.org/show_bug.cgi?id=140909

Reviewed by Antti Koivisto.

This patch transfers content position handling from createLineRuns()/LineState to
FlowContents. FlowContents becomes a real iterator class.
It tightens content and position information so that we can start supporting
no textual content such as <br>.

No change in functionality.

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::LineState::commitAndCreateRun): Remove redundant committedLogicalRight.
(WebCore::SimpleLineLayout::LineState::addUncommitted): Now that we don't have current
positon in LineState, we need to be able to figure out where we start the uncommitted content.
This is mainly relevant after collapsed whitespace, when we start a new uncommitted segment.
It was previously achieved through LineState::jumpTo().
(WebCore::SimpleLineLayout::LineState::removeTrailingWhitespace):
(WebCore::SimpleLineLayout::firstFragment): Return the first fragment for this line.
(WebCore::SimpleLineLayout::createLineRuns): Renaming and removing position handling.
(WebCore::SimpleLineLayout::closeLineEndingAndAdjustRuns): Renaming.
(WebCore::SimpleLineLayout::createTextRuns):
(WebCore::SimpleLineLayout::LineState::jumpTo): Deleted.
(WebCore::SimpleLineLayout::initializeNewLine): Deleted. : Move overflow fragment functionality
to firstFragment().
* rendering/SimpleLineLayoutFlowContents.cpp:
(WebCore::SimpleLineLayout::FlowContents::nextTextFragment):
* rendering/SimpleLineLayoutFlowContents.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (179184 => 179185)


--- trunk/Source/WebCore/ChangeLog	2015-01-27 17:00:08 UTC (rev 179184)
+++ trunk/Source/WebCore/ChangeLog	2015-01-27 17:01:07 UTC (rev 179185)
@@ -1,3 +1,35 @@
+2015-01-27  Zalan Bujtas  <[email protected]>
+
+        Simple line layout: Make FlowContents an iterator class.
+        https://bugs.webkit.org/show_bug.cgi?id=140909
+
+        Reviewed by Antti Koivisto.
+
+        This patch transfers content position handling from createLineRuns()/LineState to
+        FlowContents. FlowContents becomes a real iterator class.
+        It tightens content and position information so that we can start supporting
+        no textual content such as <br>.
+
+        No change in functionality.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::LineState::commitAndCreateRun): Remove redundant committedLogicalRight.
+        (WebCore::SimpleLineLayout::LineState::addUncommitted): Now that we don't have current
+        positon in LineState, we need to be able to figure out where we start the uncommitted content.
+        This is mainly relevant after collapsed whitespace, when we start a new uncommitted segment.
+        It was previously achieved through LineState::jumpTo().
+        (WebCore::SimpleLineLayout::LineState::removeTrailingWhitespace):
+        (WebCore::SimpleLineLayout::firstFragment): Return the first fragment for this line.
+        (WebCore::SimpleLineLayout::createLineRuns): Renaming and removing position handling.
+        (WebCore::SimpleLineLayout::closeLineEndingAndAdjustRuns): Renaming.
+        (WebCore::SimpleLineLayout::createTextRuns):
+        (WebCore::SimpleLineLayout::LineState::jumpTo): Deleted.
+        (WebCore::SimpleLineLayout::initializeNewLine): Deleted. : Move overflow fragment functionality
+        to firstFragment().
+        * rendering/SimpleLineLayoutFlowContents.cpp:
+        (WebCore::SimpleLineLayout::FlowContents::nextTextFragment):
+        * rendering/SimpleLineLayoutFlowContents.h:
+
 2015-01-27  Chris Dumez  <[email protected]>
 
         HTMLElement.dir should only return known values

Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (179184 => 179185)


--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2015-01-27 17:00:08 UTC (rev 179184)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2015-01-27 17:01:07 UTC (rev 179185)
@@ -232,10 +232,9 @@
         if (uncommittedStart == uncommittedEnd)
             return;
 
-        lineRuns.append(Run(uncommittedStart, uncommittedEnd, committedLogicalRight, committedLogicalRight + uncommittedWidth, false));
+        lineRuns.append(Run(uncommittedStart, uncommittedEnd, committedWidth, committedWidth + uncommittedWidth, false));
         // Move uncommitted to committed.
         committedWidth += uncommittedWidth;
-        committedLogicalRight += committedWidth;
         committedTrailingWhitespaceWidth = uncomittedTrailingWhitespaceWidth;
         committedTrailingWhitespaceLength = uncomittedTrailingWhitespaceLength;
         if (!m_firstCharacterFits)
@@ -245,16 +244,20 @@
         uncommittedWidth = 0;
         uncomittedTrailingWhitespaceWidth = 0;
         uncomittedTrailingWhitespaceLength = 0;
+        m_newUncommittedSegment = true;
     }
 
     void addUncommitted(const FlowContents::TextFragment& fragment)
     {
-        unsigned uncomittedFragmentLength = fragment.end - uncommittedEnd;
+        // Start a new uncommitted segment.
+        if (m_newUncommittedSegment) {
+            uncommittedStart = fragment.start;
+            m_newUncommittedSegment = false;
+        }
         uncommittedWidth += fragment.width;
         uncommittedEnd = fragment.end;
-        position = uncommittedEnd;
         uncomittedTrailingWhitespaceWidth = fragment.type == FlowContents::TextFragment::Whitespace ? fragment.width : 0;
-        uncomittedTrailingWhitespaceLength = fragment.type == FlowContents::TextFragment::Whitespace ? uncomittedFragmentLength  : 0;
+        uncomittedTrailingWhitespaceLength = fragment.type == FlowContents::TextFragment::Whitespace ? fragment.end - fragment.start  : 0;
     }
 
     void addUncommittedWhitespace(float whitespaceWidth)
@@ -262,16 +265,6 @@
         addUncommitted(FlowContents::TextFragment(uncommittedEnd, uncommittedEnd + 1, whitespaceWidth, true));
     }
 
-    void jumpTo(unsigned newPositon, float logicalRight)
-    {
-        position = newPositon;
-
-        uncommittedStart = newPositon;
-        uncommittedEnd = newPositon;
-        uncommittedWidth = 0;
-        committedLogicalRight = logicalRight;
-    }
-
     bool hasWhitespaceOnly() const
     {
         return committedTrailingWhitespaceWidth && committedWidth == committedTrailingWhitespaceWidth;
@@ -290,29 +283,25 @@
     void removeTrailingWhitespace()
     {
         committedWidth -= committedTrailingWhitespaceWidth;
-        committedLogicalRight -= committedTrailingWhitespaceWidth;
         committedTrailingWhitespaceWidth = 0;
         committedTrailingWhitespaceLength = 0;
     }
 
     float availableWidth { 0 };
     float logicalLeftOffset { 0 };
-    unsigned lineStartRunIndex { 0 }; // The run that the line starts with.
-    unsigned position { 0 };
 
     unsigned uncommittedStart { 0 };
     unsigned uncommittedEnd { 0 };
     float uncommittedWidth { 0 };
     float committedWidth { 0 };
-
-    float committedLogicalRight { 0 }; // Last committed X (coordinate) position.
     float committedTrailingWhitespaceWidth { 0 }; // Use this to remove trailing whitespace without re-mesuring the text.
     unsigned committedTrailingWhitespaceLength { 0 };
     // Having one character on the line does not necessarily mean it actually fits.
     // First character of the first fragment might be forced on to the current line even if it does not fit.
     bool m_firstCharacterFits { false };
+    bool m_newUncommittedSegment { true };
 
-    FlowContents::TextFragment oveflowedFragment;
+    FlowContents::TextFragment overflowedFragment;
 
 private:
     float uncomittedTrailingWhitespaceWidth { 0 };
@@ -356,47 +345,6 @@
     availableWidth = std::max<float>(0, logicalRightOffset - logicalLeftOffset);
 }
 
-static LineState initializeNewLine(const LineState& previousLine, const RenderBlockFlow& flow, const FlowContents& flowContents, unsigned lineStartRunIndex)
-{
-    LineState lineState;
-    lineState.jumpTo(previousLine.position, 0);
-    lineState.lineStartRunIndex = lineStartRunIndex;
-    updateLineConstrains(flow, lineState.availableWidth, lineState.logicalLeftOffset);
-
-    // Handle overflowed fragment from previous line.
-    auto overflowedFragment = previousLine.oveflowedFragment;
-    unsigned linePositon = previousLine.position;
-    // Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
-    // When the line is too short to fit one character (thought it still stays on the line) we continue with the overflow whitespace content on this line.
-    const auto& style = flowContents.style();
-    if (overflowedFragment.type == FlowContents::TextFragment::Whitespace && preWrap(style) && previousLine.m_firstCharacterFits) {
-        linePositon = overflowedFragment.end;
-        overflowedFragment = FlowContents::TextFragment();
-        // If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
-        if (flowContents.isLineBreak(linePositon))
-            ++linePositon;
-    }
-
-    if (overflowedFragment.isEmpty()) {
-        if (style.collapseWhitespace) {
-            auto firstFragment = flowContents.nextTextFragment(linePositon, 0);
-            if (firstFragment.type == FlowContents::TextFragment::Whitespace)
-                linePositon = firstFragment.end;
-        }
-        lineState.jumpTo(linePositon, 0);
-        return lineState;
-    }
-
-    if (lineState.fits(overflowedFragment.width)) {
-        lineState.addUncommitted(overflowedFragment);
-        return lineState;
-    }
-
-    // Start over with this fragment.
-    lineState.jumpTo(overflowedFragment.start, 0);
-    return lineState;
-}
-
 static FlowContents::TextFragment splitFragmentToFitLine(FlowContents::TextFragment& fragmentToSplit, float availableWidth, bool keepAtLeastOneCharacter, const FlowContents& flowContents)
 {
     // Fast path for single char fragments.
@@ -438,88 +386,107 @@
     return fragmentForNextLine;
 }
 
-static bool createLineRuns(LineState& lineState, Layout::RunVector& lineRuns, const FlowContents& flowContents)
+static FlowContents::TextFragment firstFragment(FlowContents& flowContents, const LineState& previousLine)
 {
+    // Handle overflowed fragment from previous line.
+    FlowContents::TextFragment firstFragment = previousLine.overflowedFragment;
     const auto& style = flowContents.style();
+
+    if (firstFragment.isEmpty())
+        firstFragment = flowContents.nextTextFragment();
+    else {
+        // Special overflow pre-wrap whitespace handling: ignore the overflowed whitespace if we managed to fit at least one character on the previous line.
+        // When the line is too short to fit one character (thought it still stays on the line) we continue with the overflow whitespace content on this line.
+        if (firstFragment.type == FlowContents::TextFragment::Whitespace && preWrap(style) && previousLine.m_firstCharacterFits) {
+            firstFragment = flowContents.nextTextFragment();
+            // If skipping the whitespace puts us on a hard newline, skip the newline too as we already wrapped the line.
+            if (firstFragment.type == FlowContents::TextFragment::LineBreak)
+                firstFragment = flowContents.nextTextFragment();
+        }
+    }
+
+    // Check if we need to skip the leading whitespace.
+    if (style.collapseWhitespace && firstFragment.type == FlowContents::TextFragment::Whitespace)
+        firstFragment = flowContents.nextTextFragment();
+    return firstFragment;
+}
+
+static bool createLineRuns(LineState& line, const LineState& previousLine, Layout::RunVector& lineRuns, FlowContents& flowContents)
+{
+    const auto& style = flowContents.style();
     bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
-    while (!flowContents.isEnd(lineState.position)) {
-        // Find the next text fragment.
-        auto fragment = flowContents.nextTextFragment(lineState.position, lineState.width());
+    auto fragment = firstFragment(flowContents, previousLine);
+    while (!fragment.isEmpty()) {
         // Hard linebreak.
         if (fragment.type == FlowContents::TextFragment::LineBreak) {
-            if (lineState.width()) {
-                // No need to add the new line fragment if there's already content on the line. We are about to close this line anyway.
-                ++lineState.position;
-            } else
-                lineState.addUncommitted(fragment);
+            // 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.)
+            if (!line.width())
+                line.addUncommitted(fragment);
             break;
         }
-        if (lineCanBeWrapped && !lineState.fits(fragment.width)) {
+        if (lineCanBeWrapped && !line.fits(fragment.width)) {
             // Overflow wrapping behaviour:
             // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
             // 2. Whitespace collapse off: whitespace is wrapped.
             // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
             // 4. Non-whitespace fragment when there's already another fragment on the line gets pushed to the next line.
-            bool emptyLine = !lineState.width();
+            bool emptyLine = !line.width();
             // Whitespace fragment.
             if (fragment.type == FlowContents::TextFragment::Whitespace) {
-                if (style.collapseWhitespace) {
-                    // Whitespace collapse is on: whitespace that doesn't fit is simply skipped.
-                    lineState.position = fragment.end;
-                    break;
+                if (!style.collapseWhitespace) {
+                    // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
+                    line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContents);
+                    line.addUncommitted(fragment);
                 }
-                // Split the fragment; (modified)fragment stays on this line, oveflowedFragment is pushed to next line.
-                lineState.oveflowedFragment = splitFragmentToFitLine(fragment, lineState.availableWidth - lineState.width(), emptyLine, flowContents);
-                lineState.addUncommitted(fragment);
+                // When whitespace collapse is on, whitespace that doesn't fit is simply skipped.
                 break;
             }
             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
             if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
-                // Split the fragment; (modified)fragment stays on this line, oveflowedFragment is pushed to next line.
-                lineState.oveflowedFragment = splitFragmentToFitLine(fragment, lineState.availableWidth - lineState.width(), emptyLine, flowContents);
-                lineState.addUncommitted(fragment);
+                // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
+                line.overflowedFragment = splitFragmentToFitLine(fragment, line.availableWidth - line.width(), emptyLine, flowContents);
+                line.addUncommitted(fragment);
                 break;
             }
             // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
             if (emptyLine) {
-                lineState.addUncommitted(fragment);
+                line.addUncommitted(fragment);
                 break;
             }
             // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
-            lineState.oveflowedFragment = fragment;
+            line.overflowedFragment = fragment;
             break;
         }
         // When the current fragment is collapsed whitespace, we need to create a run for what we've processed so far.
         if (fragment.isCollapsed) {
             // One trailing whitespace to preserve.
-            lineState.addUncommittedWhitespace(style.spaceWidth);
-            lineState.commitAndCreateRun(lineRuns);
-            // And skip the collapsed whitespace.
-            lineState.jumpTo(fragment.end, lineState.width() + fragment.width - style.spaceWidth);
+            line.addUncommittedWhitespace(style.spaceWidth);
+            line.commitAndCreateRun(lineRuns);
         } else
-            lineState.addUncommitted(fragment);
+            line.addUncommitted(fragment);
+        // Find the next text fragment.
+        fragment = flowContents.nextTextFragment(line.width());
     }
-    lineState.commitAndCreateRun(lineRuns);
-    return flowContents.isEnd(lineState.position) && lineState.oveflowedFragment.isEmpty();
+    line.commitAndCreateRun(lineRuns);
+    return fragment.isEmpty() && line.overflowedFragment.isEmpty();
 }
 
-static void closeLineEndingAndAdjustRuns(LineState& lineState, Layout::RunVector& lineRuns, unsigned& lineCount, const FlowContents& flowContents)
+static void closeLineEndingAndAdjustRuns(LineState& line, Layout::RunVector& runs, unsigned previousRunCount, unsigned& lineCount, const FlowContents& flowContents)
 {
-    if (lineState.lineStartRunIndex == lineRuns.size())
+    if (previousRunCount == runs.size())
         return;
-
-    ASSERT(lineRuns.size());
-    removeTrailingWhitespace(lineState, lineRuns, flowContents);
+    ASSERT(runs.size());
+    removeTrailingWhitespace(line, runs, flowContents);
+    if (!runs.size())
+        return;
     // Adjust runs' position by taking line's alignment into account.
-    if (float lineLogicalLeft = computeLineLeft(flowContents.style().textAlign, lineState.availableWidth, lineState.committedWidth, lineState.logicalLeftOffset)) {
-        for (unsigned i = lineState.lineStartRunIndex; i < lineRuns.size(); ++i) {
-            lineRuns[i].logicalLeft += lineLogicalLeft;
-            lineRuns[i].logicalRight += lineLogicalLeft;
+    if (float lineLogicalLeft = computeLineLeft(flowContents.style().textAlign, line.availableWidth, line.committedWidth, line.logicalLeftOffset)) {
+        for (unsigned i = previousRunCount; i < runs.size(); ++i) {
+            runs[i].logicalLeft += lineLogicalLeft;
+            runs[i].logicalRight += lineLogicalLeft;
         }
     }
-    lineRuns.last().isEndOfLine = true;
-    lineState.committedWidth = 0;
-    lineState.committedLogicalRight = 0;
+    runs.last().isEndOfLine = true;
     ++lineCount;
 }
 
@@ -552,19 +519,22 @@
 {
     LayoutUnit borderAndPaddingBefore = flow.borderAndPaddingBefore();
     LayoutUnit lineHeight = lineHeightFromFlow(flow);
-    LineState lineState;
+    LineState line;
     bool isEndOfContent = false;
     FlowContents flowContents = FlowContents(flow);
 
     do {
         flow.setLogicalHeight(lineHeight * lineCount + borderAndPaddingBefore);
-        lineState = initializeNewLine(lineState, flow, flowContents, runs.size());
-        isEndOfContent = createLineRuns(lineState, runs, flowContents);
-        closeLineEndingAndAdjustRuns(lineState, runs, lineCount, flowContents);
+        LineState previousLine = line;
+        unsigned previousRunCount = runs.size();
+        line = LineState();
+        updateLineConstrains(flow, line.availableWidth, line.logicalLeftOffset);
+        isEndOfContent = createLineRuns(line, previousLine, runs, flowContents);
+        closeLineEndingAndAdjustRuns(line, runs, previousRunCount, lineCount, flowContents);
     } while (!isEndOfContent);
 
     splitRunsAtRendererBoundary(runs, flowContents);
-    ASSERT(!lineState.uncommittedWidth);
+    ASSERT(!line.uncommittedWidth);
 }
 
 std::unique_ptr<Layout> create(RenderBlockFlow& flow)

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp (179184 => 179185)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp	2015-01-27 17:00:08 UTC (rev 179184)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.cpp	2015-01-27 17:01:07 UTC (rev 179185)
@@ -66,17 +66,23 @@
 {
 }
 
-FlowContents::TextFragment FlowContents::nextTextFragment(unsigned position, float xPosition) const
+FlowContents::TextFragment FlowContents::nextTextFragment(float xPosition)
 {
     // A fragment can either be
     // 1. new line character when preserveNewline is on (not considered as whitespace) or
     // 2. whitespace (collasped, non-collapsed multi or single) or
     // 3. non-whitespace characters.
+    // 4. empty, indicating content end.
     TextFragment fragment;
-    fragment.start = position;
+    fragment.start = m_position;
+    if (isEnd(fragment.start)) {
+        fragment.end = fragment.start;
+        return fragment;
+    }
     if (isLineBreak(fragment.start)) {
         fragment.type = TextFragment::LineBreak;
         fragment.end = fragment.start + 1;
+        m_position = fragment.end;
         return fragment;
     }
 
@@ -98,6 +104,7 @@
             else
                 fragment.width = textWidth(fragment.start, fragment.end, xPosition);
         }
+        m_position = fragment.end;
         return fragment;
     }
 
@@ -105,6 +112,7 @@
     fragment.isBreakable = m_style.breakWordOnOverflow;
     fragment.end = findNextBreakablePosition(fragment.start + 1);
     fragment.width = textWidth(fragment.start, fragment.end, xPosition);
+    m_position = fragment.end;
     return fragment;
 }
 

Modified: trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h (179184 => 179185)


--- trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h	2015-01-27 17:00:08 UTC (rev 179184)
+++ trunk/Source/WebCore/rendering/SimpleLineLayoutFlowContents.h	2015-01-27 17:01:07 UTC (rev 179185)
@@ -63,10 +63,8 @@
         bool isBreakable = false;
         float width = 0;
     };
-    TextFragment nextTextFragment(unsigned position, float xPosition) const;
+    TextFragment nextTextFragment(float xPosition = 0);
     float textWidth(unsigned from, unsigned to, float xPosition) const;
-    bool isLineBreak(unsigned position) const;
-    bool isEnd(unsigned position) const;
 
     struct Segment {
         unsigned start;
@@ -98,6 +96,8 @@
 private:
     unsigned findNextNonWhitespacePosition(unsigned position, unsigned& spaceCount) const;
     unsigned findNextBreakablePosition(unsigned position) const;
+    bool isLineBreak(unsigned position) const;
+    bool isEnd(unsigned position) const;
     unsigned segmentIndexForPosition(unsigned position) const;
     unsigned segmentIndexForPositionSlow(unsigned position) const;
 
@@ -109,6 +109,7 @@
 
     mutable LazyLineBreakIterator m_lineBreakIterator;
     mutable unsigned m_lastSegmentIndex;
+    unsigned m_position { 0 };
 };
 
 inline UChar FlowContents::characterAt(unsigned position) const
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to