Title: [266509] trunk/Source/WebCore
Revision
266509
Author
za...@apple.com
Date
2020-09-03 03:15:04 -0700 (Thu, 03 Sep 2020)

Log Message

[LFC][IFC] Finalize InlineBox alignment in LineBox
https://bugs.webkit.org/show_bug.cgi?id=215410

Reviewed by Antti Koivisto.

This patch completes the InlineBox transition.

LineBox now has a dedicated root inline box and additional inline boxes as needed.
Both horizontal and vertical alignments are performed on the inline boxes as opposed to on the runs.

* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::lineLayout):
(WebCore::Layout::InlineFormattingContext::constraintsForLine):
(WebCore::Layout::InlineFormattingContext::setDisplayBoxesForLine):
* layout/inlineformatting/InlineFormattingContext.h:
* layout/inlineformatting/InlineFormattingContextQuirks.cpp:
(WebCore::Layout::InlineFormattingContext::Quirks::initialLineHeight const):
* layout/inlineformatting/InlineLineBox.cpp:
(WebCore::Layout::collectHangingContent):
(WebCore::Layout::horizontalAlignmentOffset):
(WebCore::Layout::halfLeadingMetrics):
(WebCore::Layout::LineBox::InlineBox::InlineBox):
(WebCore::Layout::LineBox::LineBox):
(WebCore::Layout::m_inlineFormattingContext):
(WebCore::Layout::LineBox::inlineBoxForLayoutBox const):
(WebCore::Layout::LineBox::inlineRectForTextRun const):
(WebCore::Layout::LineBox::constructInlineBoxes):
(WebCore::Layout::LineBox::alignVertically):
(WebCore::Layout::LineBox::rectForRun const): Deleted.
(WebCore::Layout::LineBox::alignHorizontally): Deleted.
(WebCore::Layout::LineBox::adjustBaselineAndLineHeight): Deleted.
(WebCore::Layout::LineBox::collectHangingContent const): Deleted.
* layout/inlineformatting/InlineLineBox.h:
(WebCore::Layout::LineBox::InlineBox::AscentAndDescent::height const):
(WebCore::Layout::LineBox::InlineBox::logicalRect const):
(WebCore::Layout::LineBox::InlineBox::logicalTop const):
(WebCore::Layout::LineBox::InlineBox::logicalLeft const):
(WebCore::Layout::LineBox::InlineBox::logicalWidth const):
(WebCore::Layout::LineBox::InlineBox::logicalHeight const):
(WebCore::Layout::LineBox::InlineBox::baseline const):
(WebCore::Layout::LineBox::InlineBox::descent const):
(WebCore::Layout::LineBox::InlineBox::setLogicalTop):
(WebCore::Layout::LineBox::InlineBox::setLogicalWidth):
(WebCore::Layout::LineBox::InlineBox::isAtomicInlineLevelBox const):
(WebCore::Layout::LineBox::InlineBox::setHasStrut):
(WebCore::Layout::LineBox::InlineBox::hasStrut const):
(WebCore::Layout::LineBox::alignmentBaseline const):
(WebCore::Layout::AscentAndDescent::height const): Deleted.
(WebCore::Layout::LineBox::ascentAndDescent const): Deleted.
(WebCore::Layout::LineBox::setScrollableOverflow): Deleted.
(WebCore::Layout::LineBox::InlineBox::InlineBox): Deleted.
(WebCore::Layout::LineBox::setLogicalHeightIfGreater): Deleted.
(WebCore::Layout::LineBox::setAlignmentBaselineIfGreater): Deleted.
(WebCore::Layout::LineBox::setAscentIfGreater): Deleted.
(WebCore::Layout::LineBox::setDescentIfGreater): Deleted.
(WebCore::Layout::LineBox::halfLeadingMetrics): Deleted.
* layout/inlineformatting/InlineLineBuilder.h:
(WebCore::Layout::LineBuilder::Run::logicalRight const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (266508 => 266509)


--- trunk/Source/WebCore/ChangeLog	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/ChangeLog	2020-09-03 10:15:04 UTC (rev 266509)
@@ -1,3 +1,64 @@
+2020-09-03  Zalan Bujtas  <za...@apple.com>
+
+        [LFC][IFC] Finalize InlineBox alignment in LineBox
+        https://bugs.webkit.org/show_bug.cgi?id=215410
+
+        Reviewed by Antti Koivisto.
+
+        This patch completes the InlineBox transition.
+
+        LineBox now has a dedicated root inline box and additional inline boxes as needed.
+        Both horizontal and vertical alignments are performed on the inline boxes as opposed to on the runs.
+
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::lineLayout):
+        (WebCore::Layout::InlineFormattingContext::constraintsForLine):
+        (WebCore::Layout::InlineFormattingContext::setDisplayBoxesForLine):
+        * layout/inlineformatting/InlineFormattingContext.h:
+        * layout/inlineformatting/InlineFormattingContextQuirks.cpp:
+        (WebCore::Layout::InlineFormattingContext::Quirks::initialLineHeight const):
+        * layout/inlineformatting/InlineLineBox.cpp:
+        (WebCore::Layout::collectHangingContent):
+        (WebCore::Layout::horizontalAlignmentOffset):
+        (WebCore::Layout::halfLeadingMetrics):
+        (WebCore::Layout::LineBox::InlineBox::InlineBox):
+        (WebCore::Layout::LineBox::LineBox):
+        (WebCore::Layout::m_inlineFormattingContext):
+        (WebCore::Layout::LineBox::inlineBoxForLayoutBox const):
+        (WebCore::Layout::LineBox::inlineRectForTextRun const):
+        (WebCore::Layout::LineBox::constructInlineBoxes):
+        (WebCore::Layout::LineBox::alignVertically):
+        (WebCore::Layout::LineBox::rectForRun const): Deleted.
+        (WebCore::Layout::LineBox::alignHorizontally): Deleted.
+        (WebCore::Layout::LineBox::adjustBaselineAndLineHeight): Deleted.
+        (WebCore::Layout::LineBox::collectHangingContent const): Deleted.
+        * layout/inlineformatting/InlineLineBox.h:
+        (WebCore::Layout::LineBox::InlineBox::AscentAndDescent::height const):
+        (WebCore::Layout::LineBox::InlineBox::logicalRect const):
+        (WebCore::Layout::LineBox::InlineBox::logicalTop const):
+        (WebCore::Layout::LineBox::InlineBox::logicalLeft const):
+        (WebCore::Layout::LineBox::InlineBox::logicalWidth const):
+        (WebCore::Layout::LineBox::InlineBox::logicalHeight const):
+        (WebCore::Layout::LineBox::InlineBox::baseline const):
+        (WebCore::Layout::LineBox::InlineBox::descent const):
+        (WebCore::Layout::LineBox::InlineBox::setLogicalTop):
+        (WebCore::Layout::LineBox::InlineBox::setLogicalWidth):
+        (WebCore::Layout::LineBox::InlineBox::isAtomicInlineLevelBox const):
+        (WebCore::Layout::LineBox::InlineBox::setHasStrut):
+        (WebCore::Layout::LineBox::InlineBox::hasStrut const):
+        (WebCore::Layout::LineBox::alignmentBaseline const):
+        (WebCore::Layout::AscentAndDescent::height const): Deleted.
+        (WebCore::Layout::LineBox::ascentAndDescent const): Deleted.
+        (WebCore::Layout::LineBox::setScrollableOverflow): Deleted.
+        (WebCore::Layout::LineBox::InlineBox::InlineBox): Deleted.
+        (WebCore::Layout::LineBox::setLogicalHeightIfGreater): Deleted.
+        (WebCore::Layout::LineBox::setAlignmentBaselineIfGreater): Deleted.
+        (WebCore::Layout::LineBox::setAscentIfGreater): Deleted.
+        (WebCore::Layout::LineBox::setDescentIfGreater): Deleted.
+        (WebCore::Layout::LineBox::halfLeadingMetrics): Deleted.
+        * layout/inlineformatting/InlineLineBuilder.h:
+        (WebCore::Layout::LineBuilder::Run::logicalRight const):
+
 2020-09-03  Youenn Fablet  <you...@apple.com>
 
         calling transceiver setCodecPreferences doesn't change the order of codecs in the offer/answer generated by the browser

Modified: trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h (266508 => 266509)


--- trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/displaytree/DisplayInlineRect.h	2020-09-03 10:15:04 UTC (rev 266509)
@@ -58,6 +58,7 @@
 
     void moveHorizontally(InlineLayoutUnit);
     void moveVertically(InlineLayoutUnit);
+    void moveBy(InlineLayoutPoint);
 
     void expand(Optional<InlineLayoutUnit>, Optional<InlineLayoutUnit>);
     void expandToContain(const InlineRect&);
@@ -236,6 +237,13 @@
     m_rect.move(InlineLayoutSize { 0, offset });
 }
 
+inline void InlineRect::moveBy(InlineLayoutPoint offset)
+{
+    ASSERT(m_hasValidTop);
+    ASSERT(m_hasValidLeft);
+    m_rect.moveBy(offset);
+}
+
 inline void InlineRect::expand(Optional<InlineLayoutUnit> width, Optional<InlineLayoutUnit> height)
 {
     ASSERT(!width || m_hasValidWidth);
@@ -245,7 +253,13 @@
 
 inline void InlineRect::expandToContain(const InlineRect& other)
 {
-    m_rect = unionRect(other, m_rect);
+#if ASSERT_ENABLED
+    m_hasValidTop = true;
+    m_hasValidLeft = true;
+    m_hasValidWidth = true;
+    m_hasValidHeight = true;
+#endif
+    m_rect.uniteEvenIfEmpty(other);
 }
 
 inline void InlineRect::expandVerticallyToContain(const InlineRect& other)

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp	2020-09-03 10:15:04 UTC (rev 266509)
@@ -167,8 +167,10 @@
             return false;
         }();
         line.close(isLastLineWithInlineContent);
-        auto lineRect = Display::InlineRect { lineConstraints.logicalTopLeft, line.lineLogicalWidth(), lineConstraints.lineHeight};
-        auto lineBox = LineBox { *this, lineRect, lineContent.runs, line.isVisuallyEmpty() ? LineBox::IsLineVisuallyEmpty::Yes : LineBox::IsLineVisuallyEmpty::No, isLastLineWithInlineContent ? LineBox::IsLastLineWithInlineContent::Yes : LineBox::IsLastLineWithInlineContent::No };
+
+        auto lineIsVisuallyEmpty = line.isVisuallyEmpty() ? LineBox::IsLineVisuallyEmpty::Yes : LineBox::IsLineVisuallyEmpty::No;
+        auto lastLine = isLastLineWithInlineContent ? LineBox::IsLastLineWithInlineContent::Yes : LineBox::IsLastLineWithInlineContent::No;
+        auto lineBox = LineBox { *this, lineConstraints.logicalTopLeft, line.lineLogicalWidth(), line.contentLogicalWidth(), lineContent.runs, lineIsVisuallyEmpty, lastLine};
         setDisplayBoxesForLine(lineContent, lineBox, constraints.horizontal);
 
         if (!lineContentRange.isEmpty()) {
@@ -417,7 +419,6 @@
 {
     auto lineLogicalLeft = horizontalConstraints.logicalLeft;
     auto lineLogicalRight = lineLogicalLeft + horizontalConstraints.logicalWidth;
-    auto initialLineHeight = quirks().initialLineHeight(root());
     auto lineIsConstrainedByFloat = false;
 
     auto floatingContext = FloatingContext { root(), *this, formattingState().floatingState() };
@@ -424,7 +425,7 @@
     // Check for intruding floats and adjust logical left/available width for this line accordingly.
     if (!floatingContext.isEmpty()) {
         // FIXME: Add support for variable line height, where the intrusive floats should be probed as the line height grows.
-        auto floatConstraints = floatingContext.constraints(toLayoutUnit(lineLogicalTop), toLayoutUnit(lineLogicalTop + initialLineHeight));
+        auto floatConstraints = floatingContext.constraints(toLayoutUnit(lineLogicalTop), toLayoutUnit(lineLogicalTop + quirks().initialLineHeight()));
         // Check if these constraints actually put limitation on the line.
         if (floatConstraints.left && floatConstraints.left->x <= lineLogicalLeft)
             floatConstraints.left = { };
@@ -480,7 +481,7 @@
         return geometry().computedTextIndent(root, horizontalConstraints).valueOr(InlineLayoutUnit { });
     };
     lineLogicalLeft += computedTextIndent();
-    return LineConstraints { { lineLogicalLeft, lineLogicalTop }, lineLogicalRight - lineLogicalLeft, initialLineHeight, lineIsConstrainedByFloat };
+    return LineConstraints { { lineLogicalLeft, lineLogicalTop }, lineLogicalRight - lineLogicalLeft, lineIsConstrainedByFloat };
 }
 
 void InlineFormattingContext::setDisplayBoxesForLine(const LineLayoutContext::LineContent& lineContent, const LineBox& lineBox, const HorizontalConstraints& horizontalConstraints)
@@ -510,16 +511,13 @@
     auto& inlineContent = formattingState.ensureDisplayInlineContent();
     auto lineIndex = inlineContent.lineBoxes.size();
     auto lineInkOverflow = lineBox.scrollableOverflow();
-    // Compute box final geometry.
+    // Compute final box geometry.
     for (auto& lineRun : lineContent.runs) {
-        auto& logicalRect = lineBox.rectForRun(lineRun);
         auto& layoutBox = lineRun.layoutBox();
-
-        // Add final display runs to state first.
         // Inline level containers (<span>) don't generate display runs and neither do completely collapsed runs.
-        auto initiatesInlineRun = !lineRun.isContainerStart() && !lineRun.isContainerEnd();
+        auto initiatesInlineRun = lineRun.isText() || lineRun.isLineBreak() || lineRun.isBox();
         if (initiatesInlineRun) {
-            auto computedInkOverflow = [&] {
+            auto computedInkOverflow = [&] (const auto& logicalRect) {
                 // FIXME: Add support for non-text ink overflow.
                 if (!lineRun.isText())
                     return logicalRect;
@@ -535,53 +533,33 @@
                 }
                 return inkOverflow;
             };
-            auto inkOverflow = computedInkOverflow();
+            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() });
+            auto inkOverflow = computedInkOverflow(logicalRect);
             lineInkOverflow.expandToContain(inkOverflow);
-            inlineContent.runs.append({ lineIndex, lineRun.layoutBox(), logicalRect, inkOverflow, lineRun.expansion(), lineRun.textContent() });
+            inlineContent.runs.append({ lineIndex, layoutBox, logicalRect, inkOverflow, lineRun.expansion(), lineRun.textContent() });
         }
 
-        if (lineRun.isText())
-            continue;
-
-        if (lineRun.isLineBreak()) {
-            // FIXME: Since <br> and <wbr> runs have associated DOM elements, we might need to construct a display box here. 
-            continue;
-        }
-
-        // Inline level box (replaced or inline-block)
-        if (lineRun.isBox()) {
-            auto topLeft = logicalRect.topLeft();
+        // Create display boxes.
+        // FIXME: Since <br> and <wbr> runs have associated DOM elements, we might need to construct a display box here. 
+        auto initiatesDisplayBox = lineRun.isBox() || lineRun.isContainerStart();
+        if (initiatesDisplayBox) {
+            auto& displayBox = formattingState.displayBox(layoutBox);
+            auto& inlineBox = lineBox.inlineBoxForLayoutBox(layoutBox);
+            auto topLeft = inlineBox.logicalRect().topLeft();
             if (layoutBox.isInFlowPositioned())
                 topLeft += geometry().inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
-            auto& displayBox = formattingState.displayBox(layoutBox);
             displayBox.setTopLeft(toLayoutPoint(topLeft));
-            continue;
-        }
-
-        // Inline level container start (<span>)
-        if (lineRun.isContainerStart()) {
-            auto& displayBox = formattingState.displayBox(layoutBox);
-            displayBox.setTopLeft(toLayoutPoint(logicalRect.topLeft()));
-            continue;
-        }
-
-        // Inline level container end (</span>)
-        if (lineRun.isContainerEnd()) {
-            auto& displayBox = formattingState.displayBox(layoutBox);
-            if (layoutBox.isInFlowPositioned()) {
-                auto inflowOffset = geometry().inFlowPositionedPositionOffset(layoutBox, horizontalConstraints);
-                displayBox.moveHorizontally(inflowOffset.width());
-                displayBox.moveVertically(inflowOffset.height());
+            if (lineRun.isContainerStart()) {
+                auto marginBoxWidth = inlineBox.logicalWidth();
+                auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0));
+                // FIXME: Fix it for multiline.
+                displayBox.setContentBoxWidth(toLayoutUnit(contentBoxWidth));
+                displayBox.setContentBoxHeight(toLayoutUnit(inlineBox.logicalHeight()));
             }
-            auto marginBoxWidth = logicalRect.left() - displayBox.left();
-            auto contentBoxWidth = marginBoxWidth - (displayBox.marginStart() + displayBox.borderLeft() + displayBox.paddingLeft().valueOr(0));
-            // FIXME fix it for multiline.
-            displayBox.setContentBoxWidth(toLayoutUnit(contentBoxWidth));
-            displayBox.setContentBoxHeight(toLayoutUnit(logicalRect.height()));
-            continue;
         }
-
-        ASSERT_NOT_REACHED();
     }
     // FIXME: This is where the logical to physical translate should happen.
     inlineContent.lineBoxes.append({ lineBox.logicalRect(), lineBox.scrollableOverflow(), lineInkOverflow, lineBox.alignmentBaseline() });

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h	2020-09-03 10:15:04 UTC (rev 266509)
@@ -46,13 +46,10 @@
     InlineFormattingContext(const ContainerBox& formattingContextRoot, InlineFormattingState&);
     void layoutInFlowContent(InvalidationState&, const ConstraintsForInFlowContent&) override;
 
-private:
-    IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
-
     class Quirks : public FormattingContext::Quirks {
     public:
         bool lineDescentNeedsCollapsing(const LineBuilder::RunList&) const;
-        InlineLayoutUnit initialLineHeight(const ContainerBox& formattingRoot) const;
+        InlineLayoutUnit initialLineHeight() const;
 
     private:
         friend class InlineFormattingContext;
@@ -63,6 +60,9 @@
     };
     InlineFormattingContext::Quirks quirks() const { return Quirks(*this); }
 
+private:
+    IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
+
     class Geometry : public FormattingContext::Geometry {
     public:
         ContentHeightAndMargin inlineBlockHeightAndMargin(const Box&, const HorizontalConstraints&, const OverrideVerticalValues&) const;
@@ -91,7 +91,6 @@
     struct LineConstraints {
         InlineLayoutPoint logicalTopLeft;
         InlineLayoutUnit availableLogicalWidth { 0 };
-        InlineLayoutUnit lineHeight { 0 };
         bool lineIsConstrainedByFloat { false };
     };
     LineConstraints constraintsForLine(const HorizontalConstraints&, InlineLayoutUnit lineLogicalTop);

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp	2020-09-03 10:15:04 UTC (rev 266509)
@@ -70,13 +70,13 @@
     return true;
 }
 
-InlineLayoutUnit InlineFormattingContext::Quirks::initialLineHeight(const ContainerBox& formattingRoot) const
+InlineLayoutUnit InlineFormattingContext::Quirks::initialLineHeight() const
 {
-    InlineLayoutUnit computedLineHeight = formattingRoot.style().computedLineHeight();
     // Negative lineHeight value means the line-height is not set
-    if (layoutState().inNoQuirksMode() || !formattingRoot.style().lineHeight().isNegative())
-        return computedLineHeight;
-    return LineBox::halfLeadingMetrics(formattingRoot.style().fontMetrics(), computedLineHeight).height();
+    auto& root = formattingContext().root();
+    if (layoutState().inNoQuirksMode() || !root.style().lineHeight().isNegative())
+        return root.style().computedLineHeight();
+    return root.style().fontMetrics().floatHeight();
 }
 
 }

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp	2020-09-03 10:15:04 UTC (rev 266509)
@@ -31,6 +31,13 @@
 namespace WebCore {
 namespace Layout {
 
+struct AscentAndDescent {
+    InlineLayoutUnit height() const { return ascent + descent; }
+
+    InlineLayoutUnit ascent { 0 };
+    InlineLayoutUnit descent { 0 };
+};
+
 struct HangingContent {
 public:
     void reset();
@@ -52,139 +59,153 @@
     m_width =  0;
 }
 
-LineBox::LineBox(const InlineFormattingContext& inlineFormattingContext, const Display::InlineRect& lineRect, const LineBuilder::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty, IsLastLineWithInlineContent isLastLineWithInlineContent)
-    : m_inlineFormattingContext(inlineFormattingContext)
-    , m_runs(runs)
-    , m_rect(lineRect)
-    , m_scrollableOverflow(lineRect)
-    , m_rootInlineBox(InlineBox { lineRect, { }, inlineFormattingContext.root() })
+static HangingContent collectHangingContent(const LineBuilder::RunList& runs, LineBox::IsLastLineWithInlineContent isLastLineWithInlineContent)
 {
-#if ASSERT_ENABLED
-    m_hasValidAlignmentBaseline = true;
-#endif
-    auto& rootStyle = inlineFormattingContext.root().style();
-    auto halfLeadingMetrics = this->halfLeadingMetrics(rootStyle.fontMetrics(), lineRect.height());
-
-    m_rootInlineBox.ascentAndDescent = halfLeadingMetrics;
-    m_alignmentBaseline = halfLeadingMetrics.ascent;
-
-    auto contentLogicalWidth = InlineLayoutUnit { };
-    for (auto& run : m_runs) {
-        auto runHeight = [&]() -> InlineLayoutUnit {
-            auto& fontMetrics = run.style().fontMetrics();
-            if (run.isText() || run.isLineBreak())
-                return fontMetrics.height();
-
-            if (run.isContainerStart() || run.isContainerEnd())
-                return fontMetrics.height();
-
-            auto& layoutBox = run.layoutBox();
-            auto& boxGeometry = inlineFormattingContext.geometryForBox(layoutBox);
-            if (layoutBox.isReplacedBox() || layoutBox.isFloatingPositioned())
-                return boxGeometry.contentBoxHeight();
-
-            // Non-replaced inline box (e.g. inline-block). It looks a bit misleading but their margin box is considered the content height here.
-            return boxGeometry.marginBoxHeight();
-        };
-        // FIXME: This is temporary. Do not make an inline box for each run.
-        m_inlineBoxList.append(InlineBox { { 0, run.logicalLeft(), run.logicalWidth(), runHeight() }, halfLeadingMetrics, run.layoutBox() });
-        m_runToInlineBoxMap.set(&run, m_inlineBoxList.size() - 1);
-        contentLogicalWidth += run.logicalWidth();
+    auto hangingContent = HangingContent { };
+    if (isLastLineWithInlineContent == LineBox::IsLastLineWithInlineContent::Yes)
+        hangingContent.setIsConditional();
+    for (auto& run : WTF::makeReversedRange(runs)) {
+        if (run.isContainerStart() || run.isContainerEnd())
+            continue;
+        if (run.isLineBreak()) {
+            hangingContent.setIsConditional();
+            continue;
+        }
+        if (!run.hasTrailingWhitespace())
+            break;
+        // Check if we have a preserved or hung whitespace.
+        if (run.style().whiteSpace() != WhiteSpace::PreWrap)
+            break;
+        // This is either a normal or conditionally hanging trailing whitespace.
+        hangingContent.expand(run.trailingWhitespaceWidth());
     }
-    m_scrollableOverflow.setWidth(std::max(lineRect.width(), contentLogicalWidth));
-    alignVertically();
-    alignHorizontally(lineRect.width() - contentLogicalWidth, isLastLineWithInlineContent);
-
-    if (isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes) {
-        m_rect.setHeight({ });
-        m_rootInlineBox.ascentAndDescent = { };
-    }
+    return hangingContent;
 }
 
-void LineBox::alignHorizontally(InlineLayoutUnit availableWidth, IsLastLineWithInlineContent isLastLine)
+static Optional<InlineLayoutUnit> horizontalAlignmentOffset(const LineBuilder::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, LineBox::IsLastLineWithInlineContent isLastLine)
 {
-    auto hangingContent = collectHangingContent(isLastLine);
+    auto availableWidth = lineLogicalWidth - contentLogicalWidth;
+    auto hangingContent = collectHangingContent(runs, isLastLine);
     availableWidth += hangingContent.width();
-    if (m_runs.isEmpty() || availableWidth <= 0)
-        return;
+    if (availableWidth <= 0)
+        return { };
 
     auto computedHorizontalAlignment = [&] {
-        auto& rootStyle = formattingContext().root().style();
-        if (rootStyle.textAlign() != TextAlignMode::Justify)
-            return rootStyle.textAlign();
+        if (textAlign != TextAlignMode::Justify)
+            return textAlign;
         // Text is justified according to the method specified by the text-justify property,
         // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
         // the last line before a forced break or the end of the block is start-aligned.
-        if (m_runs.last().isLineBreak() || isLastLine == IsLastLineWithInlineContent::Yes)
+        if (runs.last().isLineBreak() || isLastLine == LineBox::IsLastLineWithInlineContent::Yes)
             return TextAlignMode::Start;
         return TextAlignMode::Justify;
-    }();
+    };
 
-    if (computedHorizontalAlignment == TextAlignMode::Justify) {
-        auto accumulatedExpansion = InlineLayoutUnit { };
-        for (size_t index = 0; index < m_runs.size(); ++index) {
-            m_inlineBoxList[index].rect.moveHorizontally(accumulatedExpansion);
-
-            auto horizontalExpansion = m_runs[index].expansion().horizontalExpansion;
-            m_inlineBoxList[index].rect.expandHorizontally(horizontalExpansion);
-            accumulatedExpansion += horizontalExpansion;
-        }
-        return;
+    switch (computedHorizontalAlignment()) {
+    case TextAlignMode::Left:
+    case TextAlignMode::WebKitLeft:
+    case TextAlignMode::Start:
+        return { };
+    case TextAlignMode::Right:
+    case TextAlignMode::WebKitRight:
+    case TextAlignMode::End:
+        return availableWidth;
+    case TextAlignMode::Center:
+    case TextAlignMode::WebKitCenter:
+        return availableWidth / 2;
+    case TextAlignMode::Justify:
+        // TextAlignMode::Justify is a run alignment (and we only do inline box alignment here)
+        return { };
+    default:
+        ASSERT_NOT_IMPLEMENTED_YET();
+        return { };
     }
+    ASSERT_NOT_REACHED();
+    return { };
+}
 
-    auto adjustmentForAlignment = [&] (auto availableWidth) -> Optional<InlineLayoutUnit> {
-        switch (computedHorizontalAlignment) {
-        case TextAlignMode::Left:
-        case TextAlignMode::WebKitLeft:
-        case TextAlignMode::Start:
-            return { };
-        case TextAlignMode::Right:
-        case TextAlignMode::WebKitRight:
-        case TextAlignMode::End:
-            return std::max<InlineLayoutUnit>(availableWidth, 0);
-        case TextAlignMode::Center:
-        case TextAlignMode::WebKitCenter:
-            return std::max<InlineLayoutUnit>(availableWidth / 2, 0);
-        case TextAlignMode::Justify:
-            ASSERT_NOT_REACHED();
-            break;
-        }
-        ASSERT_NOT_REACHED();
-        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) };
+}
 
-    if (auto adjustment = adjustmentForAlignment(availableWidth)) {
-        // FIXME: line box should not need to be moved, only the runs.
-        m_rect.moveHorizontally(*adjustment);
-        for (auto& inlineBox : m_inlineBoxList)
-            inlineBox.rect.moveHorizontally(*adjustment);
+LineBox::InlineBox::InlineBox(const Display::InlineRect& rect, InlineLayoutUnit syntheticBaseline)
+    : m_logicalRect(rect)
+    , m_baseline(syntheticBaseline)
+    , m_isEmpty(false)
+    , m_isAtomic(true)
+{
+}
+
+LineBox::InlineBox::InlineBox(const Display::InlineRect& rect, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty isConsideredEmpty)
+    : m_logicalRect(rect)
+    , m_baseline(baseline)
+    , m_descent(descent)
+    , m_isEmpty(isConsideredEmpty == IsConsideredEmpty::Yes)
+{
+}
+
+LineBox::LineBox(const InlineFormattingContext& inlineFormattingContext, const InlineLayoutPoint& topLeft, InlineLayoutUnit logicalWidth, InlineLayoutUnit contentLogicalWidth, const LineBuilder::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty, IsLastLineWithInlineContent isLastLineWithInlineContent)
+    : m_rect(topLeft, logicalWidth, { })
+    , m_contentLogicalWidth(contentLogicalWidth)
+    , m_inlineFormattingContext(inlineFormattingContext)
+{
+    m_lineAlignmentOffset = horizontalAlignmentOffset(runs, root().style().textAlign(), logicalWidth, contentLogicalWidth, isLastLineWithInlineContent);
+    if (m_lineAlignmentOffset) {
+        // FIXME: line box should not need to be moved, only the inline boxes.
+        m_rect.moveHorizontally(*m_lineAlignmentOffset);
     }
+    constructInlineBoxes(runs, isLineVisuallyEmpty);
+    alignVertically(isLineVisuallyEmpty);
+    // Compute scrollable overflow.
+    m_scrollableOverflow = Display::InlineRect { topLeft, std::max(logicalWidth, m_rootInlineBox.logicalWidth()), { } };
+    auto logicalBottom = m_rootInlineBox.logicalBottom();
+    for (auto& inlineBoxEntry : m_inlineBoxRectMap)
+        logicalBottom = std::max(logicalBottom, inlineBoxEntry.value->logicalBottom());
+    m_scrollableOverflow.expandVertically(logicalBottom);
+
 }
 
-void LineBox::alignVertically()
+const LineBox::InlineBox& LineBox::inlineBoxForLayoutBox(const Box& layoutBox) const
 {
-    adjustBaselineAndLineHeight();
-    for (size_t index = 0; index < m_inlineBoxList.size(); ++index) {
-        auto& inlineBox = m_inlineBoxList[index];
-        auto& run = m_runs[index];
-        auto& layoutBox = inlineBox.layoutBox;
-        auto inlineBoxHeight = inlineBox.rect.height();
+    ASSERT(&layoutBox != &root());
+    return *m_inlineBoxRectMap.get(&layoutBox);
+}
 
-        auto logicalTop = InlineLayoutUnit { };
-        auto verticalAlign = layoutBox.style().verticalAlign();
-        auto ascent = layoutBox.style().fontMetrics().ascent();
+Display::InlineRect LineBox::inlineRectForTextRun(const LineBuilder::Run& run) const
+{
+    ASSERT(run.isText() || run.isLineBreak());
+    auto inlineBoxRect = m_rootInlineBox.logicalRect();
+    if (&run.layoutBox().parent() != &root())
+        inlineBoxRect = m_inlineBoxRectMap.get(&run.layoutBox().parent())->logicalRect();
+    return { inlineBoxRect.top(), run.logicalLeft(), run.logicalWidth(), inlineBoxRect.height() };
+}
 
-        switch (verticalAlign) {
-        case VerticalAlign::Baseline:
-            if (run.isLineBreak() || run.isText())
-                logicalTop = alignmentBaseline() - ascent;
-            else if (run.isContainerStart()) {
-                auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
-                logicalTop = alignmentBaseline() - ascent - boxGeometry.borderTop() - boxGeometry.paddingTop().valueOr(0);
-            } else if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
+void LineBox::constructInlineBoxes(const LineBuilder::RunList& runs, IsLineVisuallyEmpty isLineVisuallyEmpty)
+{
+    auto lineHasImaginaryStrut = !layoutState().inQuirksMode();
+    auto lineIsConsideredEmpty = !lineHasImaginaryStrut || isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes ? InlineBox::IsConsideredEmpty::Yes : InlineBox::IsConsideredEmpty::No;
+    auto& fontMetrics = root().style().fontMetrics();
+    InlineLayoutUnit rootInlineBoxHeight = fontMetrics.height();
+    auto rootInlineRect = Display::InlineRect { { }, { }, contentLogicalWidth(), rootInlineBoxHeight };
+    InlineLayoutUnit rootInlineBaseline = fontMetrics.ascent();
+    auto rootInlineDescent = rootInlineBoxHeight - rootInlineBaseline;
+    m_rootInlineBox = InlineBox { rootInlineRect, rootInlineBaseline, rootInlineDescent, lineIsConsideredEmpty };
+
+    for (auto& run : runs) {
+        auto& layoutBox = run.layoutBox();
+        if (run.isBox()) {
+            auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
+            if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
                 auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
                 // Spec makes us generate at least one line -even if it is empty.
-                auto inlineBlockBaseline = formattingState.displayInlineContent()->lineBoxes.last().baseline();
+                auto& lastLineBox = formattingState.displayInlineContent()->lineBoxes.last();
+                auto inlineBlockBaseline = lastLineBox.top() + lastLineBox.baseline();
                 // The inline-block's baseline offset is relative to its content box. Let's convert it relative to the margin box.
                 //           _______________ <- margin box
                 //          |
@@ -197,148 +218,120 @@
                 //     text | | |   v text
                 //     -----|-|-|---------- <- baseline
                 //
-                auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
-                auto baselineFromMarginBox = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0) + inlineBlockBaseline;
-                logicalTop = alignmentBaseline() - baselineFromMarginBox;
+                auto adjustedBaseline = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0) + inlineBlockBaseline;
+                auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), run.logicalWidth(), boxGeometry.marginBoxHeight() };
+                m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, adjustedBaseline));
             } else {
-                auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
-                logicalTop = alignmentBaseline() - (boxGeometry.verticalBorder() + boxGeometry.verticalPadding().valueOr(0_lu) + inlineBoxHeight + boxGeometry.marginAfter());
+                auto runHeight = boxGeometry.marginBoxHeight();
+                auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), run.logicalWidth(), runHeight };
+                m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, runHeight));
             }
-            break;
-        case VerticalAlign::Top:
-            logicalTop = 0_lu;
-            break;
-        case VerticalAlign::Bottom:
-            logicalTop = logicalBottom() - inlineBoxHeight;
-            break;
-        default:
-            ASSERT_NOT_IMPLEMENTED_YET();
-            break;
+        } else if (run.isContainerStart()) {
+            auto initialWidth = contentLogicalWidth() - run.logicalLeft();
+            ASSERT(initialWidth >= 0);
+            auto& fontMetrics = layoutBox.style().fontMetrics();
+            InlineLayoutUnit logicalHeight = fontMetrics.height();
+            InlineLayoutUnit baseline = fontMetrics.ascent();
+            auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), initialWidth, logicalHeight };
+            m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, baseline, logicalHeight - baseline, InlineBox::IsConsideredEmpty::Yes));
+        } else if (run.isContainerEnd()) {
+            // Adjust the logical width when the inline level container closes on this line.
+            auto& inlineBox = *m_inlineBoxRectMap.get(&layoutBox);
+            inlineBox.setLogicalWidth(run.logicalRight() - inlineBox.logicalLeft());
+        } else if ((run.isText() || run.isLineBreak())) {
+            auto& containerBox = run.layoutBox().parent();
+            &containerBox == &root() ? m_rootInlineBox.setIsNonEmpty() : m_inlineBoxRectMap.get(&containerBox)->setIsNonEmpty();
         }
-        auto& inlineBoxRect = inlineBox.rect;
-        inlineBoxRect.setTop(logicalTop);
-        // Adjust scrollable overflow if the run overflows the line.
-        m_scrollableOverflow.expandVerticallyToContain(inlineBoxRect);
-        // Convert runs from relative to the line top/left to the formatting root's border box top/left.
-        inlineBoxRect.moveVertically(this->logicalTop());
-        inlineBoxRect.moveHorizontally(logicalLeft());
     }
 }
 
-void LineBox::adjustBaselineAndLineHeight()
+void LineBox::alignVertically(IsLineVisuallyEmpty isLineVisuallyEmpty)
 {
-    unsigned inlineContainerNestingLevel = 0;
-    auto hasSeenDirectTextOrLineBreak = false;
-    for (size_t index = 0; index < m_inlineBoxList.size(); ++index) {
-        auto& inlineBox = m_inlineBoxList[index];
-        auto& layoutBox = inlineBox.layoutBox;
-        auto& style = layoutBox.style();
-        auto& run = m_runs[index];
-        if (run.isText() || run.isLineBreak()) {
-            // For text content we set the baseline either through the initial strut (set by the formatting context root) or
-            // through the inline container (start). Normally the text content itself does not stretch the line.
-            if (inlineContainerNestingLevel) {
-                // We've already adjusted the line height/baseline through the parent inline container. 
-                continue;
+    if (isLineVisuallyEmpty == IsLineVisuallyEmpty::Yes)
+        return;
+    // 1. Compute line box height/alignment baseline by placing the inline boxes vertically.
+    // 2. Adjust the inline box vertical position.
+    auto& rootStyle = root().style();
+    // FIXME: We should let line box fully contain the inline boxes and move line spacing/overflow out to Display::LineBox.
+    // see webkit.org/b/215087#c9
+    InlineLayoutUnit recommendedLineBoxHeight = rootStyle.lineHeight().isNegative() ? rootStyle.fontMetrics().lineSpacing() : rootStyle.computedLineHeight();
+
+    auto contentLogicalHeight = InlineLayoutUnit { };
+    auto alignmentBaseline = InlineLayoutUnit { };
+    auto computeLineBoxHeight = [&](auto& inlineBox, auto textAlignMode) {
+        switch (textAlignMode) {
+        case VerticalAlign::Baseline: {
+            auto baselineOverflow = inlineBox.baseline() - alignmentBaseline;
+            if (baselineOverflow > 0) {
+                contentLogicalHeight += baselineOverflow;
+                alignmentBaseline += baselineOverflow;
             }
-            if (hasSeenDirectTextOrLineBreak) {
-                // e.g div>first text</div> or <div><span>nested<span>first direct text</div>.
-                continue;
+            // Table cells, inline-block boxes may stretch the line beyond their baseline.
+            auto belowBaseline = inlineBox.descent().valueOr(inlineBox.logicalHeight() - inlineBox.baseline());
+            auto belowBaselineOverflow = belowBaseline - (contentLogicalHeight - alignmentBaseline);
+            if (belowBaselineOverflow > 0)
+                contentLogicalHeight += belowBaselineOverflow;
+            break;
+        }
+        case VerticalAlign::Top: {
+            auto overflow = inlineBox.logicalHeight() - contentLogicalHeight;
+            if (overflow > 0)
+                contentLogicalHeight += overflow;
+            break;
+        }
+        case VerticalAlign::Bottom: {
+            auto overflow = inlineBox.logicalHeight() - contentLogicalHeight;
+            if (overflow > 0) {
+                contentLogicalHeight += overflow;
+                alignmentBaseline += overflow;
             }
-            hasSeenDirectTextOrLineBreak = true;
-            continue;
+            break;
         }
-
-        if (run.isContainerStart()) {
-            ++inlineContainerNestingLevel;
-            // Inline containers stretch the line by their font size.
-            // Vertical margins, paddings and borders don't contribute to the line height.
-            auto& fontMetrics = style.fontMetrics();
-            if (style.verticalAlign() == VerticalAlign::Baseline) {
-                auto halfLeading = LineBox::halfLeadingMetrics(fontMetrics, style.computedLineHeight());
-                // Both halfleading ascent and descent could be negative (tall font vs. small line-height value)
-                if (halfLeading.descent > 0)
-                    setDescentIfGreater(halfLeading.descent);
-                if (halfLeading.ascent > 0)
-                    setAscentIfGreater(halfLeading.ascent);
-                setLogicalHeightIfGreater(ascentAndDescent().height());
-            } else
-                setLogicalHeightIfGreater(fontMetrics.height());
-            continue;
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
         }
+    };
 
-        if (run.isContainerEnd()) {
-            // The line's baseline and height have already been adjusted at ContainerStart.
-            ASSERT(inlineContainerNestingLevel);
-            --inlineContainerNestingLevel;
-            continue;
-        }
+    auto shouldRootInlineBoxStretchLineBox = !m_rootInlineBox.isEmpty();
+    if (shouldRootInlineBoxStretchLineBox)
+        computeLineBoxHeight(m_rootInlineBox, VerticalAlign::Baseline);
+    for (auto& inlineBoxEntry : m_inlineBoxRectMap) {
+        auto& inlineBox = *inlineBoxEntry.value;
+        auto shouldInlineBoxStretchLineBox = !inlineBox.isEmpty();
+        if (shouldInlineBoxStretchLineBox)
+            computeLineBoxHeight(inlineBox, inlineBoxEntry.key->style().verticalAlign());
+    }
 
-        if (run.isBox()) {
-            auto& boxGeometry = formattingContext().geometryForBox(layoutBox);
-            auto marginBoxHeight = boxGeometry.marginBoxHeight();
+    auto lineBoxLogicalHeight = rootStyle.lineHeight().isNegative() ? std::max(recommendedLineBoxHeight, contentLogicalHeight) : recommendedLineBoxHeight;
+    m_rect.setHeight(lineBoxLogicalHeight);
 
-            switch (style.verticalAlign()) {
-            case VerticalAlign::Baseline: {
-                if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
-                    // Inline-blocks with inline content always have baselines.
-                    auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
-                    // There has to be at least one line -even if it is empty.
-                    auto& lastLineBox = formattingState.displayInlineContent()->lineBoxes.last();
-                    auto beforeHeight = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0);
-                    setAlignmentBaselineIfGreater(beforeHeight + lastLineBox.baseline());
-                    setLogicalHeightIfGreater(marginBoxHeight);
-                } else {
-                    // Non inline-block boxes sit on the baseline (including their bottom margin).
-                    setAscentIfGreater(marginBoxHeight);
-                    // Ignore negative descent (yes, negative descent is a thing).
-                    setLogicalHeightIfGreater(marginBoxHeight + std::max<InlineLayoutUnit>(0, ascentAndDescent().descent));
-                }
-                break;
-            }
-            case VerticalAlign::Top:
-                // Top align content never changes the baseline, it only pushes the bottom of the line further down.
-                setLogicalHeightIfGreater(marginBoxHeight);
-                break;
-            case VerticalAlign::Bottom: {
-                // Bottom aligned, tall content pushes the baseline further down from the line top.
-                auto lineLogicalHeight = logicalHeight();
-                if (marginBoxHeight > lineLogicalHeight) {
-                    setLogicalHeightIfGreater(marginBoxHeight);
-                    setAlignmentBaselineIfGreater(alignmentBaseline() + (marginBoxHeight - lineLogicalHeight));
-                }
-                break;
-            }
-            default:
-                ASSERT_NOT_IMPLEMENTED_YET();
-                break;
-            }
-            continue;
+    auto adjustInlineBoxTop = [&](auto& inlineBox, auto textAlignMode) {
+        auto inlineBoxLogicalTop = InlineLayoutUnit { };
+        switch (textAlignMode) {
+        case VerticalAlign::Baseline:
+            inlineBoxLogicalTop = alignmentBaseline - inlineBox.baseline();
+            break;
+        case VerticalAlign::Top:
+            inlineBoxLogicalTop = { };
+            break;
+        case VerticalAlign::Bottom:
+            inlineBoxLogicalTop = logicalBottom() - inlineBox.logicalHeight();
+            break;
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
         }
-    }
-}
+        inlineBox.setLogicalTop(inlineBoxLogicalTop);
+    };
 
-HangingContent LineBox::collectHangingContent(IsLastLineWithInlineContent isLastLineWithInlineContent) const
-{
-    auto hangingContent = HangingContent { };
-    if (isLastLineWithInlineContent == IsLastLineWithInlineContent::Yes)
-        hangingContent.setIsConditional();
-    for (auto& run : WTF::makeReversedRange(m_runs)) {
-        if (run.isContainerStart() || run.isContainerEnd())
-            continue;
-        if (run.isLineBreak()) {
-            hangingContent.setIsConditional();
-            continue;
-        }
-        if (!run.hasTrailingWhitespace())
-            break;
-        // Check if we have a preserved or hung whitespace.
-        if (run.style().whiteSpace() != WhiteSpace::PreWrap)
-            break;
-        // This is either a normal or conditionally hanging trailing whitespace.
-        hangingContent.expand(run.trailingWhitespaceWidth());
+    alignmentBaseline = halfLeadingMetrics(rootStyle.fontMetrics(), lineBoxLogicalHeight).ascent;
+    adjustInlineBoxTop(m_rootInlineBox, VerticalAlign::Baseline);
+    for (auto& inlineBoxEntry : m_inlineBoxRectMap) {
+        auto& layoutBox = *inlineBoxEntry.key;
+        auto& inlineBox = *inlineBoxEntry.value;
+        adjustInlineBoxTop(inlineBox, layoutBox.style().verticalAlign());
     }
-    return hangingContent;
 }
 
 }

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h	2020-09-03 10:15:04 UTC (rev 266509)
@@ -30,34 +30,52 @@
 #include "DisplayBox.h"
 #include "DisplayInlineRect.h"
 #include "InlineLineBuilder.h"
+#include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
 namespace Layout {
 
 class InlineFormattingContext;
-struct HangingContent;
 
-struct AscentAndDescent {
-    InlineLayoutUnit height() const { return ascent + descent; }
-
-    InlineLayoutUnit ascent { 0 };
-    InlineLayoutUnit descent { 0 };
-};
-
 class LineBox {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     struct InlineBox {
-        InlineBox(const Display::InlineRect&, const AscentAndDescent&, const Box&);
+        WTF_MAKE_ISO_ALLOCATED_INLINE(InlineBox);
+    public:
+        enum class IsConsideredEmpty { Yes, No };
+        InlineBox(const Display::InlineRect&, InlineLayoutUnit syntheticBaseline);
+        InlineBox(const Display::InlineRect&, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty);
+        InlineBox() = default;
 
-        Display::InlineRect rect;
-        AscentAndDescent ascentAndDescent;
-        const Box& layoutBox;
+        const Display::InlineRect& logicalRect() const { return m_logicalRect; }
+        InlineLayoutUnit logicalTop() const { return m_logicalRect.top(); }
+        InlineLayoutUnit logicalBottom() const { return m_logicalRect.bottom(); }
+        InlineLayoutUnit logicalLeft() const { return m_logicalRect.left(); }
+        InlineLayoutUnit logicalWidth() const { return m_logicalRect.width(); }
+        InlineLayoutUnit logicalHeight() const { return m_logicalRect.height(); }
+
+        InlineLayoutUnit baseline() const { return m_baseline; }
+        Optional<InlineLayoutUnit> descent() const { return m_descent; }
+
+        void setLogicalTop(InlineLayoutUnit logicalTop) { m_logicalRect.setTop(logicalTop); }
+        void setLogicalWidth(InlineLayoutUnit logicalWidth) { m_logicalRect.setWidth(logicalWidth); }
+
+        bool isEmpty() const { return m_isEmpty; }
+        void setIsNonEmpty() { m_isEmpty = false; }
+        bool isAtomic() const { return m_isAtomic; }
+
+    private:
+        Display::InlineRect m_logicalRect;
+        InlineLayoutUnit m_baseline;
+        Optional<InlineLayoutUnit> m_descent;
+        bool m_isEmpty { true };
+        bool m_isAtomic { false };
     };
 
     enum class IsLastLineWithInlineContent { No, Yes };
     enum class IsLineVisuallyEmpty { No, Yes };
-    LineBox(const InlineFormattingContext&, const Display::InlineRect&, const LineBuilder::RunList&, IsLineVisuallyEmpty, IsLastLineWithInlineContent);
+    LineBox(const InlineFormattingContext&, const InlineLayoutPoint& topLeft, InlineLayoutUnit logicalWidth, InlineLayoutUnit contentLogicalWidth, const LineBuilder::RunList&, IsLineVisuallyEmpty, IsLastLineWithInlineContent);
 
     InlineLayoutUnit logicalLeft() const { return m_rect.left(); }
     InlineLayoutUnit logicalRight() const { return m_rect.right(); }
@@ -69,116 +87,49 @@
     const Display::InlineRect& logicalRect() const { return m_rect; }
     const Display::InlineRect& scrollableOverflow() const { return m_scrollableOverflow; }
 
-    static AscentAndDescent halfLeadingMetrics(const FontMetrics&, InlineLayoutUnit lineLogicalHeight);
+    const InlineBox& inlineBoxForLayoutBox(const Box&) const;
+    Display::InlineRect inlineRectForTextRun(const LineBuilder::Run&) const;
 
-    // Aligment baseline from line logical top.
-    //
-    // -------------------    line logical top     ------------------- (top align)
-    //             ^                                              ^
-    //             |                                  ^           |
-    //   ^         | alignment baseline               |           | alignment baseline
-    //   |         |                                  |           |
-    //   | ascent  |                                  | ascent    |
-    //   |         |                                  v           v
-    //   v         v                               ------------------- baseline
-    //   ----------------- baseline                   ^
-    //   ^                                            | descent
-    //   | descent                                    v
+    // _____________________________________________________ line box logical top
+    //                      ^
+    //                      |
+    //   ____________________________________ root inline box
+    //   ^                  |
+    //   |                  |
+    //   | root line ascent |
+    //   |                  |
+    //   v                  v
+    //   ___________________________________________________ alignment baseline
+    //   ^
+    //   | root line descent
     //   v
-    // -------------------    line logical bottom  -------------------
-    InlineLayoutUnit alignmentBaseline() const;
+    //   ___________________________________
+    // _____________________________________________________ line box logical bottom
+    InlineLayoutUnit alignmentBaseline() const { return m_rootInlineBox.logicalTop() + m_rootInlineBox.baseline(); }
 
-    const Display::InlineRect& rectForRun(const LineBuilder::Run& run) const { return m_inlineBoxList[m_runToInlineBoxMap.get(&run)].rect; }
-
 private:
-    const AscentAndDescent& ascentAndDescent() const { return m_rootInlineBox.ascentAndDescent; }
+    void constructInlineBoxes(const LineBuilder::RunList&, IsLineVisuallyEmpty);
+    void alignVertically(IsLineVisuallyEmpty);
 
-    void setAlignmentBaselineIfGreater(InlineLayoutUnit);
-    void setAscentIfGreater(InlineLayoutUnit);
-    void setDescentIfGreater(InlineLayoutUnit);
-    void setLogicalHeightIfGreater(InlineLayoutUnit);
+    InlineLayoutUnit contentLogicalWidth() const { return m_contentLogicalWidth; }
 
-    void setScrollableOverflow(const Display::InlineRect& rect) { m_scrollableOverflow = rect; }
-
-    void alignHorizontally(InlineLayoutUnit availableWidth, IsLastLineWithInlineContent);
-    void alignVertically();
-    void adjustBaselineAndLineHeight();
-    HangingContent collectHangingContent(IsLastLineWithInlineContent) const;
-
     const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
+    const Box& root() const { return formattingContext().root(); }
     LayoutState& layoutState() const { return formattingContext().layoutState(); }
 
 private:
-#if ASSERT_ENABLED
-    bool m_hasValidAlignmentBaseline { false };
-#endif
-    const InlineFormattingContext& m_inlineFormattingContext;
-    const LineBuilder::RunList& m_runs;
     Display::InlineRect m_rect;
     Display::InlineRect m_scrollableOverflow;
-    InlineLayoutUnit m_alignmentBaseline { 0 };
+    InlineLayoutUnit m_contentLogicalWidth { 0 };
+
     InlineBox m_rootInlineBox;
-    Vector<InlineBox> m_inlineBoxList;
-    // FIXME: This is temporary and will be replaced by an inline box map.
-    HashMap<const LineBuilder::Run*, size_t> m_runToInlineBoxMap;
+
+    Optional<InlineLayoutUnit> m_lineAlignmentOffset;
+    HashMap<const Box*, std::unique_ptr<InlineBox>> m_inlineBoxRectMap;
+    const InlineFormattingContext& m_inlineFormattingContext;
 };
 
-inline LineBox::InlineBox::InlineBox(const Display::InlineRect& rect, const AscentAndDescent& ascentAndDescent, const Box& layoutBox)
-    : rect(rect)
-    , ascentAndDescent(ascentAndDescent)
-    , layoutBox(layoutBox)
-{
 }
-
-inline void LineBox::setLogicalHeightIfGreater(InlineLayoutUnit logicalHeight)
-{
-    if (logicalHeight <= m_rect.height())
-        return;
-    m_rect.setHeight(logicalHeight);
 }
 
-inline void LineBox::setAlignmentBaselineIfGreater(InlineLayoutUnit alignmentBaseline)
-{
-#if ASSERT_ENABLED
-    m_hasValidAlignmentBaseline = true;
 #endif
-    m_alignmentBaseline = std::max(alignmentBaseline, m_alignmentBaseline);
-}
-
-inline void LineBox::setAscentIfGreater(InlineLayoutUnit ascent)
-{
-    if (ascent < m_rootInlineBox.ascentAndDescent.ascent)
-        return;
-    setAlignmentBaselineIfGreater(ascent);
-    m_rootInlineBox.ascentAndDescent.ascent = ascent;
-}
-
-inline void LineBox::setDescentIfGreater(InlineLayoutUnit descent)
-{
-    if (descent < m_rootInlineBox.ascentAndDescent.descent)
-        return;
-    m_rootInlineBox.ascentAndDescent.descent = descent;
-}
-
-inline InlineLayoutUnit LineBox::alignmentBaseline() const
-{
-    ASSERT(m_hasValidAlignmentBaseline);
-    return m_alignmentBaseline;
-}
-
-inline AscentAndDescent LineBox::halfLeadingMetrics(const FontMetrics& fontMetrics, InlineLayoutUnit lineLogicalHeight)
-{
-    auto ascent = fontMetrics.ascent();
-    auto descent = fontMetrics.descent();
-    // 10.8.1 Leading and half-leading
-    auto halfLeading = (lineLogicalHeight - (ascent + descent)) / 2;
-    // Inline tree height is all integer based.
-    auto adjustedAscent = std::max<InlineLayoutUnit>(floorf(ascent + halfLeading), 0);
-    auto adjustedDescent = std::max<InlineLayoutUnit>(ceilf(descent + halfLeading), 0);
-    return { adjustedAscent, adjustedDescent };
-}
-
-}
-}
-
-#endif

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.cpp	2020-09-03 10:15:04 UTC (rev 266509)
@@ -110,10 +110,18 @@
         if (expansionOpportunityCount && availableWidth()) {
             // Distribute the extra space.
             auto expansionToDistribute = availableWidth() / expansionOpportunityCount;
+            auto accumulatedExpansion = InlineLayoutUnit { };
             for (auto& run : m_runs) {
-                // Expand and moves runs by the accumulated expansion.
-                if (run.hasExpansionOpportunity())
-                    run.setHorizontalExpansion(expansionToDistribute * run.expansionOpportunityCount());
+                // Expand and move runs by the accumulated expansion.
+                run.moveHorizontally(accumulatedExpansion);
+                if (!run.hasExpansionOpportunity())
+                    continue;
+                ASSERT(run.expansionOpportunityCount());
+                auto computedExpansion = expansionToDistribute * run.expansionOpportunityCount();
+                // FIXME: Check why we need to set both.
+                run.setHorizontalExpansion(computedExpansion);
+                run.shrinkHorizontally(-computedExpansion);
+                accumulatedExpansion += computedExpansion;
             }
         }
     };

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h (266508 => 266509)


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h	2020-09-03 08:38:50 UTC (rev 266508)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBuilder.h	2020-09-03 10:15:04 UTC (rev 266509)
@@ -77,6 +77,7 @@
 
         InlineLayoutUnit logicalWidth() const { return m_logicalWidth; }
         InlineLayoutUnit logicalLeft() const { return m_logicalLeft; }
+        InlineLayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); }
 
         const Display::Run::Expansion& expansion() const { return m_expansion; }
         bool hasExpansionOpportunity() const { return m_expansionOpportunityCount; }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to