[LFC][IFC] Construct only one LineLayout object per inline formatting context
https://bugs.webkit.org/show_bug.cgi?id=204561
<rdar://problem/57463666>
Reviewed by Antti Koivisto.
Let's construct only one LineLayout object per IFC.
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::lineLayout):
(WebCore::Layout::InlineFormattingContext::computedIntrinsicWidthForConstraint const):
* layout/inlineformatting/InlineLineLayout.cpp:
(WebCore::Layout::LineLayout::LineLayout):
(WebCore::Layout::LineLayout::layout):
(WebCore::Layout::LineLayout::close):
(WebCore::Layout::LineLayout::LineInput::LineInput): Deleted.
* layout/inlineformatting/InlineLineLayout.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@252861 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 88bdff3..6cc9781 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,5 +1,25 @@
2019-11-25 Zalan Bujtas <zalan@apple.com>
+ [LFC][IFC] Construct only one LineLayout object per inline formatting context
+ https://bugs.webkit.org/show_bug.cgi?id=204561
+ <rdar://problem/57463666>
+
+ Reviewed by Antti Koivisto.
+
+ Let's construct only one LineLayout object per IFC.
+
+ * layout/inlineformatting/InlineFormattingContext.cpp:
+ (WebCore::Layout::InlineFormattingContext::lineLayout):
+ (WebCore::Layout::InlineFormattingContext::computedIntrinsicWidthForConstraint const):
+ * layout/inlineformatting/InlineLineLayout.cpp:
+ (WebCore::Layout::LineLayout::LineLayout):
+ (WebCore::Layout::LineLayout::layout):
+ (WebCore::Layout::LineLayout::close):
+ (WebCore::Layout::LineLayout::LineInput::LineInput): Deleted.
+ * layout/inlineformatting/InlineLineLayout.h:
+
+2019-11-25 Zalan Bujtas <zalan@apple.com>
+
[LFC][IFC] Decouple LineLayout and Line
https://bugs.webkit.org/show_bug.cgi?id=204560
<rdar://problem/57463295>
diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
index 3e7a2a0..df7c537 100644
--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
@@ -96,13 +96,11 @@
unsigned leadingInlineItemIndex = 0;
Optional<LineLayout::PartialContent> leadingPartialContent;
auto line = Line { *this, root().style().textAlign(), Line::SkipAlignment::No };
+ auto lineLayout = LineLayout { *this, inlineItems };
while (leadingInlineItemIndex < inlineItems.size()) {
line.initialize(constraintsForLine(usedHorizontalValues, lineLogicalTop));
- auto lineInput = LineLayout::LineInput { inlineItems, leadingInlineItemIndex, leadingPartialContent };
- auto lineLayout = LineLayout { *this, lineInput, line };
-
- auto lineContent = lineLayout.layout();
+ auto lineContent = lineLayout.layout(line, leadingInlineItemIndex, leadingPartialContent);
setDisplayBoxesForLine(lineContent, usedHorizontalValues);
leadingPartialContent = { };
@@ -236,12 +234,11 @@
LayoutUnit maximumLineWidth;
unsigned leadingInlineItemIndex = 0;
auto line = Line { *this, root().style().textAlign(), Line::SkipAlignment::Yes };
+ auto lineLayout = LineLayout { *this, inlineItems };
while (leadingInlineItemIndex < inlineItems.size()) {
// Only the horiztonal available width is constrained when computing intrinsic width.
line.initialize(Line::Constraints { { }, usedHorizontalValues.constraints.width, false, { } });
- auto lineInput = LineLayout::LineInput { inlineItems, leadingInlineItemIndex, { } };
-
- auto lineContent = LineLayout(*this, lineInput, line).layout();
+ auto lineContent = lineLayout.layout(line, leadingInlineItemIndex, { });
leadingInlineItemIndex = *lineContent.trailingInlineItemIndex + 1;
LayoutUnit floatsWidth;
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp b/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp
index 74ef10a..a9ac6f1 100644
--- a/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineLineLayout.cpp
@@ -67,13 +67,6 @@
return boxGeometry.width();
}
-LineLayout::LineInput::LineInput(const InlineItems& inlineItems, unsigned leadingInlineItemIndex, Optional<PartialContent> leadingPartialContent)
- : inlineItems(inlineItems)
- , leadingInlineItemIndex(leadingInlineItemIndex)
- , leadingPartialContent(leadingPartialContent)
-{
-}
-
void LineLayout::UncommittedContent::add(const InlineItem& inlineItem, LayoutUnit logicalWidth)
{
m_uncommittedRuns.append({ inlineItem, logicalWidth });
@@ -86,69 +79,76 @@
m_width = 0;
}
-LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext, const LineInput& lineInput, Line& line)
+LineLayout::LineLayout(const InlineFormattingContext& inlineFormattingContext, const InlineItems& inlineItems)
: m_inlineFormattingContext(inlineFormattingContext)
- , m_lineInput(lineInput)
- , m_line(line)
+ , m_inlineItems(inlineItems)
{
}
-LineLayout::LineContent LineLayout::layout()
+LineLayout::LineContent LineLayout::layout(Line& line, unsigned leadingInlineItemIndex, Optional<PartialContent> leadingPartialContent)
{
+ auto initialize = [&] {
+ m_committedInlineItemCount = 0;
+ m_uncommittedContent.reset();
+ m_leadingPartialTextItem = { };
+ m_trailingPartialTextItem = { };
+ m_overflowTextLength = { };
+ };
+ initialize();
// Iterate through the inline content and place the inline boxes on the current line.
// Start with the partial leading text from the previous line.
- auto firstNonPartialInlineItemIndex = m_lineInput.leadingInlineItemIndex;
- if (m_lineInput.leadingPartialContent) {
+ auto firstNonPartialInlineItemIndex = leadingInlineItemIndex;
+ if (leadingPartialContent) {
// Handle partial inline item (split text from the previous line).
- auto& leadingTextItem = m_lineInput.inlineItems[m_lineInput.leadingInlineItemIndex];
+ auto& leadingTextItem = m_inlineItems[leadingInlineItemIndex];
RELEASE_ASSERT(leadingTextItem->isText());
// Construct a partial leading inline item.
ASSERT(!m_leadingPartialTextItem);
- m_leadingPartialTextItem = downcast<InlineTextItem>(*leadingTextItem).right(m_lineInput.leadingPartialContent->length);
- if (placeInlineItem(*m_leadingPartialTextItem) == IsEndOfLine::Yes)
- return close();
+ m_leadingPartialTextItem = downcast<InlineTextItem>(*leadingTextItem).right(leadingPartialContent->length);
+ if (placeInlineItem(line, *m_leadingPartialTextItem) == IsEndOfLine::Yes)
+ return close(line, leadingInlineItemIndex);
++firstNonPartialInlineItemIndex;
}
- for (auto inlineItemIndex = firstNonPartialInlineItemIndex; inlineItemIndex < m_lineInput.inlineItems.size(); ++inlineItemIndex) {
+ for (auto inlineItemIndex = firstNonPartialInlineItemIndex; inlineItemIndex < m_inlineItems.size(); ++inlineItemIndex) {
// FIXME: We should not need to re-measure the dropped, uncommitted content when re-using them on the next line.
- if (placeInlineItem(*m_lineInput.inlineItems[inlineItemIndex]) == IsEndOfLine::Yes)
- return close();
+ if (placeInlineItem(line, *m_inlineItems[inlineItemIndex]) == IsEndOfLine::Yes)
+ return close(line, leadingInlineItemIndex);
}
// Check the uncommitted content whether they fit now that we know we are at a commit boundary.
if (!m_uncommittedContent.isEmpty())
- processUncommittedContent();
- return close();
+ processUncommittedContent(line);
+ return close(line, leadingInlineItemIndex);
}
-void LineLayout::commitPendingContent()
+void LineLayout::commitPendingContent(Line& line)
{
if (m_uncommittedContent.isEmpty())
return;
m_committedInlineItemCount += m_uncommittedContent.size();
for (auto& uncommittedRun : m_uncommittedContent.runs())
- m_line.append(uncommittedRun.inlineItem, uncommittedRun.logicalWidth);
+ line.append(uncommittedRun.inlineItem, uncommittedRun.logicalWidth);
m_uncommittedContent.reset();
}
-LineLayout::LineContent LineLayout::close()
+LineLayout::LineContent LineLayout::close(Line& line, unsigned leadingInlineItemIndex)
{
- ASSERT(m_committedInlineItemCount || m_line.hasIntrusiveFloat());
+ ASSERT(m_committedInlineItemCount || line.hasIntrusiveFloat());
m_uncommittedContent.reset();
if (!m_committedInlineItemCount)
- return LineContent { { }, { }, WTFMove(m_floats), m_line.close(), m_line.lineBox() };
+ return LineContent { { }, { }, WTFMove(m_floats), line.close(), line.lineBox() };
Optional<PartialContent> overflowContent;
if (m_overflowTextLength)
overflowContent = PartialContent { *m_overflowTextLength };
- auto trailingInlineItemIndex = m_lineInput.leadingInlineItemIndex + m_committedInlineItemCount - 1;
+ auto trailingInlineItemIndex = leadingInlineItemIndex + m_committedInlineItemCount - 1;
auto isLastLineWithInlineContent = [&] {
if (overflowContent)
return Line::IsLastLineWithInlineContent::No;
// Skip floats backwards to see if this is going to be the last line with inline content.
- for (auto i = m_lineInput.inlineItems.size(); i--;) {
- if (!m_lineInput.inlineItems[i]->isFloat())
+ for (auto i = m_inlineItems.size(); i--;) {
+ if (!m_inlineItems[i]->isFloat())
return i == trailingInlineItemIndex ? Line::IsLastLineWithInlineContent::Yes : Line::IsLastLineWithInlineContent::No;
}
// There has to be at least one non-float item.
@@ -156,12 +156,12 @@
return Line::IsLastLineWithInlineContent::No;
};
- return LineContent { trailingInlineItemIndex, overflowContent, WTFMove(m_floats), m_line.close(isLastLineWithInlineContent()), m_line.lineBox() };
+ return LineContent { trailingInlineItemIndex, overflowContent, WTFMove(m_floats), line.close(isLastLineWithInlineContent()), line.lineBox() };
}
-LineLayout::IsEndOfLine LineLayout::placeInlineItem(const InlineItem& inlineItem)
+LineLayout::IsEndOfLine LineLayout::placeInlineItem(Line& line, const InlineItem& inlineItem)
{
- auto currentLogicalRight = m_line.lineBox().logicalRight();
+ auto currentLogicalRight = line.lineBox().logicalRight();
auto itemLogicalWidth = inlineItemWidth(formattingContext(), inlineItem, currentLogicalRight);
// Floats are special, they are intrusive but they don't really participate in the line layout context.
@@ -171,50 +171,50 @@
// Not sure what to do when the float takes up the available space and we've got continuous content. Browser engines don't agree.
// Let's just commit the pending content and try placing the float for now.
if (!m_uncommittedContent.isEmpty()) {
- if (processUncommittedContent() == IsEndOfLine::Yes)
+ if (processUncommittedContent(line) == IsEndOfLine::Yes)
return IsEndOfLine::Yes;
}
- auto lineIsConsideredEmpty = m_line.isVisuallyEmpty() && !m_line.hasIntrusiveFloat();
- if (LineBreaker().shouldWrapFloatBox(itemLogicalWidth, m_line.availableWidth() + m_line.trailingTrimmableWidth(), lineIsConsideredEmpty))
+ auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat();
+ if (LineBreaker().shouldWrapFloatBox(itemLogicalWidth, line.availableWidth() + line.trailingTrimmableWidth(), lineIsConsideredEmpty))
return IsEndOfLine::Yes;
// This float can sit on the current line.
auto& floatBox = inlineItem.layoutBox();
// Shrink available space for current line and move existing inline runs.
- floatBox.isLeftFloatingPositioned() ? m_line.moveLogicalLeft(itemLogicalWidth) : m_line.moveLogicalRight(itemLogicalWidth);
+ floatBox.isLeftFloatingPositioned() ? line.moveLogicalLeft(itemLogicalWidth) : line.moveLogicalRight(itemLogicalWidth);
m_floats.append(makeWeakPtr(inlineItem));
++m_committedInlineItemCount;
- m_line.setHasIntrusiveFloat();
+ line.setHasIntrusiveFloat();
return IsEndOfLine::No;
}
// Forced line breaks are also special.
if (inlineItem.isForcedLineBreak()) {
- auto isEndOfLine = !m_uncommittedContent.isEmpty() ? processUncommittedContent() : IsEndOfLine::No;
+ auto isEndOfLine = !m_uncommittedContent.isEmpty() ? processUncommittedContent(line) : IsEndOfLine::No;
// When the uncommitted content fits(or the line is empty), add the line break to this line as well.
if (isEndOfLine == IsEndOfLine::No) {
m_uncommittedContent.add(inlineItem, itemLogicalWidth);
- commitPendingContent();
+ commitPendingContent(line);
}
return IsEndOfLine::Yes;
}
//
auto isEndOfLine = IsEndOfLine::No;
if (!m_uncommittedContent.isEmpty() && shouldProcessUncommittedContent(inlineItem))
- isEndOfLine = processUncommittedContent();
+ isEndOfLine = processUncommittedContent(line);
// The current item might fit as well.
if (isEndOfLine == IsEndOfLine::No)
m_uncommittedContent.add(inlineItem, itemLogicalWidth);
return isEndOfLine;
}
-LineLayout::IsEndOfLine LineLayout::processUncommittedContent()
+LineLayout::IsEndOfLine LineLayout::processUncommittedContent(Line& line)
{
// Check if the pending content fits.
- auto lineIsConsideredEmpty = m_line.isVisuallyEmpty() && !m_line.hasIntrusiveFloat();
- auto breakingContext = LineBreaker().breakingContextForInlineContent(m_uncommittedContent.runs(), m_uncommittedContent.width(), m_line.availableWidth(), lineIsConsideredEmpty);
+ auto lineIsConsideredEmpty = line.isVisuallyEmpty() && !line.hasIntrusiveFloat();
+ auto breakingContext = LineBreaker().breakingContextForInlineContent(m_uncommittedContent.runs(), m_uncommittedContent.width(), line.availableWidth(), lineIsConsideredEmpty);
// The uncommitted content can fully, partially fit the current line (commit/partial commit) or not at all (reset).
if (breakingContext.contentBreak == LineBreaker::BreakingContext::ContentBreak::Keep)
- commitPendingContent();
+ commitPendingContent(line);
else if (breakingContext.contentBreak == LineBreaker::BreakingContext::ContentBreak::Split) {
ASSERT(breakingContext.trailingPartialContent);
ASSERT(m_uncommittedContent.runs()[breakingContext.trailingPartialContent->runIndex].inlineItem.isText());
@@ -230,7 +230,7 @@
// Keep the non-overflow part of the uncommitted runs and add the trailing partial content.
m_uncommittedContent.trim(overflowInlineTextItemIndex);
m_uncommittedContent.add(*m_trailingPartialTextItem, breakingContext.trailingPartialContent->logicalWidth);
- commitPendingContent();
+ commitPendingContent(line);
} else if (breakingContext.contentBreak == LineBreaker::BreakingContext::ContentBreak::Wrap)
m_uncommittedContent.reset();
else
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineLayout.h b/Source/WebCore/layout/inlineformatting/InlineLineLayout.h
index e485da8..d71b29f 100644
--- a/Source/WebCore/layout/inlineformatting/InlineLineLayout.h
+++ b/Source/WebCore/layout/inlineformatting/InlineLineLayout.h
@@ -35,25 +35,12 @@
class LineLayout {
public:
- struct LineInput;
- LineLayout(const InlineFormattingContext&, const LineInput&, Line&);
-
- struct LineContent;
- LineContent layout();
+ LineLayout(const InlineFormattingContext&, const InlineItems&);
struct PartialContent {
// This will potentially gain some more members.
unsigned length;
};
- struct LineInput {
- LineInput(const InlineItems&, unsigned leadingInlineItemIndex, Optional<PartialContent> leadingPartialContent);
-
- const InlineItems& inlineItems;
- unsigned leadingInlineItemIndex { 0 };
- Optional<PartialContent> leadingPartialContent;
- Optional<LayoutUnit> floatMinimumLogicalBottom;
- };
-
struct LineContent {
Optional<unsigned> trailingInlineItemIndex;
Optional<PartialContent> trailingPartialContent;
@@ -61,6 +48,7 @@
const Line::RunList runList;
const LineBox lineBox;
};
+ LineContent layout(Line&, unsigned leadingInlineItemIndex, Optional<PartialContent> leadingPartialContent);
struct Run {
const InlineItem& inlineItem;
@@ -72,11 +60,11 @@
private:
const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
enum class IsEndOfLine { No, Yes };
- IsEndOfLine placeInlineItem(const InlineItem&);
- void commitPendingContent();
- LineContent close();
+ IsEndOfLine placeInlineItem(Line&, const InlineItem&);
+ void commitPendingContent(Line&);
+ LineContent close(Line&, unsigned leadingInlineItemIndex);
bool shouldProcessUncommittedContent(const InlineItem&) const;
- IsEndOfLine processUncommittedContent();
+ IsEndOfLine processUncommittedContent(Line&);
struct UncommittedContent {
void add(const InlineItem&, LayoutUnit logicalWidth);
@@ -95,8 +83,7 @@
};
const InlineFormattingContext& m_inlineFormattingContext;
- const LineInput& m_lineInput;
- Line& m_line;
+ const InlineItems& m_inlineItems;
UncommittedContent m_uncommittedContent;
unsigned m_committedInlineItemCount { 0 };
Vector<WeakPtr<InlineItem>> m_floats;