Simple line layout: Add support for word-break property.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 13 Jan 2016 17:08:35 +0000 (17:08 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 13 Jan 2016 17:08:35 +0000 (17:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=153054

Reviewed by Antti Koivisto.

This patch enables word-break property for simple line layout.
(https://drafts.csswg.org/css-text-3/#propdef-word-break)

word-break: normal and keep-all -> existing, non-(force)breaking behaviour.
            break-all -> breaks words when needed.

Covered by existing tests like fast/text/word-break.html

* rendering/SimpleLineLayout.cpp:
(WebCore::SimpleLineLayout::createLineRuns):
(WebCore::SimpleLineLayout::canUseForStyle): Deleted.
(WebCore::SimpleLineLayout::printReason): Deleted.
* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
(WebCore::SimpleLineLayout::TextFragmentIterator::findNextTextFragment):
* rendering/SimpleLineLayoutTextFragmentIterator.h:
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::TextFragment):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::operator==):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::isBreakable): Deleted.
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::split): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@194965 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/platform/efl/fast/text/word-break-expected.txt
LayoutTests/platform/gtk/fast/text/word-break-expected.txt
LayoutTests/platform/ios-simulator-wk1/fast/text/word-break-expected.txt
LayoutTests/platform/ios-simulator/fast/text/word-break-expected.txt
LayoutTests/platform/mac/fast/text/word-break-expected.txt
LayoutTests/platform/win/fast/text/word-break-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/rendering/SimpleLineLayout.cpp
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.h

index 8ae4178..a2193de 100644 (file)
@@ -27,7 +27,6 @@ layer at (0,0) size 785x1016
       RenderBlock {PRE} at (0,171) size 110x25 [border: (5px solid #000000)]
         RenderText {#text} at (5,5) size 448x15
           text run at (5,5) width 448: "Thislongwordshouldnotgetbrokenbutshouldstickoutofthepre."
-          text run at (453,5) width 0: " "
       RenderBlock (anonymous) at (0,209) size 769x72
         RenderBR {BR} at (0,0) size 0x17
         RenderText {#text} at (0,18) size 760x53
@@ -58,7 +57,6 @@ layer at (0,0) size 785x1016
           text run at (5,35) width 96: "brokenbutsho"
           text run at (5,50) width 96: "uldstickouto"
           text run at (5,65) width 64: "fthepre."
-          text run at (69,65) width 0: " "
       RenderBlock (anonymous) at (0,514) size 769x72
         RenderBR {BR} at (0,0) size 0x17
         RenderText {#text} at (0,18) size 764x53
index b9800db..034b5e1 100644 (file)
@@ -27,7 +27,6 @@ layer at (0,0) size 785x998
       RenderBlock {PRE} at (0,168) size 110x25 [border: (5px solid #000000)]
         RenderText {#text} at (5,5) size 448x15
           text run at (5,5) width 448: "Thislongwordshouldnotgetbrokenbutshouldstickoutofthepre."
-          text run at (453,5) width 0: " "
       RenderBlock (anonymous) at (0,206) size 769x68
         RenderBR {BR} at (0,0) size 0x17
         RenderText {#text} at (0,17) size 760x51
@@ -58,7 +57,6 @@ layer at (0,0) size 785x998
           text run at (5,35) width 96: "brokenbutsho"
           text run at (5,50) width 96: "uldstickouto"
           text run at (5,65) width 64: "fthepre."
-          text run at (69,65) width 0: " "
       RenderBlock (anonymous) at (0,506) size 769x68
         RenderBR {BR} at (0,0) size 0x17
         RenderText {#text} at (0,17) size 764x51
index ff9ac46..73ed847 100644 (file)
@@ -27,7 +27,6 @@ layer at (0,0) size 800x1028
       RenderBlock {PRE} at (0,171) size 110x24 [border: (5px solid #000000)]
         RenderText {#text} at (5,5) size 437x14
           text run at (5,5) width 437: "Thislongwordshouldnotgetbrokenbutshouldstickoutofthepre."
-          text run at (441,5) width 1: " "
       RenderBlock (anonymous) at (0,208) size 784x80
         RenderBR {BR} at (0,0) size 0x19
         RenderText {#text} at (0,20) size 774x59
@@ -58,7 +57,6 @@ layer at (0,0) size 800x1028
           text run at (5,33) width 94: "brokenbutsho"
           text run at (5,47) width 94: "uldstickouto"
           text run at (5,61) width 63: "fthepre."
-          text run at (67,61) width 1: " "
       RenderBlock (anonymous) at (0,512) size 784x80
         RenderBR {BR} at (0,0) size 0x19
         RenderText {#text} at (0,20) size 776x59
index 1b81301..3c3ce07 100644 (file)
@@ -27,7 +27,6 @@ layer at (0,0) size 800x1028
       RenderBlock {PRE} at (0,171) size 110x24 [border: (5px solid #000000)]
         RenderText {#text} at (5,5) size 437x14
           text run at (5,5) width 437: "Thislongwordshouldnotgetbrokenbutshouldstickoutofthepre."
-          text run at (441,5) width 1: " "
       RenderBlock (anonymous) at (0,208) size 784x80
         RenderBR {BR} at (0,0) size 0x19
         RenderText {#text} at (0,20) size 774x59
@@ -58,7 +57,6 @@ layer at (0,0) size 800x1028
           text run at (5,33) width 94: "brokenbutsho"
           text run at (5,47) width 94: "uldstickouto"
           text run at (5,61) width 63: "fthepre."
-          text run at (67,61) width 1: " "
       RenderBlock (anonymous) at (0,512) size 784x80
         RenderBR {BR} at (0,0) size 0x19
         RenderText {#text} at (0,20) size 776x59
index ba5220c..5725ae4 100644 (file)
@@ -27,7 +27,6 @@ layer at (0,0) size 785x1016
       RenderBlock {PRE} at (0,171) size 110x25 [border: (5px solid #000000)]
         RenderText {#text} at (5,5) size 437x15
           text run at (5,5) width 437: "Thislongwordshouldnotgetbrokenbutshouldstickoutofthepre."
-          text run at (441,5) width 1: " "
       RenderBlock (anonymous) at (0,209) size 769x72
         RenderBR {BR} at (0,0) size 0x18
         RenderText {#text} at (0,18) size 751x54
@@ -58,7 +57,6 @@ layer at (0,0) size 785x1016
           text run at (5,35) width 94: "brokenbutsho"
           text run at (5,50) width 94: "uldstickouto"
           text run at (5,65) width 63: "fthepre."
-          text run at (67,65) width 1: " "
       RenderBlock (anonymous) at (0,514) size 769x72
         RenderBR {BR} at (0,0) size 0x18
         RenderText {#text} at (0,18) size 750x54
index e2b3ff0..805f3d1 100644 (file)
@@ -27,7 +27,6 @@ layer at (0,0) size 785x1016
       RenderBlock {PRE} at (0,171) size 110x25 [border: (5px solid #000000)]
         RenderText {#text} at (5,5) size 448x15
           text run at (5,5) width 448: "Thislongwordshouldnotgetbrokenbutshouldstickoutofthepre."
-          text run at (453,5) width 0: " "
       RenderBlock (anonymous) at (0,209) size 769x72
         RenderBR {BR} at (0,0) size 0x18
         RenderText {#text} at (0,18) size 760x54
@@ -58,7 +57,6 @@ layer at (0,0) size 785x1016
           text run at (5,35) width 96: "brokenbutsho"
           text run at (5,50) width 96: "uldstickouto"
           text run at (5,65) width 64: "fthepre."
-          text run at (69,65) width 0: " "
       RenderBlock (anonymous) at (0,514) size 769x72
         RenderBR {BR} at (0,0) size 0x18
         RenderText {#text} at (0,18) size 764x54
index 663b789..8aad65d 100644 (file)
@@ -1,3 +1,31 @@
+2016-01-13  Zalan Bujtas  <zalan@apple.com>
+
+        Simple line layout: Add support for word-break property.
+        https://bugs.webkit.org/show_bug.cgi?id=153054
+
+        Reviewed by Antti Koivisto.
+
+        This patch enables word-break property for simple line layout.
+        (https://drafts.csswg.org/css-text-3/#propdef-word-break)
+
+        word-break: normal and keep-all -> existing, non-(force)breaking behaviour.
+                    break-all -> breaks words when needed.
+
+        Covered by existing tests like fast/text/word-break.html
+
+        * rendering/SimpleLineLayout.cpp:
+        (WebCore::SimpleLineLayout::createLineRuns):
+        (WebCore::SimpleLineLayout::canUseForStyle): Deleted.
+        (WebCore::SimpleLineLayout::printReason): Deleted.
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::findNextTextFragment):
+        * rendering/SimpleLineLayoutTextFragmentIterator.h:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::TextFragment):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::operator==):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::isBreakable): Deleted.
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragment::split): Deleted.
+
 2016-01-13  Said Abou-Hallawa  <sabouhallawa@apple.com>
 
         Reference cycle between SVGPathElement and SVGPathSegWithContext leaks Document
index 44e681d..6f9767c 100644 (file)
@@ -80,39 +80,38 @@ enum AvoidanceReason_ : uint64_t {
     FlowHasLineBoxContainProperty         = 1LLU  << 15,
     FlowIsNotTopToBottom                  = 1LLU  << 16,
     FlowHasLineBreak                      = 1LLU  << 17,
-    FlowHasWordBreak                      = 1LLU  << 18,
-    FlowHasNonNormalUnicodeBiDi           = 1LLU  << 19,
-    FlowHasRTLOrdering                    = 1LLU  << 20,
-    FlowHasLineAlignEdges                 = 1LLU  << 21,
-    FlowHasLineSnap                       = 1LLU  << 22,
-    FlowHasHypensAuto                     = 1LLU  << 23,
-    FlowHasTextEmphasisFillOrMark         = 1LLU  << 24,
-    FlowHasTextShadow                     = 1LLU  << 25,
-    FlowHasPseudoFirstLine                = 1LLU  << 26,
-    FlowHasPseudoFirstLetter              = 1LLU  << 27,
-    FlowHasTextCombine                    = 1LLU  << 28,
-    FlowHasTextFillBox                    = 1LLU  << 29,
-    FlowHasBorderFitLines                 = 1LLU  << 30,
-    FlowHasNonAutoLineBreak               = 1LLU  << 31,
-    FlowHasNonAutoTrailingWord            = 1LLU  << 32,
-    FlowHasSVGFont                        = 1LLU  << 33,
-    FlowTextIsEmpty                       = 1LLU  << 34,
-    FlowTextHasNoBreakSpace               = 1LLU  << 35,
-    FlowTextHasSoftHyphen                 = 1LLU  << 36,
-    FlowTextHasDirectionCharacter         = 1LLU  << 37,
-    FlowIsMissingPrimaryFont              = 1LLU  << 38,
-    FlowFontIsMissingGlyph                = 1LLU  << 39,
-    FlowTextIsCombineText                 = 1LLU  << 40,
-    FlowTextIsRenderCounter               = 1LLU  << 41,
-    FlowTextIsRenderQuote                 = 1LLU  << 42,
-    FlowTextIsTextFragment                = 1LLU  << 43,
-    FlowTextIsSVGInlineText               = 1LLU  << 44,
-    FlowFontIsNotSimple                   = 1LLU  << 45,
-    FeatureIsDisabled                     = 1LLU  << 46,
-    FlowHasNoParent                       = 1LLU  << 47,
-    FlowHasNoChild                        = 1LLU  << 48,
-    FlowChildIsSelected                   = 1LLU  << 49,
-    EndOfReasons                          = 1LLU  << 50
+    FlowHasNonNormalUnicodeBiDi           = 1LLU  << 18,
+    FlowHasRTLOrdering                    = 1LLU  << 19,
+    FlowHasLineAlignEdges                 = 1LLU  << 20,
+    FlowHasLineSnap                       = 1LLU  << 21,
+    FlowHasHypensAuto                     = 1LLU  << 22,
+    FlowHasTextEmphasisFillOrMark         = 1LLU  << 23,
+    FlowHasTextShadow                     = 1LLU  << 24,
+    FlowHasPseudoFirstLine                = 1LLU  << 25,
+    FlowHasPseudoFirstLetter              = 1LLU  << 26,
+    FlowHasTextCombine                    = 1LLU  << 27,
+    FlowHasTextFillBox                    = 1LLU  << 28,
+    FlowHasBorderFitLines                 = 1LLU  << 29,
+    FlowHasNonAutoLineBreak               = 1LLU  << 30,
+    FlowHasNonAutoTrailingWord            = 1LLU  << 31,
+    FlowHasSVGFont                        = 1LLU  << 32,
+    FlowTextIsEmpty                       = 1LLU  << 33,
+    FlowTextHasNoBreakSpace               = 1LLU  << 34,
+    FlowTextHasSoftHyphen                 = 1LLU  << 35,
+    FlowTextHasDirectionCharacter         = 1LLU  << 36,
+    FlowIsMissingPrimaryFont              = 1LLU  << 37,
+    FlowFontIsMissingGlyph                = 1LLU  << 38,
+    FlowTextIsCombineText                 = 1LLU  << 39,
+    FlowTextIsRenderCounter               = 1LLU  << 40,
+    FlowTextIsRenderQuote                 = 1LLU  << 41,
+    FlowTextIsTextFragment                = 1LLU  << 42,
+    FlowTextIsSVGInlineText               = 1LLU  << 43,
+    FlowFontIsNotSimple                   = 1LLU  << 44,
+    FeatureIsDisabled                     = 1LLU  << 45,
+    FlowHasNoParent                       = 1LLU  << 46,
+    FlowHasNoChild                        = 1LLU  << 47,
+    FlowChildIsSelected                   = 1LLU  << 48,
+    EndOfReasons                          = 1LLU  << 49
 };
 const unsigned NoReason = 0;
 
@@ -226,8 +225,6 @@ static AvoidanceReasonFlags canUseForStyle(const RenderStyle& style, IncludeReas
         SET_REASON_AND_RETURN_IF_NEEDED(FlowIsNotTopToBottom, reasons, includeReasons);
     if (style.lineBreak() != LineBreakAuto)
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasLineBreak, reasons, includeReasons);
-    if (style.wordBreak() != NormalWordBreak)
-        SET_REASON_AND_RETURN_IF_NEEDED(FlowHasWordBreak, reasons, includeReasons);
     if (style.unicodeBidi() != UBNormal)
         SET_REASON_AND_RETURN_IF_NEEDED(FlowHasNonNormalUnicodeBiDi, reasons, includeReasons);
     if (style.rtlOrdering() != LogicalOrder)
@@ -660,7 +657,7 @@ static bool createLineRuns(LineState& line, const LineState& previousLine, Layou
 {
     const auto& style = textFragmentIterator.style();
     line.setCollapedWhitespaceWidth(style.spaceWidth + style.wordSpacing);
-    bool lineCanBeWrapped = style.wrapLines || style.breakWordOnOverflow;
+    bool lineCanBeWrapped = style.wrapLines || style.breakFirstWordOnOverflow || style.breakAnyWordOnOverflow;
     auto fragment = firstFragment(textFragmentIterator, line, previousLine, runs);
     while (fragment.type() != TextFragmentIterator::TextFragment::ContentEnd) {
         // Hard linebreak.
@@ -678,7 +675,8 @@ static bool createLineRuns(LineState& line, const LineState& previousLine, Layou
             // 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.
+            // 5. Non-whitespace fragment when there's already another fragment on the line either gets wrapped (word-break: break-all)
+            // or gets pushed to the next line.
             bool emptyLine = line.isEmpty();
             // Whitespace fragment.
             if (fragment.type() == TextFragmentIterator::TextFragment::Whitespace) {
@@ -691,7 +689,7 @@ static bool createLineRuns(LineState& line, const LineState& previousLine, Layou
                 break;
             }
             // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
-            if ((emptyLine && style.breakWordOnOverflow) || !style.wrapLines) {
+            if (((emptyLine && style.breakFirstWordOnOverflow) || style.breakAnyWordOnOverflow) || !style.wrapLines) {
                 // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
                 line.setOverflowedFragment(splitFragmentToFitLine(fragment, line.availableWidth() - line.width(), emptyLine, textFragmentIterator));
                 line.appendFragmentAndCreateRunIfNeeded(fragment, runs);
@@ -841,9 +839,6 @@ static void printReason(AvoidanceReason reason, TextStream& stream)
     case FlowHasLineBreak:
         stream << "line-break property";
         break;
-    case FlowHasWordBreak:
-        stream << "word-break property";
-        break;
     case FlowHasNonNormalUnicodeBiDi:
         stream << "non-normal Unicode bidi";
         break;
index 1cd7d6f..2c70f1a 100644 (file)
@@ -39,7 +39,8 @@ TextFragmentIterator::Style::Style(const RenderStyle& style)
     , collapseWhitespace(style.collapseWhiteSpace())
     , preserveNewline(style.preserveNewline())
     , wrapLines(style.autoWrap())
-    , breakWordOnOverflow(style.overflowWrap() == BreakOverflowWrap && (wrapLines || preserveNewline))
+    , breakAnyWordOnOverflow(style.wordBreak() == BreakAllWordBreak && wrapLines)
+    , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || preserveNewline)))
     , spaceWidth(font.width(TextRun(StringView(&space, 1))))
     , wordSpacing(font.wordSpacing())
     , tabWidth(collapseWhitespace ? 0 : style.tabSize())
@@ -90,13 +91,12 @@ TextFragmentIterator::TextFragment TextFragmentIterator::findNextTextFragment(fl
     if (startPosition < endPosition) {
         bool multipleWhitespace = startPosition + 1 < endPosition;
         bool isCollapsed = multipleWhitespace && m_style.collapseWhitespace;
-        bool isBreakable = !isCollapsed && multipleWhitespace;
         m_position = endPosition;
-        return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, endPosition == segmentEndPosition, false, isCollapsed, m_style.collapseWhitespace, isBreakable);
+        return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, endPosition == segmentEndPosition, false, isCollapsed, m_style.collapseWhitespace);
     }
     endPosition = skipToNextPosition(PositionType::Breakable, startPosition, width, xPosition, overlappingFragment);
     m_position = endPosition;
-    return TextFragment(startPosition, endPosition, width, TextFragment::NonWhitespace, endPosition == segmentEndPosition, overlappingFragment, false, false, m_style.breakWordOnOverflow);
+    return TextFragment(startPosition, endPosition, width, TextFragment::NonWhitespace, endPosition == segmentEndPosition, overlappingFragment, false, false);
 }
 
 void TextFragmentIterator::revertToEndOfFragment(const TextFragment& fragment)
index 9275a99..4821dd9 100644 (file)
@@ -44,7 +44,7 @@ public:
     public:
         enum Type { ContentEnd, SoftLineBreak, HardLineBreak, Whitespace, NonWhitespace };
         TextFragment() = default;
-        TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false, bool isBreakable = false)
+        TextFragment(unsigned start, unsigned end, float width, Type type, bool isLastInRenderer = false, bool overlapsToNextRenderer = false, bool isCollapsed = false, bool isCollapsible = false)
             : m_start(start)
             , m_end(end)
             , m_width(width)
@@ -53,7 +53,6 @@ public:
             , m_overlapsToNextRenderer(overlapsToNextRenderer)
             , m_isCollapsed(isCollapsed)
             , m_isCollapsible(isCollapsible)
-            , m_isBreakable(isBreakable)
         {
         }
 
@@ -66,7 +65,6 @@ public:
         bool isLineBreak() const { return m_type == SoftLineBreak || m_type == HardLineBreak; }
         bool isCollapsed() const { return m_isCollapsed; }
         bool isCollapsible() const { return m_isCollapsible; }
-        bool isBreakable() const { return m_isBreakable; }
 
         bool isEmpty() const { return start() == end() && !isLineBreak(); }
         TextFragment split(unsigned splitPosition, const TextFragmentIterator&);
@@ -79,8 +77,7 @@ public:
                 && m_isLastInRenderer == other.m_isLastInRenderer
                 && m_overlapsToNextRenderer == other.m_overlapsToNextRenderer
                 && m_isCollapsed == other.m_isCollapsed
-                && m_isCollapsible == other.m_isCollapsible
-                && m_isBreakable == other.m_isBreakable;
+                && m_isCollapsible == other.m_isCollapsible;
         }
 
     private:
@@ -92,7 +89,6 @@ public:
         bool m_overlapsToNextRenderer { false };
         bool m_isCollapsed { false };
         bool m_isCollapsible { false };
-        bool m_isBreakable { false };
     };
     TextFragment nextTextFragment(float xPosition = 0);
     void revertToEndOfFragment(const TextFragment&);
@@ -106,7 +102,8 @@ public:
         bool collapseWhitespace;
         bool preserveNewline;
         bool wrapLines;
-        bool breakWordOnOverflow;
+        bool breakAnyWordOnOverflow;
+        bool breakFirstWordOnOverflow;
         float spaceWidth;
         float wordSpacing;
         unsigned tabWidth;
@@ -142,7 +139,6 @@ inline TextFragmentIterator::TextFragment TextFragmentIterator::TextFragment::sp
         if (fragment.start() + 1 > fragment.end())
             return;
         fragment.m_isCollapsed = false;
-        fragment.m_isBreakable = false;
     };
 
     TextFragment newFragment(*this);