Title: [285104] trunk/Source/WebCore
Revision
285104
Author
[email protected]
Date
2021-11-01 08:40:32 -0700 (Mon, 01 Nov 2021)

Log Message

[LFC][IFC] Introduce paragraph content building to InlineItemsBuilder::handleTextContent
https://bugs.webkit.org/show_bug.cgi?id=232546

Reviewed by Antti Koivisto.

Let's check for directional control characters in text content and build
the paragraph content accordingly. Now that we've got both the inline box and
the text bidi content (atomic inline level boxes are still missing) breakInlineItemsAtBidiBoundaries
can start calling into ubidi to find content boundaries.

* layout/formattingContexts/inline/InlineItemsBuilder.cpp:
(WebCore::Layout::InlineItemsBuilder::handleTextContent):
(WebCore::Layout::InlineItemsBuilder::enterBidiContext):
(WebCore::Layout::InlineItemsBuilder::buildPreviousTextContent):
* layout/formattingContexts/inline/InlineItemsBuilder.h:
* layout/integration/LayoutIntegrationCoverage.cpp:
(WebCore::LayoutIntegration::canUseForFontAndText):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285103 => 285104)


--- trunk/Source/WebCore/ChangeLog	2021-11-01 14:11:59 UTC (rev 285103)
+++ trunk/Source/WebCore/ChangeLog	2021-11-01 15:40:32 UTC (rev 285104)
@@ -1,3 +1,23 @@
+2021-11-01  Alan Bujtas  <[email protected]>
+
+        [LFC][IFC] Introduce paragraph content building to InlineItemsBuilder::handleTextContent
+        https://bugs.webkit.org/show_bug.cgi?id=232546
+
+        Reviewed by Antti Koivisto.
+
+        Let's check for directional control characters in text content and build
+        the paragraph content accordingly. Now that we've got both the inline box and
+        the text bidi content (atomic inline level boxes are still missing) breakInlineItemsAtBidiBoundaries
+        can start calling into ubidi to find content boundaries.
+
+        * layout/formattingContexts/inline/InlineItemsBuilder.cpp:
+        (WebCore::Layout::InlineItemsBuilder::handleTextContent):
+        (WebCore::Layout::InlineItemsBuilder::enterBidiContext):
+        (WebCore::Layout::InlineItemsBuilder::buildPreviousTextContent):
+        * layout/formattingContexts/inline/InlineItemsBuilder.h:
+        * layout/integration/LayoutIntegrationCoverage.cpp:
+        (WebCore::LayoutIntegration::canUseForFontAndText):
+
 2021-11-01  Daniel Kolesa  <[email protected]>
 
         Fix build with GCC 8.4 on Ubuntu 18.04

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp (285103 => 285104)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-11-01 14:11:59 UTC (rev 285103)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-11-01 15:40:32 UTC (rev 285104)
@@ -33,6 +33,8 @@
 namespace WebCore {
 namespace Layout {
 
+#define ALLOW_BIDI_CONTENT 0
+
 struct WhitespaceContent {
     size_t length { 0 };
     bool isWordSeparator { true };
@@ -139,7 +141,8 @@
 void InlineItemsBuilder::handleTextContent(const InlineTextBox& inlineTextBox, InlineItems& inlineItems)
 {
     auto text = inlineTextBox.content();
-    if (!text.length())
+    auto contentLength = text.length();
+    if (!contentLength)
         return inlineItems.append(InlineTextItem::createEmptyItem(inlineTextBox));
 
     auto& style = inlineTextBox.style();
@@ -158,20 +161,29 @@
         return TextUtil::width(inlineTextBox, fontCascade, startPosition, startPosition + length, { });
     };
 
-    while (currentPosition < text.length()) {
-        auto isSegmentBreakCandidate = [](auto character) {
-            return character == '\n';
+    if (!m_paragraphContentBuilder.isEmpty()) {
+        m_contentOffsetMap.set(&inlineTextBox, m_paragraphContentBuilder.length());
+        m_paragraphContentBuilder.append(text);
+    }
+
+    while (currentPosition < contentLength) {
+        auto handleSegmentBreak = [&] {
+            // Segment breaks with preserve new line style (white-space: pre, pre-wrap, break-spaces and pre-line) compute to forced line break.
+            auto isSegmentBreakCandidate = text[currentPosition] == newlineCharacter;
+            if (!isSegmentBreakCandidate || !shouldPreserveNewline)
+                return false;
+            inlineItems.append(InlineSoftLineBreakItem::createSoftLineBreakItem(inlineTextBox, currentPosition++));
+            return true;
         };
-
-        // Segment breaks with preserve new line style (white-space: pre, pre-wrap, break-spaces and pre-line) compute to forced line break.
-        if (isSegmentBreakCandidate(text[currentPosition]) && shouldPreserveNewline) {
-            inlineItems.append(InlineSoftLineBreakItem::createSoftLineBreakItem(inlineTextBox, currentPosition));
-            ++currentPosition;
+        if (handleSegmentBreak())
             continue;
-        }
 
-        auto stopAtWordSeparatorBoundary = shouldPreserveSpacesAndTabs && fontCascade.wordSpacing();
-        if (auto whitespaceContent = moveToNextNonWhitespacePosition(text, currentPosition, shouldPreserveNewline, shouldPreserveSpacesAndTabs, shouldTreatNonBreakingSpaceAsRegularSpace, stopAtWordSeparatorBoundary)) {
+        auto handleWhitespace = [&] {
+            auto stopAtWordSeparatorBoundary = shouldPreserveSpacesAndTabs && fontCascade.wordSpacing();
+            auto whitespaceContent = moveToNextNonWhitespacePosition(text, currentPosition, shouldPreserveNewline, shouldPreserveSpacesAndTabs, shouldTreatNonBreakingSpaceAsRegularSpace, stopAtWordSeparatorBoundary);
+            if (!whitespaceContent)
+                return false;
+
             ASSERT(whitespaceContent->length);
             auto appendWhitespaceItem = [&] (auto startPosition, auto itemLength) {
                 auto simpleSingleWhitespaceContent = inlineTextBox.canUseSimplifiedContentMeasuring() && (itemLength == 1 || whitespaceContentIsTreatedAsSingleSpace);
@@ -187,33 +199,60 @@
             } else
                 appendWhitespaceItem(currentPosition, whitespaceContent->length);
             currentPosition += whitespaceContent->length;
+            return true;
+        };
+        if (handleWhitespace())
             continue;
-        }
 
-        auto hasTrailingSoftHyphen = false;
-        auto initialNonWhitespacePosition = currentPosition;
-        auto isAtSoftHyphen = [&](auto position) {
-            return text[position] == softHyphen;
-        };
-        if (style.hyphens() == Hyphens::None) {
-            // Let's merge candidate InlineTextItems separated by soft hyphen when the style says so.
-            while (currentPosition < text.length()) {
-                auto nonWhiteSpaceLength = moveToNextBreakablePosition(currentPosition, lineBreakIterator, style);
-                ASSERT(nonWhiteSpaceLength);
-                currentPosition += nonWhiteSpaceLength;
-                if (!isAtSoftHyphen(currentPosition - 1))
+        auto handleNonWhitespace = [&] {
+            auto startPosition = currentPosition;
+            auto endPosition = startPosition;
+            auto hasTrailingSoftHyphen = false;
+            if (style.hyphens() == Hyphens::None) {
+                // Let's merge candidate InlineTextItems separated by soft hyphen when the style says so.
+                do {
+                    endPosition += moveToNextBreakablePosition(endPosition, lineBreakIterator, style);
+                    ASSERT(startPosition < endPosition);
+                } while (endPosition < contentLength && text[endPosition - 1] == softHyphen);
+            } else {
+                endPosition += moveToNextBreakablePosition(startPosition, lineBreakIterator, style);
+                ASSERT(startPosition < endPosition);
+                hasTrailingSoftHyphen = text[endPosition - 1] == softHyphen;
+            }
+            ASSERT_IMPLIES(style.hyphens() == Hyphens::None, !hasTrailingSoftHyphen);
+            auto inlineItemLength = endPosition - startPosition;
+            inlineItems.append(InlineTextItem::createNonWhitespaceItem(inlineTextBox, startPosition, inlineItemLength, UBIDI_DEFAULT_LTR, hasTrailingSoftHyphen, inlineItemWidth(startPosition, inlineItemLength)));
+            currentPosition = endPosition;
+#if ALLOW_BIDI_CONTENT
+            // Check if the content has bidi dependency so that we have to start building the paragraph content for ubidi.
+            if (text.is8Bit() || !m_paragraphContentBuilder.isEmpty())
+                return true;
+
+            for (auto position = startPosition; position < endPosition;) {
+                UChar32 character;
+                U16_NEXT(text.characters16(), position, contentLength, character);
+
+                auto bidiCategory = u_charDirection(character);
+                auto needsBidi = bidiCategory == U_RIGHT_TO_LEFT
+                    || bidiCategory == U_RIGHT_TO_LEFT_ARABIC
+                    || bidiCategory == U_RIGHT_TO_LEFT_EMBEDDING
+                    || bidiCategory == U_RIGHT_TO_LEFT_OVERRIDE
+                    || bidiCategory == U_LEFT_TO_RIGHT_EMBEDDING
+                    || bidiCategory == U_LEFT_TO_RIGHT_OVERRIDE
+                    || bidiCategory == U_POP_DIRECTIONAL_FORMAT;
+                if (needsBidi) {
+                    buildPreviousTextContent(inlineItems);
+                    // buildPreviousTextContent takes care of this content too as some inline items have already been constructed for this text.
                     break;
+                }
             }
-        } else {
-            auto nonWhiteSpaceLength = moveToNextBreakablePosition(initialNonWhitespacePosition, lineBreakIterator, style);
-            ASSERT(nonWhiteSpaceLength);
-            currentPosition += nonWhiteSpaceLength;
-            hasTrailingSoftHyphen = isAtSoftHyphen(currentPosition - 1);
-        }
-        ASSERT(initialNonWhitespacePosition < currentPosition);
-        ASSERT_IMPLIES(style.hyphens() == Hyphens::None, !hasTrailingSoftHyphen);
-        auto length = currentPosition - initialNonWhitespacePosition;
-        inlineItems.append(InlineTextItem::createNonWhitespaceItem(inlineTextBox, initialNonWhitespacePosition, length, UBIDI_DEFAULT_LTR, hasTrailingSoftHyphen, inlineItemWidth(initialNonWhitespacePosition, length)));
+#endif
+            return true;
+        };
+        if (handleNonWhitespace())
+            continue;
+        // Unsupported content?
+        ASSERT_NOT_REACHED();
     }
 }
 
@@ -315,25 +354,8 @@
 
 void InlineItemsBuilder::enterBidiContext(const Box& box, UChar controlCharacter, const InlineItems& inlineItems)
 {
-    if (m_paragraphContentBuilder.isEmpty()) {
-        // FIXME: Move this to a dedicated function to support control characters embedded in text content.
-        auto buildPreviousTextContent = [&] {
-            const Box* lastLayoutBox = nullptr;
-            for (auto& inlineItem : inlineItems) {
-                if (!inlineItem.isText())
-                    continue;
-                auto& layoutBox = inlineItem.layoutBox();
-                if (lastLayoutBox == &layoutBox) {
-                    // We've already appended this content.
-                    continue;
-                }
-                m_contentOffsetMap.set(&layoutBox, m_paragraphContentBuilder.length());
-                m_paragraphContentBuilder.append(downcast<InlineTextBox>(layoutBox).content());
-                lastLayoutBox = &layoutBox;
-            }
-        };
-        buildPreviousTextContent();
-    }
+    if (m_paragraphContentBuilder.isEmpty())
+        buildPreviousTextContent(inlineItems);
     // Let the first control character represent the  box.
     m_contentOffsetMap.add(&box, m_paragraphContentBuilder.length());
     m_paragraphContentBuilder.append(controlCharacter);
@@ -345,7 +367,27 @@
     m_paragraphContentBuilder.append(controlCharacter);
 }
 
+void InlineItemsBuilder::buildPreviousTextContent(const InlineItems& inlineItems)
+{
+    ASSERT(m_paragraphContentBuilder.isEmpty());
+    ASSERT(m_contentOffsetMap.isEmpty());
+
+    const Box* lastLayoutBox = nullptr;
+    for (auto& inlineItem : inlineItems) {
+        if (!inlineItem.isText())
+            continue;
+        auto& layoutBox = inlineItem.layoutBox();
+        if (lastLayoutBox == &layoutBox) {
+            // We've already appended this content.
+            continue;
+        }
+        m_contentOffsetMap.set(&layoutBox, m_paragraphContentBuilder.length());
+        m_paragraphContentBuilder.append(downcast<InlineTextBox>(layoutBox).content());
+        lastLayoutBox = &layoutBox;
+    }
 }
+
 }
+}
 
 #endif

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h (285103 => 285104)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-11-01 14:11:59 UTC (rev 285103)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-11-01 15:40:32 UTC (rev 285104)
@@ -52,6 +52,8 @@
     void enterBidiContext(const Box&, UChar, const InlineItems&);
     void exitBidiContext(const Box&, UChar);
 
+    void buildPreviousTextContent(const InlineItems&);
+
     const ContainerBox& root() const { return m_root; }
 
     const ContainerBox& m_root;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to