Title: [285369] trunk/Source/WebCore
Revision
285369
Author
[email protected]
Date
2021-11-06 05:59:40 -0700 (Sat, 06 Nov 2021)

Log Message

[LFC][IFC] Build the paragraph content when all the inline items are processed
https://bugs.webkit.org/show_bug.cgi?id=232771

Reviewed by Antti Koivisto.

This patch simplifies the inline collection logic and helps with the upcoming "resolve the bidi ranges" patch.

* layout/formattingContexts/inline/InlineItemsBuilder.cpp:
(WebCore::Layout::InlineItemsBuilder::build):
(WebCore::Layout::buildBidiParagraph): Let's build the paragraph content at once.
(WebCore::Layout::InlineItemsBuilder::breakAndComputeBidiLevels):
(WebCore::Layout::InlineItemsBuilder::handleTextContent):
(WebCore::Layout::InlineItemsBuilder::handleInlineBoxStart):
(WebCore::Layout::InlineItemsBuilder::handleInlineBoxEnd):
(WebCore::Layout::InlineItemsBuilder::handleInlineLevelBox):
(WebCore::Layout::InlineItemsBuilder::enterBidiContext): Deleted.
(WebCore::Layout::InlineItemsBuilder::exitBidiContext): Deleted.
(WebCore::Layout::InlineItemsBuilder::buildPreviousTextContent): Deleted.
* layout/formattingContexts/inline/InlineItemsBuilder.h:
(WebCore::Layout::InlineItemsBuilder::hasSeenBidiContent const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285368 => 285369)


--- trunk/Source/WebCore/ChangeLog	2021-11-06 12:05:02 UTC (rev 285368)
+++ trunk/Source/WebCore/ChangeLog	2021-11-06 12:59:40 UTC (rev 285369)
@@ -1,3 +1,26 @@
+2021-11-06  Alan Bujtas  <[email protected]>
+
+        [LFC][IFC] Build the paragraph content when all the inline items are processed
+        https://bugs.webkit.org/show_bug.cgi?id=232771
+
+        Reviewed by Antti Koivisto.
+
+        This patch simplifies the inline collection logic and helps with the upcoming "resolve the bidi ranges" patch.
+
+        * layout/formattingContexts/inline/InlineItemsBuilder.cpp:
+        (WebCore::Layout::InlineItemsBuilder::build):
+        (WebCore::Layout::buildBidiParagraph): Let's build the paragraph content at once.
+        (WebCore::Layout::InlineItemsBuilder::breakAndComputeBidiLevels):
+        (WebCore::Layout::InlineItemsBuilder::handleTextContent):
+        (WebCore::Layout::InlineItemsBuilder::handleInlineBoxStart):
+        (WebCore::Layout::InlineItemsBuilder::handleInlineBoxEnd):
+        (WebCore::Layout::InlineItemsBuilder::handleInlineLevelBox):
+        (WebCore::Layout::InlineItemsBuilder::enterBidiContext): Deleted.
+        (WebCore::Layout::InlineItemsBuilder::exitBidiContext): Deleted.
+        (WebCore::Layout::InlineItemsBuilder::buildPreviousTextContent): Deleted.
+        * layout/formattingContexts/inline/InlineItemsBuilder.h:
+        (WebCore::Layout::InlineItemsBuilder::hasSeenBidiContent const):
+
 2021-11-05  Simon Fraser  <[email protected]>
 
         Simplify code that makes use of WheelEventDeltaFilter

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-11-06 12:05:02 UTC (rev 285368)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-11-06 12:59:40 UTC (rev 285369)
@@ -88,7 +88,8 @@
 {
     InlineItems inlineItems;
     collectInlineItems(inlineItems);
-    breakAndComputeBidiLevels(inlineItems);
+    if (hasSeenBidiContent())
+        breakAndComputeBidiLevels(inlineItems);
     return inlineItems;
 }
 
@@ -138,12 +139,76 @@
     }
 }
 
+using ContentOffsetMap = HashMap<const Box*, size_t>;
+static inline void buildBidiParagraph(const InlineItems& inlineItems,  StringBuilder& paragraphContentBuilder, ContentOffsetMap& contentOffsetMap)
+{
+    const Box* lastInlineTextBox = nullptr;
+    for (auto& inlineItem : inlineItems) {
+        auto& layoutBox = inlineItem.layoutBox();
+
+        if (inlineItem.isText()) {
+            if (lastInlineTextBox != &layoutBox) {
+                contentOffsetMap.set(&layoutBox, paragraphContentBuilder.length());
+                paragraphContentBuilder.append(downcast<InlineTextBox>(layoutBox).content());
+                lastInlineTextBox = &layoutBox;
+            }
+        } else if (inlineItem.isBox())
+            paragraphContentBuilder.append(objectReplacementCharacter);
+        else if (inlineItem.isInlineBoxStart() || inlineItem.isInlineBoxEnd()) {
+            // https://drafts.csswg.org/css-writing-modes/#unicode-bidi
+            auto& style = inlineItem.style();
+            auto initiatesControlCharacter = style.rtlOrdering() == Order::Logical && style.unicodeBidi() != EUnicodeBidi::UBNormal;
+            if (!initiatesControlCharacter)
+                continue;
+            auto isEnteringBidi = inlineItem.isInlineBoxStart();
+
+            if (isEnteringBidi)
+                contentOffsetMap.add(&layoutBox, paragraphContentBuilder.length());
+
+            switch (style.unicodeBidi()) {
+            case EUnicodeBidi::UBNormal:
+                // The box does not open an additional level of embedding with respect to the bidirectional algorithm.
+                // For inline boxes, implicit reordering works across box boundaries.
+                ASSERT_NOT_REACHED();
+                break;
+            case EUnicodeBidi::Embed:
+                paragraphContentBuilder.append(isEnteringBidi ? (style.isLeftToRightDirection() ? leftToRightEmbed : rightToLeftEmbed) : popDirectionalFormatting);
+                break;
+            case EUnicodeBidi::Override:
+                paragraphContentBuilder.append(isEnteringBidi ? (style.isLeftToRightDirection() ? leftToRightOverride : rightToLeftOverride) : popDirectionalFormatting);
+                break;
+            case EUnicodeBidi::Isolate:
+                paragraphContentBuilder.append(isEnteringBidi ? (style.isLeftToRightDirection() ? leftToRightIsolate : rightToLeftIsolate) : popDirectionalIsolate);
+                break;
+            case EUnicodeBidi::Plaintext:
+                paragraphContentBuilder.append(isEnteringBidi ? firstStrongIsolate : popDirectionalIsolate);
+                break;
+            case EUnicodeBidi::IsolateOverride:
+                if (isEnteringBidi) {
+                    paragraphContentBuilder.append(firstStrongIsolate);
+                    paragraphContentBuilder.append(style.isLeftToRightDirection() ? leftToRightOverride : rightToLeftOverride);
+                } else {
+                    paragraphContentBuilder.append(popDirectionalFormatting);
+                    paragraphContentBuilder.append(popDirectionalIsolate);
+                }
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+            }
+        } else
+            ASSERT_NOT_IMPLEMENTED_YET();
+    }
+}
+
 void InlineItemsBuilder::breakAndComputeBidiLevels(InlineItems& inlineItems)
 {
-    if (!hasSeenBidiContent())
-        return;
+    ASSERT(hasSeenBidiContent());
     ASSERT(!inlineItems.isEmpty());
 
+    StringBuilder paragraphContentBuilder;
+    ContentOffsetMap contentOffsetMap;
+    buildBidiParagraph(inlineItems, paragraphContentBuilder, contentOffsetMap);
+
     // 1. Setup the bidi boundary loop by calling ubidi_setPara with the paragraph text.
     // 2. Call ubidi_getLogicalRun to advance to the next bidi boundary until we hit the end of the content.
     // 3. Set the computed bidi level on the associated inline items. Split them as needed.
@@ -159,7 +224,8 @@
         bidiLevel = root().style().isLeftToRightDirection() ? UBIDI_LTR : UBIDI_RTL;
 
     UErrorCode error = U_ZERO_ERROR;
-    ubidi_setPara(ubidi, m_paragraphContentBuilder.characters16(), m_paragraphContentBuilder.length(), bidiLevel, nullptr, &error);
+    ASSERT(!paragraphContentBuilder.isEmpty());
+    ubidi_setPara(ubidi, paragraphContentBuilder.characters16(), paragraphContentBuilder.length(), bidiLevel, nullptr, &error);
     if (U_FAILURE(error)) {
         ASSERT_NOT_REACHED();
         return;
@@ -166,7 +232,7 @@
     }
 
     size_t currentInlineItemIndex = 0;
-    for (size_t currentPosition = 0; currentPosition < m_paragraphContentBuilder.length();) {
+    for (size_t currentPosition = 0; currentPosition < paragraphContentBuilder.length();) {
         UBiDiLevel level;
         int32_t endPosition = currentPosition;
         ubidi_getLogicalRun(ubidi, currentPosition, &endPosition, &level);
@@ -188,7 +254,7 @@
                 inlineTextItem.setBidiLevel(level);
 
                 auto inlineTextItemEnd = inlineTextItem.end();
-                auto bidiEnd = endPosition - m_contentOffsetMap.get(&inlineTextItem.layoutBox());
+                auto bidiEnd = endPosition - contentOffsetMap.get(&inlineTextItem.layoutBox());
                 if (bidiEnd == inlineTextItemEnd) {
                     ++currentInlineItemIndex;
                     break;
@@ -236,11 +302,6 @@
         return TextUtil::width(inlineTextBox, fontCascade, startPosition, startPosition + length, { });
     };
 
-    if (hasSeenBidiContent()) {
-        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.
@@ -308,7 +369,7 @@
                 U16_NEXT(text.characters16(), position, contentLength, character);
 
                 auto bidiCategory = u_charDirection(character);
-                auto needsBidi = bidiCategory == U_RIGHT_TO_LEFT
+                m_hasSeenBidiContent = bidiCategory == U_RIGHT_TO_LEFT
                     || bidiCategory == U_RIGHT_TO_LEFT_ARABIC
                     || bidiCategory == U_RIGHT_TO_LEFT_EMBEDDING
                     || bidiCategory == U_RIGHT_TO_LEFT_OVERRIDE
@@ -315,11 +376,8 @@
                     || 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.
+                if (m_hasSeenBidiContent)
                     break;
-                }
             }
 #endif
             return true;
@@ -334,126 +392,29 @@
 void InlineItemsBuilder::handleInlineBoxStart(const Box& inlineBox, InlineItems& inlineItems)
 {
     inlineItems.append({ inlineBox, InlineItem::Type::InlineBoxStart });
-    // https://drafts.csswg.org/css-writing-modes/#unicode-bidi
     auto& style = inlineBox.style();
-    if (style.rtlOrdering() == Order::Visual)
-        return;
-
-    auto isLeftToRightDirection = style.isLeftToRightDirection();
-    switch (style.unicodeBidi()) {
-    case EUnicodeBidi::UBNormal:
-        // The box does not open an additional level of embedding with respect to the bidirectional algorithm.
-        // For inline boxes, implicit reordering works across box boundaries.
-        break;
-    case EUnicodeBidi::Embed:
-        enterBidiContext(inlineBox, isLeftToRightDirection ? leftToRightEmbed : rightToLeftEmbed, inlineItems);
-        break;
-    case EUnicodeBidi::Override:
-        enterBidiContext(inlineBox, isLeftToRightDirection ? leftToRightOverride : rightToLeftOverride, inlineItems);
-        break;
-    case EUnicodeBidi::Isolate:
-        enterBidiContext(inlineBox, isLeftToRightDirection ? leftToRightIsolate : rightToLeftIsolate, inlineItems);
-        break;
-    case EUnicodeBidi::Plaintext:
-        enterBidiContext(inlineBox, firstStrongIsolate, inlineItems);
-        break;
-    case EUnicodeBidi::IsolateOverride:
-        enterBidiContext(inlineBox, firstStrongIsolate, inlineItems);
-        enterBidiContext(inlineBox, isLeftToRightDirection ? leftToRightOverride : rightToLeftOverride, inlineItems);
-        break;
-    default:
-        ASSERT_NOT_REACHED();
-    }
+    m_hasSeenBidiContent = m_hasSeenBidiContent || (style.rtlOrdering() == Order::Logical && style.unicodeBidi() != EUnicodeBidi::UBNormal); 
 }
 
 void InlineItemsBuilder::handleInlineBoxEnd(const Box& inlineBox, InlineItems& inlineItems)
 {
     inlineItems.append({ inlineBox, InlineItem::Type::InlineBoxEnd });
-    // https://drafts.csswg.org/css-writing-modes/#unicode-bidi
-    auto& style = inlineBox.style();
-    if (style.rtlOrdering() == Order::Visual)
-        return;
-
-    switch (style.unicodeBidi()) {
-    case EUnicodeBidi::UBNormal:
-        // The box does not open an additional level of embedding with respect to the bidirectional algorithm.
-        // For inline boxes, implicit reordering works across box boundaries.
-        break;
-    case EUnicodeBidi::Embed:
-        exitBidiContext(inlineBox, popDirectionalFormatting);
-        break;
-    case EUnicodeBidi::Override:
-        exitBidiContext(inlineBox, popDirectionalFormatting);
-        break;
-    case EUnicodeBidi::Isolate:
-        exitBidiContext(inlineBox, popDirectionalIsolate);
-        break;
-    case EUnicodeBidi::Plaintext:
-        exitBidiContext(inlineBox, popDirectionalIsolate);
-        break;
-    case EUnicodeBidi::IsolateOverride:
-        exitBidiContext(inlineBox, popDirectionalFormatting);
-        exitBidiContext(inlineBox, popDirectionalIsolate);
-        break;
-    default:
-        ASSERT_NOT_REACHED();
-    }
+    // Inline box end item itself can not trigger bidi content.
+    ASSERT(hasSeenBidiContent() || inlineBox.style().rtlOrdering() == Order::Visual || inlineBox.style().unicodeBidi() == EUnicodeBidi::UBNormal);
 }
 
 void InlineItemsBuilder::handleInlineLevelBox(const Box& layoutBox, InlineItems& inlineItems)
 {
-    if (layoutBox.isAtomicInlineLevelBox()) {
-        inlineItems.append({ layoutBox, InlineItem::Type::Box });
-        if (hasSeenBidiContent())
-            m_paragraphContentBuilder.append(objectReplacementCharacter);
-        return;
-    }
+    if (layoutBox.isAtomicInlineLevelBox())
+        return inlineItems.append({ layoutBox, InlineItem::Type::Box });
 
-    if (layoutBox.isLineBreakBox()) {
-        // FIXME: Figure out what (if any) character to append to the bidi paragraph.
+    if (layoutBox.isLineBreakBox())
         return inlineItems.append({ layoutBox, downcast<LineBreakBox>(layoutBox).isOptional() ? InlineItem::Type::WordBreakOpportunity : InlineItem::Type::HardLineBreak });
-    }
 
     ASSERT_NOT_REACHED();
 }
 
-void InlineItemsBuilder::enterBidiContext(const Box& box, UChar controlCharacter, const InlineItems& inlineItems)
-{
-    if (!hasSeenBidiContent())
-        buildPreviousTextContent(inlineItems);
-    // Let the first control character represent the  box.
-    m_contentOffsetMap.add(&box, m_paragraphContentBuilder.length());
-    m_paragraphContentBuilder.append(controlCharacter);
 }
-
-void InlineItemsBuilder::exitBidiContext(const Box&, UChar controlCharacter)
-{
-    ASSERT(hasSeenBidiContent());
-    m_paragraphContentBuilder.append(controlCharacter);
 }
 
-void InlineItemsBuilder::buildPreviousTextContent(const InlineItems& inlineItems)
-{
-    ASSERT(!hasSeenBidiContent());
-    ASSERT(m_contentOffsetMap.isEmpty());
-
-    const Box* lastInlineTextBox = nullptr;
-    for (auto& inlineItem : inlineItems) {
-        if (inlineItem.isText()) {
-            auto& layoutBox = inlineItem.layoutBox();
-            if (lastInlineTextBox != &layoutBox) {
-                m_contentOffsetMap.set(&layoutBox, m_paragraphContentBuilder.length());
-                m_paragraphContentBuilder.append(downcast<InlineTextBox>(layoutBox).content());
-                lastInlineTextBox = &layoutBox;
-            }
-        } else if (inlineItem.isBox())
-            m_paragraphContentBuilder.append(objectReplacementCharacter);
-        else
-            ASSERT_NOT_IMPLEMENTED_YET();
-    }
-}
-
-}
-}
-
 #endif

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-11-06 12:05:02 UTC (rev 285368)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-11-06 12:59:40 UTC (rev 285369)
@@ -49,22 +49,14 @@
     void handleInlineBoxEnd(const Box&, InlineItems&);
     void handleInlineLevelBox(const Box&, InlineItems&);
     
-    void enterBidiContext(const Box&, UChar, const InlineItems&);
-    void exitBidiContext(const Box&, UChar);
+    bool hasSeenBidiContent() const { return m_hasSeenBidiContent; }
 
-    void buildPreviousTextContent(const InlineItems&);
-
-    bool hasSeenBidiContent() const { return !m_paragraphContentBuilder.isEmpty(); }
-
     const ContainerBox& root() const { return m_root; }
 
     const ContainerBox& m_root;
     // FIXME: We should not need this here. This is only required by the out of flow boxes.
     InlineFormattingState& m_formattingState;
-
-    StringBuilder m_paragraphContentBuilder;
-    // Keep track of where each layout box starts in the paragraph content.
-    HashMap<const Box*, size_t> m_contentOffsetMap;
+    bool m_hasSeenBidiContent { false };
 };
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to