Title: [266510] trunk
Revision
266510
Author
[email protected]
Date
2020-09-03 04:22:19 -0700 (Thu, 03 Sep 2020)

Log Message

Source/WebCore:
[LFC][IFC] Add support nested inline box sizing and positioning
https://bugs.webkit.org/show_bug.cgi?id=215748

Reviewed by Antti Koivisto.

This patch splits the line box construction process into a few distinct steps.
1. Construct the inline boxes as needed. There's always a root inline box.
2. Size them by taking the vertical alignment into account
   - child inline boxes stretch their parent inline boxes in most cases (depending on the vertical-align property value).
3. Position the inline boxes relative to the line box.

Test: fast/layoutformattingcontext/vertical-align-middle-nested.html
      fast/layoutformattingcontext/vertical-align-middle-simple.html

* layout/inlineformatting/InlineLineBox.cpp:
(WebCore::Layout::m_inlineFormattingContext):
(WebCore::Layout::LineBox::inlineRectForTextRun const):
(WebCore::Layout::LineBox::constructInlineBoxes):
(WebCore::Layout::LineBox::computeInlineBoxesLogicalHeight):
(WebCore::Layout::LineBox::alignInlineBoxesVerticallyAndComputeLineHeight):
(WebCore::Layout::LineBox::inlineBoxForLayoutBox const): Deleted.
(WebCore::Layout::LineBox::alignVertically): Deleted.
* layout/inlineformatting/InlineLineBox.h:
(WebCore::Layout::LineBox::InlineBox::setLogicalTop):
(WebCore::Layout::LineBox::InlineBox::setLogicalWidth):
(WebCore::Layout::LineBox::InlineBox::setLogicalHeight):
(WebCore::Layout::LineBox::InlineBox::setBaseline):
(WebCore::Layout::LineBox::inlineBoxForLayoutBox const):
(WebCore::Layout::LineBox::inlineBoxForLayoutBox):

LayoutTests:
[LFC][IFC] Fix nested inline box sizing and positioning
https://bugs.webkit.org/show_bug.cgi?id=215748

Reviewed by Antti Koivisto.

* fast/layoutformattingcontext/vertical-align-middle-nested-expected.html:
* fast/layoutformattingcontext/vertical-align-middle-nested.html:
* fast/layoutformattingcontext/vertical-align-middle-simple-expected.html:
* fast/layoutformattingcontext/vertical-align-middle-simple.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (266509 => 266510)


--- trunk/LayoutTests/ChangeLog	2020-09-03 10:15:04 UTC (rev 266509)
+++ trunk/LayoutTests/ChangeLog	2020-09-03 11:22:19 UTC (rev 266510)
@@ -1,3 +1,15 @@
+2020-09-03  Zalan Bujtas  <[email protected]>
+
+        [LFC][IFC] Fix nested inline box sizing and positioning
+        https://bugs.webkit.org/show_bug.cgi?id=215748
+
+        Reviewed by Antti Koivisto.
+
+        * fast/layoutformattingcontext/vertical-align-middle-nested-expected.html:
+        * fast/layoutformattingcontext/vertical-align-middle-nested.html:
+        * fast/layoutformattingcontext/vertical-align-middle-simple-expected.html:
+        * fast/layoutformattingcontext/vertical-align-middle-simple.html:
+
 2020-09-02  Alex Christensen  <[email protected]>
 
         Rebase Windows test expectations after r266466

Added: trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-nested-expected.html (0 => 266510)


--- trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-nested-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-nested-expected.html	2020-09-03 11:22:19 UTC (rev 266510)
@@ -0,0 +1,7 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:LayoutFormattingContextEnabled=true internal:LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+div {
+    background-color: green;
+}
+</style>
+<div style="height: 44px;"></div>

Added: trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-nested.html (0 => 266510)


--- trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-nested.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-nested.html	2020-09-03 11:22:19 UTC (rev 266510)
@@ -0,0 +1,20 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ internal:LayoutFormattingContextEnabled=true internal:LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+.container {
+  background-color: green;
+  color: green;
+  font-size: 40px;
+  font-family: Ahem;
+}
+
+span {
+  vertical-align: middle;
+}
+</style>
+
+<div class=container>
+  XX
+  <span>
+    XX
+  </span>
+</div>

Added: trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-simple-expected.html (0 => 266510)


--- trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-simple-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-simple-expected.html	2020-09-03 11:22:19 UTC (rev 266510)
@@ -0,0 +1,9 @@
+<!DOCTYPE html><!-- webkit-test-runner [ internal:LayoutFormattingContextEnabled=true internal:LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+div {
+    background-color: green;
+}
+</style>
+<div style="width: 80px; height: 22px;"></div>
+<div style="width: 60px; height: 20px;"></div>
+<div style="width: 140px; height: 50px;"></div>

Added: trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-simple.html (0 => 266510)


--- trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-simple.html	                        (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/vertical-align-middle-simple.html	2020-09-03 11:22:19 UTC (rev 266510)
@@ -0,0 +1,24 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ internal:LayoutFormattingContextEnabled=true internal:LayoutFormattingContextIntegrationEnabled=false ] -->
+<style>
+.container {
+  float: left;
+  background-color: green;
+  color: green;
+  font-size: 20px;
+  font-family: Ahem;
+}
+
+.divider {
+  clear: left;
+}
+
+span {
+  vertical-align: middle;
+}
+</style>
+
+<div class=container>XX<span>XX</span></div>
+<div class=divider></div>
+<div class=container>XX<span style="font-size: 10px;">XX</span></div>
+<div class=divider></div>
+<div class=container>XX<span style="font-size: 50px;">XX</span></div>

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


--- trunk/Source/WebCore/ChangeLog	2020-09-03 10:15:04 UTC (rev 266509)
+++ trunk/Source/WebCore/ChangeLog	2020-09-03 11:22:19 UTC (rev 266510)
@@ -1,5 +1,37 @@
 2020-09-03  Zalan Bujtas  <[email protected]>
 
+        [LFC][IFC] Add support nested inline box sizing and positioning
+        https://bugs.webkit.org/show_bug.cgi?id=215748
+
+        Reviewed by Antti Koivisto.
+
+        This patch splits the line box construction process into a few distinct steps.
+        1. Construct the inline boxes as needed. There's always a root inline box.
+        2. Size them by taking the vertical alignment into account
+           - child inline boxes stretch their parent inline boxes in most cases (depending on the vertical-align property value).
+        3. Position the inline boxes relative to the line box.
+
+        Test: fast/layoutformattingcontext/vertical-align-middle-nested.html
+              fast/layoutformattingcontext/vertical-align-middle-simple.html
+
+        * layout/inlineformatting/InlineLineBox.cpp:
+        (WebCore::Layout::m_inlineFormattingContext):
+        (WebCore::Layout::LineBox::inlineRectForTextRun const):
+        (WebCore::Layout::LineBox::constructInlineBoxes):
+        (WebCore::Layout::LineBox::computeInlineBoxesLogicalHeight):
+        (WebCore::Layout::LineBox::alignInlineBoxesVerticallyAndComputeLineHeight):
+        (WebCore::Layout::LineBox::inlineBoxForLayoutBox const): Deleted.
+        (WebCore::Layout::LineBox::alignVertically): Deleted.
+        * layout/inlineformatting/InlineLineBox.h:
+        (WebCore::Layout::LineBox::InlineBox::setLogicalTop):
+        (WebCore::Layout::LineBox::InlineBox::setLogicalWidth):
+        (WebCore::Layout::LineBox::InlineBox::setLogicalHeight):
+        (WebCore::Layout::LineBox::InlineBox::setBaseline):
+        (WebCore::Layout::LineBox::inlineBoxForLayoutBox const):
+        (WebCore::Layout::LineBox::inlineBoxForLayoutBox):
+
+2020-09-03  Zalan Bujtas  <[email protected]>
+
         [LFC][IFC] Finalize InlineBox alignment in LineBox
         https://bugs.webkit.org/show_bug.cgi?id=215410
 

Modified: trunk/Source/WebCore/layout/displaytree/DisplayPainter.cpp (266509 => 266510)


--- trunk/Source/WebCore/layout/displaytree/DisplayPainter.cpp	2020-09-03 10:15:04 UTC (rev 266509)
+++ trunk/Source/WebCore/layout/displaytree/DisplayPainter.cpp	2020-09-03 11:22:19 UTC (rev 266510)
@@ -129,7 +129,7 @@
             auto absoluteLeft = absoluteOffset.x() + run.left();
             // FIXME: Add non-baseline align painting
             auto& lineBox = displayInlineContent->lineBoxForRun(run);
-            auto baseline = absoluteOffset.y() + lineBox.top() + lineBox.baseline();
+            auto baseline = absoluteOffset.y() + run.top() + style.fontMetrics().ascent();
             auto expansion = run.expansion();
             auto textRun = TextRun { textContent->content(), run.left() - lineBox.left(), expansion.horizontalExpansion, expansion.behavior };
             textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize());

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


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp	2020-09-03 10:15:04 UTC (rev 266509)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.cpp	2020-09-03 11:22:19 UTC (rev 266510)
@@ -134,16 +134,9 @@
     return { floorf(ascent + halfLeading), ceilf(descent + halfLeading) };
 }
 
-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)
+LineBox::InlineBox::InlineBox(const Box& layoutBox, const Display::InlineRect& rect, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty isConsideredEmpty)
+    : m_layoutBox(makeWeakPtr(layoutBox))
+    , m_logicalRect(rect)
     , m_baseline(baseline)
     , m_descent(descent)
     , m_isEmpty(isConsideredEmpty == IsConsideredEmpty::Yes)
@@ -161,42 +154,40 @@
         m_rect.moveHorizontally(*m_lineAlignmentOffset);
     }
     constructInlineBoxes(runs, isLineVisuallyEmpty);
-    alignVertically(isLineVisuallyEmpty);
+    computeInlineBoxesLogicalHeight();
+    alignInlineBoxesVerticallyAndComputeLineBoxHeight(isLineVisuallyEmpty);
     // Compute scrollable overflow.
     m_scrollableOverflow = Display::InlineRect { topLeft, std::max(logicalWidth, m_rootInlineBox.logicalWidth()), { } };
-    auto logicalBottom = m_rootInlineBox.logicalBottom();
+    auto logicalBottom = InlineLayoutUnit { }; 
     for (auto& inlineBoxEntry : m_inlineBoxRectMap)
-        logicalBottom = std::max(logicalBottom, inlineBoxEntry.value->logicalBottom());
+        logicalBottom = std::max(logicalBottom, inlineBoxEntry.value->logicalRect().bottom());
     m_scrollableOverflow.expandVertically(logicalBottom);
-
 }
 
-const LineBox::InlineBox& LineBox::inlineBoxForLayoutBox(const Box& layoutBox) const
-{
-    ASSERT(&layoutBox != &root());
-    return *m_inlineBoxRectMap.get(&layoutBox);
-}
-
 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();
+    auto& parentInlineBox = inlineBoxForLayoutBox(run.layoutBox().parent());
+    auto inlineBoxRect = parentInlineBox.logicalRect();
     return { inlineBoxRect.top(), run.logicalLeft(), run.logicalWidth(), inlineBoxRect.height() };
 }
 
 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 };
+    auto constructRootInlineBox = [&] {
+        auto& fontMetrics = root().style().fontMetrics();
+        InlineLayoutUnit rootInlineBoxHeight = fontMetrics.height();
+        auto rootInlineBoxRect = Display::InlineRect { { }, { }, contentLogicalWidth(), rootInlineBoxHeight };
+        InlineLayoutUnit rootInlineBoxBaseline = fontMetrics.ascent();
+        auto rootInlineBoxDescent = rootInlineBoxHeight - rootInlineBoxBaseline;
+        auto lineHasImaginaryStrut = !layoutState().inQuirksMode();
+        auto rootInlineBoxIsConsideredEmpty = isLineVisuallyEmpty == IsLineVisuallyEmpty::No && lineHasImaginaryStrut ? InlineBox::IsConsideredEmpty::No : InlineBox::IsConsideredEmpty::Yes;
 
+        m_rootInlineBox = InlineBox { root(), rootInlineBoxRect, rootInlineBoxBaseline, rootInlineBoxDescent, rootInlineBoxIsConsideredEmpty };
+        m_inlineBoxRectMap.set(&root(), &m_rootInlineBox);
+    };
+    constructRootInlineBox();
+
     for (auto& run : runs) {
         auto& layoutBox = run.layoutBox();
         if (run.isBox()) {
@@ -220,11 +211,15 @@
                 //
                 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));
+                auto inlineBox = makeUnique<InlineBox>(layoutBox, inlineBoxRect, adjustedBaseline, InlineLayoutUnit { }, InlineBox::IsConsideredEmpty::No);
+                m_inlineBoxRectMap.set(&layoutBox, inlineBox.get());
+                m_inlineBoxList.append(WTFMove(inlineBox));
             } else {
                 auto runHeight = boxGeometry.marginBoxHeight();
                 auto inlineBoxRect = Display::InlineRect { { }, run.logicalLeft(), run.logicalWidth(), runHeight };
-                m_inlineBoxRectMap.set(&layoutBox, makeUnique<InlineBox>(inlineBoxRect, runHeight));
+                auto inlineBox = makeUnique<InlineBox>(layoutBox, inlineBoxRect, runHeight, InlineLayoutUnit { }, InlineBox::IsConsideredEmpty::No);
+                m_inlineBoxRectMap.set(&layoutBox, inlineBox.get());
+                m_inlineBoxList.append(WTFMove(inlineBox));
             }
         } else if (run.isContainerStart()) {
             auto initialWidth = contentLogicalWidth() - run.logicalLeft();
@@ -233,7 +228,9 @@
             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));
+            auto inlineBox = makeUnique<InlineBox>(layoutBox, inlineBoxRect, baseline, logicalHeight - baseline, InlineBox::IsConsideredEmpty::Yes);
+            m_inlineBoxRectMap.set(&layoutBox, inlineBox.get());
+            m_inlineBoxList.append(WTFMove(inlineBox));
         } else if (run.isContainerEnd()) {
             // Adjust the logical width when the inline level container closes on this line.
             auto& inlineBox = *m_inlineBoxRectMap.get(&layoutBox);
@@ -245,46 +242,46 @@
     }
 }
 
-void LineBox::alignVertically(IsLineVisuallyEmpty isLineVisuallyEmpty)
+void LineBox::computeInlineBoxesLogicalHeight()
 {
-    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();
+    // By traversing the inline box list backwards, it's guaranteed that descendant inline boxes are sized first.
+    for (auto& inlineBox : WTF::makeReversedRange(m_inlineBoxList)) {
+        if (inlineBox->isEmpty())
+            continue;
 
-    auto contentLogicalHeight = InlineLayoutUnit { };
-    auto alignmentBaseline = InlineLayoutUnit { };
-    auto computeLineBoxHeight = [&](auto& inlineBox, auto textAlignMode) {
-        switch (textAlignMode) {
+        auto& layoutBox = inlineBox->layoutBox();
+        switch (layoutBox.style().verticalAlign()) {
+        case VerticalAlign::Top:
+        case VerticalAlign::Bottom:
+            // top and bottom alignments only stretch the line box. They don't stretch any of the inline boxes, not even the root inline box.
+            break;
         case VerticalAlign::Baseline: {
-            auto baselineOverflow = inlineBox.baseline() - alignmentBaseline;
-            if (baselineOverflow > 0) {
-                contentLogicalHeight += baselineOverflow;
-                alignmentBaseline += baselineOverflow;
+            auto& parentInlineBox = inlineBoxForLayoutBox(layoutBox.parent());
+            auto baselineOverflow = std::max(0.0f, inlineBox->baseline() - parentInlineBox.baseline());
+            if (baselineOverflow) {
+                parentInlineBox.setBaseline(parentInlineBox.baseline() + baselineOverflow);
+                parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + baselineOverflow);
             }
-            // 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;
+            auto parentLineBoxBelowBaseline = parentInlineBox.logicalHeight() - parentInlineBox.baseline();
+            auto inlineBoxBelowBaseline = inlineBox->logicalHeight() - inlineBox->baseline();
+            auto belowBaselineOverflow = std::max(0.0f, inlineBoxBelowBaseline - parentLineBoxBelowBaseline);
+            if (belowBaselineOverflow)
+                parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + 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;
+        case VerticalAlign::Middle: {
+            auto& parentLayoutBox = layoutBox.parent();
+            auto& parentInlineBox = inlineBoxForLayoutBox(parentLayoutBox);
+            auto logicalTop = parentInlineBox.baseline() - (inlineBox->logicalHeight() / 2 + parentLayoutBox.style().fontMetrics().xHeight() / 2);
+            if (logicalTop < 0) {
+                auto overflow = -logicalTop;
+                // Child inline box with middle alignment pushes the baseline down when overflows. 
+                parentInlineBox.setBaseline(parentInlineBox.baseline() + overflow);
+                parentInlineBox.setLogicalHeight(parentInlineBox.logicalHeight() + overflow);
+                logicalTop = { };
             }
+            auto logicalBottom = logicalTop + inlineBox->logicalHeight();
+            parentInlineBox.setLogicalHeight(std::max(parentInlineBox.logicalHeight(), logicalBottom));
             break;
         }
         default:
@@ -291,46 +288,96 @@
             ASSERT_NOT_IMPLEMENTED_YET();
             break;
         }
-    };
-
-    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());
     }
+}
 
-    auto lineBoxLogicalHeight = rootStyle.lineHeight().isNegative() ? std::max(recommendedLineBoxHeight, contentLogicalHeight) : recommendedLineBoxHeight;
-    m_rect.setHeight(lineBoxLogicalHeight);
+void LineBox::alignInlineBoxesVerticallyAndComputeLineBoxHeight(IsLineVisuallyEmpty isLineVisuallyEmpty)
+{
+    // 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 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();
+        for (auto& inlineBox : m_inlineBoxList) {
+            auto verticalAlign = inlineBox->layoutBox().style().verticalAlign();
+            if (verticalAlign == VerticalAlign::Bottom) {
+                // 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;
+            } else if (verticalAlign == VerticalAlign::Top)
+                contentLogicalBottom = std::max(contentLogicalBottom, inlineBox->logicalHeight());
+        }
+    };
+    alignRootInlineBox();
 
-    auto adjustInlineBoxTop = [&](auto& inlineBox, auto textAlignMode) {
+    for (auto& inlineBox : m_inlineBoxList) {
         auto inlineBoxLogicalTop = InlineLayoutUnit { };
-        switch (textAlignMode) {
-        case VerticalAlign::Baseline:
-            inlineBoxLogicalTop = alignmentBaseline - inlineBox.baseline();
+        auto& layoutBox = inlineBox->layoutBox();
+        switch (layoutBox.style().verticalAlign()) {
+        case VerticalAlign::Baseline: {
+            auto& parentInlineBox = inlineBoxForLayoutBox(layoutBox.parent());
+            inlineBoxLogicalTop = parentInlineBox.logicalTop() + parentInlineBox.baseline() - inlineBox->baseline();
             break;
+        }
         case VerticalAlign::Top:
-            inlineBoxLogicalTop = { };
+            inlineBoxLogicalTop = InlineLayoutUnit { };
             break;
         case VerticalAlign::Bottom:
-            inlineBoxLogicalTop = logicalBottom() - inlineBox.logicalHeight();
+            inlineBoxLogicalTop = contentLogicalBottom - inlineBox->logicalHeight();
             break;
+        case VerticalAlign::Middle: {
+            auto& parentLayoutBox = layoutBox.parent();
+            auto& parentInlineBox = inlineBoxForLayoutBox(parentLayoutBox);
+            inlineBoxLogicalTop = parentInlineBox.logicalTop() + parentInlineBox.baseline() - (inlineBox->logicalHeight() / 2 + parentLayoutBox.style().fontMetrics().xHeight() / 2);
+            break;
+        }
         default:
             ASSERT_NOT_IMPLEMENTED_YET();
             break;
         }
-        inlineBox.setLogicalTop(inlineBoxLogicalTop);
+        inlineBox->setLogicalTop(inlineBoxLogicalTop);
+    }
+
+    auto adjustContentBottomIfNeeded = [&] {
+        if (!m_rootInlineBox.isEmpty())
+            return;
+        auto collapsedContentLogicalTop = contentLogicalBottom;
+        auto collapsedContentLogicalBottom = InlineLayoutUnit { };
+        for (auto& inlineBox : m_inlineBoxList) {
+            auto verticalAlign = inlineBox->layoutBox().style().verticalAlign();
+            auto stretchesLineBox = verticalAlign == VerticalAlign::Bottom || verticalAlign == VerticalAlign::Top || &inlineBox->layoutBox().parent() == &m_rootInlineBox.layoutBox();
+            if (!stretchesLineBox)
+                continue;
+            if (inlineBox->isEmpty())
+                continue;
+            collapsedContentLogicalTop = std::min(collapsedContentLogicalTop, inlineBox->logicalTop());
+            collapsedContentLogicalBottom = std::max(collapsedContentLogicalBottom, inlineBox->logicalBottom());
+        }
+        if (collapsedContentLogicalTop <= 0) {
+            contentLogicalBottom = collapsedContentLogicalBottom;
+            return;
+        }
+        contentLogicalBottom = InlineLayoutUnit { };
+        for (auto& inlineBox : m_inlineBoxList) {
+            inlineBox->setLogicalTop(inlineBox->logicalTop() - collapsedContentLogicalTop);
+            contentLogicalBottom = std::max(contentLogicalBottom, inlineBox->logicalBottom());
+        }
     };
-
-    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());
+    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);
     }
 }
 

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


--- trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h	2020-09-03 10:15:04 UTC (rev 266509)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineLineBox.h	2020-09-03 11:22:19 UTC (rev 266510)
@@ -31,6 +31,7 @@
 #include "DisplayInlineRect.h"
 #include "InlineLineBuilder.h"
 #include <wtf/IsoMallocInlines.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 namespace Layout {
@@ -44,8 +45,7 @@
         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(const Box&, const Display::InlineRect&, InlineLayoutUnit baseline, InlineLayoutUnit descent, IsConsideredEmpty);
         InlineBox() = default;
 
         const Display::InlineRect& logicalRect() const { return m_logicalRect; }
@@ -58,19 +58,24 @@
         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; }
 
+        const Box& layoutBox() const { return *m_layoutBox; }
+
     private:
+        friend class LineBox;
+
+        void setLogicalTop(InlineLayoutUnit logicalTop) { m_logicalRect.setTop(logicalTop); }
+        void setLogicalWidth(InlineLayoutUnit logicalWidth) { m_logicalRect.setWidth(logicalWidth); }
+        void setLogicalHeight(InlineLayoutUnit logicalHeight) { m_logicalRect.setHeight(logicalHeight); }
+        void setBaseline(InlineLayoutUnit baseline) { m_baseline = baseline; }
+
+        WeakPtr<const Box> m_layoutBox;
         Display::InlineRect m_logicalRect;
         InlineLayoutUnit m_baseline;
         Optional<InlineLayoutUnit> m_descent;
         bool m_isEmpty { true };
-        bool m_isAtomic { false };
     };
 
     enum class IsLastLineWithInlineContent { No, Yes };
@@ -87,7 +92,7 @@
     const Display::InlineRect& logicalRect() const { return m_rect; }
     const Display::InlineRect& scrollableOverflow() const { return m_scrollableOverflow; }
 
-    const InlineBox& inlineBoxForLayoutBox(const Box&) const;
+    const InlineBox& inlineBoxForLayoutBox(const Box& layoutBox) const { return *m_inlineBoxRectMap.get(&layoutBox); }
     Display::InlineRect inlineRectForTextRun(const LineBuilder::Run&) const;
 
     // _____________________________________________________ line box logical top
@@ -109,8 +114,11 @@
 
 private:
     void constructInlineBoxes(const LineBuilder::RunList&, IsLineVisuallyEmpty);
-    void alignVertically(IsLineVisuallyEmpty);
+    void computeInlineBoxesLogicalHeight();
+    void alignInlineBoxesVerticallyAndComputeLineBoxHeight(IsLineVisuallyEmpty);
 
+    InlineBox& inlineBoxForLayoutBox(const Box& layoutBox) { return *m_inlineBoxRectMap.get(&layoutBox); }
+
     InlineLayoutUnit contentLogicalWidth() const { return m_contentLogicalWidth; }
 
     const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
@@ -125,7 +133,8 @@
     InlineBox m_rootInlineBox;
 
     Optional<InlineLayoutUnit> m_lineAlignmentOffset;
-    HashMap<const Box*, std::unique_ptr<InlineBox>> m_inlineBoxRectMap;
+    HashMap<const Box*, InlineBox*> m_inlineBoxRectMap;
+    Vector<std::unique_ptr<InlineBox>> m_inlineBoxList;
     const InlineFormattingContext& m_inlineFormattingContext;
 };
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to