Title: [159194] trunk/Source/WebCore
Revision
159194
Author
[email protected]
Date
2013-11-13 07:34:58 -0800 (Wed, 13 Nov 2013)

Log Message

Factor simple line creation loop to function
https://bugs.webkit.org/show_bug.cgi?id=124279

Reviewed by Andreas Kling.

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::Style::Style):
        
    Capture style that affects line layout to a struct.

(WebCore::SimpleLineLayout::textWidth):
(WebCore::SimpleLineLayout::measureWord):
(WebCore::SimpleLineLayout::createLineRuns):
        
    Factor the line loop here.

(WebCore::SimpleLineLayout::createTextRuns):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (159193 => 159194)


--- trunk/Source/WebCore/ChangeLog	2013-11-13 15:32:16 UTC (rev 159193)
+++ trunk/Source/WebCore/ChangeLog	2013-11-13 15:34:58 UTC (rev 159194)
@@ -1,3 +1,23 @@
+2013-11-13  Antti Koivisto  <[email protected]>
+
+        Factor simple line creation loop to function
+        https://bugs.webkit.org/show_bug.cgi?id=124279
+
+        Reviewed by Andreas Kling.
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::Style::Style):
+        
+            Capture style that affects line layout to a struct.
+
+        (WebCore::SimpleLineLayout::textWidth):
+        (WebCore::SimpleLineLayout::measureWord):
+        (WebCore::SimpleLineLayout::createLineRuns):
+        
+            Factor the line loop here.
+
+        (WebCore::SimpleLineLayout::createTextRuns):
+
 2013-11-12  Antti Koivisto  <[email protected]>
 
         Support overflow-wrap:break-word on simple line path

Modified: trunk/Source/WebCore/rendering/SimpleLineLayout.cpp (159193 => 159194)


--- trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2013-11-13 15:32:16 UTC (rev 159193)
+++ trunk/Source/WebCore/rendering/SimpleLineLayout.cpp	2013-11-13 15:34:58 UTC (rev 159194)
@@ -203,6 +203,28 @@
     return true;
 }
 
+struct Style {
+    Style(const RenderStyle& style)
+        : font(style.font())
+        , textAlign(style.textAlign())
+        , collapseWhitespace(style.collapseWhiteSpace())
+        , preserveNewline(style.preserveNewline())
+        , wrapLines(style.autoWrap())
+        , breakWordOnOverflow(style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline))
+        , spaceWidth(font.width(TextRun(&space, 1)))
+        , tabWidth(collapseWhitespace ? 0 : style.tabSize())
+    {
+    }
+    const Font& font;
+    ETextAlign textAlign;
+    bool collapseWhitespace;
+    bool preserveNewline;
+    bool wrapLines;
+    bool breakWordOnOverflow;
+    float spaceWidth;
+    unsigned tabWidth;
+};
+
 static inline bool isWhitespace(UChar character, bool preserveNewline)
 {
     return character == ' ' || character == '\t' || (!preserveNewline && character == '\n');
@@ -219,35 +241,138 @@
 }
 
 template <typename CharacterType>
-static float textWidth(const RenderText& renderText, const CharacterType* text, unsigned textLength, unsigned from, unsigned to, float xPosition, const Font& font, float tabWidth)
+static float textWidth(const RenderText& renderText, const CharacterType* text, unsigned textLength, unsigned from, unsigned to, float xPosition, const Style& style)
 {
-    if (font.isFixedPitch() || (!from && to == textLength))
-        return renderText.width(from, to - from, font, xPosition, nullptr, nullptr);
+    if (style.font.isFixedPitch() || (!from && to == textLength))
+        return renderText.width(from, to - from, style.font, xPosition, nullptr, nullptr);
 
     TextRun run(text + from, to - from);
     run.setXPos(xPosition);
     run.setCharactersLength(textLength - from);
-    run.setTabSize(!!tabWidth, tabWidth);
+    run.setTabSize(!!style.tabWidth, style.tabWidth);
 
     ASSERT(run.charactersLength() >= run.length());
 
-    return font.width(run);
+    return style.font.width(run);
 }
 
 template <typename CharacterType>
-static float measureWord(const RenderText& textRenderer, const CharacterType* text, unsigned textLength, unsigned start, unsigned end, float lineWidth, bool collapseWhitespace, const Font& font, float tabWidth, float spaceWidth)
+static float measureWord(unsigned start, unsigned end, float lineWidth, const Style& style, const CharacterType* text, unsigned textLength, const RenderText& textRenderer)
 {
     if (text[start] == ' ' && end == start + 1)
-        return spaceWidth;
+        return style.spaceWidth;
 
-    bool measureWithEndSpace = collapseWhitespace && end < textLength && text[end] == ' ';
+    bool measureWithEndSpace = style.collapseWhitespace && end < textLength && text[end] == ' ';
     if (measureWithEndSpace)
         ++end;
-    float width = textWidth(textRenderer, text, textLength, start, end, lineWidth, font, collapseWhitespace ? 0 : tabWidth);
+    float width = textWidth(textRenderer, text, textLength, start, end, lineWidth, style);
 
-    return measureWithEndSpace ? width - spaceWidth : width;
+    return measureWithEndSpace ? width - style.spaceWidth : width;
 }
 
+template <typename CharacterType>
+Vector<Run, 4> createLineRuns(unsigned lineStart, LineWidth& lineWidth, LazyLineBreakIterator& lineBreakIterator, const Style& style, const CharacterType* text, unsigned textLength, const RenderText& textRenderer)
+{
+    Vector<Run, 4> lineRuns;
+    lineRuns.uncheckedAppend(Run(lineStart, 0));
+
+    unsigned wordEnd = lineStart;
+    while (wordEnd < textLength) {
+        ASSERT(!style.collapseWhitespace || !isWhitespace(text[wordEnd], style.preserveNewline));
+
+        unsigned wordStart = wordEnd;
+
+        if (style.preserveNewline && text[wordStart] == '\n') {
+            ++wordEnd;
+            // FIXME: This creates a dedicated run for newline. This is wasteful and unnecessary but it keeps test results unchanged.
+            if (wordStart > lineStart)
+                lineRuns.append(Run(wordStart, lineRuns.last().right));
+            lineRuns.last().right = lineRuns.last().left;
+            lineRuns.last().end = wordEnd;
+            break;
+        }
+
+        if (!style.collapseWhitespace && isWhitespace(text[wordStart], style.preserveNewline))
+            wordEnd = wordStart + 1;
+        else
+            wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordStart + 1);
+
+        bool wordIsPrecededByWhitespace = style.collapseWhitespace && wordStart > lineStart && isWhitespace(text[wordStart - 1], style.preserveNewline);
+        if (wordIsPrecededByWhitespace)
+            --wordStart;
+
+        float wordWidth = measureWord(wordStart, wordEnd, lineWidth.committedWidth(), style, text, textLength, textRenderer);
+
+        lineWidth.addUncommittedWidth(wordWidth);
+
+        if (style.wrapLines) {
+            // Move to the next line if the current one is full and we have something on it.
+            if (!lineWidth.fitsOnLine() && lineWidth.committedWidth())
+                break;
+
+            // This is for white-space: pre-wrap which requires special handling for end line whitespace.
+            if (!style.collapseWhitespace && lineWidth.fitsOnLine() && wordEnd < textLength && isWhitespace(text[wordEnd], style.preserveNewline)) {
+                // Look ahead to see if the next whitespace would fit.
+                float whitespaceWidth = textWidth(textRenderer, text, textLength, wordEnd, wordEnd + 1, lineWidth.committedWidth(), style);
+                if (!lineWidth.fitsOnLineIncludingExtraWidth(whitespaceWidth)) {
+                    // If not eat away the rest of the whitespace on the line.
+                    unsigned whitespaceEnd = skipWhitespaces(text, wordEnd, textLength, style.preserveNewline);
+                    // Include newline to this run too.
+                    if (whitespaceEnd < textLength && text[whitespaceEnd] == '\n')
+                        ++whitespaceEnd;
+                    lineRuns.last().end = whitespaceEnd;
+                    lineRuns.last().right = lineWidth.availableWidth();
+                    break;
+                }
+            }
+        }
+
+        if (wordStart > lineRuns.last().end) {
+            // There were more than one consecutive whitespace.
+            ASSERT(wordIsPrecededByWhitespace);
+            // Include space to the end of the previous run.
+            lineRuns.last().end++;
+            lineRuns.last().right += style.spaceWidth;
+            // Start a new run on the same line.
+            lineRuns.append(Run(wordStart + 1, lineRuns.last().right));
+        }
+
+        if (!lineWidth.fitsOnLine() && style.breakWordOnOverflow) {
+            // Backtrack and start measuring character-by-character.
+            lineWidth.addUncommittedWidth(-lineWidth.uncommittedWidth());
+            unsigned splitEnd = wordStart;
+            for (; splitEnd < wordEnd; ++splitEnd) {
+                float charWidth = textWidth(textRenderer, text, textLength, splitEnd, splitEnd + 1, 0, style);
+                lineWidth.addUncommittedWidth(charWidth);
+                if (!lineWidth.fitsOnLine() && splitEnd > lineStart)
+                    break;
+                lineWidth.commit();
+            }
+            lineRuns.last().end = splitEnd;
+            lineRuns.last().right = lineWidth.committedWidth();
+            // To match line boxes, set single-space-only line width to zero.
+            if (text[lineRuns.last().start] == ' ' && lineRuns.last().start + 1 == lineRuns.last().end)
+                lineRuns.last().right = lineRuns.last().left;
+            break;
+        }
+
+        lineWidth.commit();
+
+        lineRuns.last().right = lineWidth.committedWidth();
+        lineRuns.last().end = wordEnd;
+
+        if (style.collapseWhitespace)
+            wordEnd = skipWhitespaces(text, wordEnd, textLength, style.preserveNewline);
+
+        if (!lineWidth.fitsOnLine() && style.wrapLines) {
+            // The first run on the line overflows.
+            ASSERT(lineRuns.size() == 1);
+            break;
+        }
+    }
+    return lineRuns;
+}
+
 static float computeLineLeft(ETextAlign textAlign, float remainingWidth)
 {
     switch (textAlign) {
@@ -282,137 +407,30 @@
 template <typename CharacterType>
 void createTextRuns(Layout::RunVector& runs, unsigned& lineCount, RenderBlockFlow& flow, RenderText& textRenderer)
 {
-    const RenderStyle& style = flow.style();
+    const Style style(flow.style());
 
-    // These properties are supported.
-    const Font& font = style.font();
-    unsigned tabWidth = style.tabSize();
-    ETextAlign textAlign = style.textAlign(); // Not 'justify'.
-    bool collapseWhitespace = style.collapseWhiteSpace();
-    bool preserveNewline = style.preserveNewline();
-    bool wrapLines = style.autoWrap();
-    bool breakWordOnOverflow = style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline);
-
     const CharacterType* text = textRenderer.text()->getCharacters<CharacterType>();
     const unsigned textLength = textRenderer.textLength();
 
-    float spaceWidth = font.width(TextRun(&space, 1));
-    LazyLineBreakIterator lineBreakIterator(textRenderer.text(), style.locale());
+    LazyLineBreakIterator lineBreakIterator(textRenderer.text(), flow.style().locale());
 
     unsigned lineEnd = 0;
     while (lineEnd < textLength) {
-        if (collapseWhitespace)
-            lineEnd = skipWhitespaces(text, lineEnd, textLength, preserveNewline);
+        if (style.collapseWhitespace)
+            lineEnd = skipWhitespaces(text, lineEnd, textLength, style.preserveNewline);
+
         unsigned lineStart = lineEnd;
-        unsigned wordEnd = lineEnd;
+
         LineWidth lineWidth(flow, false, DoNotIndentText);
+        auto lineRuns = createLineRuns(lineStart, lineWidth, lineBreakIterator, style, text, textLength, textRenderer);
 
-        Vector<Run, 4> lineRuns;
-        lineRuns.uncheckedAppend(Run(lineStart, 0));
-
-        while (wordEnd < textLength) {
-            ASSERT(!collapseWhitespace || !isWhitespace(text[wordEnd], preserveNewline));
-
-            unsigned wordStart = wordEnd;
-
-            if (preserveNewline && text[wordStart] == '\n') {
-                ++wordEnd;
-                // FIXME: This creates a dedicated run for newline. This is wasteful and unnecessary but it keeps test results unchanged.
-                if (wordStart > lineStart)
-                    lineRuns.append(Run(lineEnd, lineRuns.last().right));
-                lineRuns.last().right = lineRuns.last().left;
-                lineRuns.last().end = lineEnd + 1;
-                lineEnd = wordEnd;
-                break;
-            }
-
-            if (!collapseWhitespace && isWhitespace(text[wordStart], preserveNewline))
-                wordEnd = wordStart + 1;
-            else
-                wordEnd = nextBreakablePosition<CharacterType, false>(lineBreakIterator, text, textLength, wordStart + 1);
-
-            bool wordIsPrecededByWhitespace = collapseWhitespace && wordStart > lineStart && isWhitespace(text[wordStart - 1], preserveNewline);
-            if (wordIsPrecededByWhitespace)
-                --wordStart;
-
-            float wordWidth = measureWord(textRenderer, text, textLength, wordStart, wordEnd, lineWidth.committedWidth(), collapseWhitespace, font, tabWidth, spaceWidth);
-
-            lineWidth.addUncommittedWidth(wordWidth);
-
-            if (wrapLines) {
-                // Move to the next line if the current one is full and we have something on it.
-                if (!lineWidth.fitsOnLine() && lineWidth.committedWidth())
-                    break;
-
-                // This is for white-space: pre-wrap which requires special handling for end line whitespace.
-                if (!collapseWhitespace && lineWidth.fitsOnLine() && wordEnd < textLength && isWhitespace(text[wordEnd], preserveNewline)) {
-                    // Look ahead to see if the next whitespace would fit.
-                    float whitespaceWidth = textWidth(textRenderer, text, textLength, wordEnd, wordEnd + 1, lineWidth.committedWidth(), font, tabWidth);
-                    if (!lineWidth.fitsOnLineIncludingExtraWidth(whitespaceWidth)) {
-                        // If not eat away the rest of the whitespace on the line.
-                        unsigned whitespaceEnd = skipWhitespaces(text, wordEnd, textLength, preserveNewline);
-                        // Include newline to this run too.
-                        if (whitespaceEnd < textLength && text[whitespaceEnd] == '\n')
-                            ++whitespaceEnd;
-                        lineRuns.last().end = whitespaceEnd;
-                        lineRuns.last().right = lineWidth.availableWidth();
-                        lineEnd = whitespaceEnd;
-                        break;
-                    }
-                }
-            }
-
-            if (wordStart > lineEnd) {
-                // There were more than one consecutive whitespace.
-                ASSERT(wordIsPrecededByWhitespace);
-                // Include space to the end of the previous run.
-                lineRuns.last().end++;
-                lineRuns.last().right += spaceWidth;
-                // Start a new run on the same line.
-                lineRuns.append(Run(wordStart + 1, lineRuns.last().right));
-            }
-
-            if (!lineWidth.fitsOnLine() && breakWordOnOverflow) {
-                // Backtrack and start measuring character-by-character.
-                lineWidth.addUncommittedWidth(-lineWidth.uncommittedWidth());
-                unsigned splitEnd = wordStart;
-                for (; splitEnd < wordEnd; ++splitEnd) {
-                    float charWidth = textWidth(textRenderer, text, textLength, splitEnd, splitEnd + 1, 0, font, tabWidth);
-                    lineWidth.addUncommittedWidth(charWidth);
-                    if (!lineWidth.fitsOnLine() && splitEnd > lineStart)
-                        break;
-                    lineWidth.commit();
-                }
-                lineRuns.last().end = splitEnd;
-                lineRuns.last().right = lineWidth.committedWidth();
-                lineEnd = splitEnd;
-                // To match line boxes, set single-space-only line width to zero.
-                if (text[lineRuns.last().start] == ' ' && lineRuns.last().start + 1 == lineRuns.last().end)
-                    lineRuns.last().right = lineRuns.last().left;
-                break;
-            }
-
-            lineWidth.commit();
-
-            lineRuns.last().right = lineWidth.committedWidth();
-            lineRuns.last().end = wordEnd;
-
-            lineEnd = wordEnd;
-            if (collapseWhitespace)
-                wordEnd = skipWhitespaces(text, wordEnd, textLength, preserveNewline);
-
-            if (!lineWidth.fitsOnLine() && wrapLines) {
-                // The first run on the line overflows.
-                ASSERT(lineRuns.size() == 1);
-                break;
-            }
-        }
+        lineEnd = lineRuns.last().end;
         if (lineStart == lineEnd)
             continue;
 
         lineRuns.last().isEndOfLine = true;
 
-        float lineLeft = computeLineLeft(textAlign, lineWidth.availableWidth() - lineWidth.committedWidth());
+        float lineLeft = computeLineLeft(style.textAlign, lineWidth.availableWidth() - lineWidth.committedWidth());
         adjustRunOffsets(lineRuns, lineLeft);
 
         for (unsigned i = 0; i < lineRuns.size(); ++i)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to