[LFC] Implement height computation for non-replaced inflow elements.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 May 2018 16:46:54 +0000 (16:46 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 May 2018 16:46:54 +0000 (16:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185474

Reviewed by Antti Koivisto.

Initial implementation. Does not cover all the cases.

* layout/FormattingContext.cpp:
(WebCore::Layout::FormattingContext::computeHeight const):
* layout/FormattingContext.h:
* layout/blockformatting/BlockFormattingContext.cpp:
(WebCore::Layout::BlockFormattingContext::layout const):
(WebCore::Layout::BlockFormattingContext::computeInFlowHeight const):
(WebCore::Layout::BlockFormattingContext::computeInFlowNonReplacedHeight const):
* layout/blockformatting/BlockFormattingContext.h:
* layout/blockformatting/BlockMarginCollapse.cpp:
(WebCore::Layout::collapsedMarginBottomFromLastChild):
(WebCore::Layout::BlockMarginCollapse::isMarginBottomCollapsedWithParent):
(WebCore::Layout::BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom):
(WebCore::Layout::isMarginBottomCollapsedWithParent): Deleted.
* layout/blockformatting/BlockMarginCollapse.h:
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::computeInFlowHeight const):
* layout/inlineformatting/InlineFormattingContext.h:
* layout/layouttree/LayoutBox.cpp:
(WebCore::Layout::Box::isReplaced const):
* layout/layouttree/LayoutBox.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231642 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/layout/FormattingContext.cpp
Source/WebCore/layout/FormattingContext.h
Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp
Source/WebCore/layout/blockformatting/BlockFormattingContext.h
Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp
Source/WebCore/layout/blockformatting/BlockMarginCollapse.h
Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
Source/WebCore/layout/inlineformatting/InlineFormattingContext.h
Source/WebCore/layout/layouttree/LayoutBox.cpp
Source/WebCore/layout/layouttree/LayoutBox.h

index 3c62ace..b23ee69 100644 (file)
@@ -1,3 +1,33 @@
+2018-05-10  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC] Implement height computation for non-replaced inflow elements.
+        https://bugs.webkit.org/show_bug.cgi?id=185474
+
+        Reviewed by Antti Koivisto.
+
+        Initial implementation. Does not cover all the cases.
+
+        * layout/FormattingContext.cpp:
+        (WebCore::Layout::FormattingContext::computeHeight const):
+        * layout/FormattingContext.h:
+        * layout/blockformatting/BlockFormattingContext.cpp:
+        (WebCore::Layout::BlockFormattingContext::layout const):
+        (WebCore::Layout::BlockFormattingContext::computeInFlowHeight const):
+        (WebCore::Layout::BlockFormattingContext::computeInFlowNonReplacedHeight const):
+        * layout/blockformatting/BlockFormattingContext.h:
+        * layout/blockformatting/BlockMarginCollapse.cpp:
+        (WebCore::Layout::collapsedMarginBottomFromLastChild):
+        (WebCore::Layout::BlockMarginCollapse::isMarginBottomCollapsedWithParent):
+        (WebCore::Layout::BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom):
+        (WebCore::Layout::isMarginBottomCollapsedWithParent): Deleted.
+        * layout/blockformatting/BlockMarginCollapse.h:
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::computeInFlowHeight const):
+        * layout/inlineformatting/InlineFormattingContext.h:
+        * layout/layouttree/LayoutBox.cpp:
+        (WebCore::Layout::Box::isReplaced const):
+        * layout/layouttree/LayoutBox.h:
+
 2018-05-10  Thibault Saunier  <tsaunier@igalia.com>
 
         [GTK] Implement ImageBuffer::toBGRAData
index 79f61ee..3c1189c 100644 (file)
@@ -68,13 +68,13 @@ void FormattingContext::computeWidth(const Box& layoutBox, Display::Box& display
     return computeInFlowWidth(layoutBox, displayBox);
 }
 
-void FormattingContext::computeHeight(const Box& layoutBox, Display::Box& displayBox) const
+void FormattingContext::computeHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
 {
     if (layoutBox.isOutOfFlowPositioned())
         return computeOutOfFlowHeight(layoutBox, displayBox);
     if (layoutBox.isFloatingPositioned())
         return computeFloatingHeight(layoutBox, displayBox);
-    return computeInFlowHeight(layoutBox, displayBox);
+    return computeInFlowHeight(layoutContext, layoutBox, displayBox);
 }
 
 void FormattingContext::computeOutOfFlowWidth(const Box&, Display::Box&) const
index 6f4dfe5..3e5e870 100644 (file)
@@ -69,7 +69,7 @@ protected:
     virtual void computeOutOfFlowPosition(const Box&, Display::Box&) const;
 
     virtual void computeWidth(const Box&, Display::Box&) const;
-    virtual void computeHeight(const Box&, Display::Box&) const;
+    virtual void computeHeight(LayoutContext&, const Box&, Display::Box&) const;
 
     virtual void computeOutOfFlowWidth(const Box&, Display::Box&) const;
     virtual void computeFloatingWidth(const Box&, Display::Box&) const;
@@ -77,7 +77,7 @@ protected:
 
     virtual void computeOutOfFlowHeight(const Box&, Display::Box&) const;
     virtual void computeFloatingHeight(const Box&, Display::Box&) const;
-    virtual void computeInFlowHeight(const Box&, Display::Box&) const = 0;
+    virtual void computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const = 0;
 
     virtual LayoutUnit marginTop(const Box&) const;
     virtual LayoutUnit marginLeft(const Box&) const;
index 47bf590..e2c9c2d 100644 (file)
@@ -94,7 +94,7 @@ void BlockFormattingContext::layout(LayoutContext& layoutContext, FormattingStat
             auto& layoutBox = layoutPair->layoutBox;
             auto& displayBox = layoutPair->displayBox;
 
-            computeHeight(layoutBox, displayBox);
+            computeHeight(layoutContext, layoutBox, displayBox);
             // Adjust position now that we have all the previous floats placed in this context -if needed.
             floatingContext.computePosition(layoutBox, displayBox);
             if (!is<Container>(layoutBox))
@@ -147,8 +147,13 @@ void BlockFormattingContext::computeInFlowWidth(const Box&, Display::Box&) const
 {
 }
 
-void BlockFormattingContext::computeInFlowHeight(const Box&, Display::Box&) const
+void BlockFormattingContext::computeInFlowHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
 {
+    if (!layoutBox.isReplaced()) {
+        computeInFlowNonReplacedHeight(layoutContext, layoutBox, displayBox);
+        return;
+    }
+    ASSERT_NOT_REACHED();
 }
 
 LayoutUnit BlockFormattingContext::marginTop(const Box& layoutBox) const
@@ -161,6 +166,61 @@ LayoutUnit BlockFormattingContext::marginBottom(const Box& layoutBox) const
     return BlockMarginCollapse::marginBottom(layoutBox);
 }
 
+void BlockFormattingContext::computeInFlowNonReplacedHeight(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
+{
+    // https://www.w3.org/TR/CSS22/visudet.html
+    // If 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders:
+    // The element's height is the distance from its top content edge to the first applicable of the following:
+    // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
+    // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin
+    //    does not collapse with the element's bottom margin
+    // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
+    // 4. zero, otherwise
+    // Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored,
+    // and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box.
+    if (!layoutBox.style().logicalHeight().isAuto()) {
+        // FIXME: Only fixed values yet.
+        displayBox.setHeight(layoutBox.style().logicalHeight().value());
+        return;
+    }
+
+    if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild()) {
+        displayBox.setHeight(0);
+        return;
+    }
+
+    // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
+    if (layoutBox.establishesInlineFormattingContext()) {
+        // height = lastLineBox().bottom();
+        displayBox.setHeight(0);
+        return;
+    }
+
+    // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin...
+    auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild();
+    ASSERT(lastInFlowChild);
+    if (!BlockMarginCollapse::isMarginBottomCollapsedWithParent(*lastInFlowChild)) {
+        auto* lastInFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*lastInFlowChild);
+        ASSERT(lastInFlowDisplayBox);
+        displayBox.setHeight(lastInFlowDisplayBox->bottom() + lastInFlowDisplayBox->marginBottom());
+        return;
+    }
+
+    // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
+    auto* inFlowChild = lastInFlowChild;
+    while (inFlowChild && BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom(*inFlowChild))
+        inFlowChild = inFlowChild->previousInFlowSibling();
+    if (inFlowChild) {
+        auto* inFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*inFlowChild);
+        ASSERT(inFlowDisplayBox);
+        displayBox.setHeight(inFlowDisplayBox->top() + inFlowDisplayBox->borderBox().height());
+        return;
+    }
+
+    // 4. zero, otherwise
+    displayBox.setHeight(0);
+}
+
 }
 }
 
index 691c469..e2ac84a 100644 (file)
@@ -49,10 +49,11 @@ public:
     std::unique_ptr<FormattingState> createFormattingState(Ref<FloatingState>&&) const override;
     Ref<FloatingState> createOrFindFloatingState(LayoutContext&) const override;
 
-protected:
+private:
     void computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const override;
     void computeInFlowWidth(const Box&, Display::Box&) const override;
-    void computeInFlowHeight(const Box&, Display::Box&) const override;
+    void computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const override;
+    void computeInFlowNonReplacedHeight(LayoutContext&, const Box&, Display::Box&) const;
 
     LayoutUnit marginTop(const Box&) const override;
     LayoutUnit marginBottom(const Box&) const override;
index 8ecfcbe..584f43a 100644 (file)
@@ -114,42 +114,6 @@ static bool isMarginTopCollapsedWithParent(const Box& layoutBox)
     return true;
 }
 
-static bool isMarginBottomCollapsedWithParent(const Box& layoutBox)
-{
-    // last inflow box to parent.
-    // https://www.w3.org/TR/CSS21/box.html#collapsing-margins
-    if (layoutBox.isAnonymous())
-        return false;
-
-    if (layoutBox.isFloatingOrOutOfFlowPositioned())
-        return false;
-
-    // We never margin collapse the initial containing block.
-    ASSERT(layoutBox.parent());
-    auto& parent = *layoutBox.parent();
-    // Is this the last inlflow child?
-    if (parent.lastInFlowChild() != &layoutBox)
-        return false;
-
-    if (parent.establishesBlockFormattingContext())
-        return false;
-
-    // Margins of the root element's box do not collapse.
-    if (parent.isInitialContainingBlock())
-        return false;
-
-    if (!parent.style().borderTop().nonZero())
-        return false;
-
-    if (!parent.style().paddingTop().isZero())
-        return false;
-
-    if (!parent.style().height().isAuto())
-        return false;
-
-    return true;
-}
-
 static LayoutUnit collapsedMarginTopFromFirstChild(const Box& layoutBox)
 {
     // Check if the first child collapses its margin top.
@@ -171,7 +135,7 @@ static LayoutUnit collapsedMarginBottomFromLastChild(const Box& layoutBox)
         return 0;
 
     auto& lastInFlowChild = *downcast<Container>(layoutBox).lastInFlowChild();
-    if (!isMarginBottomCollapsedWithParent(lastInFlowChild))
+    if (!BlockMarginCollapse::isMarginBottomCollapsedWithParent(lastInFlowChild))
         return 0;
 
     // Collect collapsed margin bottom recursively.
@@ -249,6 +213,47 @@ LayoutUnit BlockMarginCollapse::marginBottom(const Box& layoutBox)
     return nonCollapsedMarginBottom(layoutBox);
 }
 
+bool BlockMarginCollapse::isMarginBottomCollapsedWithParent(const Box& layoutBox)
+{
+    // last inflow box to parent.
+    // https://www.w3.org/TR/CSS21/box.html#collapsing-margins
+    if (layoutBox.isAnonymous())
+        return false;
+
+    if (layoutBox.isFloatingOrOutOfFlowPositioned())
+        return false;
+
+    // We never margin collapse the initial containing block.
+    ASSERT(layoutBox.parent());
+    auto& parent = *layoutBox.parent();
+    // Is this the last inlflow child?
+    if (parent.lastInFlowChild() != &layoutBox)
+        return false;
+
+    if (parent.establishesBlockFormattingContext())
+        return false;
+
+    // Margins of the root element's box do not collapse.
+    if (parent.isInitialContainingBlock())
+        return false;
+
+    if (!parent.style().borderTop().nonZero())
+        return false;
+
+    if (!parent.style().paddingTop().isZero())
+        return false;
+
+    if (!parent.style().height().isAuto())
+        return false;
+
+    return true;
+}
+
+bool BlockMarginCollapse::isMarginTopCollapsedWithParentMarginBottom(const Box&)
+{
+    return false;
+}
+
 }
 }
 #endif
index 72fe57c..9de8b2d 100644 (file)
@@ -42,6 +42,9 @@ class BlockMarginCollapse {
 public:
     static LayoutUnit marginTop(const Box&);
     static LayoutUnit marginBottom(const Box&);
+
+    static bool isMarginBottomCollapsedWithParent(const Box&);
+    static bool isMarginTopCollapsedWithParentMarginBottom(const Box&);
 };
 
 }
index 49c73e8..bb8a390 100644 (file)
@@ -70,7 +70,7 @@ void InlineFormattingContext::computeInFlowWidth(const Box&, Display::Box&) cons
 {
 }
 
-void InlineFormattingContext::computeInFlowHeight(const Box&, Display::Box&) const
+void InlineFormattingContext::computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const
 {
 }
 
index 3b1f258..4437bd8 100644 (file)
@@ -49,7 +49,7 @@ public:
 
 private:
     void computeInFlowWidth(const Box&, Display::Box&) const override;
-    void computeInFlowHeight(const Box&, Display::Box&) const override;
+    void computeInFlowHeight(LayoutContext&, const Box&, Display::Box&) const override;
 
 };
 
index 44797af..fe0d5ca 100644 (file)
@@ -179,6 +179,12 @@ bool Box::isInitialContainingBlock() const
     return !parent();
 }
 
+bool Box::isReplaced() const
+{
+    // HTMLAudioElement || HTMLCanvasElement || HTMLEmbedElement || HTMLIFrameElement || HTMLImageElement || HTMLInputElement || HTMLObjectElement || HTMLVideoElement
+    return false;
+}
+
 const Box* Box::nextInFlowSibling() const
 {
     if (auto* nextSibling = this->nextSibling()) {
index 5c4563c..23af846 100644 (file)
@@ -72,6 +72,7 @@ public:
     bool isInlineBlockBox() const;
     bool isBlockContainerBox() const;
     bool isInitialContainingBlock() const;
+    bool isReplaced() const;
 
     const Container* parent() const { return m_parent; }
     const Box* nextSibling() const { return m_nextSibling; }