Skip to content

Commit

Permalink
[IFC] Use opaque InlineItem to compute out-of-flow static position
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=260776

Reviewed by Antti Koivisto.

Let's replace existing out-of-flow handling with using opaque inline items instead.
1. Add out-of-flow content to the inline item list as opaque box and run regular inline layout.
2. Set static position as part of the inline display content building process where we iterate through the runs on the current line.
3. Since this is all part of _inflow_ layout, we don't need the dedicated _out_of_flow_ method on InlineFormattingContext anymore.
4. Remove existing logic where we compute the static position by looking at adjacent display box geometries.

* LayoutTests/compositing/repaint/move-backing-sharing-layer-expected.txt:
* LayoutTests/platform/ios-wk2/compositing/repaint/move-backing-sharing-layer-expected.txt:
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::layoutOutOfFlowContent): Deleted.
(WebCore::Layout::InlineFormattingContext::computeStaticPositionForOutOfFlowContent): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h:
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp:
(WebCore::Layout::firstDisplayBoxIndexForLayoutBox): Deleted.
(WebCore::Layout::lastDisplayBoxIndexForLayoutBox): Deleted.
(WebCore::Layout::previousDisplayBoxIndex): Deleted.
(WebCore::Layout::nextDisplayBoxIndex): Deleted.
(WebCore::Layout::InlineFormattingGeometry::contentLeftAfterLastLine const): Deleted.
(WebCore::Layout::InlineFormattingGeometry::staticPositionForOutOfFlowInlineLevelBox const): Deleted.
(WebCore::Layout::InlineFormattingGeometry::staticPositionForOutOfFlowBlockLevelBox const): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h:
* Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.cpp:
(WebCore::Layout::InlineItemsBuilder::build):
(WebCore::Layout::InlineItemsBuilder::collectInlineItems):
* Source/WebCore/layout/formattingContexts/inline/InlineItemsBuilder.h:
* Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::removeOverflowingOurOfFlowContent):
* Source/WebCore/layout/formattingContexts/inline/InlineLine.h:
* Source/WebCore/layout/formattingContexts/inline/InlineLineBox.cpp:
(WebCore::Layout::LineBox::logicalRectForOpaqueBox const):
* Source/WebCore/layout/formattingContexts/inline/InlineLineBox.h:
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::placeInlineAndFloatContent):
* Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::InlineDisplayContentBuilder::processNonBidiContent):
* Source/WebCore/layout/integration/inline/LayoutIntegrationLineLayout.cpp:
(WebCore::LayoutIntegration::LineLayout::layout):

Canonical link: https://commits.webkit.org/267456@main
  • Loading branch information
alanbaradlay committed Aug 30, 2023
1 parent 9dce195 commit bac664c
Show file tree
Hide file tree
Showing 18 changed files with 104 additions and 218 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
(bounds 802.00 202.00)
(drawsContent 1)
(repaint rects
(rect 0.00 1.00 802.00 1.00)
(rect 201.00 51.00 100.00 100.00)
(rect 401.00 51.00 100.00 100.00)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
(bounds 802.00 202.00)
(drawsContent 1)
(repaint rects
(rect 0.00 1.00 802.00 1.00)
(rect 201.00 51.00 100.00 100.00)
(rect 401.00 51.00 100.00 100.00)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ FlexLayout::SizeList FlexLayout::hypotheticalCrossSizeForFlexItems(const Logical
auto& inlineFormattingState = flexFormattingContext().layoutState().ensureInlineFormattingState(flexItemBox);
auto inlineFormattingContext = InlineFormattingContext { flexItemBox, inlineFormattingState };
auto constraintsForInFlowContent = ConstraintsForInFlowContent { HorizontalConstraints { { }, flexItemsMainSizeList[flexItemIndex] }, { } };
auto layoutResult = inlineFormattingContext.layoutInFlowAndFloatContent({ constraintsForInFlowContent, { } }, inlineLayoutState);
auto layoutResult = inlineFormattingContext.layout({ constraintsForInFlowContent, { } }, inlineLayoutState);
return LayoutUnit { layoutResult.displayContent.lines.last().lineBoxLogicalRect().maxY() };
};
auto usedCrossSize = crossSizeAfterPerformingLayout();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ InlineFormattingContext::InlineFormattingContext(const ElementBox& formattingCon
{
}

InlineLayoutResult InlineFormattingContext::layoutInFlowAndFloatContent(const ConstraintsForInlineContent& constraints, InlineLayoutState& inlineLayoutState, const InlineDamage* lineDamage)
InlineLayoutResult InlineFormattingContext::layout(const ConstraintsForInlineContent& constraints, InlineLayoutState& inlineLayoutState, const InlineDamage* lineDamage)
{
auto& floatingState = inlineLayoutState.parentBlockLayoutState().floatingState();
if (!root().hasInFlowChild()) {
if (!root().hasInFlowChild() && !root().hasOutOfFlowChild()) {
// Float only content does not support partial layout.
ASSERT(!lineDamage);
layoutFloatContentOnly(constraints, floatingState);
Expand Down Expand Up @@ -114,12 +114,6 @@ InlineLayoutResult InlineFormattingContext::layoutInFlowAndFloatContent(const Co
return lineLayout(lineBuilder, inlineItems, needsLayoutRange, previousLine(), constraints, inlineLayoutState, lineDamage);
}

void InlineFormattingContext::layoutOutOfFlowContent(const ConstraintsForInlineContent& constraints, InlineLayoutState& inlineLayoutState, const InlineDisplay::Content& inlineDisplayContent)
{
// Collecting out-of-flow boxes happens during the in-flow phase.
computeStaticPositionForOutOfFlowContent(formattingState().outOfFlowBoxes(), constraints, inlineDisplayContent, inlineLayoutState.parentBlockLayoutState().floatingState());
}

IntrinsicWidthConstraints InlineFormattingContext::computedIntrinsicSizes(const InlineDamage* lineDamage)
{
auto& inlineFormattingState = formattingState();
Expand Down Expand Up @@ -243,26 +237,6 @@ void InlineFormattingContext::layoutFloatContentOnly(const ConstraintsForInlineC
}
}

void InlineFormattingContext::computeStaticPositionForOutOfFlowContent(const FormattingState::OutOfFlowBoxList& outOfFlowBoxes, const ConstraintsForInFlowContent& constraints, const InlineDisplay::Content& displayContent, const FloatingState& floatingState)
{
// This function computes the static position for out-of-flow content inside the inline formatting context.
// As per spec, the static position of an out-of-flow box is computed as if the position was set to static.
// However it does not mean that the out-of-flow box should be involved in the inline layout process.
// Instead we figure out this static position after the inline layout by looking at the previous/next sibling (or parent) box's geometry and
// place the out-of-flow box at the logical right position.
auto& formattingGeometry = this->formattingGeometry();
auto& formattingState = this->formattingState();
auto floatingContext = FloatingContext { *this, floatingState };

for (auto& outOfFlowBox : outOfFlowBoxes) {
if (outOfFlowBox->style().isOriginalDisplayInlineType()) {
formattingState.boxGeometry(outOfFlowBox).setLogicalTopLeft(formattingGeometry.staticPositionForOutOfFlowInlineLevelBox(outOfFlowBox, constraints, displayContent, floatingContext));
continue;
}
formattingState.boxGeometry(outOfFlowBox).setLogicalTopLeft(formattingGeometry.staticPositionForOutOfFlowBlockLevelBox(outOfFlowBox, constraints, displayContent));
}
}

static LineEndingEllipsisPolicy lineEndingEllipsisPolicy(const RenderStyle& rootStyle, size_t numberOfLines, std::optional<size_t> numberOfVisibleLinesAllowed)
{
// We may have passed the line-clamp line with overflow visible.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ class InlineFormattingContext final : public FormattingContext {
public:
InlineFormattingContext(const ElementBox& formattingContextRoot, InlineFormattingState&);

InlineLayoutResult layoutInFlowAndFloatContent(const ConstraintsForInlineContent&, InlineLayoutState&, const InlineDamage* = nullptr);
void layoutOutOfFlowContent(const ConstraintsForInlineContent&, InlineLayoutState&, const InlineDisplay::Content&);
InlineLayoutResult layout(const ConstraintsForInlineContent&, InlineLayoutState&, const InlineDamage* = nullptr);
IntrinsicWidthConstraints computedIntrinsicSizes(const InlineDamage*);
LayoutUnit maximumContentSize();

Expand All @@ -71,7 +70,6 @@ class InlineFormattingContext final : public FormattingContext {
private:
InlineLayoutResult lineLayout(AbstractLineBuilder&, const InlineItems&, InlineItemRange, std::optional<PreviousLine>, const ConstraintsForInlineContent&, InlineLayoutState&, const InlineDamage* = nullptr);
void layoutFloatContentOnly(const ConstraintsForInlineContent&, FloatingState&);
void computeStaticPositionForOutOfFlowContent(const FormattingState::OutOfFlowBoxList&, const ConstraintsForInFlowContent&, const InlineDisplay::Content&, const FloatingState&);

void collectContentIfNeeded();
InlineRect createDisplayContentForLine(size_t lineIndex, const LineLayoutResult&, const ConstraintsForInlineContent&, const InlineLayoutState&, InlineDisplay::Content&);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,174 +209,6 @@ InlineLayoutUnit InlineFormattingGeometry::computedTextIndent(IsIntrinsicWidthMo
return { minimumValueForLength(textIndent, availableWidth) };
}

static std::optional<size_t> firstDisplayBoxIndexForLayoutBox(const Box& layoutBox, const InlineDisplay::Boxes& displayBoxes)
{
// FIXME: Build a first/last hashmap for these boxes.
for (size_t index = 0; index < displayBoxes.size(); ++index) {
if (displayBoxes[index].isRootInlineBox())
continue;
if (&displayBoxes[index].layoutBox() == &layoutBox)
return index;
}
return { };
}

static std::optional<size_t> lastDisplayBoxIndexForLayoutBox(const Box& layoutBox, const InlineDisplay::Boxes& displayBoxes)
{
// FIXME: Build a first/last hashmap for these boxes.
for (auto index = displayBoxes.size(); index--;) {
if (displayBoxes[index].isRootInlineBox())
continue;
if (&displayBoxes[index].layoutBox() == &layoutBox)
return index;
}
return { };
}

static std::optional<size_t> previousDisplayBoxIndex(const Box& outOfFlowBox, const InlineDisplay::Boxes& displayBoxes)
{
auto previousDisplayBoxIndexOf = [&] (auto& layoutBox) -> std::optional<size_t> {
for (auto* box = &layoutBox; box; box = box->previousInFlowSibling()) {
if (auto displayBoxIndex = lastDisplayBoxIndexForLayoutBox(*box, displayBoxes))
return displayBoxIndex;
}
return { };
};

auto* candidateBox = outOfFlowBox.previousInFlowSibling();
if (!candidateBox)
candidateBox = outOfFlowBox.parent().isInlineBox() ? &outOfFlowBox.parent() : nullptr;
while (candidateBox) {
if (auto displayBoxIndex = previousDisplayBoxIndexOf(*candidateBox))
return displayBoxIndex;
candidateBox = candidateBox->parent().isInlineBox() ? &candidateBox->parent() : nullptr;
}
return { };
}

static std::optional<size_t> nextDisplayBoxIndex(const Box& outOfFlowBox, const InlineDisplay::Boxes& displayBoxes)
{
auto nextDisplayBoxIndexOf = [&] (auto& layoutBox) -> std::optional<size_t> {
for (auto* box = &layoutBox; box; box = box->nextInFlowSibling()) {
if (auto displayBoxIndex = firstDisplayBoxIndexForLayoutBox(*box, displayBoxes))
return displayBoxIndex;
}
return { };
};

auto* candidateBox = outOfFlowBox.nextInFlowSibling();
if (!candidateBox)
candidateBox = outOfFlowBox.parent().isInlineBox() ? outOfFlowBox.parent().nextInFlowSibling() : nullptr;
while (candidateBox) {
if (auto displayBoxIndex = nextDisplayBoxIndexOf(*candidateBox))
return displayBoxIndex;
candidateBox = candidateBox->parent().isInlineBox() ? candidateBox->parent().nextInFlowSibling() : nullptr;
}
return { };
}

InlineLayoutUnit InlineFormattingGeometry::contentLeftAfterLastLine(const ConstraintsForInFlowContent& constraints, std::optional<InlineLayoutUnit> lastLineLogicalBottom, const FloatingContext& floatingContext) const
{
auto contentHasPreviousLine = lastLineLogicalBottom ? std::make_optional(true) : std::nullopt;
auto textIndent = computedTextIndent(IsIntrinsicWidthMode::No, contentHasPreviousLine, constraints.horizontal().logicalWidth);
auto floatConstraints = floatConstraintsForLine(lastLineLogicalBottom.value_or(constraints.logicalTop()), 0, floatingContext);
auto lineBoxLeft = constraints.horizontal().logicalLeft;
auto lineBoxWidth = constraints.horizontal().logicalWidth;
// FIXME: Add missing RTL support.
if (floatConstraints.left) {
auto floatOffset = std::max(0_lu, floatConstraints.left->x - constraints.horizontal().logicalLeft);
lineBoxLeft += floatOffset;
lineBoxWidth -= floatOffset;
}
if (floatConstraints.right) {
auto lineBoxRight = (constraints.horizontal().logicalLeft + constraints.horizontal().logicalWidth);
auto floatOffset = std::max(0_lu, lineBoxRight - floatConstraints.right->x);
lineBoxWidth -= floatOffset;
}
lineBoxLeft += textIndent;
auto rootInlineBoxLeft = horizontalAlignmentOffset(formattingContext().root().style(), { }, lineBoxWidth, { }, { }, true);
return lineBoxLeft + rootInlineBoxLeft;
}

LayoutPoint InlineFormattingGeometry::staticPositionForOutOfFlowInlineLevelBox(const Box& outOfFlowBox, const ConstraintsForInFlowContent& constraints, const InlineDisplay::Content& displayContent, const FloatingContext& floatingContext) const
{
ASSERT(outOfFlowBox.style().isOriginalDisplayInlineType());
auto& lines = displayContent.lines;
auto& boxes = displayContent.boxes;

if (lines.isEmpty()) {
ASSERT(boxes.isEmpty());
return { contentLeftAfterLastLine(constraints, { }, floatingContext), constraints.logicalTop() };
}

auto isHorizontalWritingMode = formattingContext().root().style().isHorizontalWritingMode();
auto leftSideToLogicalTopLeft = [&] (auto& displayBox, auto& line, bool mayNeedMarginAdjustment = true) {
auto marginStart = LayoutUnit { };
if (mayNeedMarginAdjustment && displayBox.isNonRootInlineLevelBox())
marginStart = formattingContext().geometryForBox(displayBox.layoutBox()).marginStart();
return isHorizontalWritingMode ? LayoutPoint(displayBox.left() - marginStart, line.top()) : LayoutPoint(displayBox.top() - marginStart, line.left());
};
auto rightSideToLogicalTopLeft = [&] (auto& displayBox, auto& line) {
auto marginEnd = LayoutUnit { };
if (displayBox.isNonRootInlineLevelBox())
marginEnd = formattingContext().geometryForBox(displayBox.layoutBox()).marginEnd();
return isHorizontalWritingMode ? LayoutPoint(displayBox.right() + marginEnd, line.top()) : LayoutPoint(displayBox.bottom() + marginEnd, line.left());
};

auto previousDisplayBoxIndexBeforeOutOfFlowBox = previousDisplayBoxIndex(outOfFlowBox, boxes);
if (!previousDisplayBoxIndexBeforeOutOfFlowBox)
return leftSideToLogicalTopLeft(boxes[0], lines[0]);

auto& previousDisplayBox = boxes[*previousDisplayBoxIndexBeforeOutOfFlowBox];
auto& currentLine = lines[previousDisplayBox.lineIndex()];
if (previousDisplayBox.isInlineBox() && &outOfFlowBox.parent() == &previousDisplayBox.layoutBox()) {
// Special handling for cases when this is the first box inside an inline box:
// <div>text<span><img style="position: absolute">content</span></div>
auto& inlineBox = previousDisplayBox.layoutBox();
auto inlineBoxDisplayBox = boxes[*firstDisplayBoxIndexForLayoutBox(inlineBox, boxes)];
auto inlineContentBoxOffset = formattingContext().geometryForBox(inlineBox).borderAndPaddingStart();
if (isHorizontalWritingMode)
inlineBoxDisplayBox.moveHorizontally(inlineContentBoxOffset);
else
inlineBoxDisplayBox.moveVertically(inlineContentBoxOffset);
return leftSideToLogicalTopLeft(inlineBoxDisplayBox, lines[inlineBoxDisplayBox.lineIndex()], false);
}

auto previousBoxOverflows = (isHorizontalWritingMode ? previousDisplayBox.right() > currentLine.right() : previousDisplayBox.bottom() > currentLine.bottom()) || previousDisplayBox.isLineBreakBox();
if (!previousBoxOverflows)
return rightSideToLogicalTopLeft(previousDisplayBox, currentLine);

auto nextDisplayBoxIndexAfterOutOfFlow = nextDisplayBoxIndex(outOfFlowBox, boxes);
if (!nextDisplayBoxIndexAfterOutOfFlow) {
// This is the last content on the block and it does not fit the last line.
return { contentLeftAfterLastLine(constraints, currentLine.bottom(), floatingContext), isHorizontalWritingMode ? currentLine.bottom() : currentLine.right() };
}
auto& nextDisplayBox = boxes[*nextDisplayBoxIndexAfterOutOfFlow];
return leftSideToLogicalTopLeft(nextDisplayBox, lines[nextDisplayBox.lineIndex()]);
}

LayoutPoint InlineFormattingGeometry::staticPositionForOutOfFlowBlockLevelBox(const Box& outOfFlowBox, const ConstraintsForInFlowContent& constraints, const InlineDisplay::Content& displayContent) const
{
ASSERT(outOfFlowBox.style().isDisplayBlockLevel());

auto isHorizontalWritingMode = formattingContext().root().style().isHorizontalWritingMode();
auto& lines = displayContent.lines;
auto& boxes = displayContent.boxes;
auto contentBoxTopLeft = LayoutPoint { constraints.horizontal().logicalLeft, constraints.logicalTop() };

if (lines.isEmpty()) {
ASSERT(boxes.isEmpty());
return contentBoxTopLeft;
}

// Block level boxes are placed under the current line as if they were normal inflow block level boxes.
auto previousDisplayBoxIndexBeforeOutOfFlowBox = previousDisplayBoxIndex(outOfFlowBox, boxes);
if (!previousDisplayBoxIndexBeforeOutOfFlowBox)
return { contentBoxTopLeft.x(), isHorizontalWritingMode ? lines[0].top() : lines[0].left() };
auto& currentLine = lines[boxes[*previousDisplayBoxIndexBeforeOutOfFlowBox].lineIndex()];
return { contentBoxTopLeft.x(), LayoutUnit { isHorizontalWritingMode ? currentLine.bottom() : currentLine.right() } };
}

InlineLayoutUnit InlineFormattingGeometry::initialLineHeight(bool isFirstLine) const
{
if (layoutState().inStandardsMode())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ class InlineFormattingGeometry : public FormattingGeometry {

static InlineRect flipVisualRectToLogicalForWritingMode(const InlineRect& visualRect, WritingMode);

LayoutPoint staticPositionForOutOfFlowInlineLevelBox(const Box&, const ConstraintsForInFlowContent&, const InlineDisplay::Content&, const FloatingContext&) const;
LayoutPoint staticPositionForOutOfFlowBlockLevelBox(const Box&, const ConstraintsForInFlowContent&, const InlineDisplay::Content&) const;

void adjustMarginStartForListMarker(const ElementBox&, LayoutUnit nestedListMarkerMarginStart, InlineLayoutUnit rootInlineBoxOffset) const;

static InlineLayoutUnit horizontalAlignmentOffset(const RenderStyle& rootStyle, InlineLayoutUnit contentLogicalRight, InlineLayoutUnit lineLogicalRight, InlineLayoutUnit hangingTrailingWidth, const Line::RunList& runs, bool isLastLine, std::optional<TextDirection> inlineBaseDirectionOverride = std::nullopt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ InlineItemsBuilder::InlineItemsBuilder(const ElementBox& formattingContextRoot,
void InlineItemsBuilder::build(InlineItemPosition startPosition)
{
InlineItems inlineItems;
FormattingState::OutOfFlowBoxList outOfFlowBoxes;

collectInlineItems(inlineItems, outOfFlowBoxes, startPosition);
collectInlineItems(inlineItems, startPosition);

if (!root().style().isLeftToRightDirection() || contentRequiresVisualReordering()) {
// FIXME: Add support for partial, yet paragraph level bidi content handling.
Expand All @@ -109,7 +107,6 @@ void InlineItemsBuilder::build(InlineItemPosition startPosition)
m_formattingState.appendInlineItems(WTFMove(inlineItems));
};
adjustInlineFormattingStateWithNewInlineItems();
m_formattingState.setOutOfFlowBoxes(WTFMove(outOfFlowBoxes));

#if ASSERT_ENABLED
// Check if we've got matching inline box start/end pairs and unique inline level items (non-text, non-inline box items).
Expand Down Expand Up @@ -191,7 +188,7 @@ static LayoutQueue initializeLayoutQueue(const ElementBox& formattingContextRoot
return layoutQueue;
}

void InlineItemsBuilder::collectInlineItems(InlineItems& inlineItems, FormattingState::OutOfFlowBoxList& outOfFlowBoxes, InlineItemPosition startPosition)
void InlineItemsBuilder::collectInlineItems(InlineItems& inlineItems, InlineItemPosition startPosition)
{
// 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]
Expand Down Expand Up @@ -233,9 +230,8 @@ void InlineItemsBuilder::collectInlineItems(InlineItems& inlineItems, Formatting
while (!layoutQueue.isEmpty()) {
auto layoutBox = layoutQueue.takeLast();
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.
outOfFlowBoxes.append(layoutBox);
m_isNonBidiTextAndForcedLineBreakOnlyContent = false;
inlineItems.append({ layoutBox, InlineItem::Type::Opaque });
} else if (layoutBox->isInlineTextBox()) {
auto& inlineTextBox = downcast<InlineTextBox>(layoutBox);
handleTextContent(inlineTextBox, inlineItems, partialContentOffset(inlineTextBox));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class InlineItemsBuilder {
void build(InlineItemPosition startPosition);

private:
void collectInlineItems(InlineItems&, FormattingState::OutOfFlowBoxList&, InlineItemPosition startPosition);
void collectInlineItems(InlineItems&, InlineItemPosition startPosition);
void breakAndComputeBidiLevels(InlineItems&);
void computeInlineTextItemWidths(InlineItems&);

Expand Down
Loading

0 comments on commit bac664c

Please sign in to comment.