Title: [286475] trunk/Source/WebCore
Revision
286475
Author
za...@apple.com
Date
2021-12-02 19:01:38 -0800 (Thu, 02 Dec 2021)

Log Message

[LFC][IFC] Create display boxes for fragmented inline boxes on bidi boundaries
https://bugs.webkit.org/show_bug.cgi?id=233736

Reviewed by Antti Koivisto.

In this patch we insert inline box type of display boxes in-between bidi display boxes as needed.
We don't yet compute visual geometry and/or offset the rest of the content with the injected margins, borders and padding.

* layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::InlineDisplayContentBuilder::insertInlineBoxDisplayBoxForBidiBoundary):
(WebCore::Layout::InlineDisplayContentBuilder::processBidiContent):
(WebCore::Layout::InlineDisplayContentBuilder::appendInlineBoxDisplayBoxForBidiBoundary): Deleted.
* layout/formattingContexts/inline/InlineDisplayContentBuilder.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (286474 => 286475)


--- trunk/Source/WebCore/ChangeLog	2021-12-03 02:54:36 UTC (rev 286474)
+++ trunk/Source/WebCore/ChangeLog	2021-12-03 03:01:38 UTC (rev 286475)
@@ -1,3 +1,19 @@
+2021-12-02  Alan Bujtas  <za...@apple.com>
+
+        [LFC][IFC] Create display boxes for fragmented inline boxes on bidi boundaries
+        https://bugs.webkit.org/show_bug.cgi?id=233736
+
+        Reviewed by Antti Koivisto.
+
+        In this patch we insert inline box type of display boxes in-between bidi display boxes as needed.
+        We don't yet compute visual geometry and/or offset the rest of the content with the injected margins, borders and padding. 
+
+        * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
+        (WebCore::Layout::InlineDisplayContentBuilder::insertInlineBoxDisplayBoxForBidiBoundary):
+        (WebCore::Layout::InlineDisplayContentBuilder::processBidiContent):
+        (WebCore::Layout::InlineDisplayContentBuilder::appendInlineBoxDisplayBoxForBidiBoundary): Deleted.
+        * layout/formattingContexts/inline/InlineDisplayContentBuilder.h:
+
 2021-12-02  Chris Dumez  <cdu...@apple.com>
 
         Introduce a MainThreadBridge class inside WebLockManager

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp (286474 => 286475)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp	2021-12-03 02:54:36 UTC (rev 286474)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp	2021-12-03 03:01:38 UTC (rev 286475)
@@ -33,6 +33,7 @@
 #include "LayoutInitialContainingBlock.h"
 #include "RuntimeEnabledFeatures.h"
 #include "TextUtil.h"
+#include <wtf/ListHashSet.h>
 
 namespace WebCore {
 namespace Layout {
@@ -269,11 +270,20 @@
     setInlineBoxGeometry(layoutBox, inlineBoxBorderBox, false);
 }
 
-void InlineDisplayContentBuilder::appendInlineBoxDisplayBoxForBidiBoundary(const Box& layoutBox, const InlineRect& inlineBoxRect, DisplayBoxes& boxes)
+void InlineDisplayContentBuilder::insertInlineBoxDisplayBoxForBidiBoundary(const InlineLevelBox& inlineBox, const InlineRect& inlineBoxRect, size_t insertionPoint, DisplayBoxes& boxes)
 {
-    UNUSED_PARAM(layoutBox);
-    UNUSED_PARAM(inlineBoxRect);
-    UNUSED_PARAM(boxes);
+    ASSERT(inlineBox.isInlineBox());
+    // FIXME: Compute ink overflow.
+    boxes.insert(insertionPoint, { m_lineIndex
+        , InlineDisplay::Box::Type::NonRootInlineBox
+        , inlineBox.layoutBox()
+        , UBIDI_DEFAULT_LTR
+        , inlineBoxRect
+        , inlineBoxRect
+        , { }
+        , { }
+        , true
+        , isFirstLastBox(inlineBox) });
 }
 
 void InlineDisplayContentBuilder::adjustInlineBoxDisplayBoxForBidiBoundary(InlineDisplay::Box& displayBox, const InlineRect& inlineBoxRect)
@@ -340,6 +350,7 @@
 {
     ASSERT(lineContent.visualOrderList.size() == lineContent.runs.size());
 
+    auto needsNonRootInlineBoxDisplayBox = false;
     auto createDisplayBoxesInVisualOrderForContentRuns = [&] {
         auto rootInlineBoxRect = lineBox.logicalRectForRootInlineBox();
         auto contentRightInVisualOrder = InlineLayoutUnit { };
@@ -358,7 +369,7 @@
 
             auto isContentRun = !lineRun.isInlineBoxStart() && !lineRun.isLineSpanningInlineBoxStart() && !lineRun.isInlineBoxEnd();
             if (!isContentRun) {
-                // FIXME: Add support for inline boxes.
+                needsNonRootInlineBoxDisplayBox = true;
                 continue;
             }
 
@@ -397,6 +408,76 @@
         }
     };
     createDisplayBoxesInVisualOrderForContentRuns();
+
+    auto createDisplayBoxesInVisualOrderForInlineBoxes = [&] {
+        // Visual order could introduce gaps and/or inject runs outside from the current inline box content.
+        // In such cases, we need to "close" and "open" display boxes for these inline box fragments
+        // to accommodate the current content.
+        // We do it by finding the lowest common ancestor of the last and the current content display boxes and
+        // traverse both ancestor chains and close/open the parent (inline) boxes.
+        // (open here means to create a new display box, while close means to simply pop it out of parentBoxStack).
+        // <div>a<span id=first>b&#8238;g</span>f<span id=second>e&#8237;c</span>d</div>
+        // produces the following output (note the #8238; #8237; RTL/LTR control characters):
+        // abcdefg
+        // with the following, fragmented inline boxes:
+        // a[first open]b[first close][second open]c[second close]d[second open]e[second close]f[first open]g[first close]
+        ListHashSet<const Box*> parentBoxStack;
+        parentBoxStack.add(&root());
+
+        ASSERT(boxes[0].isRootInlineBox());
+        for (size_t index = 1; index < boxes.size(); ++index) {
+            auto& parentBox = boxes[index].layoutBox().parent();
+            ASSERT(parentBox.isInlineBox() || &parentBox == &root());
+
+            auto runParentIsCurrentInlineBox = &parentBox == parentBoxStack.last();
+            if (runParentIsCurrentInlineBox) {
+                // We've got the correct inline box as parent. Nothing to do here.
+                continue;
+            }
+            auto parentBoxStackEnd = parentBoxStack.end();
+            Vector<const Box*> inlineBoxNeedingDisplayBoxList;
+            for (auto* ancestor = &parentBox; ancestor; ancestor = &ancestor->parent()) {
+                ASSERT(ancestor == &root() || ancestor->isInlineBox());
+                auto parentBoxIterator = parentBoxStack.find(ancestor);
+                if (parentBoxIterator != parentBoxStackEnd) {
+                    // This is the lowest common ancestor.
+                    // Let's traverse both ancestor chains and create/close display boxes as needed.
+                    Vector<const Box*> inlineBoxFragmentsToClose;
+                    for (auto it = ++parentBoxIterator; it != parentBoxStackEnd; ++it)
+                        inlineBoxFragmentsToClose.append(*it);
+
+                    for (auto* inlineBox : makeReversedRange(inlineBoxFragmentsToClose)) {
+                        ASSERT(inlineBox->isInlineBox());
+                        parentBoxStack.remove(inlineBox);
+                    }
+
+                    // Insert new display boxes for inline box fragments on bidi boundary.
+                    for (auto* inlineBox : makeReversedRange(inlineBoxNeedingDisplayBoxList)) {
+                        ASSERT(inlineBox->isInlineBox());
+                        parentBoxStack.add(inlineBox);
+
+                        auto createAndInsertDisplayBoxForInlineBoxFragment = [&] {
+                            auto visualRect = lineBox.logicalBorderBoxForInlineBox(*inlineBox, formattingState().boxGeometry(*inlineBox));
+                            // Use the current content left as the starting point for this display box.
+                            visualRect.setLeft(boxes[index].logicalLeft());
+                            visualRect.moveVertically(lineBoxLogicalTopLeft.y());
+                            // Visual width is not yet known.
+                            visualRect.setWidth({ });
+                            insertInlineBoxDisplayBoxForBidiBoundary(lineBox.inlineLevelBoxForLayoutBox(*inlineBox), visualRect, index, boxes);
+                            ++index;
+                        };
+                        createAndInsertDisplayBoxForInlineBoxFragment();
+                    }
+                    break;
+                }
+                // root may not be the lowest but always a common ancestor.
+                ASSERT(ancestor != &root());
+                inlineBoxNeedingDisplayBoxList.append(ancestor);
+            }
+        }
+    };
+    if (needsNonRootInlineBoxDisplayBox)
+        createDisplayBoxesInVisualOrderForInlineBoxes();
 }
 
 void InlineDisplayContentBuilder::processOverflownRunsForEllipsis(DisplayBoxes& boxes, InlineLayoutUnit lineBoxLogicalRight)

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h (286474 => 286475)


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h	2021-12-03 02:54:36 UTC (rev 286474)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.h	2021-12-03 03:01:38 UTC (rev 286475)
@@ -55,7 +55,7 @@
     void appendAtomicInlineLevelDisplayBox(const Line::Run&, const InlineRect& , DisplayBoxes&);
     void appendInlineBoxDisplayBox(const Line::Run&, const InlineLevelBox&, const InlineRect&, bool linehasContent, DisplayBoxes&);
     void appendSpanningInlineBoxDisplayBox(const Line::Run&, const InlineLevelBox&, const InlineRect&, DisplayBoxes&);
-    void appendInlineBoxDisplayBoxForBidiBoundary(const Box&, const InlineRect&, DisplayBoxes&);
+    void insertInlineBoxDisplayBoxForBidiBoundary(const InlineLevelBox&, const InlineRect&, size_t insertionPoint, DisplayBoxes&);
     void adjustInlineBoxDisplayBoxForBidiBoundary(InlineDisplay::Box&, const InlineRect&);
 
     void setInlineBoxGeometry(const Box&, const InlineRect&, bool isFirstInlineBoxFragment);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to