[LFC] Layout::Box::parent() should return const ContainerBox&
https://bugs.webkit.org/show_bug.cgi?id=209400
<rdar://problem/60742432>

Reviewed by Antti Koivisto.

Layout tree is immutable during layout, so every box should be able to return a valid parent (except the ICB, but
class InitialContainingBlock deletes parent() function anyway).

* layout/FormattingContextGeometry.cpp:
(WebCore::Layout::FormattingContext::Geometry::staticVerticalPositionForOutOfFlowPositioned const):
(WebCore::Layout::FormattingContext::Geometry::staticHorizontalPositionForOutOfFlowPositioned const):
* layout/blockformatting/BlockFormattingContextQuirks.cpp:
(WebCore::Layout::BlockFormattingContext::Quirks::stretchedInFlowHeight):
* layout/blockformatting/BlockMarginCollapse.cpp:
(WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginAfter const):
(WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginBefore const):
(WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMarginBefore const):
(WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMarginAfter const):
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::nextInlineLevelBoxToLayout):
(WebCore::Layout::InlineFormattingContext::constraintsForLine):
* layout/layouttree/LayoutBox.cpp:
(WebCore::Layout::Box::containingBlock const):
(WebCore::Layout::Box::formattingContextRoot const):
(WebCore::Layout::Box::initialContainingBlock const):
(WebCore::Layout::Box::isOverflowVisible const):
* layout/layouttree/LayoutBox.h:
(WebCore::Layout::Box::parent const):
* layout/layouttree/LayoutIterator.h:
(WebCore::Layout::LayoutBoxTraversal::nextAncestorSibling):
(WebCore::Layout::LayoutBoxTraversal::next):
(WebCore::Layout::Traversal::firstWithin):
(WebCore::Layout::Traversal::next):
(WebCore::Layout::LayoutIterator<T>::traverseNext):
* layout/tableformatting/TableGrid.cpp:
(WebCore::Layout::TableGrid::appendCell):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@259180 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 7f5a89b..1513a26 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,43 @@
+2020-03-29  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC] Layout::Box::parent() should return const ContainerBox&
+        https://bugs.webkit.org/show_bug.cgi?id=209400
+        <rdar://problem/60742432>
+
+        Reviewed by Antti Koivisto.
+
+        Layout tree is immutable during layout, so every box should be able to return a valid parent (except the ICB, but
+        class InitialContainingBlock deletes parent() function anyway).
+
+        * layout/FormattingContextGeometry.cpp:
+        (WebCore::Layout::FormattingContext::Geometry::staticVerticalPositionForOutOfFlowPositioned const):
+        (WebCore::Layout::FormattingContext::Geometry::staticHorizontalPositionForOutOfFlowPositioned const):
+        * layout/blockformatting/BlockFormattingContextQuirks.cpp:
+        (WebCore::Layout::BlockFormattingContext::Quirks::stretchedInFlowHeight):
+        * layout/blockformatting/BlockMarginCollapse.cpp:
+        (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginAfter const):
+        (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginBeforeCollapsesWithParentMarginBefore const):
+        (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMarginBefore const):
+        (WebCore::Layout::BlockFormattingContext::MarginCollapse::marginAfterCollapsesWithParentMarginAfter const):
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::nextInlineLevelBoxToLayout):
+        (WebCore::Layout::InlineFormattingContext::constraintsForLine):
+        * layout/layouttree/LayoutBox.cpp:
+        (WebCore::Layout::Box::containingBlock const):
+        (WebCore::Layout::Box::formattingContextRoot const):
+        (WebCore::Layout::Box::initialContainingBlock const):
+        (WebCore::Layout::Box::isOverflowVisible const):
+        * layout/layouttree/LayoutBox.h:
+        (WebCore::Layout::Box::parent const):
+        * layout/layouttree/LayoutIterator.h:
+        (WebCore::Layout::LayoutBoxTraversal::nextAncestorSibling):
+        (WebCore::Layout::LayoutBoxTraversal::next):
+        (WebCore::Layout::Traversal::firstWithin):
+        (WebCore::Layout::Traversal::next):
+        (WebCore::Layout::LayoutIterator<T>::traverseNext):
+        * layout/tableformatting/TableGrid.cpp:
+        (WebCore::Layout::TableGrid::appendCell):
+
 2020-03-29  David Kilzer  <ddkilzer@apple.com>
 
         Windows build fix: Web Inspector: support editing cookie key/values from inspector
diff --git a/Source/WebCore/layout/FormattingContextGeometry.cpp b/Source/WebCore/layout/FormattingContextGeometry.cpp
index 2e1e727..7c10f53 100644
--- a/Source/WebCore/layout/FormattingContextGeometry.cpp
+++ b/Source/WebCore/layout/FormattingContextGeometry.cpp
@@ -232,15 +232,13 @@
         // Add sibling offset
         auto& previousInFlowBoxGeometry = formattingContext.geometryForBox(*layoutBox.previousInFlowSibling(), EscapeReason::OutOfFlowBoxNeedsInFlowGeometry);
         top += previousInFlowBoxGeometry.bottom() + previousInFlowBoxGeometry.nonCollapsedMarginAfter();
-    } else {
-        ASSERT(layoutBox.parent());
-        top = formattingContext.geometryForBox(*layoutBox.parent(), EscapeReason::OutOfFlowBoxNeedsInFlowGeometry).contentBoxTop();
-    }
+    } else
+        top = formattingContext.geometryForBox(layoutBox.parent(), EscapeReason::OutOfFlowBoxNeedsInFlowGeometry).contentBoxTop();
 
     // Resolve top all the way up to the containing block.
     auto& containingBlock = layoutBox.containingBlock();
     // Start with the parent since we pretend that this box is normal flow.
-    for (auto* ancestor = layoutBox.parent(); ancestor != &containingBlock; ancestor = &ancestor->containingBlock()) {
+    for (auto* ancestor = &layoutBox.parent(); ancestor != &containingBlock; ancestor = &ancestor->containingBlock()) {
         auto& boxGeometry = formattingContext.geometryForBox(*ancestor, EscapeReason::OutOfFlowBoxNeedsInFlowGeometry);
         // Display::Box::top is the border box top position in its containing block's coordinate system.
         top += boxGeometry.top();
@@ -257,13 +255,12 @@
 
     // Start with this box's border box offset from the parent's border box.
     auto& formattingContext = this->formattingContext();
-    ASSERT(layoutBox.parent());
-    auto left = formattingContext.geometryForBox(*layoutBox.parent(), EscapeReason::OutOfFlowBoxNeedsInFlowGeometry).contentBoxLeft();
+    auto left = formattingContext.geometryForBox(layoutBox.parent(), EscapeReason::OutOfFlowBoxNeedsInFlowGeometry).contentBoxLeft();
 
     // Resolve left all the way up to the containing block.
     auto& containingBlock = layoutBox.containingBlock();
     // Start with the parent since we pretend that this box is normal flow.
-    for (auto* ancestor = layoutBox.parent(); ancestor != &containingBlock; ancestor = &ancestor->containingBlock()) {
+    for (auto* ancestor = &layoutBox.parent(); ancestor != &containingBlock; ancestor = &ancestor->containingBlock()) {
         auto& boxGeometry = formattingContext.geometryForBox(*ancestor, EscapeReason::OutOfFlowBoxNeedsInFlowGeometry);
         // Display::Box::left is the border box left position in its containing block's coordinate system.
         left += boxGeometry.left();
diff --git a/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp b/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp
index 2ae382d..ebfbb1fd 100644
--- a/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp
+++ b/Source/WebCore/layout/blockformatting/BlockFormattingContextQuirks.cpp
@@ -86,7 +86,7 @@
     usedVerticalMargin += collapsedMargin.isCollapsedThrough ? nonCollapsedMargin.after : collapsedMargin.after.valueOr(nonCollapsedMargin.after);
     bodyBoxContentHeight -= usedVerticalMargin;
     // Document box's padding and border also shrink the body box's content height.
-    auto& documentBox = *layoutBox.parent();
+    auto& documentBox = layoutBox.parent();
     auto& documentBoxGeometry = formattingContext.geometryForBox(documentBox, EscapeReason::BodyStrechesToViewportQuirk);
     bodyBoxContentHeight -= documentBoxGeometry.verticalBorder() + documentBoxGeometry.verticalPadding().valueOr(0);
     // However the non-in-flow document box's vertical margins are ignored. They don't affect the body box's content height.
diff --git a/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp b/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp
index b49ea7d..4a70f32 100644
--- a/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp
+++ b/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp
@@ -97,7 +97,7 @@
     // 1. This is the last in-flow child and its margins collapse through and the margin after collapses with parent's margin after or
     // 2. This box's margin after collapses with the next sibling's margin before and that sibling collapses through and
     // we can get to the last in-flow child like that.
-    auto* lastInFlowChild = layoutBox.parent()->lastInFlowChild();
+    auto* lastInFlowChild = layoutBox.parent().lastInFlowChild();
     for (auto* currentBox = &layoutBox; currentBox; currentBox = currentBox->nextInFlowSibling()) {
         if (!marginsCollapseThrough(*currentBox))
             return false;
@@ -132,7 +132,7 @@
     if (layoutBox.previousInFlowSibling())
         return false;
 
-    auto& parent = *layoutBox.parent();
+    auto& parent = layoutBox.parent();
     // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children
     if (establishesBlockFormattingContext(parent))
         return false;
@@ -234,7 +234,7 @@
     // 1. This is the first in-flow child and its margins collapse through and the margin before collapses with parent's margin before or
     // 2. This box's margin before collapses with the previous sibling's margin after and that sibling collapses through and
     // we can get to the first in-flow child like that.
-    auto* firstInFlowChild = layoutBox.parent()->firstInFlowChild();
+    auto* firstInFlowChild = layoutBox.parent().firstInFlowChild();
     for (auto* currentBox = &layoutBox; currentBox; currentBox = currentBox->previousInFlowSibling()) {
         if (!marginsCollapseThrough(*currentBox))
             return false;
@@ -267,7 +267,7 @@
     if (layoutBox.nextInFlowSibling())
         return false;
 
-    auto& parent = *layoutBox.parent();
+    auto& parent = layoutBox.parent();
     // Margins of elements that establish new block formatting contexts do not collapse with their in-flow children.
     if (establishesBlockFormattingContext(parent))
         return false;
diff --git a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
index 59761ca..3a3c038 100644
--- a/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
+++ b/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
@@ -68,7 +68,7 @@
         }
     }
 
-    for (auto* nextInPreOrder = &layoutBox; nextInPreOrder && nextInPreOrder != &stayWithin; nextInPreOrder = nextInPreOrder->parent()) {
+    for (auto* nextInPreOrder = &layoutBox; nextInPreOrder && nextInPreOrder != &stayWithin; nextInPreOrder = &nextInPreOrder->parent()) {
         if (auto* nextSibling = nextInPreOrder->nextInFlowOrFloatingSibling())
             return nextSibling;
     }
@@ -427,7 +427,7 @@
             // For example, the first line of an anonymous block box is only affected if it is the first child of its parent element.
             isFormattingContextRootCandidateToTextIndent = RuntimeEnabledFeatures::sharedFeatures().layoutFormattingContextIntegrationEnabled()
                 ? layoutState().isIntegratedRootBoxFirstChild()
-                : root.parent()->firstInFlowChild() == &root;
+                : root.parent().firstInFlowChild() == &root;
         }
         if (!isFormattingContextRootCandidateToTextIndent)
             return InlineLayoutUnit { };
diff --git a/Source/WebCore/layout/layouttree/LayoutBox.cpp b/Source/WebCore/layout/layouttree/LayoutBox.cpp
index 55afc8a..53c9aa4 100644
--- a/Source/WebCore/layout/layouttree/LayoutBox.cpp
+++ b/Source/WebCore/layout/layouttree/LayoutBox.cpp
@@ -192,8 +192,8 @@
     // If the element has 'position: absolute', the containing block is established by the nearest ancestor with a
     // 'position' of 'absolute', 'relative' or 'fixed'.
     if (!isPositioned() || isInFlowPositioned()) {
-        auto* ancestor = parent();
-        for (; !is<InitialContainingBlock>(*ancestor); ancestor = ancestor->parent()) {
+        auto* ancestor = &parent();
+        for (; !is<InitialContainingBlock>(*ancestor); ancestor = &ancestor->parent()) {
             if (ancestor->isBlockContainerBox() || ancestor->establishesFormattingContext())
                 return *ancestor;
         }
@@ -201,8 +201,8 @@
     }
 
     if (isFixedPositioned()) {
-        auto* ancestor = parent();
-        for (; !is<InitialContainingBlock>(*ancestor); ancestor = ancestor->parent()) {
+        auto* ancestor = &parent();
+        for (; !is<InitialContainingBlock>(*ancestor); ancestor = &ancestor->parent()) {
             if (ancestor->style().hasTransform())
                 return *ancestor;
         }
@@ -210,8 +210,8 @@
     }
 
     if (isOutOfFlowPositioned()) {
-        auto* ancestor = parent();
-        for (; !is<InitialContainingBlock>(*ancestor); ancestor = ancestor->parent()) {
+        auto* ancestor = &parent();
+        for (; !is<InitialContainingBlock>(*ancestor); ancestor = &ancestor->parent()) {
             if (ancestor->isPositioned() || ancestor->style().hasTransform())
                 return *ancestor;
         }
@@ -235,7 +235,7 @@
     // <div id=outer style="position: absolute"><div id=inner><span style="position: relative">content</span></div></div>
     // While the relatively positioned inline container (span) is placed relative to its containing block "outer", it lives in the inline
     // formatting context established by "inner".
-    auto& ancestor = isInlineLevelBox() && isInFlowPositioned() ? *parent() : containingBlock();
+    auto& ancestor = isInlineLevelBox() && isInFlowPositioned() ? parent() : containingBlock();
     if (ancestor.establishesFormattingContext())
         return ancestor;
     return ancestor.formattingContextRoot();
@@ -246,9 +246,8 @@
     if (is<InitialContainingBlock>(*this))
         return downcast<InitialContainingBlock>(*this);
 
-    auto* ancestor = parent();
-    for (; ancestor->parent(); ancestor = ancestor->parent()) { }
-
+    auto* ancestor = &parent();
+    for (; !is<InitialContainingBlock>(*ancestor); ancestor = &ancestor->parent()) { }
     return downcast<InitialContainingBlock>(*ancestor);
 }
 
@@ -353,11 +352,10 @@
     // if the value on the root element is 'visible'. The 'visible' value when used for the viewport must be interpreted as 'auto'.
     // The element from which the value is propagated must have a used value for 'overflow' of 'visible'.
     if (isBodyBox()) {
-        auto* documentBox = parent();
-        ASSERT(documentBox);
-        if (!documentBox->isDocumentBox())
+        auto& documentBox = parent();
+        if (!documentBox.isDocumentBox())
             return isOverflowVisible;
-        if (!documentBox->isOverflowVisible())
+        if (!documentBox.isOverflowVisible())
             return isOverflowVisible;
         return true;
     }
diff --git a/Source/WebCore/layout/layouttree/LayoutBox.h b/Source/WebCore/layout/layouttree/LayoutBox.h
index 86d1b8a..0bd4221 100644
--- a/Source/WebCore/layout/layouttree/LayoutBox.h
+++ b/Source/WebCore/layout/layouttree/LayoutBox.h
@@ -127,7 +127,7 @@
     bool isIFrame() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::IFrame; }
     bool isImage() const { return m_elementAttributes && m_elementAttributes.value().elementType == ElementType::Image; }
 
-    const ContainerBox* parent() const { return m_parent; }
+    const ContainerBox& parent() const { return *m_parent; }
     const Box* nextSibling() const { return m_nextSibling; }
     const Box* nextInFlowSibling() const;
     const Box* nextInFlowOrFloatingSibling() const;
diff --git a/Source/WebCore/layout/layouttree/LayoutInitialContainingBlock.h b/Source/WebCore/layout/layouttree/LayoutInitialContainingBlock.h
index a99ec95..902edaa 100644
--- a/Source/WebCore/layout/layouttree/LayoutInitialContainingBlock.h
+++ b/Source/WebCore/layout/layouttree/LayoutInitialContainingBlock.h
@@ -40,7 +40,7 @@
     virtual ~InitialContainingBlock() = default;
 
 private:
-    const ContainerBox* parent() const = delete;
+    const ContainerBox& parent() const = delete;
     const Box* nextSibling() const = delete;
     const Box* nextInFlowSibling() const = delete;
     const Box* nextInFlowOrFloatingSibling() const = delete;
diff --git a/Source/WebCore/layout/layouttree/LayoutIterator.h b/Source/WebCore/layout/layouttree/LayoutIterator.h
index cb0fcf4..8d85935 100644
--- a/Source/WebCore/layout/layouttree/LayoutIterator.h
+++ b/Source/WebCore/layout/layouttree/LayoutIterator.h
@@ -69,10 +69,10 @@
     return nullptr;
 }
 
-inline const Box* nextAncestorSibling(const Box& current, const ContainerBox* stayWithin)
+inline const Box* nextAncestorSibling(const Box& current, const ContainerBox& stayWithin)
 {
-    for (auto* ancestor = current.parent(); ancestor; ancestor = ancestor->parent()) {
-        if (ancestor == stayWithin)
+    for (auto* ancestor = &current.parent(); !is<InitialContainingBlock>(*ancestor); ancestor = &ancestor->parent()) {
+        if (ancestor == &stayWithin)
             return nullptr;
         if (auto* sibling = ancestor->nextSibling())
             return sibling;
@@ -81,12 +81,12 @@
 }
 
 template <typename U>
-inline const Box* next(const U& current, const ContainerBox* stayWithin)
+inline const Box* next(const U& current, const ContainerBox& stayWithin)
 {
     if (auto* child = firstChild(current))
         return child;
 
-    if (&current == stayWithin)
+    if (&current == &stayWithin)
         return nullptr;
 
     if (auto* sibling = current.nextSibling())
@@ -122,12 +122,12 @@
 {
     auto* descendant = LayoutBoxTraversal::firstChild(stayWithin);
     while (descendant && !isLayoutBoxOfType<T>(*descendant))
-        descendant = LayoutBoxTraversal::next(*descendant, &stayWithin);
+        descendant = LayoutBoxTraversal::next(*descendant, stayWithin);
     return static_cast<const T*>(descendant);
 }
 
 template <typename T, typename U>
-inline const T* next(const U& current, const ContainerBox* stayWithin)
+inline const T* next(const U& current, const ContainerBox& stayWithin)
 {
     auto* descendant = LayoutBoxTraversal::next(current, stayWithin);
     while (descendant && !isLayoutBoxOfType<T>(*descendant))
@@ -165,7 +165,7 @@
 inline LayoutIterator<T>& LayoutIterator<T>::traverseNext()
 {
     ASSERT(m_current);
-    m_current = Traversal::next<T>(*m_current, m_root);
+    m_current = Traversal::next<T>(*m_current, *m_root);
     return *this;
 }
 
diff --git a/Source/WebCore/layout/tableformatting/TableGrid.cpp b/Source/WebCore/layout/tableformatting/TableGrid.cpp
index d3f59ef..8018879 100644
--- a/Source/WebCore/layout/tableformatting/TableGrid.cpp
+++ b/Source/WebCore/layout/tableformatting/TableGrid.cpp
@@ -157,7 +157,7 @@
         m_columnsContext.addColumn();
 
     if (isInNewRow)
-        m_rows.append({ *tableCellBox.parent() });
+        m_rows.append({ tableCellBox.parent() });
 
     m_cellList.add(WTFMove(cellInfo));
 }