Modified: trunk/Source/WebCore/ChangeLog (286445 => 286446)
--- trunk/Source/WebCore/ChangeLog 2021-12-02 20:22:40 UTC (rev 286445)
+++ trunk/Source/WebCore/ChangeLog 2021-12-02 21:04:38 UTC (rev 286446)
@@ -1,5 +1,22 @@
2021-12-02 Alan Bujtas <za...@apple.com>
+ [LFC][IFC] Introduce createDisplayBoxesInVisualOrderForContentRuns
+ https://bugs.webkit.org/show_bug.cgi?id=233733
+
+ Reviewed by Antti Koivisto.
+
+ Revert some of the inline box related bidi changes and start with
+ a very simple "let's create the display boxes for all _content_ runs in visual order".
+ This is very similar to InlineDisplayContentBuilder::processNonBidiContent() where we just
+ loop through the content and construct display boxes.
+ This is also in preparation for advancing with the inline box case.
+
+ * layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp:
+ (WebCore::Layout::InlineDisplayContentBuilder::processNonBidiContent):
+ (WebCore::Layout::InlineDisplayContentBuilder::processBidiContent):
+
+2021-12-02 Alan Bujtas <za...@apple.com>
+
[LFC][IFC] Move inline box geometry (BoxGeometry) update logic to a dedicated function
https://bugs.webkit.org/show_bug.cgi?id=233615
Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp (286445 => 286446)
--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp 2021-12-02 20:22:40 UTC (rev 286445)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineDisplayContentBuilder.cpp 2021-12-02 21:04:38 UTC (rev 286446)
@@ -282,7 +282,7 @@
UNUSED_PARAM(inlineBoxRect);
}
-void InlineDisplayContentBuilder::processNonBidiContent(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, DisplayBoxes& boxes)
+void InlineDisplayContentBuilder::processNonBidiContent(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, DisplayBoxes& boxes)
{
// Create the inline boxes on the current line. This is mostly text and atomic inline boxes.
for (auto& lineRun : lineContent.runs) {
@@ -341,118 +341,65 @@
void InlineDisplayContentBuilder::processBidiContent(const LineBuilder::LineContent& lineContent, const LineBox& lineBox, const InlineLayoutPoint& lineBoxLogicalTopLeft, DisplayBoxes& boxes)
{
- // Create the inline boxes on the current line. This is mostly text and atomic inline boxes.
- auto& runs = lineContent.runs;
- ASSERT(lineContent.visualOrderList.size() == runs.size());
+ ASSERT(lineContent.visualOrderList.size() == lineContent.runs.size());
- auto rootInlineBoxRect = lineBox.logicalRectForRootInlineBox();
- auto contentRightInVisualOrder = lineBoxLogicalTopLeft.x();
- // First visual run's initial content position depends on the block's inline direction.
- if (!root().style().isLeftToRightDirection()) {
- // FIXME: This needs the block end position instead of the lineLogicalWidth.
- contentRightInVisualOrder += lineContent.lineLogicalWidth - rootInlineBoxRect.width();
- }
- // Adjust the content start position with the (text)alignment offset (root inline box has the alignment offset and not the individual runs).
- contentRightInVisualOrder += rootInlineBoxRect.left();
- Vector<size_t> inlineBoxStack;
- inlineBoxStack.reserveInitialCapacity(lineBox.nonRootInlineLevelBoxes().size());
+ auto createDisplayBoxesInVisualOrderForContentRuns = [&] {
+ auto rootInlineBoxRect = lineBox.logicalRectForRootInlineBox();
+ auto contentRightInVisualOrder = InlineLayoutUnit { };
+ // First visual run's initial content position depends on the block's inline direction.
+ if (!root().style().isLeftToRightDirection()) {
+ // FIXME: This needs the block end position instead of the lineLogicalWidth.
+ contentRightInVisualOrder += lineContent.lineLogicalWidth - rootInlineBoxRect.width();
+ }
+ // Adjust the content start position with the (text)alignment offset (root inline box has the alignment offset and not the individual runs).
+ contentRightInVisualOrder += rootInlineBoxRect.left();
- for (size_t i = 0; i < runs.size(); ++i) {
- auto visualIndex = lineContent.visualOrderList[i];
- auto& lineRun = runs[visualIndex];
+ auto& runs = lineContent.runs;
+ for (size_t i = 0; i < runs.size(); ++i) {
+ auto visualIndex = lineContent.visualOrderList[i];
+ auto& lineRun = runs[visualIndex];
- auto isContentRun = !lineRun.isInlineBoxStart() && !lineRun.isLineSpanningInlineBoxStart() && !lineRun.isInlineBoxEnd() && !lineRun.isWordBreakOpportunity();
- if (!isContentRun)
- continue;
-
- auto displayBoxRect = [&] {
- auto& layoutBox = lineRun.layoutBox();
- auto logicalRect = InlineRect { };
- auto marginStart = std::optional<LayoutUnit> { };
-
- 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()) {
- marginStart = boxGeometry.marginStart();
- logicalRect = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry);
- } else
- ASSERT_NOT_REACHED();
+ auto isContentRun = !lineRun.isInlineBoxStart() && !lineRun.isLineSpanningInlineBoxStart() && !lineRun.isInlineBoxEnd();
+ if (!isContentRun) {
+ // FIXME: Add support for inline boxes.
+ continue;
}
- 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 + marginStart.value_or(0);
- visualOrderRect.setLeft(contentLeft);
- return visualOrderRect;
- }();
- auto handleInlineBoxBoundariesIfApplicable = [&] {
- // Visual order could introduce gaps and/or inject runs outside from the current inline box content.
- // In such cases, we need to "close" the inline box(es) and "open" a new one(s) to accommodate the current content.
- // <div>a<span id=first>b‮g</span>f<span id=second>e‭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]
- auto& parentBox = lineRun.layoutBox().parent();
- ASSERT(parentBox.isInlineBox() || &parentBox == &root());
+ auto visualRectRelativeToRoot = [&](auto logicallRect) {
+ logicallRect.setLeft(contentRightInVisualOrder);
+ logicallRect.moveBy(lineBoxLogicalTopLeft);
+ return logicallRect;
+ };
- auto runParentIsCurrentInlineBox = (&parentBox == &root() && inlineBoxStack.isEmpty())
- || (!inlineBoxStack.isEmpty() && &parentBox == &boxes[inlineBoxStack.last()].layoutBox());
- if (runParentIsCurrentInlineBox) {
- // We've got the correct inline box as parent. Nothing to do here.
- return;
+ if (lineRun.isText()) {
+ auto visualRect = visualRectRelativeToRoot(lineBox.logicalRectForTextRun(lineRun));
+ appendTextDisplayBox(lineRun, visualRect, boxes);
+ contentRightInVisualOrder += visualRect.width();
+ continue;
}
- // If this run is not nested inside the current inline box (meaning it visually got injected in-between the inline box content)
- // we need to "close" all the nested inline boxes first (e.g. see the example above; right before appending "c").
- while (!inlineBoxStack.isEmpty()) {
- auto& inlineBoxDisplayBox = boxes[inlineBoxStack.last()];
- if (&parentBox == &inlineBoxDisplayBox.layoutBox())
- break;
- inlineBoxStack.removeLast();
- // FIXME: Compute geometry for this inline box fragment.
- adjustInlineBoxDisplayBoxForBidiBoundary(inlineBoxDisplayBox, { });
+ if (lineRun.isSoftLineBreak()) {
+ ASSERT(!visualRectRelativeToRoot(lineBox.logicalRectForTextRun(lineRun)).width());
+ appendSoftLineBreakDisplayBox(lineRun, visualRectRelativeToRoot(lineBox.logicalRectForTextRun(lineRun)), boxes);
+ continue;
}
-
- // We also may need to "open" new inline boxes if the current content is nested inside inline boxes (e.g. see the example above; right before "g")
- for (auto* ancestor = &parentBox; ancestor != &root(); ancestor = &ancestor->parent()) {
- ASSERT(ancestor->isInlineBox());
- auto& inlineBox = *ancestor;
- inlineBoxStack.append(boxes.size());
- // FIXME: Compute geometry for this inline box fragment.
- appendInlineBoxDisplayBoxForBidiBoundary(inlineBox, { }, boxes);
+ if (lineRun.isHardLineBreak()) {
+ ASSERT(!visualRectRelativeToRoot(lineBox.logicalRectForLineBreakBox(lineRun.layoutBox())).width());
+ appendHardLineBreakDisplayBox(lineRun, visualRectRelativeToRoot(lineBox.logicalRectForLineBreakBox(lineRun.layoutBox())), boxes);
+ continue;
}
- };
- handleInlineBoxBoundariesIfApplicable();
-
- if (lineRun.isText())
- appendTextDisplayBox(lineRun, displayBoxRect, boxes);
- else if (lineRun.isSoftLineBreak())
- appendSoftLineBreakDisplayBox(lineRun, displayBoxRect, boxes);
- else if (lineRun.isHardLineBreak())
- appendHardLineBreakDisplayBox(lineRun, displayBoxRect, boxes);
- else if (lineRun.isBox())
- appendAtomicInlineLevelDisplayBox(lineRun, displayBoxRect, boxes);
- else
- ASSERT_NOT_REACHED();
-
- contentRightInVisualOrder = displayBoxRect.right();
- }
-
- // Close the remaining nested inline boxes.
- // <div>a<span>b‮d</span>c</div>
- // At the end of the run list loop when we finished processing [d], the inline box (<span>) is still "open".
- for (auto& inlineBoxIndex : inlineBoxStack) {
- // FIXME: Compute geometry for this inline box fragment.
- adjustInlineBoxDisplayBoxForBidiBoundary(boxes[inlineBoxIndex], { });
- }
+ if (lineRun.isBox()) {
+ auto& layoutBox = lineRun.layoutBox();
+ auto& boxGeometry = formattingState().boxGeometry(layoutBox);
+ auto visualRect = visualRectRelativeToRoot(lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, boxGeometry));
+ visualRect.moveHorizontally(boxGeometry.marginStart());
+ appendAtomicInlineLevelDisplayBox(lineRun, visualRect, boxes);
+ contentRightInVisualOrder += boxGeometry.marginStart() + visualRect.width() + boxGeometry.marginEnd();
+ continue;
+ }
+ ASSERT(lineRun.isWordBreakOpportunity());
+ }
+ };
+ createDisplayBoxesInVisualOrderForContentRuns();
}
void InlineDisplayContentBuilder::processOverflownRunsForEllipsis(DisplayBoxes& boxes, InlineLayoutUnit lineBoxLogicalRight)