Title: [285119] trunk/Source/WebCore
Revision
285119
Author
[email protected]
Date
2021-11-01 12:22:20 -0700 (Mon, 01 Nov 2021)

Log Message

[LFC][IFC] Start using ubidi to find bidi boundaries
https://bugs.webkit.org/show_bug.cgi?id=232552

Reviewed by Antti Koivisto.

In this patch, we start using ubidi to find the bidi boundaries in the paragraph content.
We also set the bidi levels on the associated inline item range. Later we'll be using these levels
to compute the visual order (after line breaking).
(see breakAndComputeBidiLevels for details)

* layout/formattingContexts/inline/InlineItem.h:
(WebCore::Layout::InlineItem::setBidiLevel):
* layout/formattingContexts/inline/InlineItemsBuilder.cpp:
(WebCore::Layout::InlineItemsBuilder::breakAndComputeBidiLevels):
* layout/formattingContexts/inline/InlineTextItem.cpp:
(WebCore::Layout::InlineTextItem::splitAt):
* layout/formattingContexts/inline/InlineTextItem.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285118 => 285119)


--- trunk/Source/WebCore/ChangeLog	2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/ChangeLog	2021-11-01 19:22:20 UTC (rev 285119)
@@ -1,3 +1,23 @@
+2021-11-01  Alan Bujtas  <[email protected]>
+
+        [LFC][IFC] Start using ubidi to find bidi boundaries
+        https://bugs.webkit.org/show_bug.cgi?id=232552
+
+        Reviewed by Antti Koivisto.
+
+        In this patch, we start using ubidi to find the bidi boundaries in the paragraph content.
+        We also set the bidi levels on the associated inline item range. Later we'll be using these levels
+        to compute the visual order (after line breaking).
+        (see breakAndComputeBidiLevels for details)
+
+        * layout/formattingContexts/inline/InlineItem.h:
+        (WebCore::Layout::InlineItem::setBidiLevel):
+        * layout/formattingContexts/inline/InlineItemsBuilder.cpp:
+        (WebCore::Layout::InlineItemsBuilder::breakAndComputeBidiLevels):
+        * layout/formattingContexts/inline/InlineTextItem.cpp:
+        (WebCore::Layout::InlineTextItem::splitAt):
+        * layout/formattingContexts/inline/InlineTextItem.h:
+
 2021-11-01  Chris Dumez  <[email protected]>
 
         Crash under HIDDevice::HIDDevice()

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineItem.h (285118 => 285119)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItem.h	2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItem.h	2021-11-01 19:22:20 UTC (rev 285119)
@@ -34,6 +34,8 @@
 namespace WebCore {
 namespace Layout {
 
+class InlineItemsBuilder;
+
 class InlineItem {
 public:
     enum class Type : uint8_t {
@@ -65,6 +67,10 @@
     bool isInlineBoxEnd() const { return type() == Type::InlineBoxEnd; }
 
 private:
+    friend class InlineItemsBuilder;
+
+    void setBidiLevel(UBiDiLevel bidiLevel) { m_bidiLevel = bidiLevel; }
+
     const Box* m_layoutBox { nullptr };
     Type m_type { };
     UBiDiLevel m_bidiLevel { UBIDI_DEFAULT_LTR };

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-11-01 19:22:20 UTC (rev 285119)
@@ -29,6 +29,7 @@
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "InlineSoftLineBreakItem.h"
+#include <wtf/Scope.h>
 
 namespace WebCore {
 namespace Layout {
@@ -83,7 +84,7 @@
 {
     InlineItems inlineItems;
     collectInlineItems(inlineItems);
-    breakInlineItemsAtBidiBoundaries(inlineItems);
+    breakAndComputeBidiLevels(inlineItems);
     return inlineItems;
 }
 
@@ -133,9 +134,74 @@
     }
 }
 
-void InlineItemsBuilder::breakInlineItemsAtBidiBoundaries(InlineItems&)
+void InlineItemsBuilder::breakAndComputeBidiLevels(InlineItems& inlineItems)
 {
-    // FIXME: Use ubidi to split the content at bidi boundaries.
+    if (m_paragraphContentBuilder.isEmpty())
+        return;
+    ASSERT(!inlineItems.isEmpty());
+
+    // 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.
+    UBiDi* ubidi = ubidi_open();
+
+    auto closeUBiDiOnExit = makeScopeExit([&] {
+        ubidi_close(ubidi);
+    });
+
+    UBiDiLevel bidiLevel = UBIDI_DEFAULT_LTR;
+    bool useHeuristicBaseDirection = root().style().unicodeBidi() == EUnicodeBidi::Plaintext;
+    if (!useHeuristicBaseDirection)
+        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);
+    if (U_FAILURE(error)) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    size_t currentInlineItemIndex = 0;
+    for (size_t currentPosition = 0; currentPosition < m_paragraphContentBuilder.length();) {
+        UBiDiLevel level;
+        int32_t endPosition = currentPosition;
+        ubidi_getLogicalRun(ubidi, currentPosition, &endPosition, &level);
+
+        auto setBidiLevelOnRange = [&] {
+            // We should always have inline item(s) associated with a bidi range.
+            ASSERT(currentInlineItemIndex < inlineItems.size());
+
+            while (currentInlineItemIndex < inlineItems.size()) {
+                auto& inlineItem = inlineItems[currentInlineItemIndex];
+                if (!inlineItem.isText()) {
+                    // FIXME: This fails with multiple inline boxes as they don't advance position.
+                    inlineItem.setBidiLevel(level);
+                    ++currentInlineItemIndex;
+                    continue;
+                }
+                auto& inlineTextItem = downcast<InlineTextItem>(inlineItem);
+                inlineTextItem.setBidiLevel(level);
+
+                auto inlineTextItemEnd = inlineTextItem.end();
+                auto bidiEnd = endPosition - m_contentOffsetMap.get(&inlineTextItem.layoutBox());
+                if (bidiEnd == inlineTextItemEnd) {
+                    ++currentInlineItemIndex;
+                    break;
+                }
+                if (bidiEnd < inlineTextItemEnd) {
+                    if (currentInlineItemIndex == inlineItems.size() - 1)
+                        inlineItems.append(inlineTextItem.splitAt(bidiEnd));
+                    else
+                        inlineItems.insert(currentInlineItemIndex + 1, inlineTextItem.splitAt(bidiEnd));
+                    ++currentInlineItemIndex;
+                    break;
+                }
+                ++currentInlineItemIndex;
+            }
+        };
+        setBidiLevelOnRange();
+        currentPosition = endPosition;
+    }
 }
 
 void InlineItemsBuilder::handleTextContent(const InlineTextBox& inlineTextBox, InlineItems& inlineItems)

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-11-01 19:22:20 UTC (rev 285119)
@@ -42,7 +42,7 @@
 
 private:
     void collectInlineItems(InlineItems&);
-    void breakInlineItemsAtBidiBoundaries(InlineItems&);
+    void breakAndComputeBidiLevels(InlineItems&);
 
     void handleTextContent(const InlineTextBox&, InlineItems&);
     void handleInlineBoxStart(const Box&, InlineItems&);

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp (285118 => 285119)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp	2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.cpp	2021-11-01 19:22:20 UTC (rev 285119)
@@ -71,6 +71,15 @@
     return { inlineTextBox(), end() - length, length, bidiLevel(), hasTrailingSoftHyphen(), isWordSeparator(), width, m_textItemType };
 }
 
+InlineTextItem InlineTextItem::splitAt(size_t position)
+{
+    RELEASE_ASSERT(length() > 1);
+    RELEASE_ASSERT(position > start() && position < end());
+    auto rightSide = right(end() - position, { });
+    m_length = length() - rightSide.length();
+    return rightSide;
+}
+
 bool InlineTextItem::isZeroWidthSpaceSeparator() const
 {
     // FIXME: We should check for more zero width content and not just U+200B.

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h (285118 => 285119)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h	2021-11-01 19:21:11 UTC (rev 285118)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineTextItem.h	2021-11-01 19:22:20 UTC (rev 285119)
@@ -33,6 +33,8 @@
 namespace WebCore {
 namespace Layout {
 
+class InlineItemsBuilder;
+
 using InlineItems = Vector<InlineItem>;
 
 class InlineTextItem : public InlineItem {
@@ -59,8 +61,11 @@
     static bool shouldPreserveSpacesAndTabs(const InlineTextItem&);
 
 private:
+    friend class InlineItemsBuilder;
     using InlineItem::TextItemType;
 
+    InlineTextItem splitAt(size_t position);
+
     InlineTextItem(const InlineTextBox&, unsigned start, unsigned length, UBiDiLevel, bool hasTrailingSoftHyphen, bool isWordSeparator, std::optional<InlineLayoutUnit> width, TextItemType);
     explicit InlineTextItem(const InlineTextBox&, UBiDiLevel);
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to