Title: [285082] trunk/Source/WebCore
Revision
285082
Author
za...@apple.com
Date
2021-10-30 10:26:57 -0700 (Sat, 30 Oct 2021)

Log Message

[LFC][IFC] Add skeleton implementation for bidi content handling
https://bugs.webkit.org/show_bug.cgi?id=232524

Reviewed by Antti Koivisto.

Add dedicated functions for inline content types that need separate bidi handling (text vs. inline box vs. atomic etc).

* layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::collectContentIfNeeded):
* layout/formattingContexts/inline/InlineFormattingState.h:
(WebCore::Layout::InlineFormattingState::addInlineItems):
(WebCore::Layout::InlineFormattingState::addInlineItem): Deleted.
* layout/formattingContexts/inline/InlineItemsBuilder.cpp:
(WebCore::Layout::InlineItemsBuilder::build):
(WebCore::Layout::InlineItemsBuilder::collectInlineItems):
(WebCore::Layout::InlineItemsBuilder::breakInlineItemsAtBidiBoundaries):
(WebCore::Layout::InlineItemsBuilder::handleTextContent):
(WebCore::Layout::InlineItemsBuilder::handleInlineBox):
(WebCore::Layout::InlineItemsBuilder::handleInlineLevelBox):
(WebCore::Layout::InlineItemsBuilder::createAndAppendTextItems): Deleted.
* layout/formattingContexts/inline/InlineItemsBuilder.h:
(WebCore::Layout::InlineItemsBuilder::root const):
(WebCore::Layout::InlineItemsBuilder::formattingState const): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285081 => 285082)


--- trunk/Source/WebCore/ChangeLog	2021-10-30 17:09:52 UTC (rev 285081)
+++ trunk/Source/WebCore/ChangeLog	2021-10-30 17:26:57 UTC (rev 285082)
@@ -1,5 +1,31 @@
 2021-10-30  Alan Bujtas  <za...@apple.com>
 
+        [LFC][IFC] Add skeleton implementation for bidi content handling
+        https://bugs.webkit.org/show_bug.cgi?id=232524
+
+        Reviewed by Antti Koivisto.
+
+        Add dedicated functions for inline content types that need separate bidi handling (text vs. inline box vs. atomic etc).
+
+        * layout/formattingContexts/inline/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::collectContentIfNeeded):
+        * layout/formattingContexts/inline/InlineFormattingState.h:
+        (WebCore::Layout::InlineFormattingState::addInlineItems):
+        (WebCore::Layout::InlineFormattingState::addInlineItem): Deleted.
+        * layout/formattingContexts/inline/InlineItemsBuilder.cpp:
+        (WebCore::Layout::InlineItemsBuilder::build):
+        (WebCore::Layout::InlineItemsBuilder::collectInlineItems):
+        (WebCore::Layout::InlineItemsBuilder::breakInlineItemsAtBidiBoundaries):
+        (WebCore::Layout::InlineItemsBuilder::handleTextContent):
+        (WebCore::Layout::InlineItemsBuilder::handleInlineBox):
+        (WebCore::Layout::InlineItemsBuilder::handleInlineLevelBox):
+        (WebCore::Layout::InlineItemsBuilder::createAndAppendTextItems): Deleted.
+        * layout/formattingContexts/inline/InlineItemsBuilder.h:
+        (WebCore::Layout::InlineItemsBuilder::root const):
+        (WebCore::Layout::InlineItemsBuilder::formattingState const): Deleted.
+
+2021-10-30  Alan Bujtas  <za...@apple.com>
+
         [LFC][IFC] InlineItem should not cross bidi level boundary
         https://bugs.webkit.org/show_bug.cgi?id=232509
 

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp (285081 => 285082)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp	2021-10-30 17:09:52 UTC (rev 285081)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp	2021-10-30 17:26:57 UTC (rev 285082)
@@ -524,7 +524,7 @@
     if (!formattingState.inlineItems().isEmpty())
         return;
     auto inlineItemsBuilder = InlineItemsBuilder { root(), formattingState };
-    inlineItemsBuilder.build();
+    formattingState.addInlineItems(inlineItemsBuilder.build());
 }
 
 InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuilder::LineContent& lineContent)

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingState.h (285081 => 285082)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingState.h	2021-10-30 17:09:52 UTC (rev 285081)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingState.h	2021-10-30 17:26:57 UTC (rev 285082)
@@ -51,7 +51,7 @@
 
     InlineItems& inlineItems() { return m_inlineItems; }
     const InlineItems& inlineItems() const { return m_inlineItems; }
-    void addInlineItem(InlineItem&& inlineItem) { m_inlineItems.append(WTFMove(inlineItem)); }
+    void addInlineItems(InlineItems&& inlineItems) { m_inlineItems.appendVector(WTFMove(inlineItems)); }
 
     const InlineLineBoxes& lineBoxes() const { return m_lineBoxes; }
     void addLineBox(LineBox&& lineBox) { m_lineBoxes.append(WTFMove(lineBox)); }

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-10-30 17:09:52 UTC (rev 285081)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp	2021-10-30 17:26:57 UTC (rev 285082)
@@ -77,13 +77,19 @@
 {
 }
 
-void InlineItemsBuilder::build()
+InlineItems InlineItemsBuilder::build()
 {
+    InlineItems inlineItems;
+    collectInlineItems(inlineItems);
+    breakInlineItemsAtBidiBoundaries(inlineItems);
+    return inlineItems;
+}
+
+void InlineItemsBuilder::collectInlineItems(InlineItems& inlineItems)
+{
     // Traverse the tree and create inline items out of inline boxes and leaf nodes. This essentially turns the tree inline structure into a flat one.
     // <span>text<span></span><img></span> -> [InlineBoxStart][InlineLevelBox][InlineBoxStart][InlineBoxEnd][InlineLevelBox][InlineBoxEnd]
     ASSERT(root().hasInFlowOrFloatingChild());
-    auto& formattingState = this->formattingState();
-
     Vector<const Box*> layoutQueue;
     layoutQueue.append(root().firstChild());
     while (!layoutQueue.isEmpty()) {
@@ -93,31 +99,28 @@
             if (!isInlineBoxWithInlineContent)
                 break;
             // This is the start of an inline box (e.g. <span>).
-            formattingState.addInlineItem({ layoutBox, InlineItem::Type::InlineBoxStart });
-            auto& inlineBoxWithInlineContent = downcast<ContainerBox>(layoutBox);
-            if (!inlineBoxWithInlineContent.hasChild())
+            handleInlineBox(layoutBox, EnterInlineBox::Yes, inlineItems);
+            auto& inlineBox = downcast<ContainerBox>(layoutBox);
+            if (!inlineBox.hasChild())
                 break;
-            layoutQueue.append(inlineBoxWithInlineContent.firstChild());
+            layoutQueue.append(inlineBox.firstChild());
         }
 
         while (!layoutQueue.isEmpty()) {
             auto& layoutBox = *layoutQueue.takeLast();
-            if (layoutBox.isOutOfFlowPositioned()) {
+            if (layoutBox.isInlineTextBox())
+                handleTextContent(downcast<InlineTextBox>(layoutBox), inlineItems);
+            else if (layoutBox.isAtomicInlineLevelBox() || layoutBox.isLineBreakBox())
+                handleInlineLevelBox(layoutBox, inlineItems);
+            else if (layoutBox.isInlineBox())
+                handleInlineBox(layoutBox, EnterInlineBox::No, inlineItems);
+            else if (layoutBox.isFloatingPositioned())
+                inlineItems.append({ layoutBox, InlineItem::Type::Float });
+            else if (layoutBox.isOutOfFlowPositioned()) {
                 // Let's not construct InlineItems for out-of-flow content as they don't participate in the inline layout.
                 // However to be able to static positioning them, we need to compute their approximate positions.
-                formattingState.addOutOfFlowBox(layoutBox);
-            } else if (is<LineBreakBox>(layoutBox)) {
-                auto& lineBreakBox = downcast<LineBreakBox>(layoutBox);
-                formattingState.addInlineItem({ layoutBox, lineBreakBox.isOptional() ? InlineItem::Type::WordBreakOpportunity : InlineItem::Type::HardLineBreak });
-            } else if (layoutBox.isFloatingPositioned())
-                formattingState.addInlineItem({ layoutBox, InlineItem::Type::Float });
-            else if (layoutBox.isAtomicInlineLevelBox())
-                formattingState.addInlineItem({ layoutBox, InlineItem::Type::Box });
-            else if (layoutBox.isInlineTextBox()) {
-                createAndAppendTextItems(downcast<InlineTextBox>(layoutBox));
-            } else if (layoutBox.isInlineBox())
-                formattingState.addInlineItem({ layoutBox, InlineItem::Type::InlineBoxEnd });
-            else
+                m_formattingState.addOutOfFlowBox(layoutBox);
+            } else
                 ASSERT_NOT_REACHED();
 
             if (auto* nextSibling = layoutBox.nextSibling()) {
@@ -128,13 +131,16 @@
     }
 }
 
-void InlineItemsBuilder::createAndAppendTextItems(const InlineTextBox& inlineTextBox)
+void InlineItemsBuilder::breakInlineItemsAtBidiBoundaries(InlineItems&)
 {
-    auto& formattingState = this->formattingState();
+    // FIXME: Use ubidi to split the content at bidi boundaries.
+}
 
+void InlineItemsBuilder::handleTextContent(const InlineTextBox& inlineTextBox, InlineItems& inlineItems)
+{
     auto text = inlineTextBox.content();
     if (!text.length())
-        return formattingState.addInlineItem(InlineTextItem::createEmptyItem(inlineTextBox));
+        return inlineItems.append(InlineTextItem::createEmptyItem(inlineTextBox));
 
     auto& style = inlineTextBox.style();
     auto& fontCascade = style.fontCascade();
@@ -159,7 +165,7 @@
 
         // 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) {
-            formattingState.addInlineItem(InlineSoftLineBreakItem::createSoftLineBreakItem(inlineTextBox, currentPosition));
+            inlineItems.append(InlineSoftLineBreakItem::createSoftLineBreakItem(inlineTextBox, currentPosition));
             ++currentPosition;
             continue;
         }
@@ -170,7 +176,7 @@
             auto appendWhitespaceItem = [&] (auto startPosition, auto itemLength) {
                 auto simpleSingleWhitespaceContent = inlineTextBox.canUseSimplifiedContentMeasuring() && (itemLength == 1 || whitespaceContentIsTreatedAsSingleSpace);
                 auto width = simpleSingleWhitespaceContent ? std::make_optional(InlineLayoutUnit { fontCascade.spaceWidth() }) : inlineItemWidth(startPosition, itemLength);
-                formattingState.addInlineItem(InlineTextItem::createWhitespaceItem(inlineTextBox, startPosition, itemLength, UBIDI_DEFAULT_LTR, whitespaceContent->isWordSeparator, width));
+                inlineItems.append(InlineTextItem::createWhitespaceItem(inlineTextBox, startPosition, itemLength, UBIDI_DEFAULT_LTR, whitespaceContent->isWordSeparator, width));
             };
             if (style.whiteSpace() == WhiteSpace::BreakSpaces) {
                 // https://www.w3.org/TR/css-text-3/#white-space-phase-1
@@ -207,10 +213,28 @@
         ASSERT(initialNonWhitespacePosition < currentPosition);
         ASSERT_IMPLIES(style.hyphens() == Hyphens::None, !hasTrailingSoftHyphen);
         auto length = currentPosition - initialNonWhitespacePosition;
-        formattingState.addInlineItem(InlineTextItem::createNonWhitespaceItem(inlineTextBox, initialNonWhitespacePosition, length, UBIDI_DEFAULT_LTR, hasTrailingSoftHyphen, inlineItemWidth(initialNonWhitespacePosition, length)));
+        inlineItems.append(InlineTextItem::createNonWhitespaceItem(inlineTextBox, initialNonWhitespacePosition, length, UBIDI_DEFAULT_LTR, hasTrailingSoftHyphen, inlineItemWidth(initialNonWhitespacePosition, length)));
     }
 }
+
+void InlineItemsBuilder::handleInlineBox(const Box& inlineBox, EnterInlineBox enterInlineBox, InlineItems& inlineItems)
+{
+    // FIXME: Inject bidi control codes when crossing inline boxes with unicode-bidi/direction.
+    inlineItems.append({ inlineBox, enterInlineBox == EnterInlineBox::Yes ? InlineItem::Type::InlineBoxStart : InlineItem::Type::InlineBoxEnd });
 }
+
+void InlineItemsBuilder::handleInlineLevelBox(const Box& layoutBox, InlineItems& inlineItems)
+{
+    if (layoutBox.isAtomicInlineLevelBox())
+        return inlineItems.append({ layoutBox, InlineItem::Type::Box });
+
+    if (layoutBox.isLineBreakBox())
+        return inlineItems.append({ layoutBox, downcast<LineBreakBox>(layoutBox).isOptional() ? InlineItem::Type::WordBreakOpportunity : InlineItem::Type::HardLineBreak });
+
+    ASSERT_NOT_REACHED();
 }
 
+}
+}
+
 #endif

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-10-30 17:09:52 UTC (rev 285081)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h	2021-10-30 17:26:57 UTC (rev 285082)
@@ -37,15 +37,21 @@
 class InlineItemsBuilder {
 public:
     InlineItemsBuilder(const ContainerBox& formattingContextRoot, InlineFormattingState&);
-    void build();
+    InlineItems build();
 
 private:
-    void createAndAppendTextItems(const InlineTextBox&);
+    void collectInlineItems(InlineItems&);
+    void breakInlineItemsAtBidiBoundaries(InlineItems&);
 
+    void handleTextContent(const InlineTextBox&, InlineItems&);
+    enum class EnterInlineBox { Yes, No };
+    void handleInlineBox(const Box&, EnterInlineBox, InlineItems&);
+    void handleInlineLevelBox(const Box&, InlineItems&);
+
     const ContainerBox& root() const { return m_root; }
-    InlineFormattingState& formattingState() const { return m_formattingState; }
 
     const ContainerBox& m_root;
+    // FIXME: We should not need this here. This is only required by the out of flow boxes.
     InlineFormattingState& m_formattingState;
 };
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to