Title: [285204] trunk/Source/WebCore
Revision
285204
Author
za...@apple.com
Date
2021-11-03 06:37:55 -0700 (Wed, 03 Nov 2021)

Log Message

[LFC][IFC] Display box builder should take visual order into account when computing horizontal positions
https://bugs.webkit.org/show_bug.cgi?id=232655

Reviewed by Antti Koivisto.

In this patch we turn logical horizontal positions into "physical" positions based on the visual order of the runs.
With this change, now IFC can render simple RTL content.

* layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::InlineDisplayContentBuilder::createBoxesAndUpdateGeometryForLineContent): Move shared code to displayBoxRect.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285203 => 285204)


--- trunk/Source/WebCore/ChangeLog	2021-11-03 12:45:37 UTC (rev 285203)
+++ trunk/Source/WebCore/ChangeLog	2021-11-03 13:37:55 UTC (rev 285204)
@@ -1,3 +1,16 @@
+2021-11-03  Zalan Bujtas  <za...@apple.com>
+
+        [LFC][IFC] Display box builder should take visual order into account when computing horizontal positions
+        https://bugs.webkit.org/show_bug.cgi?id=232655
+
+        Reviewed by Antti Koivisto.
+
+        In this patch we turn logical horizontal positions into "physical" positions based on the visual order of the runs.
+        With this change, now IFC can render simple RTL content.
+
+        * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
+        (WebCore::Layout::InlineDisplayContentBuilder::createBoxesAndUpdateGeometryForLineContent): Move shared code to displayBoxRect. 
+
 2021-11-03  Antti Koivisto  <an...@apple.com>
 
         Use Style::ScopeOrdinal for finding the right scope for ::part matching

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp	2021-11-03 12:45:37 UTC (rev 285203)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp	2021-11-03 13:37:55 UTC (rev 285204)
@@ -74,17 +74,63 @@
     auto& runs = lineContent.runs;
     auto contentNeedsBidiReordering = !lineContent.visualOrderList.isEmpty();
     ASSERT(!contentNeedsBidiReordering || lineContent.visualOrderList.size() == runs.size());
+
+    auto contentRightInVisualOrder = InlineLayoutUnit { };
     for (size_t i = 0; i < runs.size(); ++i) {
-        auto& lineRun = runs[contentNeedsBidiReordering ? lineContent.visualOrderList[i] : i];
+        auto visualIndex = contentNeedsBidiReordering ? lineContent.visualOrderList[i] : i;
+        auto& lineRun = runs[visualIndex];
         auto& layoutBox = lineRun.layoutBox();
         auto& style = [&] () -> const RenderStyle& {
             return !lineIndex ? layoutBox.firstLineStyle() : layoutBox.style();
         }();
 
+        auto displayBoxRect = [&] {
+            auto logicalRect = InlineRect { };
+
+            if (lineRun.isText() || lineRun.isSoftLineBreak())
+                logicalRect = lineBox.logicalRectForTextRun(lineRun);
+            else if (lineRun.isHardLineBreak())
+                logicalRect = lineBox.logicalRectForLineBreakBox(layoutBox);
+            else {
+                auto& boxGeometry = formattingState.boxGeometry(layoutBox);
+                if (lineRun.isBox())
+                    logicalRect = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry);
+                else if (lineRun.isInlineBoxStart() || lineRun.isLineSpanningInlineBoxStart())
+                    logicalRect = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
+                else
+                    ASSERT_NOT_REACHED();
+            }
+            if (!contentNeedsBidiReordering) {
+                logicalRect.moveBy(lineBoxLogicalTopLeft);
+                return logicalRect;
+            }
+            logicalRect.moveVertically(lineBoxLogicalTopLeft.y());
+            // Use the distance from the logical previous run to place the display box horizontally in visual terms.
+            auto* logicalPreviousRun = visualIndex ? &runs[visualIndex - 1] : nullptr;
+            // Certain css properties (e.g. word-spacing) may introduce a gap between runs.
+            auto distanceFromLogicalPreviousRun = logicalPreviousRun ? lineRun.logicalLeft() - logicalPreviousRun->logicalRight() : lineRun.logicalLeft();
+            auto visualOrderRect = logicalRect;
+            auto contentLeft = contentRightInVisualOrder + distanceFromLogicalPreviousRun;
+            if (!i) {
+                // First visual run. Initial content position depends on the block's inline direction.
+                contentLeft += lineBoxLogicalTopLeft.x();
+
+                auto rootInlineBox = boxes[0];
+                ASSERT(rootInlineBox.isRootInlineBox());
+                if (!rootInlineBox.style().isLeftToRightDirection())
+                    contentLeft += lineContent.lineLogicalWidth - rootInlineBox.logicalWidth();
+            }
+            visualOrderRect.setLeft(contentLeft);
+            // The inline box right edge includes its content as well as the inline box end (padding-right etc).
+            // What we need here is the inline box start run's width.
+            contentRightInVisualOrder = lineRun.isInlineBoxStart() || lineRun.isLineSpanningInlineBoxStart()
+                ? visualOrderRect.left() + lineRun.logicalWidth()
+                : visualOrderRect.right();
+            return visualOrderRect;
+        };
+
         if (lineRun.isText()) {
-            auto textRunRect = lineBox.logicalRectForTextRun(lineRun);
-            textRunRect.moveBy(lineBoxLogicalTopLeft);
-
+            auto textRunRect = displayBoxRect();
             auto inkOverflow = [&] {
                 auto initialContaingBlockSize = RuntimeEnabledFeatures::sharedFeatures().layoutFormattingContextIntegrationEnabled()
                     ? formattingState.layoutState().viewportSize()
@@ -116,10 +162,8 @@
             continue;
         }
         if (lineRun.isSoftLineBreak()) {
-            auto softLineBreakRunRect = lineBox.logicalRectForTextRun(lineRun);
-            softLineBreakRunRect.moveBy(lineBoxLogicalTopLeft);
-
             ASSERT(lineRun.textContent() && is<InlineTextBox>(layoutBox));
+            auto softLineBreakRunRect = displayBoxRect();
             auto& text = lineRun.textContent();
             boxes.append({ lineIndex
                 , InlineDisplay::Box::Type::SoftLineBreak
@@ -133,8 +177,7 @@
         }
         if (lineRun.isHardLineBreak()) {
             // Only hard linebreaks have associated layout boxes.
-            auto lineBreakBoxRect = lineBox.logicalRectForLineBreakBox(layoutBox);
-            lineBreakBoxRect.moveBy(lineBoxLogicalTopLeft);
+            auto lineBreakBoxRect = displayBoxRect();
             boxes.append({ lineIndex, InlineDisplay::Box::Type::LineBreakBox, layoutBox, lineRun.bidiLevel(), lineBreakBoxRect, lineBreakBoxRect, lineRun.expansion(), { } });
 
             auto& boxGeometry = formattingState.boxGeometry(layoutBox);
@@ -144,16 +187,13 @@
         }
         if (lineRun.isBox()) {
             ASSERT(layoutBox.isAtomicInlineLevelBox());
-            auto& boxGeometry = formattingState.boxGeometry(layoutBox);
-            auto logicalBorderBox = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry);
-            logicalBorderBox.moveBy(lineBoxLogicalTopLeft);
+            auto borderBoxRect = displayBoxRect();
             // FIXME: Add ink overflow support for atomic inline level boxes (e.g. box shadow).
-            boxes.append({ lineIndex, InlineDisplay::Box::Type::AtomicInlineLevelBox, layoutBox, lineRun.bidiLevel(), logicalBorderBox, logicalBorderBox, lineRun.expansion(), { } });
+            boxes.append({ lineIndex, InlineDisplay::Box::Type::AtomicInlineLevelBox, layoutBox, lineRun.bidiLevel(), borderBoxRect, borderBoxRect, lineRun.expansion(), { } });
 
-            auto borderBoxLogicalTopLeft = logicalBorderBox.topLeft();
             // Note that inline boxes are relative to the line and their top position can be negative.
             // Atomic inline boxes are all set. Their margin/border/content box geometries are already computed. We just have to position them here.
-            boxGeometry.setLogicalTopLeft(toLayoutPoint(borderBoxLogicalTopLeft));
+            formattingState.boxGeometry(layoutBox).setLogicalTopLeft(toLayoutPoint(borderBoxRect.topLeft()));
 
             auto adjustParentInlineBoxInkOverflow = [&] {
                 auto& parentInlineBox = layoutBox.parent();
@@ -162,7 +202,7 @@
                     return;
                 }
                 RELEASE_ASSERT(m_inlineBoxIndexMap.contains(&parentInlineBox));
-                boxes[m_inlineBoxIndexMap.get(&parentInlineBox)].adjustInkOverflow(logicalBorderBox);
+                boxes[m_inlineBoxIndexMap.get(&parentInlineBox)].adjustInkOverflow(borderBoxRect);
             };
             adjustParentInlineBoxInkOverflow();
             continue;
@@ -169,9 +209,7 @@
         }
         if (lineRun.isInlineBoxStart()) {
             // This inline box showed up first on this line.
-            auto& boxGeometry = formattingState.boxGeometry(layoutBox);
-            auto inlineBoxBorderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
-            inlineBoxBorderBox.moveBy(lineBoxLogicalTopLeft);
+            auto inlineBoxBorderBox = displayBoxRect();
             if (lineBox.hasContent()) {
                 // FIXME: It's expected to not have any boxes on empty lines. We should reconsider this.
                 m_inlineBoxIndexMap.add(&layoutBox, boxes.size());
@@ -182,6 +220,7 @@
                 boxes.append({ lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, layoutBox, lineRun.bidiLevel(), inlineBoxBorderBox, inlineBoxBorderBox, { }, { }, inlineBox.hasContent(), isFirstLastBox(inlineBox) });
             }
 
+            auto& boxGeometry = formattingState.boxGeometry(layoutBox);
             auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
             auto logicalRect = Rect { LayoutPoint { inlineBoxBorderBox.topLeft() }, inlineBoxSize };
             boxGeometry.setLogicalTopLeft(logicalRect.topLeft());
@@ -198,13 +237,10 @@
                 // don't extend the spanning line box over to this line -also there is no next line in cases like this.
                 continue;
             }
-            auto& boxGeometry = formattingState.boxGeometry(layoutBox);
-            auto inlineBoxBorderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
-            inlineBoxBorderBox.moveBy(lineBoxLogicalTopLeft);
-
             m_inlineBoxIndexMap.add(&layoutBox, boxes.size());
 
             auto& inlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox);
+            auto inlineBoxBorderBox = displayBoxRect();
             ASSERT(!inlineBox.isFirstBox());
             boxes.append({ lineIndex, InlineDisplay::Box::Type::NonRootInlineBox, layoutBox, lineRun.bidiLevel(), inlineBoxBorderBox, inlineBoxBorderBox, { }, { }, inlineBox.hasContent(), isFirstLastBox(inlineBox) });
 
@@ -211,6 +247,7 @@
             auto inlineBoxSize = LayoutSize { LayoutUnit::fromFloatCeil(inlineBoxBorderBox.width()), LayoutUnit::fromFloatCeil(inlineBoxBorderBox.height()) };
             auto logicalRect = Rect { LayoutPoint { inlineBoxBorderBox.topLeft() }, inlineBoxSize };
             // Middle or end of the inline box. Let's stretch the box as needed.
+            auto& boxGeometry = formattingState.boxGeometry(layoutBox);
             auto enclosingBorderBoxRect = BoxGeometry::borderBoxRect(boxGeometry);
             enclosingBorderBoxRect.expandToContain(logicalRect);
             boxGeometry.setLogicalLeft(enclosingBorderBoxRect.left());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to