[LFC][IFC] Add Display::Run/LineBox mapping
https://bugs.webkit.org/show_bug.cgi?id=203051
<rdar://problem/56342487>

Reviewed by Antti Koivisto.

Mapping enables us to paint baseline aligned runs on the current line. This is temporary until after we figure out the final run/line structure.

* layout/FormattingContextGeometry.cpp:
(WebCore::Layout::FormattingContext::Geometry::contentHeightForFormattingContextRoot const):
* layout/Verification.cpp:
(WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):
(WebCore::Layout::outputMismatchingComplexLineInformationIfNeeded):
* layout/blockformatting/BlockFormattingContextGeometry.cpp:
(WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin):
* layout/displaytree/DisplayPainter.cpp:
(WebCore::Display::paintInlineContent):
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::setDisplayBoxesForLine):
* layout/inlineformatting/InlineFormattingContextQuirks.cpp:
(WebCore::Layout::InlineFormattingContext::Quirks::lineDescentNeedsCollapsing const):
* layout/inlineformatting/InlineFormattingState.h:
(WebCore::Layout::InlineFormattingState::addLineBox):
(WebCore::Layout::InlineFormattingState::lineBoxForRun const):
(WebCore::Layout::InlineFormattingState::addInlineRun):
* layout/inlineformatting/InlineLine.cpp:
(WebCore::Layout::Line::Run::Run):
(WebCore::Layout::Line::alignContentVertically):
(WebCore::Layout::Line::adjustBaselineAndLineHeight):
* layout/inlineformatting/InlineLine.h:
(WebCore::Layout::Line::Run::displayRun const):
(WebCore::Layout::Line::Run::logicalRect const):
(WebCore::Layout::Line::Run::adjustLogicalTop):
(WebCore::Layout::Line::Run::moveVertically):
(WebCore::Layout::Line::Run::moveHorizontally):
(WebCore::Layout::Line::Run::expand):
* layout/inlineformatting/InlineLineBox.h:
* layout/inlineformatting/InlineLineLayout.h:
* layout/layouttree/LayoutTreeBuilder.cpp:
(WebCore::Layout::outputInlineRuns):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251238 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index d962f5c..42f50db 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,46 @@
+2019-10-17  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC][IFC] Add Display::Run/LineBox mapping
+        https://bugs.webkit.org/show_bug.cgi?id=203051
+        <rdar://problem/56342487>
+
+        Reviewed by Antti Koivisto.
+
+        Mapping enables us to paint baseline aligned runs on the current line. This is temporary until after we figure out the final run/line structure.
+
+        * layout/FormattingContextGeometry.cpp:
+        (WebCore::Layout::FormattingContext::Geometry::contentHeightForFormattingContextRoot const):
+        * layout/Verification.cpp:
+        (WebCore::Layout::outputMismatchingSimpleLineInformationIfNeeded):
+        (WebCore::Layout::outputMismatchingComplexLineInformationIfNeeded):
+        * layout/blockformatting/BlockFormattingContextGeometry.cpp:
+        (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin):
+        * layout/displaytree/DisplayPainter.cpp:
+        (WebCore::Display::paintInlineContent):
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::setDisplayBoxesForLine):
+        * layout/inlineformatting/InlineFormattingContextQuirks.cpp:
+        (WebCore::Layout::InlineFormattingContext::Quirks::lineDescentNeedsCollapsing const):
+        * layout/inlineformatting/InlineFormattingState.h:
+        (WebCore::Layout::InlineFormattingState::addLineBox):
+        (WebCore::Layout::InlineFormattingState::lineBoxForRun const):
+        (WebCore::Layout::InlineFormattingState::addInlineRun):
+        * layout/inlineformatting/InlineLine.cpp:
+        (WebCore::Layout::Line::Run::Run):
+        (WebCore::Layout::Line::alignContentVertically):
+        (WebCore::Layout::Line::adjustBaselineAndLineHeight):
+        * layout/inlineformatting/InlineLine.h:
+        (WebCore::Layout::Line::Run::displayRun const):
+        (WebCore::Layout::Line::Run::logicalRect const):
+        (WebCore::Layout::Line::Run::adjustLogicalTop):
+        (WebCore::Layout::Line::Run::moveVertically):
+        (WebCore::Layout::Line::Run::moveHorizontally):
+        (WebCore::Layout::Line::Run::expand):
+        * layout/inlineformatting/InlineLineBox.h:
+        * layout/inlineformatting/InlineLineLayout.h:
+        * layout/layouttree/LayoutTreeBuilder.cpp:
+        (WebCore::Layout::outputInlineRuns):
+
 2019-10-17  Antoine Quint  <graouts@apple.com>
 
         [Web Animations] Enable the Web Animations JavaScript API by default
diff --git a/Source/WebCore/layout/FormattingContextGeometry.cpp b/Source/WebCore/layout/FormattingContextGeometry.cpp
index 0d61d0d..1306201 100644
--- a/Source/WebCore/layout/FormattingContextGeometry.cpp
+++ b/Source/WebCore/layout/FormattingContextGeometry.cpp
@@ -134,8 +134,8 @@
         auto& lineBoxes = downcast<InlineFormattingState>(layoutState.establishedFormattingState(formattingRootContainer)).lineBoxes();
         // Even empty containers generate one line. 
         ASSERT(!lineBoxes.isEmpty());
-        top = lineBoxes.first().logicalTop();
-        bottom = lineBoxes.last().logicalBottom();
+        top = lineBoxes.first()->logicalTop();
+        bottom = lineBoxes.last()->logicalBottom();
     } else if (formattingRootContainer.establishesBlockFormattingContext() || formattingRootContainer.establishesTableFormattingContext() || formattingRootContainer.isDocumentBox()) {
         if (formattingRootContainer.hasInFlowChild()) {
             auto& firstBoxGeometry = formattingContext.geometryForBox(*formattingRootContainer.firstInFlowChild(), EscapeType::AccessChildFormattingContext);
diff --git a/Source/WebCore/layout/Verification.cpp b/Source/WebCore/layout/Verification.cpp
index 2f56f62..3efc23b 100644
--- a/Source/WebCore/layout/Verification.cpp
+++ b/Source/WebCore/layout/Verification.cpp
@@ -87,7 +87,7 @@
     auto mismatched = false;
     for (unsigned i = 0; i < lineLayoutData->runCount(); ++i) {
         auto& simpleRun = lineLayoutData->runAt(i);
-        auto& inlineRun = inlineRunList[i];
+        auto& inlineRun = *inlineRunList[i];
 
         auto matchingRuns = areEssentiallyEqual(simpleRun.logicalLeft, inlineRun.logicalLeft()) && areEssentiallyEqual(simpleRun.logicalRight, inlineRun.logicalRight());
         if (matchingRuns && inlineRun.textContext()) {
@@ -173,7 +173,7 @@
     }
 
     for (unsigned inlineBoxIndex = 0; inlineBoxIndex < inlineBoxes.size() && runIndex < inlineRunList.size(); ++inlineBoxIndex) {
-        auto& inlineRun = inlineRunList[runIndex];
+        auto& inlineRun = *inlineRunList[runIndex];
         auto* inlineBox = inlineBoxes[inlineBoxIndex];
         auto* inlineTextBox = is<InlineTextBox>(inlineBox) ? downcast<InlineTextBox>(inlineBox) : nullptr;
         bool matchingRuns = inlineTextBox ? checkForMatchingTextRuns(inlineRun, *inlineTextBox) : matchingRuns = checkForMatchingNonTextRuns(inlineRun, *inlineBox);
diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp
index ed8a386..54f7e6f 100644
--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp
+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp
@@ -75,7 +75,7 @@
             auto& lineBoxes = downcast<InlineFormattingState>(layoutState().establishedFormattingState(layoutContainer)).lineBoxes();
             // Even empty containers generate one line. 
             ASSERT(!lineBoxes.isEmpty());
-            return { lineBoxes.last().logicalBottom() - borderAndPaddingTop, nonCollapsedMargin };
+            return { lineBoxes.last()->logicalBottom() - borderAndPaddingTop, nonCollapsedMargin };
         }
 
         // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin...
diff --git a/Source/WebCore/layout/displaytree/DisplayPainter.cpp b/Source/WebCore/layout/displaytree/DisplayPainter.cpp
index 5f051a1..4ad95c6 100644
--- a/Source/WebCore/layout/displaytree/DisplayPainter.cpp
+++ b/Source/WebCore/layout/displaytree/DisplayPainter.cpp
@@ -113,11 +113,11 @@
             auto& inlineTextItem = downcast<Layout::InlineTextItem>(*inlineItem);
             auto inlineContent = inlineTextItem.layoutBox().textContent();
             while (true) {
-                auto& run = inlineRuns[runIndex++];
+                auto& run = *inlineRuns[runIndex++];
                 auto textContext = run.textContext().value();
                 auto runContent = inlineContent.substring(textContext.start(), textContext.length());
                 auto logicalTopLeft = rootAbsoluteDisplayBox.topLeft() + run.logicalTopLeft();
-                context.drawText(style.fontCascade(), TextRun { runContent }, { logicalTopLeft.x(), logicalTopLeft.y() + formattingState.lineBoxes()[0].baselineOffset() });
+                context.drawText(style.fontCascade(), TextRun { runContent }, { logicalTopLeft.x(), logicalTopLeft.y() + formattingState.lineBoxes()[0]->baselineOffset() });
                 if (inlineTextItem.end() == textContext.end())
                     break;
                 if (runIndex == inlineRuns.size())
@@ -127,7 +127,7 @@
         }
 
         if (inlineItem->isBox()) {
-            auto& run = inlineRuns[runIndex++];
+            auto& run = *inlineRuns[runIndex++];
             auto logicalTopLeft = rootAbsoluteDisplayBox.topLeft() + run.logicalTopLeft();
             context.fillRect({ logicalTopLeft, FloatSize { run.logicalWidth(), run.logicalHeight() } });
             continue;
diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
index d4d89e85..12f24b3 100644
--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
@@ -418,6 +418,9 @@
     }
 
     // Add final display runs to state.
+    formattingState.addLineBox(lineContent.lineBox);
+    // FIXME: This is tempoary.
+    auto& currentLine = *formattingState.lineBoxes().last();
     for (auto& lineRun : lineContent.runList) {
         // Inline level containers (<span>) don't generate inline runs.
         if (lineRun->isContainerStart() || lineRun->isContainerEnd())
@@ -425,7 +428,7 @@
         // Collapsed line runs don't generate display runs.
         if (lineRun->isVisuallyEmpty())
             continue;
-        formattingState.addInlineRun(lineRun->displayRun());
+        formattingState.addInlineRun(lineRun->displayRun(), currentLine);
     }
 
     // Compute box final geometry.
@@ -491,7 +494,6 @@
         }
         ASSERT_NOT_REACHED();
     }
-    formattingState.addLineBox(lineContent.lineBox);
 }
 
 }
diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp
index 37f67f1..2f5e5bb 100644
--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContextQuirks.cpp
@@ -64,7 +64,7 @@
             if (layoutBox.isInlineBlockBox() && layoutBox.establishesInlineFormattingContext()) {
                 auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox)));
                 ASSERT(!formattingState.lineBoxes().isEmpty());
-                auto inlineBlockBaseline = formattingState.lineBoxes().last().baseline();
+                auto inlineBlockBaseline = formattingState.lineBoxes().last()->baseline();
                 if (inlineBlockBaseline.descent())
                     return false;
             }
diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingState.h b/Source/WebCore/layout/inlineformatting/InlineFormattingState.h
index 3534588..006ae6d 100644
--- a/Source/WebCore/layout/inlineformatting/InlineFormattingState.h
+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingState.h
@@ -39,8 +39,8 @@
 
 // Temp
 using InlineItems = Vector<std::unique_ptr<InlineItem>>;
-using InlineRuns = Vector<Display::Run>;
-using LineBoxes = Vector<LineBox>;
+using InlineRuns = Vector<std::unique_ptr<Display::Run>>;
+using LineBoxes = Vector<std::unique_ptr<LineBox>>;
 // InlineFormattingState holds the state for a particular inline formatting context tree.
 class InlineFormattingState : public FormattingState {
     WTF_MAKE_ISO_ALLOCATED(InlineFormattingState);
@@ -54,18 +54,29 @@
 
     const InlineRuns& inlineRuns() const { return m_inlineRuns; }
     InlineRuns& inlineRuns() { return m_inlineRuns; }
-    void addInlineRun(const Display::Run& inlineRun) { m_inlineRuns.append(inlineRun); }
+    void addInlineRun(const Display::Run&, const LineBox&);
 
     const LineBoxes& lineBoxes() const { return m_lineBoxes; }
     LineBoxes& lineBoxes() { return m_lineBoxes; }
-    void addLineBox(LineBox lineBox) { m_lineBoxes.append(lineBox); }
+    void addLineBox(const LineBox& lineBox) { m_lineBoxes.append(makeUnique<LineBox>(lineBox)); }
+
+    const LineBox& lineBoxForRun(const Display::Run& inlineRun) const { return *m_inlineRunToLineMap.get(&inlineRun); }
 
 private:
     InlineItems m_inlineItems;
     InlineRuns m_inlineRuns;
     LineBoxes m_lineBoxes;
+    // This is temporary until after we figure out the display run/line relationships.
+    HashMap<const Display::Run*, const LineBox*> m_inlineRunToLineMap;
 };
 
+inline void InlineFormattingState::addInlineRun(const Display::Run& inlineRun, const LineBox& line)
+{
+    auto run = makeUnique<Display::Run>(inlineRun);
+    m_inlineRunToLineMap.set(run.get(), &line);
+    m_inlineRuns.append(WTFMove(run));
+}
+
 }
 }
 
diff --git a/Source/WebCore/layout/inlineformatting/InlineLine.cpp b/Source/WebCore/layout/inlineformatting/InlineLine.cpp
index c1f7150..62c327d 100644
--- a/Source/WebCore/layout/inlineformatting/InlineLine.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineLine.cpp
@@ -173,7 +173,7 @@
                 auto& formattingState = downcast<InlineFormattingState>(layoutState.establishedFormattingState(downcast<Container>(layoutBox)));
                 // Spec makes us generate at least one line -even if it is empty.
                 ASSERT(!formattingState.lineBoxes().isEmpty());
-                auto inlineBlockBaselineOffset = formattingState.lineBoxes().last().baselineOffset();
+                auto inlineBlockBaselineOffset = formattingState.lineBoxes().last()->baselineOffset();
                 // The inline-block's baseline offset is relative to its content box. Let's convert it relative to the margin box.
                 //   inline-block
                 //              \
@@ -459,7 +459,7 @@
                 auto& formattingState = downcast<InlineFormattingState>(layoutState().establishedFormattingState(downcast<Container>(layoutBox)));
                 // Spec makes us generate at least one line -even if it is empty.
                 ASSERT(!formattingState.lineBoxes().isEmpty());
-                auto& lastLineBox = formattingState.lineBoxes().last();
+                auto& lastLineBox = *formattingState.lineBoxes().last();
                 auto inlineBlockBaseline = lastLineBox.baseline();
                 auto beforeHeight = boxGeometry.marginBefore() + boxGeometry.borderTop() + boxGeometry.paddingTop().valueOr(0);
 
diff --git a/Source/WebCore/layout/inlineformatting/InlineLineBox.h b/Source/WebCore/layout/inlineformatting/InlineLineBox.h
index d1bd051..daf4b07 100644
--- a/Source/WebCore/layout/inlineformatting/InlineLineBox.h
+++ b/Source/WebCore/layout/inlineformatting/InlineLineBox.h
@@ -33,6 +33,7 @@
 namespace Layout {
 
 class LineBox {
+    WTF_MAKE_FAST_ALLOCATED;
 public:
     struct Baseline {
         Baseline(LayoutUnit ascent, LayoutUnit descent);
diff --git a/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp b/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp
index 71928a8..e5b588b 100644
--- a/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp
+++ b/Source/WebCore/layout/layouttree/LayoutTreeBuilder.cpp
@@ -274,7 +274,7 @@
 
     stream << "lines are -> ";
     for (auto& lineBox : lineBoxes)
-        stream << "[" << lineBox.logicalLeft() << "," << lineBox.logicalTop() << " " << lineBox.logicalWidth() << "x" << lineBox.logicalHeight() << "] ";
+        stream << "[" << lineBox->logicalLeft() << "," << lineBox->logicalTop() << " " << lineBox->logicalWidth() << "x" << lineBox->logicalHeight() << "] ";
     stream.nextLine();
 
     for (auto& inlineRun : inlineRuns) {
@@ -282,13 +282,13 @@
         while (++printedCharacters <= depth * 2)
             stream << " ";
         stream << "  ";
-        if (inlineRun.textContext())
+        if (inlineRun->textContext())
             stream << "inline text box";
         else
             stream << "inline box";
-        stream << " at (" << inlineRun.logicalLeft() << "," << inlineRun.logicalTop() << ") size " << inlineRun.logicalWidth() << "x" << inlineRun.logicalHeight();
-        if (inlineRun.textContext())
-            stream << " run(" << inlineRun.textContext()->start() << ", " << inlineRun.textContext()->end() << ")";
+        stream << " at (" << inlineRun->logicalLeft() << "," << inlineRun->logicalTop() << ") size " << inlineRun->logicalWidth() << "x" << inlineRun->logicalHeight();
+        if (inlineRun->textContext())
+            stream << " run(" << inlineRun->textContext()->start() << ", " << inlineRun->textContext()->end() << ")";
         stream.nextLine();
     }
 }