Skip to content
Permalink
Browse files
[LFC][IFC] LineBox provides redundant geometry information
https://bugs.webkit.org/show_bug.cgi?id=228050

Reviewed by Sam Weinig.

LineBoxGeometry class provides the line's geometry. This is also in preparation for making LineBox a non-persistent type of structure.

* layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
* layout/formattingContexts/inline/InlineFormattingGeometry.cpp:
(WebCore::Layout::LineBoxBuilder::build):
(WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes):
(WebCore::Layout::LineBoxBuilder::computeLineBoxHeightAndAlignInlineLevelBoxesVertically):
(WebCore::Layout::InlineFormattingGeometry::verticallyAdjustedLineForLineContent const):
(WebCore::Layout::InlineFormattingGeometry::lineBoxForLineContent const): Deleted.
* layout/formattingContexts/inline/InlineFormattingGeometry.h:
* layout/formattingContexts/inline/InlineLineBox.cpp:
(WebCore::Layout::LineBox::LineBox):
(WebCore::Layout::m_rootInlineBox): Deleted.
* layout/formattingContexts/inline/InlineLineBox.h:
(WebCore::Layout::LineBox::logicalRect const): Deleted.
(WebCore::Layout::LineBox::alignmentBaseline const): Deleted.
(WebCore::Layout::LineBox::setLogicalHeight): Deleted.
* layout/integration/LayoutIntegrationInlineContentBuilder.cpp:
(WebCore::LayoutIntegration::InlineContentBuilder::createDisplayNonRootInlineBoxes const):


Canonical link: https://commits.webkit.org/240752@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@281335 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
alanbujtas committed Aug 20, 2021
1 parent 5a2690c commit 591dc1f1d8c8f7c8b50b9ca0d699b25e02f3a058
Showing 11 changed files with 98 additions and 62 deletions.
@@ -1,3 +1,31 @@
2021-08-20 Alan Bujtas <zalan@apple.com>

[LFC][IFC] LineBox provides redundant geometry information
https://bugs.webkit.org/show_bug.cgi?id=228050

Reviewed by Sam Weinig.

LineBoxGeometry class provides the line's geometry. This is also in preparation for making LineBox a non-persistent type of structure.

* layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::computeGeometryForLineContent):
* layout/formattingContexts/inline/InlineFormattingGeometry.cpp:
(WebCore::Layout::LineBoxBuilder::build):
(WebCore::Layout::LineBoxBuilder::constructAndAlignInlineLevelBoxes):
(WebCore::Layout::LineBoxBuilder::computeLineBoxHeightAndAlignInlineLevelBoxesVertically):
(WebCore::Layout::InlineFormattingGeometry::verticallyAdjustedLineForLineContent const):
(WebCore::Layout::InlineFormattingGeometry::lineBoxForLineContent const): Deleted.
* layout/formattingContexts/inline/InlineFormattingGeometry.h:
* layout/formattingContexts/inline/InlineLineBox.cpp:
(WebCore::Layout::LineBox::LineBox):
(WebCore::Layout::m_rootInlineBox): Deleted.
* layout/formattingContexts/inline/InlineLineBox.h:
(WebCore::Layout::LineBox::logicalRect const): Deleted.
(WebCore::Layout::LineBox::alignmentBaseline const): Deleted.
(WebCore::Layout::LineBox::setLogicalHeight): Deleted.
* layout/integration/LayoutIntegrationInlineContentBuilder.cpp:
(WebCore::LayoutIntegration::InlineContentBuilder::createDisplayNonRootInlineBoxes const):

2021-08-20 Wenson Hsieh <wenson_hsieh@apple.com>

Followup to <trac.webkit.org/r281288>
@@ -143,7 +143,7 @@ std::unique_ptr<Box> BoxFactory::displayBoxForLayoutBox(const Layout::Box& layou
return makeUnique<Box>(m_treeBuilder.tree(), pixelSnappedBorderBoxRect, WTFMove(style), flags);
}

std::unique_ptr<Box> BoxFactory::displayBoxForTextRun(const Layout::LineRun& run, const Layout::InlineLineGeometry& lineGeometry, const ContainingBlockContext& containingBlockContext) const
std::unique_ptr<Box> BoxFactory::displayBoxForTextRun(const Layout::LineRun& run, const Layout::LineGeometry& lineGeometry, const ContainingBlockContext& containingBlockContext) const
{
ASSERT(run.text());
auto lineRect = lineGeometry.lineBoxLogicalRect();
@@ -40,7 +40,7 @@ namespace Layout {
class Box;
class BoxGeometry;
class ContainerBox;
class InlineLineGeometry;
class LineGeometry;
struct LineRun;
}

@@ -74,7 +74,7 @@ class BoxFactory {
std::unique_ptr<Box> displayBoxForBodyBox(const Layout::Box&, const Layout::BoxGeometry&, const ContainingBlockContext&, RootBackgroundPropagation) const;
std::unique_ptr<Box> displayBoxForLayoutBox(const Layout::Box&, const Layout::BoxGeometry&, const ContainingBlockContext&) const;

std::unique_ptr<Box> displayBoxForTextRun(const Layout::LineRun&, const Layout::InlineLineGeometry&, const ContainingBlockContext&) const;
std::unique_ptr<Box> displayBoxForTextRun(const Layout::LineRun&, const Layout::LineGeometry&, const ContainingBlockContext&) const;

private:
std::unique_ptr<Box> displayBoxForLayoutBox(const Layout::Box&, const Layout::BoxGeometry&, const ContainingBlockContext&, const RenderStyle* styleForBackground, Style&&) const;
@@ -467,11 +467,15 @@ InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuil
{
auto& formattingState = this->formattingState();
auto& formattingGeometry = this->formattingGeometry();
auto lineIndex = formattingState.lines().size();

auto lineBoxAndGeometry = formattingGeometry.lineBoxForLineContent(lineContent);
formattingState.addLineBox(WTFMove(lineBoxAndGeometry.lineBox));
formattingState.addLine(lineBoxAndGeometry.lineGeometry);

formattingState.addLineBox(formattingGeometry.lineBoxForLineContent(lineContent));
const auto& lineBox = formattingState.lineBoxes().last();
auto lineIndex = formattingState.lines().size();
auto& lineBoxLogicalRect = lineBox.logicalRect();
auto lineBoxLogicalRect = lineBoxAndGeometry.lineGeometry.lineBoxLogicalRect();

if (!lineBox.hasContent()) {
// Fast path for lines with no content e.g. <div><span></span><span></span></div> or <span><div></div></span> where we construct empty pre and post blocks.
ASSERT(!lineBox.rootInlineBox().hasContent() && !lineBoxLogicalRect.height());
@@ -495,14 +499,10 @@ InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuil
}
};
updateInlineBoxesGeometryIfApplicable();
formattingState.addLine({ lineBoxLogicalRect, { { }, { } }, { }, { }, { } });
return lineBoxLogicalRect;
}

auto rootInlineBoxLogicalRect = lineBox.logicalRectForRootInlineBox();
auto enclosingTopAndBottom = InlineLineGeometry::EnclosingTopAndBottom { rootInlineBoxLogicalRect.top(), rootInlineBoxLogicalRect.bottom() };
HashSet<const Box*> inlineBoxStartSet;

auto constructLineRunsAndUpdateBoxGeometry = [&] {
// Create the inline runs on the current line. This is mostly text and atomic inline runs.
for (auto& lineRun : lineContent.runs) {
@@ -539,31 +539,16 @@ InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuil
borderBoxLogicalTopLeft += formattingGeometry.inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
// 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));

auto borderBoxTop = borderBoxLogicalTopLeft.y();
auto borderBoxBottom = borderBoxTop + boxGeometry.borderBoxHeight();
enclosingTopAndBottom.top = std::min(enclosingTopAndBottom.top, borderBoxTop);
enclosingTopAndBottom.bottom = std::max(enclosingTopAndBottom.bottom, borderBoxBottom);
continue;
}
if (lineRun.isInlineBoxStart()) {
auto& boxGeometry = formattingState.boxGeometry(layoutBox);
auto inlineBoxLogicalRect = lineBox.logicalBorderBoxForInlineBox(layoutBox, boxGeometry);
formattingState.addLineRun({ lineIndex, layoutBox, inlineBoxLogicalRect, lineRun.expansion(), { } });
inlineBoxStartSet.add(&layoutBox);
enclosingTopAndBottom.top = std::min(enclosingTopAndBottom.top, inlineBoxLogicalRect.top());
continue;
}
if (lineRun.isInlineBoxEnd()) {
if (!inlineBoxStartSet.contains(&layoutBox)) {
// An inline box can span multiple lines. Use the [inline box end] signal to include it in the enclosing geometry
// only when it starts at a previous line.
auto inlineBoxLogicalRect = lineBox.logicalBorderBoxForInlineBox(layoutBox, formattingState.boxGeometry(layoutBox));
enclosingTopAndBottom.bottom = std::max(enclosingTopAndBottom.bottom, inlineBoxLogicalRect.bottom());
}
continue;
}
ASSERT(lineRun.isWordBreakOpportunity());
ASSERT(lineRun.isInlineBoxEnd() || lineRun.isWordBreakOpportunity());
}
};
constructLineRunsAndUpdateBoxGeometry();
@@ -603,12 +588,7 @@ InlineRect InlineFormattingContext::computeGeometryForLineContent(const LineBuil
}
};
updateBoxGeometryForInlineBoxes();

auto constructLineGeometry = [&] {
formattingState.addLine({ lineBoxLogicalRect, enclosingTopAndBottom, lineBox.alignmentBaseline(), rootInlineBoxLogicalRect.left(), lineContent.contentLogicalWidth });
};
constructLineGeometry();


return lineBoxLogicalRect;
}

@@ -43,7 +43,8 @@ namespace Layout {
class LineBoxBuilder {
public:
LineBoxBuilder(const InlineFormattingContext&);
LineBox build(const LineBuilder::LineContent&);

InlineFormattingGeometry::LineBoxAndGeometry build(const LineBuilder::LineContent&);

private:
struct SimplifiedVerticalAlignment {
@@ -81,6 +82,7 @@ class LineBoxBuilder {

private:
const InlineFormattingContext& m_inlineFormattingContext;
InlineLayoutUnit m_logicalHeight { 0 };
};

static InlineLayoutUnit hangingGlyphWidth(InlineLayoutUnit extraHorizontalSpace, const Line::RunList& runs, bool isLastLineWithInlineContent)
@@ -156,15 +158,41 @@ LineBoxBuilder::LineBoxBuilder(const InlineFormattingContext& inlineFormattingCo
{
}

LineBox LineBoxBuilder::build(const LineBuilder::LineContent& lineContent)
InlineFormattingGeometry::LineBoxAndGeometry LineBoxBuilder::build(const LineBuilder::LineContent& lineContent)
{
auto& runs = lineContent.runs;
auto lineLogicalWidth = lineContent.lineLogicalWidth;
auto contentLogicalWidth = lineContent.contentLogicalWidth;
auto horizontalAlignmentOffset = Layout::horizontalAlignmentOffset(runs, rootBox().style().textAlign(), lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent);
auto lineBox = LineBox { rootBox(), lineContent.logicalTopLeft, lineLogicalWidth, horizontalAlignmentOffset.value_or(InlineLayoutUnit { }), contentLogicalWidth, lineContent.nonSpanningInlineLevelBoxCount };
auto contentLogicalLeft = Layout::horizontalAlignmentOffset(runs, rootBox().style().textAlign(), lineContent.lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent).value_or(InlineLayoutUnit { });
auto lineBox = LineBox { rootBox(), contentLogicalLeft, contentLogicalWidth, lineContent.nonSpanningInlineLevelBoxCount };

constructAndAlignInlineLevelBoxes(lineBox, runs);
return lineBox;

auto lineGeometry = [&] {
auto lineBoxLogicalRect = InlineRect { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, m_logicalHeight };
auto& rootInlineBox = lineBox.rootInlineBox();
auto enclosingTopAndBottom = LineGeometry::EnclosingTopAndBottom { rootInlineBox.logicalTop(), rootInlineBox.logicalBottom() };

for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
if (!inlineLevelBox.isAtomicInlineLevelBox() || !inlineLevelBox.isInlineBox())
continue;

auto& layoutBox = inlineLevelBox.layoutBox();
auto borderBox = InlineRect { };

if (inlineLevelBox.isAtomicInlineLevelBox())
borderBox = lineBox.logicalBorderBoxForAtomicInlineLevelBox(layoutBox, formattingContext().geometryForBox(layoutBox));
else if (inlineLevelBox.isInlineBox())
borderBox = lineBox.logicalBorderBoxForInlineBox(layoutBox, formattingContext().geometryForBox(layoutBox));
else
ASSERT_NOT_REACHED();

borderBox.moveBy(lineBoxLogicalRect.topLeft());
enclosingTopAndBottom.top = std::min(enclosingTopAndBottom.top, borderBox.top());
enclosingTopAndBottom.bottom = std::max(enclosingTopAndBottom.bottom, borderBox.bottom());
}
return LineGeometry { lineBoxLogicalRect, enclosingTopAndBottom, rootInlineBox.logicalTop() + rootInlineBox.baseline(), rootInlineBox.logicalLeft(), rootInlineBox.logicalWidth() };
};
return { lineBox, lineGeometry() };
}

void LineBoxBuilder::setVerticalGeometryForInlineBox(InlineLevelBox& inlineLevelBox) const
@@ -358,10 +386,13 @@ void LineBoxBuilder::constructAndAlignInlineLevelBoxes(LineBox& lineBox, const L
}

lineBox.setHasContent(lineHasContent);
if (simplifiedVerticalAlignment.isEnabled() || !lineHasContent) {
if (!lineHasContent) {
m_logicalHeight = { };
rootInlineBox.setLogicalTop(-rootInlineBox.baseline());
} else if (simplifiedVerticalAlignment.isEnabled()) {
// We should always be able to exercise the fast path when the line has no content at all, even in non-standards mode or with line-height set.
rootInlineBox.setLogicalTop(lineHasContent ? simplifiedVerticalAlignment.rootInlineBoxLogicalTop() : -rootInlineBox.baseline());
lineBox.setLogicalHeight(lineHasContent ? simplifiedVerticalAlignment.lineBoxHeight() : InlineLayoutUnit());
m_logicalHeight = simplifiedVerticalAlignment.lineBoxHeight();
rootInlineBox.setLogicalTop(simplifiedVerticalAlignment.rootInlineBoxLogicalTop());
} else
computeLineBoxHeightAndAlignInlineLevelBoxesVertically(lineBox);
}
@@ -464,7 +495,7 @@ void LineBoxBuilder::computeLineBoxHeightAndAlignInlineLevelBoxesVertically(Line
continue;
lineBoxLogicalHeight = std::max(lineBoxLogicalHeight, lineBoxRelativeInlineLevelBox->layoutBounds().height());
}
lineBox.setLogicalHeight(lineBoxLogicalHeight);
m_logicalHeight = lineBoxLogicalHeight;
};
computeLineBoxLogicalHeight();

@@ -589,7 +620,7 @@ void LineBoxBuilder::computeLineBoxHeightAndAlignInlineLevelBoxesVertically(Line
break;
case VerticalAlign::Bottom:
// Note that this logical top is not relative to the parent inline box.
logicalTop = lineBox.logicalRect().height() - inlineLevelBox.layoutBounds().descent - inlineLevelBox.baseline();
logicalTop = m_logicalHeight - inlineLevelBox.layoutBounds().descent - inlineLevelBox.baseline();
break;
default:
ASSERT_NOT_IMPLEMENTED_YET();
@@ -654,7 +685,7 @@ InlineFormattingGeometry::InlineFormattingGeometry(const InlineFormattingContext
{
}

LineBox InlineFormattingGeometry::lineBoxForLineContent(const LineBuilder::LineContent& lineContent) const
InlineFormattingGeometry::LineBoxAndGeometry InlineFormattingGeometry::lineBoxForLineContent(const LineBuilder::LineContent& lineContent) const
{
return LineBoxBuilder(formattingContext()).build(lineContent);
}
@@ -40,7 +40,11 @@ class InlineFormattingGeometry : public FormattingGeometry {
public:
InlineFormattingGeometry(const InlineFormattingContext&);

LineBox lineBoxForLineContent(const LineBuilder::LineContent&) const;
struct LineBoxAndGeometry {
LineBox lineBox;
LineGeometry lineGeometry;
};
LineBoxAndGeometry lineBoxForLineContent(const LineBuilder::LineContent&) const;
InlineLayoutUnit logicalTopForNextLine(const LineBuilder::LineContent&, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext&) const;

ContentHeightAndMargin inlineBlockContentHeightAndMargin(const Box&, const HorizontalConstraints&, const OverriddenVerticalValues&) const;
@@ -38,7 +38,7 @@ namespace WebCore {
namespace Layout {

using InlineItems = Vector<InlineItem>;
using InlineLines = Vector<InlineLineGeometry>;
using InlineLines = Vector<LineGeometry>;
using InlineLineBoxes = Vector<LineBox>;
using InlineLineRuns = Vector<LineRun>;

@@ -55,7 +55,7 @@ class InlineFormattingState : public FormattingState {

const InlineLines& lines() const { return m_lines; }
InlineLines& lines() { return m_lines; }
void addLine(const InlineLineGeometry& line) { m_lines.append(line); }
void addLine(const LineGeometry& line) { m_lines.append(line); }

const InlineLineBoxes& lineBoxes() const { return m_lineBoxes; }
void addLineBox(LineBox&& lineBox) { m_lineBoxes.append(WTFMove(lineBox)); }
@@ -34,9 +34,8 @@
namespace WebCore {
namespace Layout {

LineBox::LineBox(const Box& rootLayoutBox, const InlineLayoutPoint& logicalTopleft, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth, size_t nonSpanningInlineLevelBoxCount)
: m_logicalRect(logicalTopleft, InlineLayoutSize { lineLogicalWidth, { } })
, m_rootInlineBox(rootLayoutBox, contentLogicalLeft, InlineLayoutSize { contentLogicalWidth, { } }, InlineLevelBox::Type::RootInlineBox)
LineBox::LineBox(const Box& rootLayoutBox, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth, size_t nonSpanningInlineLevelBoxCount)
: m_rootInlineBox(rootLayoutBox, contentLogicalLeft, InlineLayoutSize { contentLogicalWidth, { } }, InlineLevelBox::Type::RootInlineBox)
{
m_nonRootInlineLevelBoxList.reserveInitialCapacity(nonSpanningInlineLevelBoxCount);
m_nonRootInlineLevelBoxMap.reserveInitialCapacity(nonSpanningInlineLevelBoxCount);
@@ -60,9 +60,8 @@ struct SimplifiedVerticalAlignment;
class LineBox {
WTF_MAKE_FAST_ALLOCATED;
public:
LineBox(const Box& rootLayoutBox, const InlineLayoutPoint& logicalTopLeft, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, size_t nonSpanningInlineLevelBoxCount);
LineBox(const Box& rootLayoutBox, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth, size_t nonSpanningInlineLevelBoxCount);

const InlineRect& logicalRect() const { return m_logicalRect; }
// Note that the line can have many inline boxes and be "empty" the same time e.g. <div><span></span><span></span></div>
bool hasContent() const { return m_hasContent; }
bool hasInlineBox() const { return m_boxTypes.contains(InlineLevelBox::Type::InlineBox); }
@@ -81,13 +80,9 @@ class LineBox {
using InlineLevelBoxList = Vector<InlineLevelBox>;
const InlineLevelBoxList& nonRootInlineLevelBoxes() const { return m_nonRootInlineLevelBoxList; }

InlineLayoutUnit alignmentBaseline() const { return m_rootInlineBox.logicalTop() + m_rootInlineBox.baseline(); }

private:
friend class LineBoxBuilder;

void setLogicalHeight(InlineLayoutUnit logicalHeight) { m_logicalRect.setHeight(logicalHeight); }

void addInlineLevelBox(InlineLevelBox&&);
InlineLevelBoxList& nonRootInlineLevelBoxes() { return m_nonRootInlineLevelBoxList; }

@@ -99,7 +94,6 @@ class LineBox {
void setHasContent(bool hasContent) { m_hasContent = hasContent; }

private:
InlineRect m_logicalRect;
bool m_hasContent { false };
OptionSet<InlineLevelBox::Type> m_boxTypes;

@@ -32,15 +32,15 @@
namespace WebCore {
namespace Layout {

class InlineLineGeometry {
class LineGeometry {
WTF_MAKE_FAST_ALLOCATED;
public:
struct EnclosingTopAndBottom {
// This values encloses the root inline box and any other inline level box's border box.
InlineLayoutUnit top { 0 };
InlineLayoutUnit bottom { 0 };
};
InlineLineGeometry(const InlineRect& lineBoxLogicalRect, EnclosingTopAndBottom, InlineLayoutUnit aligmentBaseline, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth);
LineGeometry(const InlineRect& lineBoxLogicalRect, EnclosingTopAndBottom, InlineLayoutUnit aligmentBaseline, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth);

const InlineRect& lineBoxLogicalRect() const { return m_lineBoxLogicalRect; }

@@ -65,7 +65,7 @@ class InlineLineGeometry {
InlineLayoutUnit m_contentLogicalWidth { 0 };
};

inline InlineLineGeometry::InlineLineGeometry(const InlineRect& lineBoxLogicalRect, EnclosingTopAndBottom enclosingTopAndBottom, InlineLayoutUnit aligmentBaseline, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth)
inline LineGeometry::LineGeometry(const InlineRect& lineBoxLogicalRect, EnclosingTopAndBottom enclosingTopAndBottom, InlineLayoutUnit aligmentBaseline, InlineLayoutUnit contentLogicalLeft, InlineLayoutUnit contentLogicalWidth)
: m_lineBoxLogicalRect(lineBoxLogicalRect)
, m_enclosingTopAndBottom(enclosingTopAndBottom)
, m_aligmentBaseline(aligmentBaseline)

0 comments on commit 591dc1f

Please sign in to comment.