Skip to content

Commit

Permalink
REGRESSION(267944@main): wpt /css/CSS2/positioning/abspos-block-level…
Browse files Browse the repository at this point in the history
…-001.html

https://bugs.webkit.org/show_bug.cgi?id=263892

Reviewed by Antti Koivisto.

This patch extends the logic of "is there an inflow content before this out of flow box" by
taking inline direction into account.

We already handle bidi (logical position vs. visual position) just fine but there's another layer of visual order here.
When the content is RTL (again not to be confused with bidi) the logic of finding out if an out of flow box
has preceding in flow content needs to start from the (visual) right edge and follow the inline direction.
(i.e. in addition to resolving the logical -> visual order, we also need to travers these run lists in inline direction order)

* Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::InlineDisplayContentBuilder::processBidiContent):
(WebCore::Layout::setGeometryForOutOfFlowBoxes):
(WebCore::Layout::InlineDisplayContentBuilder::setGeometryForBlockLevelOutOfFlowBoxes):
* Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.h:
(WebCore::Layout::InlineDisplayContentBuilder::setGeometryForBlockLevelOutOfFlowBoxes):

Canonical link: https://commits.webkit.org/270069@main
  • Loading branch information
alanbaradlay committed Nov 1, 2023
1 parent af06b86 commit f1664d7
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<style>
.container {
direction: rtl;
}
.abs_pos {
display: inline-block;
width: 500px;
height: 100px;
background-color: blue;
}
</style>
<div class=container>PASS if this text is visible<br><div class=abs_pos></div></div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<style>
.container {
direction: rtl;
}
.abs_pos {
position: absolute;
width: 500px;
height: 100px;
background-color: blue;
}
</style>
<div class=container>PASS if this text is visible <div class=abs_pos></div></div>
Original file line number Diff line number Diff line change
Expand Up @@ -763,10 +763,10 @@ void InlineDisplayContentBuilder::processBidiContent(const LineLayoutResult& lin
auto contentRightInInlineDirectionVisualOrder = contentStartInInlineDirectionVisualOrder;
auto& inlineContent = lineLayoutResult.inlineContent;
for (size_t index = 0; index < lineLayoutResult.directionality.visualOrderList.size(); ++index) {
auto visualOrder = lineLayoutResult.directionality.visualOrderList[index];
ASSERT(inlineContent[visualOrder].bidiLevel() != InlineItem::opaqueBidiLevel);
auto logicalIndex = lineLayoutResult.directionality.visualOrderList[index];
ASSERT(inlineContent[logicalIndex].bidiLevel() != InlineItem::opaqueBidiLevel);

auto& lineRun = inlineContent[visualOrder];
auto& lineRun = inlineContent[logicalIndex];
auto& layoutBox = lineRun.layoutBox();

auto needsDisplayBoxOrGeometrySetting = !lineRun.isWordBreakOpportunity() && !lineRun.isInlineBoxEnd();
Expand Down Expand Up @@ -951,32 +951,75 @@ void InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes(InlineDisplay
}
}

void InlineDisplayContentBuilder::setGeometryForBlockLevelOutOfFlowBoxes(const Vector<size_t> indexListOfOutOfFlowBoxes, const LineBox& lineBox, const Line::RunList& lineRuns, const Vector<int32_t>& visualOrderList)
static inline size_t runIndex(auto i, auto listSize, auto isLeftToRightDirection)
{
if (isLeftToRightDirection)
return i;
auto lastIndex = listSize - 1;
return lastIndex - i;
}

static inline void setGeometryForOutOfFlowBoxes(const Vector<size_t>& indexListOfOutOfFlowBoxes, std::optional<size_t> firstOutOfFlowIndexWithPreviousInflowSibling, const Line::RunList& lineRuns, const Vector<int32_t>& visualOrderList, InlineFormattingContext& formattingContext, const LineBox& lineBox, const ConstraintsForInlineContent& constraints)
{
auto isLeftToRightDirection = formattingContext.root().style().isLeftToRightDirection();
auto outOfFlowBoxListSize = indexListOfOutOfFlowBoxes.size();

auto outOfFlowBox = [&](size_t i) -> const Box& {
auto outOfFlowRunIndex = indexListOfOutOfFlowBoxes[runIndex(i, outOfFlowBoxListSize, isLeftToRightDirection)];
return (visualOrderList.isEmpty() ? lineRuns[outOfFlowRunIndex] : lineRuns[visualOrderList[outOfFlowRunIndex]]).layoutBox();
};
// Set geometry on "before inflow content" boxes first, followed by the "after inflow content" list.
auto beforeAfterBoundary = firstOutOfFlowIndexWithPreviousInflowSibling.value_or(outOfFlowBoxListSize);
// These out of flow boxes "sit" on the line start (they are before any inflow content e.g. <div><div class=out-of-flow></div>some text<div>)
for (size_t i = 0; i < beforeAfterBoundary; ++i)
formattingContext.geometryForBox(outOfFlowBox(i)).setTopLeft({ constraints.horizontal().logicalLeft, lineBox.logicalRect().top() });
// These out of flow boxes are all _after_ an inflow content and get "wrapped" to the next line.
for (size_t i = beforeAfterBoundary; i < outOfFlowBoxListSize; ++i)
formattingContext.geometryForBox(outOfFlowBox(i)).setTopLeft({ constraints.horizontal().logicalLeft, lineBox.logicalRect().bottom() });
}

void InlineDisplayContentBuilder::setGeometryForBlockLevelOutOfFlowBoxes(const Vector<size_t>& indexListOfOutOfFlowBoxes, const LineBox& lineBox, const Line::RunList& lineRuns, const Vector<int32_t>& visualOrderList)
{
if (indexListOfOutOfFlowBoxes.isEmpty())
return;

// Block level boxes are placed either at the start of the line or "under" depending whether they have previous inflow sibling.
// Here we figure out if a particular out of flow box has an inflow sibling or not.
// 1. Find the first inflow content. Any out of flow box after this gets moved _under_ the line box.
// 2. Loop through the out of flow boxes (indexListOfOutOfFlowBoxes) and set their vertical geometry depending whether they are before or after the first inflow content.
// Note that there's an extra layer of directionality here: in case of right to left inline direction, the before inflow content check starts from the right edge and progresses in a leftward manner
// and not in visual order. However this is not logical order either (which is more about bidi than inline direction). So LTR starts at the left while RTL starts at the right and in
// both cases jumping from run to run in bidi order.
auto& formattingContext = this->formattingContext();
auto outOfFlowContentHasPreviousInFlowSiblingWithContentOrDecoration = false;

for (size_t i = 0; i < indexListOfOutOfFlowBoxes.size(); ++i) {
auto outOfFlowBoxIndex = indexListOfOutOfFlowBoxes[i];
ASSERT(outOfFlowBoxIndex < lineRuns.size());

auto hasPreviousInFlowContent = [&] {
if (outOfFlowContentHasPreviousInFlowSiblingWithContentOrDecoration)
return true;
for (size_t previousRunIndex = !i ? 0 : indexListOfOutOfFlowBoxes[i - 1] + 1; previousRunIndex < outOfFlowBoxIndex; ++previousRunIndex) {
auto& previousRun = visualOrderList.isEmpty() ? lineRuns[previousRunIndex] : lineRuns[visualOrderList[previousRunIndex]];
if (Line::Run::isContentfulOrHasDecoration(previousRun, formattingContext)) {
outOfFlowContentHasPreviousInFlowSiblingWithContentOrDecoration = true;
return true;
}
}
return false;
};
// Block level boxes are placed either at the start of the line or "under" depending whether they have previous inflow sibling.
auto logicalTop = hasPreviousInFlowContent() ? lineBox.logicalRect().bottom() : lineBox.logicalRect().top();
auto& lineRun = visualOrderList.isEmpty() ? lineRuns[outOfFlowBoxIndex] : lineRuns[visualOrderList[outOfFlowBoxIndex]];
formattingContext.geometryForBox(lineRun.layoutBox()).setTopLeft({ constraints().horizontal().logicalLeft, logicalTop });
auto isLeftToRightDirection = root().style().isLeftToRightDirection();

auto firstContentfulInFlowRunIndex = std::optional<size_t> { };
auto contentListSize = visualOrderList.isEmpty() ? lineRuns.size() : visualOrderList.size();
for (size_t i = 0; i < contentListSize; ++i) {
auto index = runIndex(i, contentListSize, isLeftToRightDirection);
auto& lineRun = visualOrderList.isEmpty() ? lineRuns[index] : lineRuns[visualOrderList[index]];
if (lineRun.layoutBox().isInFlow() && Line::Run::isContentfulOrHasDecoration(lineRun, formattingContext)) {
firstContentfulInFlowRunIndex = index;
break;
}
}

if (!firstContentfulInFlowRunIndex) {
setGeometryForOutOfFlowBoxes(indexListOfOutOfFlowBoxes, { }, lineRuns, visualOrderList, formattingContext, lineBox, constraints());
return;
}

auto firstOutOfFlowIndexWithPreviousInflowSibling = std::optional<size_t> { };
auto outOfFlowBoxListSize = indexListOfOutOfFlowBoxes.size();
for (size_t i = 0; i < outOfFlowBoxListSize; ++i) {
auto outOfFlowIndex = runIndex(i, outOfFlowBoxListSize, isLeftToRightDirection);
auto hasPreviousInflowSibling = (isLeftToRightDirection && indexListOfOutOfFlowBoxes[outOfFlowIndex] > *firstContentfulInFlowRunIndex) || (!isLeftToRightDirection && indexListOfOutOfFlowBoxes[outOfFlowIndex] < *firstContentfulInFlowRunIndex);
if (hasPreviousInflowSibling) {
firstOutOfFlowIndexWithPreviousInflowSibling = outOfFlowIndex;
break;
}
}
setGeometryForOutOfFlowBoxes(indexListOfOutOfFlowBoxes, firstOutOfFlowIndexWithPreviousInflowSibling, lineRuns, visualOrderList, formattingContext, lineBox, constraints());
}

static float logicalBottomForTextDecorationContent(const InlineDisplay::Boxes& boxes, bool isHorizontalWritingMode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class InlineDisplayContentBuilder {
void setRightForWritingMode(InlineDisplay::Box&, InlineLayoutUnit logicalRight, WritingMode) const;
InlineLayoutPoint movePointHorizontallyForWritingMode(const InlineLayoutPoint& topLeft, InlineLayoutUnit horizontalOffset, WritingMode) const;
InlineLayoutUnit outsideListMarkerVisualPosition(const ElementBox&) const;
void setGeometryForBlockLevelOutOfFlowBoxes(const Vector<size_t> indexList, const LineBox&, const Line::RunList&, const Vector<int32_t>& visualOrderList = { });
void setGeometryForBlockLevelOutOfFlowBoxes(const Vector<size_t>& indexList, const LineBox&, const Line::RunList&, const Vector<int32_t>& visualOrderList = { });

bool isLineFullyTruncatedInBlockDirection() const { return m_lineIsFullyTruncatedInBlockDirection; }

Expand Down

0 comments on commit f1664d7

Please sign in to comment.