[LFC][IFC] Make InlineTextItem reusable when 'segment break' behavior changes
https://bugs.webkit.org/show_bug.cgi?id=203184
<rdar://problem/56438945>

Reviewed by Antti Koivisto.

InlineTextItem::isWhitespace should dynamically check for 'preserve new line' behavior. This way we don't have to rebuild the inline item list
when the related style property value changes.

* layout/inlineformatting/InlineTextItem.cpp:
(WebCore::Layout::isWhitespaceCharacter):
(WebCore::Layout::moveToNextNonWhitespacePosition):
(WebCore::Layout::InlineTextItem::createAndAppendTextItems):
(WebCore::Layout::InlineTextItem::createWhitespaceItem):
(WebCore::Layout::InlineTextItem::createNonWhitespaceItem):
(WebCore::Layout::InlineTextItem::createSegmentBreakItem):
(WebCore::Layout::InlineTextItem::createEmptyItem):
(WebCore::Layout::InlineTextItem::InlineTextItem):
(WebCore::Layout::InlineTextItem::split const):
(WebCore::Layout::InlineTextItem::isWhitespace const):
(WebCore::Layout::isSoftLineBreak): Deleted.
* layout/inlineformatting/InlineTextItem.h:
(WebCore::Layout::InlineTextItem::isSegmentBreak const):
(WebCore::Layout::InlineTextItem::isWhitespace const): Deleted.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251330 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 12d8a96..bcb17e7 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,5 +1,32 @@
 2019-10-20  Zalan Bujtas  <zalan@apple.com>
 
+        [LFC][IFC] Make InlineTextItem reusable when 'segment break' behavior changes
+        https://bugs.webkit.org/show_bug.cgi?id=203184
+        <rdar://problem/56438945>
+
+        Reviewed by Antti Koivisto.
+
+        InlineTextItem::isWhitespace should dynamically check for 'preserve new line' behavior. This way we don't have to rebuild the inline item list
+        when the related style property value changes.
+
+        * layout/inlineformatting/InlineTextItem.cpp:
+        (WebCore::Layout::isWhitespaceCharacter):
+        (WebCore::Layout::moveToNextNonWhitespacePosition):
+        (WebCore::Layout::InlineTextItem::createAndAppendTextItems):
+        (WebCore::Layout::InlineTextItem::createWhitespaceItem):
+        (WebCore::Layout::InlineTextItem::createNonWhitespaceItem):
+        (WebCore::Layout::InlineTextItem::createSegmentBreakItem):
+        (WebCore::Layout::InlineTextItem::createEmptyItem):
+        (WebCore::Layout::InlineTextItem::InlineTextItem):
+        (WebCore::Layout::InlineTextItem::split const):
+        (WebCore::Layout::InlineTextItem::isWhitespace const):
+        (WebCore::Layout::isSoftLineBreak): Deleted.
+        * layout/inlineformatting/InlineTextItem.h:
+        (WebCore::Layout::InlineTextItem::isSegmentBreak const):
+        (WebCore::Layout::InlineTextItem::isWhitespace const): Deleted.
+
+2019-10-20  Zalan Bujtas  <zalan@apple.com>
+
         [LFC][IFC] Move the collapsed bit from InlineItems to runs
         https://bugs.webkit.org/show_bug.cgi?id=203183
 
diff --git a/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp b/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp
index 2c94efb..f79403c 100644
--- a/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineTextItem.cpp
@@ -33,20 +33,15 @@
 namespace WebCore {
 namespace Layout {
 
-static inline bool isWhitespaceCharacter(char character, bool preserveNewline)
+static inline bool isWhitespaceCharacter(char character)
 {
-    return character == ' ' || character == '\t' || (character == '\n' && !preserveNewline);
+    return character == ' ' || character == '\t';
 }
 
-static inline bool isSoftLineBreak(char character, bool preserveNewline)
-{
-    return preserveNewline && character == '\n';
-}
-
-static unsigned moveToNextNonWhitespacePosition(String textContent, unsigned startPosition, bool preserveNewline)
+static unsigned moveToNextNonWhitespacePosition(String textContent, unsigned startPosition)
 {
     auto nextNonWhiteSpacePosition = startPosition;
-    while (nextNonWhiteSpacePosition < textContent.length() && isWhitespaceCharacter(textContent[nextNonWhiteSpacePosition], preserveNewline))
+    while (nextNonWhiteSpacePosition < textContent.length() && isWhitespaceCharacter(textContent[nextNonWhiteSpacePosition]))
         ++nextNonWhiteSpacePosition;
     return nextNonWhiteSpacePosition - startPosition;
 }
@@ -89,37 +84,64 @@
 {
     auto text = inlineBox.textContent();
     if (!text.length())
-        return inlineContent.append(makeUnique<InlineTextItem>(inlineBox, 0, 0, false));
+        return inlineContent.append(InlineTextItem::createEmptyItem(inlineBox));
 
     auto& style = inlineBox.style();
-    auto preserveNewline = style.preserveNewline();
     LazyLineBreakIterator lineBreakIterator(text);
     unsigned currentPosition = 0;
     while (currentPosition < text.length()) {
-        // Soft linebreak?
-        if (isSoftLineBreak(text[currentPosition], preserveNewline)) {
-            inlineContent.append(makeUnique<InlineTextItem>(inlineBox, currentPosition, 1, true));
+        auto isSegmentBreakCandidate = [](auto character) {
+            return character == '\n';
+        };
+
+        if (isSegmentBreakCandidate(text[currentPosition])) {
+            inlineContent.append(InlineTextItem::createSegmentBreakItem(inlineBox, currentPosition));
             ++currentPosition;
             continue;
         }
-        if (isWhitespaceCharacter(text[currentPosition], preserveNewline)) {
-            auto length = moveToNextNonWhitespacePosition(text, currentPosition, preserveNewline);
-            inlineContent.append(makeUnique<InlineTextItem>(inlineBox, currentPosition, length, true));
+        if (isWhitespaceCharacter(text[currentPosition])) {
+            auto length = moveToNextNonWhitespacePosition(text, currentPosition);
+            inlineContent.append(InlineTextItem::createWhitespaceItem(inlineBox, currentPosition, length));
             currentPosition += length;
             continue;
         }
 
         auto length = moveToNextBreakablePosition(currentPosition, lineBreakIterator, style);
-        inlineContent.append(makeUnique<InlineTextItem>(inlineBox, currentPosition, length, false));
+        inlineContent.append(InlineTextItem::createNonWhitespaceItem(inlineBox, currentPosition, length));
         currentPosition += length;
     }
 }
 
-InlineTextItem::InlineTextItem(const Box& inlineBox, unsigned start, unsigned length, bool isWhitespace)
+std::unique_ptr<InlineTextItem> InlineTextItem::createWhitespaceItem(const Box& inlineBox, unsigned start, unsigned length)
+{
+    return makeUnique<InlineTextItem>(inlineBox, start, length, TextItemType::Whitespace);
+}
+
+std::unique_ptr<InlineTextItem> InlineTextItem::createNonWhitespaceItem(const Box& inlineBox, unsigned start, unsigned length)
+{
+    return makeUnique<InlineTextItem>(inlineBox, start, length, TextItemType::NonWhitespace);
+}
+
+std::unique_ptr<InlineTextItem> InlineTextItem::createSegmentBreakItem(const Box& inlineBox, unsigned position)
+{
+    return makeUnique<InlineTextItem>(inlineBox, position, 1, TextItemType::SegmentBreak);
+}
+
+std::unique_ptr<InlineTextItem> InlineTextItem::createEmptyItem(const Box& inlineBox)
+{
+    return makeUnique<InlineTextItem>(inlineBox);
+}
+
+InlineTextItem::InlineTextItem(const Box& inlineBox, unsigned start, unsigned length, TextItemType textItemType)
     : InlineItem(inlineBox, Type::Text)
     , m_start(start)
     , m_length(length)
-    , m_isWhitespace(isWhitespace)
+    , m_textItemType(textItemType)
+{
+}
+
+InlineTextItem::InlineTextItem(const Box& inlineBox)
+    : InlineItem(inlineBox, Type::Text)
 {
 }
 
@@ -127,7 +149,16 @@
 {
     RELEASE_ASSERT(splitPosition >= this->start());
     RELEASE_ASSERT(splitPosition + length <= end());
-    return makeUnique<InlineTextItem>(layoutBox(), splitPosition, length, isWhitespace());
+    ASSERT(!isSegmentBreak());
+    ASSERT(m_textItemType != TextItemType::Undefined);
+    return makeUnique<InlineTextItem>(layoutBox(), splitPosition, length, m_textItemType);
+}
+
+bool InlineTextItem::isWhitespace() const
+{
+    if (isSegmentBreak())
+        return !style().preserveNewline();
+    return m_textItemType == TextItemType::Whitespace;
 }
 
 }
diff --git a/Source/WebCore/layout/inlineformatting/InlineTextItem.h b/Source/WebCore/layout/inlineformatting/InlineTextItem.h
index 45fa6e1..0a9c305 100644
--- a/Source/WebCore/layout/inlineformatting/InlineTextItem.h
+++ b/Source/WebCore/layout/inlineformatting/InlineTextItem.h
@@ -37,23 +37,36 @@
 public:
     static void createAndAppendTextItems(InlineItems&, const Box&);
 
-    InlineTextItem(const Box&, unsigned start, unsigned length, bool isWhitespace);
+    static std::unique_ptr<InlineTextItem> createWhitespaceItem(const Box&, unsigned start, unsigned length);
+    static std::unique_ptr<InlineTextItem> createNonWhitespaceItem(const Box&, unsigned start, unsigned length);
+    static std::unique_ptr<InlineTextItem> createSegmentBreakItem(const Box&, unsigned position);
+    static std::unique_ptr<InlineTextItem> createEmptyItem(const Box&);
 
     unsigned start() const { return m_start; }
     unsigned end() const { return start() + length(); }
     unsigned length() const { return m_length; }
 
-    bool isWhitespace() const { return m_isWhitespace; }
+    bool isWhitespace() const;
     bool isCollapsible() const { return isWhitespace() && style().collapseWhiteSpace(); }
+    bool isSegmentBreak() const;
 
     std::unique_ptr<InlineTextItem> split(unsigned splitPosition, unsigned length) const;
 
+    enum class TextItemType { Undefined, Whitespace, NonWhitespace, SegmentBreak };
+    InlineTextItem(const Box&, unsigned start, unsigned length, TextItemType);
+    InlineTextItem(const Box&);
+
 private:
     unsigned m_start { 0 };
     unsigned m_length { 0 };
-    bool m_isWhitespace { false };
+    TextItemType m_textItemType { TextItemType::Undefined };
 };
 
+inline bool InlineTextItem::isSegmentBreak() const
+{
+    return m_textItemType == TextItemType::SegmentBreak;
+}
+
 }
 }