Diff
Modified: trunk/Source/WebCore/ChangeLog (266681 => 266682)
--- trunk/Source/WebCore/ChangeLog 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/ChangeLog 2020-09-06 21:32:35 UTC (rev 266682)
@@ -1,3 +1,69 @@
+2020-09-06 Zalan Bujtas <[email protected]>
+
+ [LFC][IFC] LineBox should contain all inline boxes
+ https://bugs.webkit.org/show_bug.cgi?id=216221
+
+ Reviewed by Antti Koivisto.
+
+ In this patch we decouple the line box and the line.
+
+ Previously the LineBox was pretty much representing the line.
+ It was responsible for both placing the inline boxes and sizing the line and position itself based on line-height/half leading.
+ Now the LineBox is only responsible for placing the inline boxes and sizing itself, it has no position geometry anymore neither
+ does it compute the line height.
+ The line size is computed later using the combination of line-height property/LineBox height/FontMetrics::lineSpacing/half leading.
+ This geometry is preserved in Display::LineBox (this needs to be renamed to Display::Line).
+
+ 1. LineBuilder places the runs on the line after each other (at this point they only have horizontal geometry).
+ 2. LineBreaker tells when to stop.
+ 3. We start constructing inline boxes for the runs (root inline box etc) and place them inside an LineBox. This is when horizontal and vertical alignment happen.
+ 4. We use the fully sized LineBox to compute the line geometry. Note that the line's geometry does not necessarily match the LineBox width/height (see below).
+ 5. We construct a Display::LineBox for the line and Display::Runs for the runs inside the inline boxes.
+
+ LineBox:
+ - fully contains all the inline boxes, both horizontally and vertically.
+ - has only width and height geometry
+ - height is not constrained by the line-height property
+ - does not have the concept of overflow.
+
+ Line:
+ - contains the LineBox, but the LineBox can overflow the line, both horizontally and vertically.
+ - has position relative to the root block container.
+
+ Simple case.
+ <div>font went crazy with line spacing</div>
+ ___________________________________________ line
+ | ^ |
+ | | line spacing |
+ | v |
+ | -------------------------------------------|--------- LineBox
+ || ^ | |
+ || | line box height | |
+ ||----v--------------------------------------|-------- | alignment baseline
+ | -------------------------------------------|---------
+ | ^ | ^
+ | | line spacing | |
+ |____________________v_______________________| scrollable overflow
+
+
+ When glyphs in subsequent lines overflow:
+ <div style="line-height: 5px; font-size: 20px;">line box overflows the line</div>
+ ___________________________________________ LineBox
+ | ^ |
+ | | line box height |
+ | | |
+ -|--------------------------|-----------------|- Line
+ | | ^ | | |
+ | | | line height | | |
+ -|-----v--------------------|-----------------|-
+ | | |
+ |--------------------------|-----------------| alignment baseline
+ | | |
+ |__________________________v_________________|
+
+ * layout/inlineformatting/InlineFormattingContext.cpp:
+ (WebCore::Layout::InlineFormattingContext::createDisplayBoxesForLineContent):
+
2020-09-06 Darin Adler <[email protected]>
TextCodec refinements
Modified: trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h (266681 => 266682)
--- trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h 2020-09-06 21:32:35 UTC (rev 266682)
@@ -37,6 +37,7 @@
InlineRect() = default;
InlineRect(InlineLayoutUnit top, InlineLayoutUnit left, InlineLayoutUnit width, InlineLayoutUnit height);
InlineRect(const InlineLayoutPoint& topLeft, InlineLayoutUnit width, InlineLayoutUnit height);
+ InlineRect(const InlineLayoutPoint& topLeft, const InlineLayoutSize&);
InlineLayoutUnit top() const;
InlineLayoutUnit left() const;
@@ -108,6 +109,11 @@
{
}
+inline InlineRect::InlineRect(const InlineLayoutPoint& topLeft, const InlineLayoutSize& size)
+ : InlineRect(topLeft.y(), topLeft.x(), size.width(), size.height())
+{
+}
+
#if ASSERT_ENABLED
inline void InlineRect::invalidatePosition()
{
Modified: trunk/Source/WebCore/layout/displaytree/DisplayRect.h (266681 => 266682)
--- trunk/Source/WebCore/layout/displaytree/DisplayRect.h 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/displaytree/DisplayRect.h 2020-09-06 21:32:35 UTC (rev 266682)
@@ -38,6 +38,7 @@
Rect() = default;
Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height);
Rect(LayoutPoint topLeft, LayoutUnit width, LayoutUnit height);
+ Rect(const LayoutPoint& topLeft, const LayoutSize&);
LayoutUnit top() const;
LayoutUnit left() const;
@@ -113,6 +114,11 @@
{
}
+inline Rect::Rect(const LayoutPoint& topLeft, const LayoutSize& size)
+ : Rect(topLeft.y(), topLeft.x(), size.width(), size.height())
+{
+}
+
#if ASSERT_ENABLED
inline void Rect::invalidatePosition()
{
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (266681 => 266682)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp 2020-09-06 21:32:35 UTC (rev 266682)
@@ -150,12 +150,13 @@
auto partialLeadingContentLength = previousLine ? previousLine->overflowContentLength : WTF::nullopt;
auto initialLineConstraints = ConstraintsForInFlowContent { constraints.horizontal, { lineLogicalTop, makeOptional(toLayoutUnit(quirks().initialLineHeight())) } };
auto lineContent = lineBuilder.layoutInlineContent(needsLayoutRange, partialLeadingContentLength, initialLineConstraints, isFirstLine);
- setDisplayBoxesForLine(lineContent, constraints.horizontal);
+ auto lineLogicalRect = createDisplayBoxesForLineContent(lineContent, constraints.horizontal);
+
auto lineContentRange = lineContent.inlineItemRange;
if (!lineContentRange.isEmpty()) {
ASSERT(needsLayoutRange.start < lineContentRange.end);
isFirstLine = false;
- lineLogicalTop = lineContent.lineBox.logicalBottom();
+ lineLogicalTop = lineLogicalRect.bottom();
// When the trailing content is partial, we need to reuse the last InlineTextItem.
auto lastInlineItemNeedsPartialLayout = lineContent.partialContent.hasValue();
if (lastInlineItemNeedsPartialLayout) {
@@ -178,7 +179,7 @@
ASSERT(lineContent.runs.isEmpty());
ASSERT(lineContent.hasIntrusiveFloat);
// Move the next line below the intrusive float.
- auto floatConstraints = floatingContext.constraints(lineLogicalTop, toLayoutUnit(lineContent.lineBox.logicalBottom()));
+ auto floatConstraints = floatingContext.constraints(lineLogicalTop, toLayoutUnit(lineLogicalRect.bottom()));
ASSERT(floatConstraints.left || floatConstraints.right);
static auto inifitePoint = PointInContextRoot::max();
// In case of left and right constraints, we need to pick the one that's closer to the current line.
@@ -390,10 +391,54 @@
}
}
-void InlineFormattingContext::setDisplayBoxesForLine(const LineBuilder::LineContent& lineContent, const HorizontalConstraints& horizontalConstraints)
+InlineFormattingContext::LineRectAndLineBoxOffset InlineFormattingContext::computedLineLogicalRect(const LineBuilder::LineContent& lineContent) const
{
+ // Compute the line height and the line box vertical offset.
+ // The line height is either the line-height value (negative value means line height is not set) or the font metrics's line spacing/line box height.
+ // The line box is then positioned using the half leading centering.
+ // ___________________________________________ line
+ // | ^ |
+ // | | line spacing |
+ // | v |
+ // | -------------------------------------------|--------- LineBox
+ // || ^ | |
+ // || | line box height | |
+ // ||----v--------------------------------------|-------- | alignment baseline
+ // | -------------------------------------------|---------
+ // | ^ | ^
+ // | | line spacing | |
+ // |____________________v_______________________| scrollable overflow
+ //
+ if (lineContent.runs.isEmpty() || lineContent.lineBox.isLineVisuallyEmpty())
+ return { { }, { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, { } } };
+ auto& rootStyle = root().style();
+ auto& fontMetrics = rootStyle.fontMetrics();
+ InlineLayoutUnit lineSpacing = fontMetrics.lineSpacing();
+ auto& lineBox = lineContent.lineBox;
+ auto lineLogicalHeight = rootStyle.lineHeight().isNegative() ? std::max(lineBox.logicalHeight(), lineSpacing) : rootStyle.computedLineHeight();
+ auto logicalRect = Display::InlineRect { lineContent.logicalTopLeft, lineContent.lineLogicalWidth, lineLogicalHeight};
+
+ auto halfLeadingOffset = [&] {
+ InlineLayoutUnit ascent = fontMetrics.ascent();
+ InlineLayoutUnit descent = fontMetrics.descent();
+ // 10.8.1 Leading and half-leading
+ auto halfLeading = (lineLogicalHeight - (ascent + descent)) / 2;
+ // Inline tree height is all integer based.
+ return floorf(ascent + halfLeading);
+ }();
+ auto lineBoxOffset = logicalRect.height() == lineBox.logicalHeight() ? InlineLayoutUnit() : halfLeadingOffset - lineBox.alignmentBaseline();
+ return { lineBoxOffset, logicalRect };
+}
+
+Display::InlineRect InlineFormattingContext::createDisplayBoxesForLineContent(const LineBuilder::LineContent& lineContent, const HorizontalConstraints& horizontalConstraints)
+{
auto& formattingState = this->formattingState();
auto& lineBox = lineContent.lineBox;
+ auto lineRectAndLineBoxOffset = computedLineLogicalRect(lineContent);
+ auto lineLogicalRect = lineRectAndLineBoxOffset.logicalRect;
+ auto lineBoxVerticalOffset = lineRectAndLineBoxOffset.lineBoxVerticalOffset;
+ auto scrollableOverflow = Display::InlineRect { lineLogicalRect.topLeft(), std::max(lineLogicalRect.width(), lineBox.logicalWidth()), std::max(lineLogicalRect.height(), lineBoxVerticalOffset + lineBox.logicalHeight()) };
+
if (!lineContent.floats.isEmpty()) {
auto floatingContext = FloatingContext { root(), *this, formattingState.floatingState() };
// Move floats to their final position.
@@ -401,8 +446,8 @@
auto& floatBox = floatCandidate.item->layoutBox();
auto& displayBox = formattingState.displayBox(floatBox);
// Set static position first.
- auto verticalStaticPosition = floatCandidate.isIntrusive ? lineBox.logicalTop() : lineBox.logicalBottom();
- displayBox.setTopLeft({ lineBox.logicalLeft(), verticalStaticPosition });
+ auto verticalStaticPosition = floatCandidate.isIntrusive ? lineLogicalRect.top() : lineLogicalRect.bottom();
+ displayBox.setTopLeft({ lineLogicalRect.left(), verticalStaticPosition });
// Float it.
displayBox.setTopLeft(floatingContext.positionForFloat(floatBox, horizontalConstraints));
floatingContext.append(floatBox);
@@ -417,7 +462,7 @@
initialContaingBlockSize = geometryForBox(root().initialContainingBlock(), EscapeReason::StrokeOverflowNeedsViewportGeometry).contentBox().size();
auto& inlineContent = formattingState.ensureDisplayInlineContent();
auto lineIndex = inlineContent.lineBoxes.size();
- auto lineInkOverflow = lineBox.scrollableOverflow();
+ auto lineInkOverflow = scrollableOverflow;
// Compute final box geometry.
for (auto& lineRun : lineContent.runs) {
auto& layoutBox = lineRun.layoutBox();
@@ -443,7 +488,7 @@
auto logicalRect = lineRun.isBox() ? lineBox.inlineBoxForLayoutBox(layoutBox).logicalRect() : lineBox.inlineRectForTextRun(lineRun);
// Inline boxes are relative to the line box while final Display::Runs need to be relative to the parent Display:Box
// FIXME: Shouldn't we just leave them be relative to the line box?
- logicalRect.moveBy({ lineBox.logicalLeft(), lineBox.logicalTop() });
+ logicalRect.moveBy({ lineLogicalRect.left(), lineLogicalRect.top() + lineBoxVerticalOffset });
auto inkOverflow = computedInkOverflow(logicalRect);
lineInkOverflow.expandToContain(inkOverflow);
inlineContent.runs.append({ lineIndex, layoutBox, logicalRect, inkOverflow, lineRun.expansion(), lineRun.textContent() });
@@ -456,6 +501,7 @@
auto& displayBox = formattingState.displayBox(layoutBox);
auto& inlineBox = lineBox.inlineBoxForLayoutBox(layoutBox);
auto topLeft = inlineBox.logicalRect().topLeft();
+ topLeft.move({ }, lineBoxVerticalOffset);
if (layoutBox.isInFlowPositioned())
topLeft += geometry().inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
displayBox.setTopLeft(toLayoutPoint(topLeft));
@@ -468,17 +514,17 @@
}
}
}
- // FIXME: This is where the logical to physical translate should happen.
auto constructDisplayLine = [&] {
- // FIXME: Layout::LineBox should contain all inline boxes and it should not have neither top/left geometry nor overflow.
- auto lineRect = lineBox.logicalRect();
+ // FIXME: This is where the logical to physical translate should happen.
if (auto horizontalAlignmentOffset = lineBox.horizontalAlignmentOffset()) {
// Painting code (specifically TextRun's xPos) needs the aligned offset to be able to compute tab positions.
- lineRect.moveHorizontally(*horizontalAlignmentOffset);
+ lineLogicalRect.moveHorizontally(*horizontalAlignmentOffset);
}
- inlineContent.lineBoxes.append({ lineRect, lineBox.scrollableOverflow(), lineInkOverflow, lineBox.alignmentBaseline() });
+ // FIXME: Display::LineBox should really be named Display::Line
+ inlineContent.lineBoxes.append({ lineLogicalRect, scrollableOverflow, lineInkOverflow, lineBoxVerticalOffset + lineBox.alignmentBaseline() });
};
constructDisplayLine();
+ return lineLogicalRect;
}
void InlineFormattingContext::invalidateFormattingState(const InvalidationState&)
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h (266681 => 266682)
--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h 2020-09-06 21:32:35 UTC (rev 266682)
@@ -87,7 +87,12 @@
void computeWidthAndMargin(const Box&, const HorizontalConstraints&);
void collectInlineContentIfNeeded();
- void setDisplayBoxesForLine(const LineBuilder::LineContent&, const HorizontalConstraints&);
+ Display::InlineRect createDisplayBoxesForLineContent(const LineBuilder::LineContent&, const HorizontalConstraints&);
+ struct LineRectAndLineBoxOffset {
+ InlineLayoutUnit lineBoxVerticalOffset;
+ Display::InlineRect logicalRect;
+ };
+ LineRectAndLineBoxOffset computedLineLogicalRect(const LineBuilder::LineContent&) const;
void invalidateFormattingState(const InvalidationState&);
const InlineFormattingState& formattingState() const { return downcast<InlineFormattingState>(FormattingContext::formattingState()); }
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp (266681 => 266682)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp 2020-09-06 21:32:35 UTC (rev 266682)
@@ -31,13 +31,6 @@
namespace WebCore {
namespace Layout {
-struct AscentAndDescent {
- InlineLayoutUnit height() const { return ascent + descent; }
-
- InlineLayoutUnit ascent { 0 };
- InlineLayoutUnit descent { 0 };
-};
-
struct HangingContent {
public:
void reset();
@@ -124,16 +117,6 @@
return { };
}
-inline static AscentAndDescent halfLeadingMetrics(const FontMetrics& fontMetrics, InlineLayoutUnit lineLogicalHeight)
-{
- InlineLayoutUnit ascent = fontMetrics.ascent();
- InlineLayoutUnit descent = fontMetrics.descent();
- // 10.8.1 Leading and half-leading
- auto halfLeading = (lineLogicalHeight - (ascent + descent)) / 2;
- // Inline tree height is all integer based.
- return { floorf(ascent + halfLeading), ceilf(descent + halfLeading) };
-}
-
LineBox::InlineBox::InlineBox(const Box& layoutBox, const Display::InlineRect& rect, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty isConsideredEmpty)
: m_layoutBox(makeWeakPtr(layoutBox))
, m_logicalRect(rect)
@@ -143,21 +126,15 @@
{
}
-LineBox::LineBox(const InlineFormattingContext& inlineFormattingContext, const InlineLayoutPoint& topLeft, InlineLayoutUnit logicalWidth, InlineLayoutUnit contentLogicalWidth, const Line::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty, IsLastLineWithInlineContent isLastLineWithInlineContent)
- : m_rect(topLeft, logicalWidth, { })
- , m_contentLogicalWidth(contentLogicalWidth)
+LineBox::LineBox(const InlineFormattingContext& inlineFormattingContext, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, const Line::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty, IsLastLineWithInlineContent isLastLineWithInlineContent)
+ : m_logicalSize(contentLogicalWidth, { })
+ , m_isLineVisuallyEmpty(isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes)
, m_inlineFormattingContext(inlineFormattingContext)
{
- m_horizontalAlignmentOffset = Layout::horizontalAlignmentOffset(runs, root().style().textAlign(), logicalWidth, contentLogicalWidth, isLastLineWithInlineContent);
- constructInlineBoxes(runs, isLineVisuallyEmpty);
+ m_horizontalAlignmentOffset = Layout::horizontalAlignmentOffset(runs, root().style().textAlign(), lineLogicalWidth, contentLogicalWidth, isLastLineWithInlineContent);
+ constructInlineBoxes(runs);
computeInlineBoxesLogicalHeight();
- alignInlineBoxesVerticallyAndComputeLineBoxHeight(isLineVisuallyEmpty);
- // Compute scrollable overflow.
- m_scrollableOverflow = Display::InlineRect { topLeft, std::max(logicalWidth, m_rootInlineBox.logicalWidth()), { } };
- auto logicalBottom = InlineLayoutUnit { };
- for (auto& inlineBoxEntry : m_inlineBoxRectMap)
- logicalBottom = std::max(logicalBottom, inlineBoxEntry.value->logicalRect().bottom());
- m_scrollableOverflow.expandVertically(logicalBottom);
+ alignInlineBoxesVerticallyAndComputeLineBoxHeight();
}
Display::InlineRect LineBox::inlineRectForTextRun(const Line::Run& run) const
@@ -168,18 +145,17 @@
return { inlineBoxRect.top(), m_horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }) + run.logicalLeft(), run.logicalWidth(), inlineBoxRect.height() };
}
-void LineBox::constructInlineBoxes(const Line::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty)
+void LineBox::constructInlineBoxes(const Line::RunList& runs)
{
auto constructRootInlineBox = [&] {
auto& fontMetrics = root().style().fontMetrics();
- InlineLayoutUnit rootInlineBoxHeight = fontMetrics.height();
- auto rootInlineBoxRect = Display::InlineRect { { }, m_horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }), contentLogicalWidth(), rootInlineBoxHeight };
- InlineLayoutUnit rootInlineBoxBaseline = fontMetrics.ascent();
- auto rootInlineBoxDescent = rootInlineBoxHeight - rootInlineBoxBaseline;
+ InlineLayoutUnit logicalHeight = fontMetrics.height();
+ auto logicalRect = Display::InlineRect { { }, m_horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }), logicalWidth(), logicalHeight };
+ InlineLayoutUnit baseline = fontMetrics.ascent();
+ auto descent = logicalHeight - baseline;
auto lineHasImaginaryStrut = !layoutState().inQuirksMode();
- auto rootInlineBoxIsConsideredEmpty = isLineVisuallyEmpty == IsLineVisuallyEmpty::No && lineHasImaginaryStrut ? InlineBox::IsConsideredEmpty::No : InlineBox::IsConsideredEmpty::Yes;
-
- m_rootInlineBox = InlineBox { root(), rootInlineBoxRect, rootInlineBoxBaseline, rootInlineBoxDescent, rootInlineBoxIsConsideredEmpty };
+ auto isInitiallyConsideredEmpty = !m_isLineVisuallyEmpty && lineHasImaginaryStrut ? InlineBox::IsConsideredEmpty::No : InlineBox::IsConsideredEmpty::Yes;
+ m_rootInlineBox = InlineBox { root(), logicalRect, baseline, descent, isInitiallyConsideredEmpty };
m_inlineBoxRectMap.set(&root(), &m_rootInlineBox);
};
constructRootInlineBox();
@@ -219,8 +195,8 @@
m_inlineBoxList.append(WTFMove(inlineBox));
}
} else if (run.isContainerStart()) {
- auto initialWidth = contentLogicalWidth() - run.logicalLeft();
auto inlineBoxLogicalLeft = m_horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }) + run.logicalLeft();
+ auto initialWidth = logicalWidth() - run.logicalLeft();
ASSERT(initialWidth >= 0);
auto& fontMetrics = layoutBox.style().fontMetrics();
InlineLayoutUnit logicalHeight = fontMetrics.height();
@@ -306,20 +282,13 @@
}
}
-void LineBox::alignInlineBoxesVerticallyAndComputeLineBoxHeight(IsLineVisuallyEmpty isLineVisuallyEmpty)
+void LineBox::alignInlineBoxesVerticallyAndComputeLineBoxHeight()
{
// Inline boxes are in the coordinate system of the line box (and not in the coordinate system of their parents).
// Starting with the root inline box, position the ancestors first so that the descendant line boxes see absolute vertical positions.
- auto& rootStyle = root().style();
- auto contentLogicalBottom = InlineLayoutUnit { };
+ auto contentLogicalHeight = InlineLayoutUnit { };
auto alignRootInlineBox = [&] {
- auto usedLineHeight = InlineLayoutUnit { };
- if (isLineVisuallyEmpty == IsLineVisuallyEmpty::No)
- usedLineHeight = rootStyle.computedLineHeight();
- auto alignmentBaseline = halfLeadingMetrics(rootStyle.fontMetrics(), usedLineHeight).ascent;
- auto rootInlineBoxTopPosition = alignmentBaseline - m_rootInlineBox.baseline();
- m_rootInlineBox.setLogicalTop(rootInlineBoxTopPosition);
- contentLogicalBottom = m_rootInlineBox.logicalHeight();
+ contentLogicalHeight = m_rootInlineBox.logicalHeight();
for (auto& inlineBox : m_inlineBoxList) {
auto verticalAlign = inlineBox->layoutBox().style().verticalAlign();
if (verticalAlign == VerticalAlign::Bottom) {
@@ -326,9 +295,9 @@
// bottom align always pushes the root inline box downwards.
auto overflow = std::max(0.0f, inlineBox->logicalBottom() - m_rootInlineBox.logicalBottom());
m_rootInlineBox.setLogicalTop(m_rootInlineBox.logicalTop() + overflow);
- contentLogicalBottom += overflow;
+ contentLogicalHeight += overflow;
} else if (verticalAlign == VerticalAlign::Top)
- contentLogicalBottom = std::max(contentLogicalBottom, inlineBox->logicalHeight());
+ contentLogicalHeight = std::max(contentLogicalHeight, inlineBox->logicalHeight());
}
};
alignRootInlineBox();
@@ -359,7 +328,7 @@
inlineBoxLogicalTop = InlineLayoutUnit { };
break;
case VerticalAlign::Bottom:
- inlineBoxLogicalTop = contentLogicalBottom - inlineBox->logicalHeight();
+ inlineBoxLogicalTop = contentLogicalHeight - inlineBox->logicalHeight();
break;
case VerticalAlign::Middle: {
auto& parentLayoutBox = layoutBox.parent();
@@ -377,7 +346,7 @@
auto adjustContentBottomIfNeeded = [&] {
if (!m_rootInlineBox.isEmpty())
return;
- auto collapsedContentLogicalTop = contentLogicalBottom;
+ auto collapsedContentLogicalTop = contentLogicalHeight;
auto collapsedContentLogicalBottom = InlineLayoutUnit { };
for (auto& inlineBox : m_inlineBoxList) {
auto verticalAlign = inlineBox->layoutBox().style().verticalAlign();
@@ -389,24 +358,19 @@
collapsedContentLogicalTop = std::min(collapsedContentLogicalTop, inlineBox->logicalTop());
collapsedContentLogicalBottom = std::max(collapsedContentLogicalBottom, inlineBox->logicalBottom());
}
- if (collapsedContentLogicalTop <= 0) {
- contentLogicalBottom = collapsedContentLogicalBottom;
+ if (!collapsedContentLogicalTop) {
+ contentLogicalHeight = collapsedContentLogicalBottom;
return;
}
- contentLogicalBottom = InlineLayoutUnit { };
+ contentLogicalHeight = InlineLayoutUnit { };
for (auto& inlineBox : m_inlineBoxList) {
inlineBox->setLogicalTop(inlineBox->logicalTop() - collapsedContentLogicalTop);
- contentLogicalBottom = std::max(contentLogicalBottom, inlineBox->logicalBottom());
+ contentLogicalHeight = std::max(contentLogicalHeight, inlineBox->logicalBottom());
}
};
adjustContentBottomIfNeeded();
- // Compute the line box height. It's either the line-height value (negative value means line height it not set) or
- // maximum of the root inline box's bottom and the top aligned content height.
- if (isLineVisuallyEmpty == IsLineVisuallyEmpty::No) {
- InlineLayoutUnit lineSpacing = rootStyle.fontMetrics().lineSpacing();
- auto lineBoxLogicalHeight = !rootStyle.lineHeight().isNegative() ? rootStyle.computedLineHeight() : std::max(lineSpacing, contentLogicalBottom);
- m_rect.setHeight(lineBoxLogicalHeight);
- }
+ if (!m_isLineVisuallyEmpty)
+ m_logicalSize.setHeight(contentLogicalHeight);
}
const InlineFormattingContext& LineBox::formattingContext() const
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h (266681 => 266682)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h 2020-09-06 21:32:35 UTC (rev 266682)
@@ -38,6 +38,21 @@
class InlineFormattingContext;
+// LineBox contains all the inline boxes both horizontally and vertically. It only has width and height geometry.
+//
+// ____________________________________________________________ Line Box
+// | --------------
+// | | |
+// | ----------------------------------|--------------|---------- Root Inline Box
+// || _____ ___ ___ | |
+// || | / \ / \ | Inline Box |
+// || |_____ | | | | | | ascent
+// || | | | | | | |
+// ||__|________\___/____\___/_________|______________|_______ alignment_baseline
+// ||
+// || descent
+// ||_______________________________________________________________
+// |________________________________________________________________
class LineBox {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -80,57 +95,34 @@
enum class IsLastLineWithInlineContent { No, Yes };
enum class IsLineVisuallyEmpty { No, Yes };
- LineBox(const InlineFormattingContext&, const InlineLayoutPoint& topLeft, InlineLayoutUnit logicalWidth, InlineLayoutUnit contentLogicalWidth, const Line::RunList&, IsLineVisuallyEmpty, IsLastLineWithInlineContent);
+ LineBox(const InlineFormattingContext&, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, const Line::RunList&, IsLineVisuallyEmpty, IsLastLineWithInlineContent);
- InlineLayoutUnit logicalLeft() const { return m_rect.left(); }
- InlineLayoutUnit logicalRight() const { return m_rect.right(); }
- InlineLayoutUnit logicalTop() const { return m_rect.top(); }
- InlineLayoutUnit logicalBottom() const { return m_rect.bottom(); }
- InlineLayoutUnit logicalWidth() const { return m_rect.width(); }
- InlineLayoutUnit logicalHeight() const { return m_rect.height(); }
+ InlineLayoutUnit logicalWidth() const { return m_logicalSize.width(); }
+ InlineLayoutUnit logicalHeight() const { return m_logicalSize.height(); }
+ InlineLayoutSize logicalSize() const { return m_logicalSize; }
- const Display::InlineRect& logicalRect() const { return m_rect; }
- const Display::InlineRect& scrollableOverflow() const { return m_scrollableOverflow; }
-
Optional<InlineLayoutUnit> horizontalAlignmentOffset() const { return m_horizontalAlignmentOffset; }
+ bool isLineVisuallyEmpty() const { return m_isLineVisuallyEmpty; }
const InlineBox& inlineBoxForLayoutBox(const Box& layoutBox) const { return *m_inlineBoxRectMap.get(&layoutBox); }
Display::InlineRect inlineRectForTextRun(const Line::Run&) const;
- // _____________________________________________________ line box logical top
- // ^
- // |
- // ____________________________________ root inline box
- // ^ |
- // | |
- // | root line ascent |
- // | |
- // v v
- // ___________________________________________________ alignment baseline
- // ^
- // | root line descent
- // v
- // ___________________________________
- // _____________________________________________________ line box logical bottom
InlineLayoutUnit alignmentBaseline() const { return m_rootInlineBox.logicalTop() + m_rootInlineBox.baseline(); }
private:
- void constructInlineBoxes(const Line::RunList&, IsLineVisuallyEmpty);
+ void constructInlineBoxes(const Line::RunList&);
void computeInlineBoxesLogicalHeight();
- void alignInlineBoxesVerticallyAndComputeLineBoxHeight(IsLineVisuallyEmpty);
+ void alignInlineBoxesVerticallyAndComputeLineBoxHeight();
InlineBox& inlineBoxForLayoutBox(const Box& layoutBox) { return *m_inlineBoxRectMap.get(&layoutBox); }
- InlineLayoutUnit contentLogicalWidth() const { return m_contentLogicalWidth; }
-
const InlineFormattingContext& formattingContext() const;
const Box& root() const;
LayoutState& layoutState() const;
private:
- Display::InlineRect m_rect;
- Display::InlineRect m_scrollableOverflow;
- InlineLayoutUnit m_contentLogicalWidth { 0 };
+ InlineLayoutSize m_logicalSize;
+ bool m_isLineVisuallyEmpty { true };
InlineBox m_rootInlineBox;
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp (266681 => 266682)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp 2020-09-06 21:32:35 UTC (rev 266682)
@@ -302,7 +302,9 @@
auto isLastLine = isLastLineWithInlineContent(committedRange, needsLayoutRange.end, committedContent.partialTrailingContent.hasValue());
auto lineIsVisuallyEmpty = m_line.isVisuallyEmpty() ? LineBox::IsLineVisuallyEmpty::Yes : LineBox::IsLineVisuallyEmpty::No;
return LineContent { committedContent.partialTrailingContent, committedRange, m_floats, m_line.hasIntrusiveFloat()
- , LineBox { formattingContext(), lineLogicalTopLeft, m_line.lineLogicalWidth(), m_line.contentLogicalWidth(), m_line.runs(), lineIsVisuallyEmpty
+ , lineLogicalTopLeft
+ , m_line.lineLogicalWidth()
+ , LineBox { formattingContext(), m_line.lineLogicalWidth(), m_line.contentLogicalWidth(), m_line.runs(), lineIsVisuallyEmpty
, isLastLine ? LineBox::IsLastLineWithInlineContent::Yes : LineBox::IsLastLineWithInlineContent::No }
, m_line.runs() };
}
Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h (266681 => 266682)
--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h 2020-09-06 19:10:11 UTC (rev 266681)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h 2020-09-06 21:32:35 UTC (rev 266682)
@@ -61,6 +61,8 @@
using FloatList = Vector<Float>;
const FloatList& floats;
bool hasIntrusiveFloat { false };
+ InlineLayoutPoint logicalTopLeft;
+ InlineLayoutUnit lineLogicalWidth;
const LineBox lineBox;
const Line::RunList& runs;
};