[LFC][Integration] RenderBlockFlow::positionForPointWithInlineChildren should use iterator
https://bugs.webkit.org/show_bug.cgi?id=218283

Reviewed by Zalan Bujtas.

Reduce InlineBox access and eliminate one ensureLineBoxes() call.

* layout/integration/LayoutIntegrationLineIterator.h:
(WebCore::LayoutIntegration::PathLine::topWithLeading const):
(WebCore::LayoutIntegration::PathLine::bottomWithLeading const):
(WebCore::LayoutIntegration::PathLine::legacyRootInlineBox const):
* layout/integration/LayoutIntegrationLineIteratorLegacyPath.h:
(WebCore::LayoutIntegration::LineIteratorLegacyPath::topWithLeading const):
(WebCore::LayoutIntegration::LineIteratorLegacyPath::bottomWithLeading const):
(WebCore::LayoutIntegration::LineIteratorLegacyPath::legacyRootInlineBox const):
* layout/integration/LayoutIntegrationLineIteratorModernPath.h:
(WebCore::LayoutIntegration::LineIteratorModernPath::topWithLeading const):
(WebCore::LayoutIntegration::LineIteratorModernPath::bottomWithLeading const):
(WebCore::LayoutIntegration::LineIteratorModernPath::legacyRootInlineBox const):
* layout/integration/LayoutIntegrationRunIteratorModernPath.h:
(WebCore::LayoutIntegration::RunIteratorModernPath::legacyInlineBox const):
* rendering/RenderBlockFlow.cpp:
(WebCore::positionForRun):
(WebCore::RenderBlockFlow::positionForPointWithInlineChildren):
(WebCore::RenderBlockFlow::positionForBox const): Deleted.
* rendering/RenderBlockFlow.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@269146 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index a1bc395..8c675f4 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,32 @@
+2020-10-29  Antti Koivisto  <antti@apple.com>
+
+        [LFC][Integration] RenderBlockFlow::positionForPointWithInlineChildren should use iterator
+        https://bugs.webkit.org/show_bug.cgi?id=218283
+
+        Reviewed by Zalan Bujtas.
+
+        Reduce InlineBox access and eliminate one ensureLineBoxes() call.
+
+        * layout/integration/LayoutIntegrationLineIterator.h:
+        (WebCore::LayoutIntegration::PathLine::topWithLeading const):
+        (WebCore::LayoutIntegration::PathLine::bottomWithLeading const):
+        (WebCore::LayoutIntegration::PathLine::legacyRootInlineBox const):
+        * layout/integration/LayoutIntegrationLineIteratorLegacyPath.h:
+        (WebCore::LayoutIntegration::LineIteratorLegacyPath::topWithLeading const):
+        (WebCore::LayoutIntegration::LineIteratorLegacyPath::bottomWithLeading const):
+        (WebCore::LayoutIntegration::LineIteratorLegacyPath::legacyRootInlineBox const):
+        * layout/integration/LayoutIntegrationLineIteratorModernPath.h:
+        (WebCore::LayoutIntegration::LineIteratorModernPath::topWithLeading const):
+        (WebCore::LayoutIntegration::LineIteratorModernPath::bottomWithLeading const):
+        (WebCore::LayoutIntegration::LineIteratorModernPath::legacyRootInlineBox const):
+        * layout/integration/LayoutIntegrationRunIteratorModernPath.h:
+        (WebCore::LayoutIntegration::RunIteratorModernPath::legacyInlineBox const):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::positionForRun):
+        (WebCore::RenderBlockFlow::positionForPointWithInlineChildren):
+        (WebCore::RenderBlockFlow::positionForBox const): Deleted.
+        * rendering/RenderBlockFlow.h:
+
 2020-10-29  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][Integration] Implement outputLineTreeAndMark for IFC
diff --git a/Source/WebCore/layout/integration/LayoutIntegrationLineIterator.h b/Source/WebCore/layout/integration/LayoutIntegrationLineIterator.h
index 24216e1..26bcb3d 100644
--- a/Source/WebCore/layout/integration/LayoutIntegrationLineIterator.h
+++ b/Source/WebCore/layout/integration/LayoutIntegrationLineIterator.h
@@ -55,6 +55,8 @@
     LayoutUnit selectionTop() const;
     LayoutUnit selectionTopForHitTesting() const;
     LayoutUnit selectionBottom() const;
+    LayoutUnit topWithLeading() const;
+    LayoutUnit bottomWithLeading() const;
 
     float y() const;
     float logicalHeight() const;
@@ -64,6 +66,7 @@
     bool isHorizontal() const;
 
     const RenderBlockFlow& containingBlock() const;
+    const RootInlineBox* legacyRootInlineBox() const;
 
 protected:
     friend class LineIterator;
@@ -128,7 +131,7 @@
 inline LayoutUnit PathLine::bottom() const
 {
     return WTF::switchOn(m_pathVariant, [](const auto& path) {
-        return path.top();
+        return path.bottom();
     });
 }
 
@@ -153,6 +156,20 @@
     });
 }
 
+inline LayoutUnit PathLine::topWithLeading() const
+{
+    return WTF::switchOn(m_pathVariant, [](const auto& path) {
+        return path.topWithLeading();
+    });
+}
+
+inline LayoutUnit PathLine::bottomWithLeading() const
+{
+    return WTF::switchOn(m_pathVariant, [](const auto& path) {
+        return path.bottomWithLeading();
+    });
+}
+
 inline float PathLine::y() const
 {
     return WTF::switchOn(m_pathVariant, [](const auto& path) {
@@ -181,6 +198,13 @@
     });
 }
 
+inline const RootInlineBox* PathLine::legacyRootInlineBox() const
+{
+    return WTF::switchOn(m_pathVariant, [](const auto& path) {
+        return path.legacyRootInlineBox();
+    });
+}
+
 }
 }
 
diff --git a/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorLegacyPath.h b/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorLegacyPath.h
index 5081f9c..c8b6db3 100644
--- a/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorLegacyPath.h
+++ b/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorLegacyPath.h
@@ -49,12 +49,15 @@
     LayoutUnit selectionTop() const { return m_rootInlineBox->selectionTop(); }
     LayoutUnit selectionTopForHitTesting() const { return m_rootInlineBox->selectionTop(RootInlineBox::ForHitTesting::Yes); }
     LayoutUnit selectionBottom() const { return m_rootInlineBox->selectionBottom(); }
+    LayoutUnit topWithLeading() const { return m_rootInlineBox->lineTopWithLeading(); }
+    LayoutUnit bottomWithLeading() const { return m_rootInlineBox->lineBottomWithLeading(); }
 
     float y() const { return m_rootInlineBox->y(); }
     float logicalHeight() const { return m_rootInlineBox->logicalHeight(); }
     bool isHorizontal() const { return m_rootInlineBox->isHorizontal(); }
 
     const RenderBlockFlow& containingBlock() const { return m_rootInlineBox->blockFlow(); }
+    const RootInlineBox* legacyRootInlineBox() const { return m_rootInlineBox; }
 
     void traverseNext()
     {
diff --git a/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorModernPath.h b/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorModernPath.h
index 08e7488..b4eb127 100644
--- a/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorModernPath.h
+++ b/Source/WebCore/layout/integration/LayoutIntegrationLineIteratorModernPath.h
@@ -51,15 +51,19 @@
 
     LayoutUnit top() const { return LayoutUnit::fromFloatRound(line().rect().y()); }
     LayoutUnit bottom() const { return LayoutUnit::fromFloatRound(line().rect().maxY()); }
+    // FIXME: What should these really be?
     LayoutUnit selectionTop() const { return top(); }
     LayoutUnit selectionTopForHitTesting() const { return top(); }
     LayoutUnit selectionBottom() const { return bottom(); }
+    LayoutUnit topWithLeading() const { return top(); }
+    LayoutUnit bottomWithLeading() const { return bottom(); }
 
     float y() const { return top(); }
     float logicalHeight() const { return line().rect().height(); }
     bool isHorizontal() const { return true; }
 
     const RenderBlockFlow& containingBlock() const { return m_inlineContent->containingBlock(); }
+    const RootInlineBox* legacyRootInlineBox() const { return nullptr; }
 
     void traverseNext()
     {
diff --git a/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h b/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h
index 6871ec4..a7c2648 100644
--- a/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h
+++ b/Source/WebCore/layout/integration/LayoutIntegrationRunIteratorModernPath.h
@@ -170,7 +170,6 @@
 
     InlineBox* legacyInlineBox() const
     {
-        ASSERT_NOT_REACHED();
         return nullptr;
     }
 
diff --git a/Source/WebCore/rendering/RenderBlockFlow.cpp b/Source/WebCore/rendering/RenderBlockFlow.cpp
index 45867f4..aca5ab0 100644
--- a/Source/WebCore/rendering/RenderBlockFlow.cpp
+++ b/Source/WebCore/rendering/RenderBlockFlow.cpp
@@ -3306,19 +3306,19 @@
     return false;
 }
 
-Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
+static Position positionForRun(const RenderBlockFlow& flow, LayoutIntegration::RunIterator run, bool start)
 {
-    if (!box)
+    if (!run)
         return Position();
 
-    if (!box->renderer().nonPseudoNode())
-        return makeDeprecatedLegacyPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
+    if (!run->renderer().nonPseudoNode())
+        return makeDeprecatedLegacyPosition(flow.nonPseudoElement(), start ? flow.caretMinOffset() : flow.caretMaxOffset());
 
-    if (!is<InlineTextBox>(*box))
-        return makeDeprecatedLegacyPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
+    if (!is<LayoutIntegration::TextRunIterator>(run))
+        return makeDeprecatedLegacyPosition(run->renderer().nonPseudoNode(), start ? run->renderer().caretMinOffset() : run->renderer().caretMaxOffset());
 
-    auto& textBox = downcast<InlineTextBox>(*box);
-    return makeDeprecatedLegacyPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
+    auto& textRun = downcast<LayoutIntegration::TextRunIterator>(run);
+    return makeDeprecatedLegacyPosition(textRun->renderer().nonPseudoNode(), start ? textRun->localStartOffset() : textRun->localEndOffset());
 }
 
 RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
@@ -3390,89 +3390,86 @@
 {
     ASSERT(childrenInline());
 
-    ensureLineBoxes();
+    auto firstLine = LayoutIntegration::firstLineFor(*this);
 
-    if (!firstRootBox())
+    if (!firstLine)
         return createVisiblePosition(0, Affinity::Downstream);
 
     bool linesAreFlipped = style().isFlippedLinesWritingMode();
     bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
 
     // look for the closest line box in the root box which is at the passed-in y coordinate
-    InlineBox* closestBox = 0;
-    RootInlineBox* firstRootBoxWithChildren = 0;
-    RootInlineBox* lastRootBoxWithChildren = 0;
-    for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
-        if (fragment && root->containingFragment() != fragment)
+    LayoutIntegration::RunIterator closestRun;
+    LayoutIntegration::LineIterator firstLineWithChildren;
+    LayoutIntegration::LineIterator lastLineWithChildren;
+    for (auto line = firstLine; line; line.traverseNext()) {
+        if (fragment && line->legacyRootInlineBox() && line->legacyRootInlineBox()->containingFragment() != fragment)
             continue;
 
-        if (!root->firstLeafDescendant())
+        if (!line.firstRun())
             continue;
-        if (!firstRootBoxWithChildren)
-            firstRootBoxWithChildren = root;
+        if (!firstLineWithChildren)
+            firstLineWithChildren = line;
 
-        if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
-            || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
+        if (!linesAreFlipped && line->legacyRootInlineBox() && line->legacyRootInlineBox()->isFirstAfterPageBreak()
+            && (pointInLogicalContents.y() < line->topWithLeading() || (blocksAreFlipped && pointInLogicalContents.y() == line->topWithLeading())))
             break;
 
-        lastRootBoxWithChildren = root;
+        lastLineWithChildren = line;
 
         // check if this root line box is located at this y coordinate
-        if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
+        if (pointInLogicalContents.y() < line->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == line->selectionBottom())) {
             if (linesAreFlipped) {
-                RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
-                while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafDescendant())
-                    nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
+                auto nextLineWithChildren = line.next();
+                while (nextLineWithChildren && !nextLineWithChildren.firstRun())
+                    nextLineWithChildren.traverseNext();
 
-                if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
-                    || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
+                if (nextLineWithChildren && nextLineWithChildren->legacyRootInlineBox() && nextLineWithChildren->legacyRootInlineBox()->isFirstAfterPageBreak()
+                    && (pointInLogicalContents.y() > nextLineWithChildren->topWithLeading() || (!blocksAreFlipped && pointInLogicalContents.y() == nextLineWithChildren->topWithLeading())))
                     continue;
             }
-            if (auto closestRun = LayoutIntegration::LineIterator(root).closestRunForLogicalLeftPosition(pointInLogicalContents.x()))
-                closestBox = closestRun->legacyInlineBox();
-            if (closestBox)
+            closestRun = line.closestRunForLogicalLeftPosition(pointInLogicalContents.x());
+            if (closestRun)
                 break;
         }
     }
 
     bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
 
-    if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
+    if (!moveCaretToBoundary && !closestRun && lastLineWithChildren) {
         // y coordinate is below last root line box, pretend we hit it
-        auto closestRun = LayoutIntegration::LineIterator(lastRootBoxWithChildren).closestRunForLogicalLeftPosition(pointInLogicalContents.x());
-        closestBox = closestRun ? closestRun->legacyInlineBox() : nullptr;
+        closestRun = lastLineWithChildren.closestRunForLogicalLeftPosition(pointInLogicalContents.x());
     }
 
-    if (closestBox) {
+    if (closestRun) {
         if (moveCaretToBoundary) {
-            LayoutUnit firstRootBoxWithChildrenTop = std::min(firstRootBoxWithChildren->selectionTop(RootInlineBox::ForHitTesting::Yes), LayoutUnit(firstRootBoxWithChildren->logicalTop()));
-            if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
-                || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
-                InlineBox* box = firstRootBoxWithChildren->firstLeafDescendant();
-                if (box->isLineBreak()) {
-                    if (InlineBox* newBox = box->nextLeafOnLineIgnoringLineBreak())
-                        box = newBox;
+            LayoutUnit firstLineWithChildrenTop = std::min(firstLineWithChildren->selectionTopForHitTesting(), LayoutUnit(firstLineWithChildren->top()));
+            if (pointInLogicalContents.y() < firstLineWithChildrenTop
+                || (blocksAreFlipped && pointInLogicalContents.y() == firstLineWithChildrenTop)) {
+                auto run = firstLineWithChildren.firstRun();
+                if (run->isLineBreak()) {
+                    if (auto next = run.nextOnLineIgnoringLineBreak())
+                        run = next;
                 }
                 // y coordinate is above first root line box, so return the start of the first
-                return positionForBox(box, true);
+                return positionForRun(*this, run, true);
             }
         }
 
         // pass the box a top position that is inside it
-        LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
+        LayoutPoint point(pointInLogicalContents.x(), closestRun.line()->blockDirectionPointInLine());
         if (!isHorizontalWritingMode())
             point = point.transposedPoint();
-        if (closestBox->renderer().isReplaced())
-            return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
-        return closestBox->renderer().positionForPoint(point, nullptr);
+        if (closestRun->renderer().isReplaced())
+            return positionForPointRespectingEditingBoundaries(*this, const_cast<RenderBox&>(downcast<RenderBox>(closestRun->renderer())), point);
+        return const_cast<RenderObject&>(closestRun->renderer()).positionForPoint(point, nullptr);
     }
 
-    if (lastRootBoxWithChildren) {
+    if (lastLineWithChildren) {
         // We hit this case for Mac behavior when the Y coordinate is below the last box.
         ASSERT(moveCaretToBoundary);
-        InlineBox* logicallyLastBox;
-        if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
-            return positionForBox(logicallyLastBox, false);
+        if (auto logicallyLastRun = lastLineWithChildren.logicalEndRunWithNode())
+            return positionForRun(*this, logicallyLastRun, false);
     }
 
     // Can't reach this. We have a root line box, but it has no kids.
@@ -3483,7 +3480,6 @@
 
 Position RenderBlockFlow::positionForPoint(const LayoutPoint& point)
 {
-    // FIXME: This forces Complex Line Layout.
     return positionForPoint(point, nullptr).deepEquivalent();
 }
 
diff --git a/Source/WebCore/rendering/RenderBlockFlow.h b/Source/WebCore/rendering/RenderBlockFlow.h
index 1562da6..3d9b51f 100644
--- a/Source/WebCore/rendering/RenderBlockFlow.h
+++ b/Source/WebCore/rendering/RenderBlockFlow.h
@@ -527,7 +527,6 @@
     GapRects inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
         LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches&, const PaintInfo*) override;
     
-    Position positionForBox(InlineBox*, bool start = true) const;
     VisiblePosition positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer*) override;
     void addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*) override;
 
diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp
index fb7034a..45a42bb 100644
--- a/Source/WebCore/rendering/RootInlineBox.cpp
+++ b/Source/WebCore/rendering/RootInlineBox.cpp
@@ -750,11 +750,6 @@
     return nextTop;
 }
 
-int RootInlineBox::blockDirectionPointInLine() const
-{
-    return !blockFlow().style().isFlippedBlocksWritingMode() ? std::max(lineTop(), selectionTop()) : std::min(lineBottom(), selectionBottom());
-}
-
 RenderBlockFlow& RootInlineBox::blockFlow() const
 {
     return downcast<RenderBlockFlow>(renderer());
diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h
index 972e7da..9e06a43 100644
--- a/Source/WebCore/rendering/RootInlineBox.h
+++ b/Source/WebCore/rendering/RootInlineBox.h
@@ -80,8 +80,6 @@
     LayoutUnit selectionTopAdjustedForPrecedingBlock() const;
     LayoutUnit selectionHeightAdjustedForPrecedingBlock() const { return std::max<LayoutUnit>(0, selectionBottom() - selectionTopAdjustedForPrecedingBlock()); }
 
-    int blockDirectionPointInLine() const;
-
     LayoutUnit alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
     void setLineTopBottomPositions(LayoutUnit top, LayoutUnit bottom, LayoutUnit topWithLeading, LayoutUnit bottomWithLeading)
     {