Title: [235034] releases/WebKitGTK/webkit-2.22/Source/WebCore
Revision
235034
Author
carlo...@webkit.org
Date
2018-08-20 02:31:14 -0700 (Mon, 20 Aug 2018)

Log Message

Merge r234927 - [lFC][Floating] Add estimated margin top computation.
https://bugs.webkit.org/show_bug.cgi?id=188619

Reviewed by Antti Koivisto.

In order to figure out whether a box should avoid a float, we need to know the final positions of both (ignore relative positioning for now).
In block formatting context the final position for a normal flow box includes
1. the static position and
2. the corresponding (non)collapsed margins.
Now the vertical margins are computed when all the descendants are finalized, because the margin values might be depending on the height of the box
(and the height might be based on the content).
So when we get to the point where we intersect the box with the float to decide if the box needs to move, we don't yet have the final vertical position.

The idea here is that as long as we don't cross the block formatting context boundary, we should be able to pre-compute the final top margin.
(if this holds true for all the cases, the estimated prefix could be removed and just use marginTop() instead.)

Covered by existing block-only tests.

* layout/blockformatting/BlockFormattingContext.cpp:
(WebCore::Layout::BlockFormattingContext::layout const):
(WebCore::Layout::BlockFormattingContext::computeEstimatedMarginTop const):
(WebCore::Layout::BlockFormattingContext::computeEstimatedMarginTopForAncestors const):
(WebCore::Layout::BlockFormattingContext::computeFloatingPosition const):
(WebCore::Layout::BlockFormattingContext::computeVerticalPositionForFloatClear const):
(WebCore::Layout::BlockFormattingContext::computeInFlowHeightAndMargin const):
* layout/blockformatting/BlockFormattingContext.h:
* layout/blockformatting/BlockMarginCollapse.cpp:
(WebCore::Layout::BlockFormattingContext::MarginCollapse::estimatedMarginTop):
* layout/displaytree/DisplayBox.cpp:
(WebCore::Display::Box::Box):
* layout/displaytree/DisplayBox.h:
(WebCore::Display::Box::setHasValidTop):
(WebCore::Display::Box::setHasValidLeft):
(WebCore::Display::Box::top const):
(WebCore::Display::Box::left const):
(WebCore::Display::Box::topLeft const):
(WebCore::Display::Box::setTopLeft):
(WebCore::Display::Box::setTop):
(WebCore::Display::Box::setLeft):
(WebCore::Display::Box::setVerticalMargin):
(WebCore::Display::Box::setEstimatedMarginTop):
(WebCore::Display::Box::estimatedMarginTop const):

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog (235033 => 235034)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog	2018-08-20 09:31:06 UTC (rev 235033)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/ChangeLog	2018-08-20 09:31:14 UTC (rev 235034)
@@ -1,5 +1,50 @@
 2018-08-16  Zalan Bujtas  <za...@apple.com>
 
+        [lFC][Floating] Add estimated margin top computation.
+        https://bugs.webkit.org/show_bug.cgi?id=188619
+
+        Reviewed by Antti Koivisto.
+
+        In order to figure out whether a box should avoid a float, we need to know the final positions of both (ignore relative positioning for now).
+        In block formatting context the final position for a normal flow box includes
+        1. the static position and
+        2. the corresponding (non)collapsed margins.
+        Now the vertical margins are computed when all the descendants are finalized, because the margin values might be depending on the height of the box
+        (and the height might be based on the content).
+        So when we get to the point where we intersect the box with the float to decide if the box needs to move, we don't yet have the final vertical position.
+
+        The idea here is that as long as we don't cross the block formatting context boundary, we should be able to pre-compute the final top margin.
+        (if this holds true for all the cases, the estimated prefix could be removed and just use marginTop() instead.)
+
+        Covered by existing block-only tests.
+
+        * layout/blockformatting/BlockFormattingContext.cpp:
+        (WebCore::Layout::BlockFormattingContext::layout const):
+        (WebCore::Layout::BlockFormattingContext::computeEstimatedMarginTop const):
+        (WebCore::Layout::BlockFormattingContext::computeEstimatedMarginTopForAncestors const):
+        (WebCore::Layout::BlockFormattingContext::computeFloatingPosition const):
+        (WebCore::Layout::BlockFormattingContext::computeVerticalPositionForFloatClear const):
+        (WebCore::Layout::BlockFormattingContext::computeInFlowHeightAndMargin const):
+        * layout/blockformatting/BlockFormattingContext.h:
+        * layout/blockformatting/BlockMarginCollapse.cpp:
+        (WebCore::Layout::BlockFormattingContext::MarginCollapse::estimatedMarginTop):
+        * layout/displaytree/DisplayBox.cpp:
+        (WebCore::Display::Box::Box):
+        * layout/displaytree/DisplayBox.h:
+        (WebCore::Display::Box::setHasValidTop):
+        (WebCore::Display::Box::setHasValidLeft):
+        (WebCore::Display::Box::top const):
+        (WebCore::Display::Box::left const):
+        (WebCore::Display::Box::topLeft const):
+        (WebCore::Display::Box::setTopLeft):
+        (WebCore::Display::Box::setTop):
+        (WebCore::Display::Box::setLeft):
+        (WebCore::Display::Box::setVerticalMargin):
+        (WebCore::Display::Box::setEstimatedMarginTop):
+        (WebCore::Display::Box::estimatedMarginTop const):
+
+2018-08-16  Zalan Bujtas  <za...@apple.com>
+
         [LFC][BFC] Display::Box interface should reflect that padding is optional.
         https://bugs.webkit.org/show_bug.cgi?id=188630
 

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp (235033 => 235034)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp	2018-08-20 09:31:06 UTC (rev 235033)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp	2018-08-20 09:31:14 UTC (rev 235034)
@@ -113,7 +113,7 @@
             computeHeightAndMargin(layoutContext, layoutBox, displayBox);
             // Finalize position with clearance.
             if (layoutBox.hasFloatClear())
-                computeVerticalPositionForFloatClear(floatingContext, layoutBox, displayBox);
+                computeVerticalPositionForFloatClear(layoutContext, floatingContext, layoutBox, displayBox);
             if (!is<Container>(layoutBox))
                 continue;
             auto& container = downcast<Container>(layoutBox);
@@ -156,6 +156,39 @@
     displayBox.setTopLeft(Geometry::staticPosition(layoutContext, layoutBox));
 }
 
+void BlockFormattingContext::computeEstimatedMarginTop(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
+{
+    auto estimatedMarginTop = MarginCollapse::estimatedMarginTop(layoutContext, layoutBox);
+    displayBox.setEstimatedMarginTop(estimatedMarginTop);
+    displayBox.moveVertically(estimatedMarginTop);
+}
+
+void BlockFormattingContext::computeEstimatedMarginTopForAncestors(LayoutContext& layoutContext, const Box& layoutBox) const
+{
+    // We only need to estimate margin top for float related layout.
+    ASSERT(layoutBox.isFloatingPositioned() || layoutBox.hasFloatClear());
+
+    // In order to figure out whether a box should avoid a float, we need to know the final positions of both (ignore relative positioning for now).
+    // In block formatting context the final position for a normal flow box includes
+    // 1. the static position and
+    // 2. the corresponding (non)collapsed margins.
+    // Now the vertical margins are computed when all the descendants are finalized, because the margin values might be depending on the height of the box
+    // (and the height might be based on the content).
+    // So when we get to the point where we intersect the box with the float to decide if the box needs to move, we don't yet have the final vertical position.
+    //
+    // The idea here is that as long as we don't cross the block formatting context boundary, we should be able to pre-compute the final top margin.
+
+    for (auto* ancestor = layoutBox.containingBlock(); ancestor && !ancestor->establishesBlockFormattingContext(); ancestor = ancestor->containingBlock()) {
+        auto* displayBox = layoutContext.displayBoxForLayoutBox(*ancestor);
+        ASSERT(displayBox);
+        // FIXME: with incremental layout, we might actually have a valid (non-estimated) margin top as well.
+        if (displayBox->estimatedMarginTop())
+            return;
+
+        computeEstimatedMarginTop(layoutContext, *ancestor, *displayBox);
+    }
+}
+
 void BlockFormattingContext::computeFloatingPosition(LayoutContext& layoutContext, FloatingContext& floatingContext, const Box& layoutBox, Display::Box& displayBox) const
 {
     ASSERT(layoutBox.isFloatingPositioned());
@@ -166,13 +199,18 @@
         auto& previousDisplayBox = *layoutContext.displayBoxForLayoutBox(*previousInFlowBox);
         displayBox.moveVertically(previousDisplayBox.nonCollapsedMarginBottom() - previousDisplayBox.marginBottom());
     }
+    computeEstimatedMarginTopForAncestors(layoutContext, layoutBox);
     displayBox.setTopLeft(floatingContext.positionForFloat(layoutBox));
     floatingContext.floatingState().append(layoutBox);
 }
 
-void BlockFormattingContext::computeVerticalPositionForFloatClear(const FloatingContext& floatingContext, const Box& layoutBox, Display::Box& displayBox) const
+void BlockFormattingContext::computeVerticalPositionForFloatClear(LayoutContext& layoutContext, const FloatingContext& floatingContext, const Box& layoutBox, Display::Box& displayBox) const
 {
     ASSERT(layoutBox.hasFloatClear());
+    if (floatingContext.floatingState().isEmpty())
+        return;
+
+    computeEstimatedMarginTopForAncestors(layoutContext, layoutBox);
     if (auto verticalPositionWithClearance = floatingContext.verticalPositionWithClearance(layoutBox))
         displayBox.setTop(*verticalPositionWithClearance);
 }
@@ -208,9 +246,13 @@
 {
     auto heightAndMargin = Geometry::inFlowHeightAndMargin(layoutContext, layoutBox);
     displayBox.setContentBoxHeight(heightAndMargin.height);
-    displayBox.moveVertically(heightAndMargin.collapsedMargin.value_or(heightAndMargin.margin).top);
-    displayBox.setVerticalMargin(heightAndMargin.collapsedMargin.value_or(heightAndMargin.margin));
+    auto marginValue = heightAndMargin.collapsedMargin.value_or(heightAndMargin.margin);
+    displayBox.setVerticalMargin(marginValue);
     displayBox.setVerticalNonCollapsedMargin(heightAndMargin.margin);
+
+    // This box has already been moved by the estimated vertical margin. No need to move it again.
+    if (!displayBox.estimatedMarginTop())
+        displayBox.moveVertically(marginValue.top);
 }
 
 void BlockFormattingContext::computeInFlowWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockFormattingContext.h (235033 => 235034)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockFormattingContext.h	2018-08-20 09:31:06 UTC (rev 235033)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockFormattingContext.h	2018-08-20 09:31:14 UTC (rev 235034)
@@ -57,10 +57,12 @@
 
     void computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const override;
     void computeFloatingPosition(LayoutContext&, FloatingContext&, const Box&, Display::Box&) const;
-    void computeVerticalPositionForFloatClear(const FloatingContext&, const Box&, Display::Box&) const;
+    void computeVerticalPositionForFloatClear(LayoutContext&, const FloatingContext&, const Box&, Display::Box&) const;
     void computeInFlowPositionedPosition(LayoutContext&, const Box&, Display::Box&) const override;
     void computeInFlowWidthAndMargin(LayoutContext&, const Box&, Display::Box&) const;
     void computeInFlowHeightAndMargin(LayoutContext&, const Box&, Display::Box&) const;
+    void computeEstimatedMarginTop(LayoutContext&, const Box&, Display::Box&) const;
+    void computeEstimatedMarginTopForAncestors(LayoutContext&, const Box&) const;
 
     FormattingContext::InstrinsicWidthConstraints instrinsicWidthConstraints(LayoutContext&, const Box&) const override;
 
@@ -87,6 +89,7 @@
     class MarginCollapse {
     public:
         static LayoutUnit marginTop(const LayoutContext&, const Box&);
+        static LayoutUnit estimatedMarginTop(const LayoutContext&, const Box&);
         static LayoutUnit marginBottom(const LayoutContext&, const Box&);
 
         static bool isMarginBottomCollapsedWithParent(const LayoutContext&, const Box&);

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp (235033 => 235034)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp	2018-08-20 09:31:06 UTC (rev 235033)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/blockformatting/BlockMarginCollapse.cpp	2018-08-20 09:31:14 UTC (rev 235034)
@@ -332,6 +332,18 @@
     return marginValue(computedNonCollapsedMarginBottom(layoutContext, layoutBox), collapsedMarginBottomFromLastChild(layoutContext, layoutBox));
 }
 
+LayoutUnit BlockFormattingContext::MarginCollapse::estimatedMarginTop(const LayoutContext& layoutContext, const Box& layoutBox)
+{
+    ASSERT(layoutBox.isBlockLevelBox());
+    // Can't estimate vertical margins for out of flow boxes (and we shouldn't need to do it for float boxes).
+    ASSERT(layoutBox.isInFlow());
+    // Can't cross block formatting context boundary.
+    ASSERT(!layoutBox.establishesBlockFormattingContext());
+
+    // Let's just use the normal path for now.
+    return marginTop(layoutContext, layoutBox);
 }
+
 }
+}
 #endif

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/displaytree/DisplayBox.cpp (235033 => 235034)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/displaytree/DisplayBox.cpp	2018-08-20 09:31:06 UTC (rev 235033)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/displaytree/DisplayBox.cpp	2018-08-20 09:31:14 UTC (rev 235034)
@@ -59,9 +59,12 @@
     , m_contentHeight(other.m_contentHeight)
     , m_margin(other.m_margin)
     , m_verticalNonCollapsedMargin(other.m_verticalNonCollapsedMargin)
+    , m_estimatedMarginTop(other.m_estimatedMarginTop)
     , m_border(other.m_border)
     , m_padding(other.m_padding)
 #if !ASSERT_DISABLED
+    , m_hasValidTop(other.m_hasValidTop)
+    , m_hasValidLeft(other.m_hasValidLeft)
     , m_hasValidHorizontalMargin(other.m_hasValidHorizontalMargin)
     , m_hasValidVerticalMargin(other.m_hasValidVerticalMargin)
     , m_hasValidVerticalNonCollapsedMargin(other.m_hasValidVerticalNonCollapsedMargin)

Modified: releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/displaytree/DisplayBox.h (235033 => 235034)


--- releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/displaytree/DisplayBox.h	2018-08-20 09:31:06 UTC (rev 235033)
+++ releases/WebKitGTK/webkit-2.22/Source/WebCore/layout/displaytree/DisplayBox.h	2018-08-20 09:31:14 UTC (rev 235034)
@@ -117,12 +117,12 @@
 
     ~Box();
 
-    LayoutUnit top() const { return m_topLeft.y(); }
-    LayoutUnit left() const { return m_topLeft.x(); }
+    LayoutUnit top() const;
+    LayoutUnit left() const;
     LayoutUnit bottom() const { return top() + height(); }
     LayoutUnit right() const { return left() + width(); }
 
-    LayoutPoint topLeft() const { return m_topLeft; }
+    LayoutPoint topLeft() const;
     LayoutPoint bottomRight() const { return { right(), bottom() }; }
 
     LayoutSize size() const { return { width(), height() }; }
@@ -138,6 +138,7 @@
 
     LayoutUnit nonCollapsedMarginTop() const;
     LayoutUnit nonCollapsedMarginBottom() const;
+    std::optional<LayoutUnit> estimatedMarginTop() const { return m_estimatedMarginTop; }
 
     LayoutUnit borderTop() const;
     LayoutUnit borderLeft() const;
@@ -172,9 +173,9 @@
         BoxSizing boxSizing { BoxSizing::ContentBox };
     };
 
-    void setTopLeft(const LayoutPoint& topLeft) { m_topLeft = topLeft; }
-    void setTop(LayoutUnit top) { m_topLeft.setY(top); }
-    void setLeft(LayoutUnit left) { m_topLeft.setX(left); }
+    void setTopLeft(const LayoutPoint&);
+    void setTop(LayoutUnit);
+    void setLeft(LayoutUnit);
     void moveHorizontally(LayoutUnit offset) { m_topLeft.move(offset, { }); }
     void moveVertically(LayoutUnit offset) { m_topLeft.move({ }, offset); }
 
@@ -184,6 +185,7 @@
     void setHorizontalMargin(Layout::HorizontalEdges);
     void setVerticalMargin(Layout::VerticalEdges);
     void setVerticalNonCollapsedMargin(Layout::VerticalEdges);
+    void setEstimatedMarginTop(LayoutUnit marginTop) { m_estimatedMarginTop = marginTop; }
 
     void setBorder(Layout::Edges);
     void setPadding(std::optional<Layout::Edges>);
@@ -193,6 +195,8 @@
     void invalidateBorder() { m_hasValidBorder = false; }
     void invalidatePadding() { m_hasValidPadding = false; }
 
+    void setHasValidTop() { m_hasValidTop = true; }
+    void setHasValidLeft() { m_hasValidLeft = true; }
     void setHasValidVerticalMargin() { m_hasValidVerticalMargin = true; }
     void setHasValidVerticalNonCollapsedMargin() { m_hasValidVerticalNonCollapsedMargin = true; }
     void setHasValidHorizontalMargin() { m_hasValidHorizontalMargin = true; }
@@ -212,11 +216,14 @@
 
     Layout::Edges m_margin;
     Layout::VerticalEdges m_verticalNonCollapsedMargin;
+    std::optional<LayoutUnit> m_estimatedMarginTop;
 
     Layout::Edges m_border;
     std::optional<Layout::Edges> m_padding;
 
 #if !ASSERT_DISABLED
+    bool m_hasValidTop { false };
+    bool m_hasValidLeft { false };
     bool m_hasValidHorizontalMargin { false };
     bool m_hasValidVerticalMargin { false };
     bool m_hasValidVerticalNonCollapsedMargin { false };
@@ -416,6 +423,50 @@
     return m_rect;
 }
 
+inline LayoutUnit Box::top() const
+{
+    ASSERT(m_hasValidTop && (m_estimatedMarginTop || m_hasValidVerticalMargin));
+    return m_topLeft.y();
+}
+
+inline LayoutUnit Box::left() const
+{
+    ASSERT(m_hasValidLeft && m_hasValidHorizontalMargin);
+    return m_topLeft.x();
+}
+
+inline LayoutPoint Box::topLeft() const
+{
+    ASSERT(m_hasValidTop && (m_estimatedMarginTop || m_hasValidVerticalMargin));
+    ASSERT(m_hasValidLeft && m_hasValidHorizontalMargin);
+    return m_topLeft;
+}
+
+inline void Box::setTopLeft(const LayoutPoint& topLeft)
+{
+#if !ASSERT_DISABLED
+    setHasValidTop();
+    setHasValidLeft();
+#endif
+    m_topLeft = topLeft;
+}
+
+inline void Box::setTop(LayoutUnit top)
+{
+#if !ASSERT_DISABLED
+    setHasValidTop();
+#endif
+    m_topLeft.setY(top);
+}
+
+inline void Box::setLeft(LayoutUnit left)
+{
+#if !ASSERT_DISABLED
+    setHasValidLeft();
+#endif
+    m_topLeft.setX(left);
+}
+
 inline void Box::setContentBoxHeight(LayoutUnit height)
 { 
 #if !ASSERT_DISABLED
@@ -457,6 +508,7 @@
 #if !ASSERT_DISABLED
     setHasValidVerticalMargin();
 #endif
+    ASSERT(!m_estimatedMarginTop || *m_estimatedMarginTop == margin.top);
     m_margin.vertical = margin;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to