Title: [248262] trunk/Source/WebCore
Revision
248262
Author
[email protected]
Date
2019-08-04 03:16:06 -0700 (Sun, 04 Aug 2019)

Log Message

[LFC] Cleanup preferred width computation
https://bugs.webkit.org/show_bug.cgi?id=200426
<rdar://problem/53912607>

Reviewed by Antti Koivisto.

The intrinsic width for a formatting root box has 2 sets of values now. One set(min/max) is stored in the established formatting context's state
while the other is in the formatting context's state where the box lives.

<div style="position: absolute"><div style="float: left; border: 1px solid green">foobar</div></div>

The float box participates in the formatting context established by the absolutely position box, but it also establishes an inline formatting context.
The min/max width pair in the established context is the width of the "foobar" (same value for min/max). This set is stored in the inline formatting state.
However the float box has horizontal border so the "final" min/max width pair is expanded by this border value and stored in the formatting state where
the box lives (which is different from the one it establishes).

This and the "remove the formatting context type classes from the tree" changes open up interesting optimization opportunities.
Here is a very simple case:
<div style="display: inline-block; width: auto;">
  <div style="float: left">some text</div>
  <div style="float: left">some super long .... text</div>
  <div></div>
</div>
In order to lay out this content properly, we
1. Compute the min/max width of the first float (expensive text measuring)
2. Compute the min/max width of the second float (some more expensive text measuring)
3. Compute the min/max width of the inline-block (that is pretty much the 2 float's min/max)
4. Lay out the 2 floats, the empty div and the inline-block using these min/max width pairs.

Now if the inline-block box's display value is changed to "block" and the positioning is to absolute (style="display: box; position: absolute;")
we currently(on trunk) tear down the render tree, build a new one and run all the steps again from #1 to #4.

In LFC, we start with the following layout tree
<container> -> block formatting context
  <container> -> inline formatting context
    <anonymous inline box>
  <container> -> inline formatting context
    <anonymous inline box>
  <container> -> inline formatting context
and when the style change happens, we don't need to tear down the tree at all. Not only that, but since every formatting contexts stay the same
we can just reuse their states and actually skip all the steps (even the positioning since the absolutely positioned container has static top/bottom/left/right).

Surprisingly the final layout produces the exact same "display boxes" as the original layout.

* layout/FormattingContext.h:
(WebCore::Layout::FormattingContext::IntrinsicWidthConstraints::expand):
* layout/FormattingContextGeometry.cpp:
(WebCore::Layout::FormattingContext::Geometry::shrinkToFitWidth):
* layout/FormattingState.h:
(WebCore::Layout::FormattingState::setIntrinsicWidthConstraints):
(WebCore::Layout::FormattingState::intrinsicWidthConstraints const):
(WebCore::Layout::FormattingState::setIntrinsicWidthConstraintsForBox):
(WebCore::Layout::FormattingState::clearIntrinsicWidthConstraints):
(WebCore::Layout::FormattingState::intrinsicWidthConstraintsForBox const):
* layout/blockformatting/BlockFormattingContext.cpp:
(WebCore::Layout::BlockFormattingContext::computedIntrinsicWidthConstraints const):
(WebCore::Layout::BlockFormattingContext::computeIntrinsicWidthConstraints const): Deleted.
* layout/blockformatting/BlockFormattingContext.h:
* layout/blockformatting/BlockFormattingContextGeometry.cpp:
(WebCore::Layout::BlockFormattingContext::Geometry::intrinsicWidthConstraints):
(WebCore::Layout::BlockFormattingContext::Geometry::intrinsicWidthConstraintsNeedChildrenWidth): Deleted.
* layout/displaytree/DisplayBox.h:
(WebCore::Display::Box::horizontalMarginBorderAndPadding const):
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::nextInPreOrder):
(WebCore::Layout::InlineFormattingContext::computedIntrinsicWidthConstraints const):
(WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForFormattingRoot const):
(WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthConstraints const): Deleted.
(WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForFloatBox const): Deleted.
(WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForInlineBlock const): Deleted.
* layout/inlineformatting/InlineFormattingContext.h:
* layout/tableformatting/TableFormattingContext.cpp:
(WebCore::Layout::TableFormattingContext::computedIntrinsicWidthConstraints const):
* layout/tableformatting/TableFormattingContext.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (248261 => 248262)


--- trunk/Source/WebCore/ChangeLog	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/ChangeLog	2019-08-04 10:16:06 UTC (rev 248262)
@@ -1,3 +1,80 @@
+2019-08-04  Zalan Bujtas  <[email protected]>
+
+        [LFC] Cleanup preferred width computation
+        https://bugs.webkit.org/show_bug.cgi?id=200426
+        <rdar://problem/53912607>
+
+        Reviewed by Antti Koivisto.
+
+        The intrinsic width for a formatting root box has 2 sets of values now. One set(min/max) is stored in the established formatting context's state
+        while the other is in the formatting context's state where the box lives.
+
+        <div style="position: absolute"><div style="float: left; border: 1px solid green">foobar</div></div>
+
+        The float box participates in the formatting context established by the absolutely position box, but it also establishes an inline formatting context.
+        The min/max width pair in the established context is the width of the "foobar" (same value for min/max). This set is stored in the inline formatting state.
+        However the float box has horizontal border so the "final" min/max width pair is expanded by this border value and stored in the formatting state where
+        the box lives (which is different from the one it establishes).
+
+        This and the "remove the formatting context type classes from the tree" changes open up interesting optimization opportunities.
+        Here is a very simple case:
+        <div style="display: inline-block; width: auto;">
+          <div style="float: left">some text</div>
+          <div style="float: left">some super long .... text</div>
+          <div></div>
+        </div>
+        In order to lay out this content properly, we
+        1. Compute the min/max width of the first float (expensive text measuring)
+        2. Compute the min/max width of the second float (some more expensive text measuring)
+        3. Compute the min/max width of the inline-block (that is pretty much the 2 float's min/max)
+        4. Lay out the 2 floats, the empty div and the inline-block using these min/max width pairs.
+
+        Now if the inline-block box's display value is changed to "block" and the positioning is to absolute (style="display: box; position: absolute;")
+        we currently(on trunk) tear down the render tree, build a new one and run all the steps again from #1 to #4.
+
+        In LFC, we start with the following layout tree
+        <container> -> block formatting context
+          <container> -> inline formatting context
+            <anonymous inline box>
+          <container> -> inline formatting context
+            <anonymous inline box>
+          <container> -> inline formatting context
+        and when the style change happens, we don't need to tear down the tree at all. Not only that, but since every formatting contexts stay the same
+        we can just reuse their states and actually skip all the steps (even the positioning since the absolutely positioned container has static top/bottom/left/right).
+
+        Surprisingly the final layout produces the exact same "display boxes" as the original layout.
+
+        * layout/FormattingContext.h:
+        (WebCore::Layout::FormattingContext::IntrinsicWidthConstraints::expand):
+        * layout/FormattingContextGeometry.cpp:
+        (WebCore::Layout::FormattingContext::Geometry::shrinkToFitWidth):
+        * layout/FormattingState.h:
+        (WebCore::Layout::FormattingState::setIntrinsicWidthConstraints):
+        (WebCore::Layout::FormattingState::intrinsicWidthConstraints const):
+        (WebCore::Layout::FormattingState::setIntrinsicWidthConstraintsForBox):
+        (WebCore::Layout::FormattingState::clearIntrinsicWidthConstraints):
+        (WebCore::Layout::FormattingState::intrinsicWidthConstraintsForBox const):
+        * layout/blockformatting/BlockFormattingContext.cpp:
+        (WebCore::Layout::BlockFormattingContext::computedIntrinsicWidthConstraints const):
+        (WebCore::Layout::BlockFormattingContext::computeIntrinsicWidthConstraints const): Deleted.
+        * layout/blockformatting/BlockFormattingContext.h:
+        * layout/blockformatting/BlockFormattingContextGeometry.cpp:
+        (WebCore::Layout::BlockFormattingContext::Geometry::intrinsicWidthConstraints):
+        (WebCore::Layout::BlockFormattingContext::Geometry::intrinsicWidthConstraintsNeedChildrenWidth): Deleted.
+        * layout/displaytree/DisplayBox.h:
+        (WebCore::Display::Box::horizontalMarginBorderAndPadding const):
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::nextInPreOrder):
+        (WebCore::Layout::InlineFormattingContext::computedIntrinsicWidthConstraints const):
+        (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForFormattingRoot const):
+        (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthConstraints const): Deleted.
+        (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForFloatBox const): Deleted.
+        (WebCore::Layout::InlineFormattingContext::computeIntrinsicWidthForInlineBlock const): Deleted.
+        * layout/inlineformatting/InlineFormattingContext.h:
+        * layout/tableformatting/TableFormattingContext.cpp:
+        (WebCore::Layout::TableFormattingContext::computedIntrinsicWidthConstraints const):
+        * layout/tableformatting/TableFormattingContext.h:
+
 2019-08-03  Devin Rousso  <[email protected]>
 
         Web Inspector: DOM: add a special breakpoint for "All Events"

Modified: trunk/Source/WebCore/layout/FormattingContext.h (248261 => 248262)


--- trunk/Source/WebCore/layout/FormattingContext.h	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/FormattingContext.h	2019-08-04 10:16:06 UTC (rev 248262)
@@ -53,10 +53,12 @@
     void layoutOutOfFlowDescendants(const Box&) const;
 
     struct IntrinsicWidthConstraints {
+        void expand(LayoutUnit horizontalValue);
+
         LayoutUnit minimum;
         LayoutUnit maximum;
     };
-    virtual void computeIntrinsicWidthConstraints() const = 0;
+    virtual IntrinsicWidthConstraints computedIntrinsicWidthConstraints() const = 0;
 
     static Display::Box mapBoxToAncestor(const LayoutState&, const Box&, const Container& ancestor);
     static LayoutUnit mapTopToAncestor(const LayoutState&, const Box&, const Container& ancestor);
@@ -139,6 +141,12 @@
     FormattingState& m_formattingState;
 };
 
+inline void FormattingContext::IntrinsicWidthConstraints::expand(LayoutUnit horizontalValue)
+{
+    minimum += horizontalValue;
+    maximum += horizontalValue;
 }
+
 }
+}
 #endif

Modified: trunk/Source/WebCore/layout/FormattingContextGeometry.cpp (248261 => 248262)


--- trunk/Source/WebCore/layout/FormattingContextGeometry.cpp	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/FormattingContextGeometry.cpp	2019-08-04 10:16:06 UTC (rev 248262)
@@ -250,12 +250,10 @@
     // 'padding-left', 'padding-right', 'border-right-width', 'margin-right', and the widths of any relevant scroll bars.
 
     // Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).
-    auto& formattingStateForRoot = layoutState.formattingStateForBox(formattingRoot);
-    auto intrinsicWidthConstraints = formattingStateForRoot.intrinsicWidthConstraints(formattingRoot);
-    if (!intrinsicWidthConstraints) {
-        layoutState.createFormattingContext(formattingRoot)->computeIntrinsicWidthConstraints();
-        intrinsicWidthConstraints = formattingStateForRoot.intrinsicWidthConstraints(formattingRoot);
-    }
+    auto& formattingStateForRoot = layoutState.createFormattingStateForFormattingRootIfNeeded(formattingRoot);
+    auto intrinsicWidthConstraints = formattingStateForRoot.intrinsicWidthConstraints();
+    if (!intrinsicWidthConstraints)
+        intrinsicWidthConstraints = layoutState.createFormattingContext(formattingRoot)->computedIntrinsicWidthConstraints();
     auto availableWidth = *usedValues.containingBlockWidth;
     return std::min(std::max(intrinsicWidthConstraints->minimum, availableWidth), intrinsicWidthConstraints->maximum);
 }

Modified: trunk/Source/WebCore/layout/FormattingState.h (248261 => 248262)


--- trunk/Source/WebCore/layout/FormattingState.h	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/FormattingState.h	2019-08-04 10:16:06 UTC (rev 248262)
@@ -51,10 +51,13 @@
     void markNeedsLayout(const Box&, StyleDiff);
     bool needsLayout(const Box&);
 
-    void setIntrinsicWidthConstraints(const Box&,  FormattingContext::IntrinsicWidthConstraints);
+    void setIntrinsicWidthConstraintsForBox(const Box&,  FormattingContext::IntrinsicWidthConstraints);
+    Optional<FormattingContext::IntrinsicWidthConstraints> intrinsicWidthConstraintsForBox(const Box&) const;
     void clearIntrinsicWidthConstraints(const Box&);
-    Optional<FormattingContext::IntrinsicWidthConstraints> intrinsicWidthConstraints(const Box&) const;
 
+    void setIntrinsicWidthConstraints(FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraints) { m_intrinsicWidthConstraints = intrinsicWidthConstraints; }
+    Optional<FormattingContext::IntrinsicWidthConstraints> intrinsicWidthConstraints() const { return m_intrinsicWidthConstraints; }
+
     bool isBlockFormattingState() const { return m_type == Type::Block; }
     bool isInlineFormattingState() const { return m_type == Type::Inline; }
     bool isTableFormattingState() const { return m_type == Type::Table; }
@@ -68,27 +71,29 @@
 private:
     LayoutState& m_layoutState;
     Ref<FloatingState> m_floatingState;
-    HashMap<const Box*, FormattingContext::IntrinsicWidthConstraints> m_intrinsicWidthConstraints;
+    HashMap<const Box*, FormattingContext::IntrinsicWidthConstraints> m_intrinsicWidthConstraintsForBoxes;
+    Optional<FormattingContext::IntrinsicWidthConstraints> m_intrinsicWidthConstraints;
     Type m_type;
 };
 
-inline void FormattingState::setIntrinsicWidthConstraints(const Box& layoutBox, FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraints)
+inline void FormattingState::setIntrinsicWidthConstraintsForBox(const Box& layoutBox, FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraints)
 {
-    ASSERT(!m_intrinsicWidthConstraints.contains(&layoutBox));
+    ASSERT(!m_intrinsicWidthConstraintsForBoxes.contains(&layoutBox));
     ASSERT(&m_layoutState.formattingStateForBox(layoutBox) == this);
-    m_intrinsicWidthConstraints.set(&layoutBox, intrinsicWidthConstraints);
+    m_intrinsicWidthConstraintsForBoxes.set(&layoutBox, intrinsicWidthConstraints);
 }
 
 inline void FormattingState::clearIntrinsicWidthConstraints(const Box& layoutBox)
 {
-    m_intrinsicWidthConstraints.remove(&layoutBox);
+    m_intrinsicWidthConstraints = { };
+    m_intrinsicWidthConstraintsForBoxes.remove(&layoutBox);
 }
 
-inline Optional<FormattingContext::IntrinsicWidthConstraints> FormattingState::intrinsicWidthConstraints(const Box& layoutBox) const
+inline Optional<FormattingContext::IntrinsicWidthConstraints> FormattingState::intrinsicWidthConstraintsForBox(const Box& layoutBox) const
 {
     ASSERT(&m_layoutState.formattingStateForBox(layoutBox) == this);
-    auto iterator = m_intrinsicWidthConstraints.find(&layoutBox);
-    if (iterator == m_intrinsicWidthConstraints.end())
+    auto iterator = m_intrinsicWidthConstraintsForBoxes.find(&layoutBox);
+    if (iterator == m_intrinsicWidthConstraintsForBoxes.end())
         return { };
     return iterator->value;
 }

Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp (248261 => 248262)


--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp	2019-08-04 10:16:06 UTC (rev 248262)
@@ -452,17 +452,13 @@
     MarginCollapse::updateMarginAfterForPreviousSibling(layoutState, layoutBox);
 }
 
-void BlockFormattingContext::computeIntrinsicWidthConstraints() const
+FormattingContext::IntrinsicWidthConstraints BlockFormattingContext::computedIntrinsicWidthConstraints() const
 {
     auto& layoutState = this->layoutState();
     auto& formattingRoot = root();
-    auto& formattingStateForRoot = layoutState.formattingStateForBox(formattingRoot);
-    ASSERT(!formattingStateForRoot.intrinsicWidthConstraints(formattingRoot));
+    auto& formattingState = this->formattingState();
+    ASSERT(!formattingState.intrinsicWidthConstraints());
 
-    // Can we just compute them without checking the children?
-    if (!Geometry::intrinsicWidthConstraintsNeedChildrenWidth(formattingRoot))
-        return formattingStateForRoot.setIntrinsicWidthConstraints(formattingRoot, Geometry::intrinsicWidthConstraints(layoutState, formattingRoot));
-
     // Visit the in-flow descendants and compute their min/max intrinsic width if needed.
     // 1. Go all the way down to the leaf node
     // 2. Check if actually need to visit all the boxes as we traverse down (already computed, container's min/max does not depend on descendants etc)
@@ -469,50 +465,38 @@
     // 3. As we climb back on the tree, compute min/max intrinsic width
     // (Any subtrees with new formatting contexts need to layout synchronously)
     Vector<const Box*> queue;
-    ASSERT(is<Container>(formattingRoot));
-    if (auto* firstChild = downcast<Container>(formattingRoot).firstInFlowOrFloatingChild())
-        queue.append(firstChild);
+    if (is<Container>(formattingRoot) && downcast<Container>(formattingRoot).hasInFlowOrFloatingChild())
+        queue.append(downcast<Container>(formattingRoot).firstInFlowOrFloatingChild());
 
-    auto& formattingState = this->formattingState();
+    IntrinsicWidthConstraints constraints;
     while (!queue.isEmpty()) {
         while (true) {
-            auto& childBox = *queue.last();
-            auto childIntrinsicWidthConstraints = formattingState.intrinsicWidthConstraints(childBox);
-            auto skipDescendants = childIntrinsicWidthConstraints || !Geometry::intrinsicWidthConstraintsNeedChildrenWidth(childBox) || childBox.establishesFormattingContext();
-
-            if (skipDescendants) {
-                if (!childIntrinsicWidthConstraints) {
-                    if (!Geometry::intrinsicWidthConstraintsNeedChildrenWidth(childBox))
-                        formattingState.setIntrinsicWidthConstraints(childBox, Geometry::intrinsicWidthConstraints(layoutState, childBox));
-                    else if (childBox.establishesFormattingContext())
-                        layoutState.createFormattingContext(childBox)->computeIntrinsicWidthConstraints();
-                    else
-                        ASSERT_NOT_REACHED();
-                }
-                queue.removeLast();
-                if (!childBox.nextInFlowOrFloatingSibling())
-                    break;
-                queue.append(childBox.nextInFlowOrFloatingSibling());
-                // Skip descendants
-                continue;
-            }
-            if (!is<Container>(childBox) || !downcast<Container>(childBox).hasInFlowOrFloatingChild())
+            auto& layoutBox = *queue.last();
+            auto hasInFlowOrFloatingChild = is<Container>(layoutBox) && downcast<Container>(layoutBox).hasInFlowOrFloatingChild();
+            auto skipDescendants = formattingState.intrinsicWidthConstraintsForBox(layoutBox) || !hasInFlowOrFloatingChild || layoutBox.establishesFormattingContext() || layoutBox.style().width().isFixed();
+            if (skipDescendants)
                 break;
-            queue.append(downcast<Container>(childBox).firstInFlowOrFloatingChild());
+            queue.append(downcast<Container>(layoutBox).firstInFlowOrFloatingChild());
         }
-
-        // Compute min/max intrinsic width bottom up.
+        // Compute min/max intrinsic width bottom up if needed.
         while (!queue.isEmpty()) {
-            auto& childBox = *queue.takeLast();
-            formattingState.setIntrinsicWidthConstraints(childBox, Geometry::intrinsicWidthConstraints(layoutState, childBox)); 
+            auto& layoutBox = *queue.takeLast();
+            auto desdendantConstraints = formattingState.intrinsicWidthConstraintsForBox(layoutBox); 
+            if (!desdendantConstraints) {
+                desdendantConstraints = Geometry::intrinsicWidthConstraints(layoutState, layoutBox);
+                formattingState.setIntrinsicWidthConstraintsForBox(layoutBox, *desdendantConstraints);
+            }
+            constraints.minimum = std::max(constraints.minimum, desdendantConstraints->minimum);
+            constraints.maximum = std::max(constraints.maximum, desdendantConstraints->maximum);
             // Move over to the next sibling or take the next box in the queue.
-            if (auto* nextSibling = childBox.nextInFlowOrFloatingSibling()) {
+            if (auto* nextSibling = layoutBox.nextInFlowOrFloatingSibling()) {
                 queue.append(nextSibling);
                 break;
             }
         }
     }
-    formattingStateForRoot.setIntrinsicWidthConstraints(formattingRoot, Geometry::intrinsicWidthConstraints(layoutState, formattingRoot));
+    formattingState.setIntrinsicWidthConstraints(constraints);
+    return constraints;
 }
 
 LayoutUnit BlockFormattingContext::verticalPositionWithMargin(const Box& layoutBox, const UsedVerticalMargin& verticalMargin) const

Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h (248261 => 248262)


--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContext.h	2019-08-04 10:16:06 UTC (rev 248262)
@@ -69,7 +69,7 @@
     void computeEstimatedVerticalPositionForFormattingRoot(const Box&) const;
     void computeEstimatedVerticalPositionForFloatClear(const FloatingContext&, const Box&) const;
 
-    void computeIntrinsicWidthConstraints() const override;
+    IntrinsicWidthConstraints computedIntrinsicWidthConstraints() const override;
     LayoutUnit verticalPositionWithMargin(const Box&, const UsedVerticalMargin&) const;
 
     // This class implements positioning and sizing for boxes participating in a block formatting context.
@@ -82,8 +82,7 @@
         static LayoutUnit staticVerticalPosition(const LayoutState&, const Box&);
         static LayoutUnit staticHorizontalPosition(const LayoutState&, const Box&);
 
-        static bool intrinsicWidthConstraintsNeedChildrenWidth(const Box&);
-        static IntrinsicWidthConstraints intrinsicWidthConstraints(const LayoutState&, const Box&);
+        static IntrinsicWidthConstraints intrinsicWidthConstraints(LayoutState&, const Box&);
 
     private:
         static HeightAndMargin inFlowNonReplacedHeightAndMargin(const LayoutState&, const Box&, UsedVerticalValues);

Modified: trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp (248261 => 248262)


--- trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp	2019-08-04 10:16:06 UTC (rev 248262)
@@ -285,15 +285,18 @@
     return inFlowReplacedWidthAndMargin(layoutState, layoutBox, usedValues);
 }
 
-bool BlockFormattingContext::Geometry::intrinsicWidthConstraintsNeedChildrenWidth(const Box& layoutBox)
+FormattingContext::IntrinsicWidthConstraints BlockFormattingContext::Geometry::intrinsicWidthConstraints(LayoutState& layoutState, const Box& layoutBox)
 {
-    if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
-        return false;
-    return layoutBox.style().width().isAuto();
-}
+    auto fixedMarginBorderAndPadding = [&](auto& layoutBox) {
+        auto& style = layoutBox.style();
+        return fixedValue(style.marginStart()).valueOr(0)
+            + LayoutUnit { style.borderLeftWidth() }
+            + fixedValue(style.paddingLeft()).valueOr(0)
+            + fixedValue(style.paddingRight()).valueOr(0)
+            + LayoutUnit { style.borderRightWidth() }
+            + fixedValue(style.marginEnd()).valueOr(0);
+    };
 
-FormattingContext::IntrinsicWidthConstraints BlockFormattingContext::Geometry::intrinsicWidthConstraints(const LayoutState& layoutState, const Box& layoutBox)
-{
     auto computedIntrinsicWidthConstraints = [&]() -> IntrinsicWidthConstraints {
         auto& style = layoutBox.style();
         if (auto width = fixedValue(style.logicalWidth()))
@@ -311,32 +314,31 @@
             return { };
         }
 
-        if (!is<Container>(layoutBox))
+        if (layoutBox.establishesFormattingContext())
+            return layoutState.createFormattingContext(layoutBox)->computedIntrinsicWidthConstraints();
+
+        if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
             return { };
 
         auto intrinsicWidthConstraints = IntrinsicWidthConstraints { };
+        auto& formattingState = layoutState.formattingStateForBox(layoutBox);
         for (auto& child : childrenOfType<Box>(downcast<Container>(layoutBox))) {
             if (child.isOutOfFlowPositioned())
                 continue;
-            const auto& formattingState = layoutState.formattingStateForBox(child);
-            ASSERT(formattingState.isBlockFormattingState());
-            auto childIntrinsicWidthConstraints = formattingState.intrinsicWidthConstraints(child);
+            auto childIntrinsicWidthConstraints = formattingState.intrinsicWidthConstraintsForBox(child);
             ASSERT(childIntrinsicWidthConstraints);
 
-            auto& childStyle = child.style();
-            auto marginBorderAndPadding = fixedValue(childStyle.marginStart()).valueOr(0)
-                + LayoutUnit { childStyle.borderLeftWidth() }
-                + fixedValue(childStyle.paddingLeft()).valueOr(0)
-                + fixedValue(childStyle.paddingRight()).valueOr(0)
-                + LayoutUnit { childStyle.borderRightWidth() }
-                + fixedValue(childStyle.marginEnd()).valueOr(0);
+            // FIXME Check for box-sizing: border-box;
+            auto marginBorderAndPadding = fixedMarginBorderAndPadding(child);
             intrinsicWidthConstraints.minimum = std::max(intrinsicWidthConstraints.minimum, childIntrinsicWidthConstraints->minimum + marginBorderAndPadding);
             intrinsicWidthConstraints.maximum = std::max(intrinsicWidthConstraints.maximum, childIntrinsicWidthConstraints->maximum + marginBorderAndPadding);
         }
         return intrinsicWidthConstraints;
     };
-
-    return constrainByMinMaxWidth(layoutBox, computedIntrinsicWidthConstraints());
+    // FIXME Check for box-sizing: border-box;
+    auto intrinsicWidthConstraints = constrainByMinMaxWidth(layoutBox, computedIntrinsicWidthConstraints());
+    intrinsicWidthConstraints.expand(fixedMarginBorderAndPadding(layoutBox));
+    return intrinsicWidthConstraints;
 }
 
 }

Modified: trunk/Source/WebCore/layout/displaytree/DisplayBox.h (248261 => 248262)


--- trunk/Source/WebCore/layout/displaytree/DisplayBox.h	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/displaytree/DisplayBox.h	2019-08-04 10:16:06 UTC (rev 248262)
@@ -124,6 +124,8 @@
     LayoutUnit marginBoxHeight() const { return marginBefore() + borderBoxHeight() + marginAfter(); }
     LayoutUnit marginBoxWidth() const { return marginStart() + borderBoxWidth() + marginEnd(); }
 
+    LayoutUnit horizontalMarginBorderAndPadding() const { return marginStart() + horizontalBorder() + horizontalPadding().valueOr(0) + marginEnd(); }
+
     Rect marginBox() const;
     Rect nonCollapsedMarginBox() const;
 

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp (248261 => 248262)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp	2019-08-04 10:16:06 UTC (rev 248262)
@@ -49,13 +49,13 @@
 {
 }
 
-static inline const Box* nextInPreOrder(const Box& layoutBox, const Container& root)
+static inline const Box* nextInPreOrder(const Box& layoutBox, const Container& stayWithin)
 {
     const Box* nextInPreOrder = nullptr;
     if (!layoutBox.establishesFormattingContext() && is<Container>(layoutBox) && downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
         return downcast<Container>(layoutBox).firstInFlowOrFloatingChild();
 
-    for (nextInPreOrder = &layoutBox; nextInPreOrder && nextInPreOrder != &root; nextInPreOrder = nextInPreOrder->parent()) {
+    for (nextInPreOrder = &layoutBox; nextInPreOrder && nextInPreOrder != &stayWithin; nextInPreOrder = nextInPreOrder->parent()) {
         if (auto* nextSibling = nextInPreOrder->nextInFlowOrFloatingSibling())
             return nextSibling;
     }
@@ -99,18 +99,18 @@
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> formatting root(" << &root << ")");
 }
 
-void InlineFormattingContext::computeIntrinsicWidthConstraints() const
+FormattingContext::IntrinsicWidthConstraints InlineFormattingContext::computedIntrinsicWidthConstraints() const
 {
     auto& layoutState = this->layoutState();
-    ASSERT(!layoutState.formattingStateForBox(root()).intrinsicWidthConstraints(root()));
+    ASSERT(!formattingState().intrinsicWidthConstraints());
 
-    ASSERT(is<Container>(root()));
-    auto& root = downcast<Container>(this->root());
-    if (!root.hasInFlowOrFloatingChild()) {
-        layoutState.formattingStateForBox(root).setIntrinsicWidthConstraints(root, Geometry::constrainByMinMaxWidth(root, { 0, 0 }));
-        return;
+    if (!is<Container>(root()) || !downcast<Container>(root()).hasInFlowOrFloatingChild()) {
+        auto constraints = Geometry::constrainByMinMaxWidth(root(), { });
+        formattingState().setIntrinsicWidthConstraints(constraints);
+        return constraints;
     }
 
+    auto& root = downcast<Container>(this->root());
     Vector<const Box*> formattingContextRootList;
     auto usedValues = UsedHorizontalValues { };
     auto* layoutBox = root.firstInFlowOrFloatingChild();
@@ -117,16 +117,11 @@
     while (layoutBox) {
         if (layoutBox->establishesFormattingContext()) {
             formattingContextRootList.append(layoutBox);
-            if (layoutBox->isFloatingPositioned())
-                computeIntrinsicWidthForFloatBox(*layoutBox);
-            else if (layoutBox->isInlineBlockBox())
-                computeIntrinsicWidthForInlineBlock(*layoutBox);
-            else
-                ASSERT_NOT_REACHED();
+            computeIntrinsicWidthForFormattingRoot(*layoutBox);
         } else if (layoutBox->isReplaced() || is<Container>(*layoutBox)) {
             computeBorderAndPadding(*layoutBox, usedValues);
             // inline-block and replaced.
-            auto needsWidthComputation = layoutBox->isReplaced() || layoutBox->establishesFormattingContext();
+            auto needsWidthComputation = layoutBox->isReplaced();
             if (needsWidthComputation)
                 computeWidthAndMargin(*layoutBox, usedValues);
             else {
@@ -142,14 +137,17 @@
     auto maximumLineWidth = [&](auto availableWidth) {
         // Switch to the min/max formatting root width values before formatting the lines.
         for (auto* formattingRoot : formattingContextRootList) {
-            auto intrinsicWidths = layoutState.formattingStateForBox(*formattingRoot).intrinsicWidthConstraints(*formattingRoot);
-            layoutState.displayBoxForLayoutBox(*formattingRoot).setContentBoxWidth(availableWidth ? intrinsicWidths->maximum : intrinsicWidths->minimum);
+            auto intrinsicWidths = layoutState.formattingStateForBox(*formattingRoot).intrinsicWidthConstraintsForBox(*formattingRoot);
+            auto& displayBox = layoutState.displayBoxForLayoutBox(*formattingRoot);
+            auto contentWidth = (availableWidth ? intrinsicWidths->maximum : intrinsicWidths->minimum) - displayBox.horizontalMarginBorderAndPadding();
+            displayBox.setContentBoxWidth(contentWidth);
         }
         return InlineLayout(*this).computedIntrinsicWidth(formattingState().inlineItems(), availableWidth);
     };
 
-    auto intrinsicWidthConstraints = Geometry::constrainByMinMaxWidth(root, { maximumLineWidth(0), maximumLineWidth(LayoutUnit::max()) });
-    layoutState.formattingStateForBox(root).setIntrinsicWidthConstraints(root, intrinsicWidthConstraints);
+    auto constraints = Geometry::constrainByMinMaxWidth(root, { maximumLineWidth(0), maximumLineWidth(LayoutUnit::max()) });
+    formattingState().setIntrinsicWidthConstraints(constraints);
+    return constraints;
 }
 
 void InlineFormattingContext::initializeMarginBorderAndPaddingForGenericInlineBox(const Box& layoutBox) const
@@ -171,24 +169,23 @@
     layoutState().displayBoxForLayoutBox(container).setVerticalMargin({ { }, { } });
 }
 
-void InlineFormattingContext::computeIntrinsicWidthForFloatBox(const Box& layoutBox) const
+void InlineFormattingContext::computeIntrinsicWidthForFormattingRoot(const Box& formattingRoot) const
 {
-    ASSERT(layoutBox.isFloatingPositioned());
+    ASSERT(formattingRoot.establishesFormattingContext());
+    auto& layoutState = this->layoutState();
 
     auto usedValues = UsedHorizontalValues { };
-    computeBorderAndPadding(layoutBox, usedValues);
-    computeHorizontalMargin(layoutBox, usedValues);
-    layoutState().createFormattingContext(layoutBox)->computeIntrinsicWidthConstraints();
-}
+    computeBorderAndPadding(formattingRoot, usedValues);
+    computeHorizontalMargin(formattingRoot, usedValues);
 
-void InlineFormattingContext::computeIntrinsicWidthForInlineBlock(const Box& layoutBox) const
-{
-    ASSERT(layoutBox.isInlineBlockBox());
-
-    auto usedValues = UsedHorizontalValues { };
-    computeBorderAndPadding(layoutBox, usedValues);
-    computeHorizontalMargin(layoutBox, usedValues);
-    layoutState().createFormattingContext(layoutBox)->computeIntrinsicWidthConstraints();
+    IntrinsicWidthConstraints constraints;
+    if (auto fixedWidth = Geometry::fixedValue(formattingRoot.style().logicalWidth()))
+        constraints = { *fixedWidth, *fixedWidth };
+    else
+        constraints = layoutState.createFormattingContext(formattingRoot)->computedIntrinsicWidthConstraints();
+    constraints = Geometry::constrainByMinMaxWidth(formattingRoot, constraints);
+    constraints.expand(layoutState.displayBoxForLayoutBox(formattingRoot).horizontalMarginBorderAndPadding());
+    formattingState().setIntrinsicWidthConstraintsForBox(formattingRoot, constraints);
 }
 
 void InlineFormattingContext::computeHorizontalMargin(const Box& layoutBox, UsedHorizontalValues usedValues) const

Modified: trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h (248261 => 248262)


--- trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/inlineformatting/InlineFormattingContext.h	2019-08-04 10:16:06 UTC (rev 248262)
@@ -49,7 +49,7 @@
     void layout() const override;
 
 private:
-    void computeIntrinsicWidthConstraints() const override;
+    IntrinsicWidthConstraints computedIntrinsicWidthConstraints() const override;
 
     class InlineLayout {
     public:
@@ -81,10 +81,9 @@
     };
 
     void layoutFormattingContextRoot(const Box&, UsedHorizontalValues) const;
-    void computeIntrinsicWidthForFloatBox(const Box&) const;
     void computeMarginBorderAndPaddingForInlineContainer(const Container&, UsedHorizontalValues) const;
     void initializeMarginBorderAndPaddingForGenericInlineBox(const Box&) const;
-    void computeIntrinsicWidthForInlineBlock(const Box&) const;
+    void computeIntrinsicWidthForFormattingRoot(const Box&) const;
     void computeWidthAndHeightForReplacedInlineBox(const Box&, UsedHorizontalValues) const;
     void computeHorizontalMargin(const Box&, UsedHorizontalValues) const;
     void computeHeightAndMargin(const Box&) const;

Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp (248261 => 248262)


--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp	2019-08-04 10:16:06 UTC (rev 248262)
@@ -46,7 +46,12 @@
 {
 }
 
+FormattingContext::IntrinsicWidthConstraints TableFormattingContext::computedIntrinsicWidthConstraints() const
+{
+    return { };
 }
+
 }
+}
 
 #endif

Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h (248261 => 248262)


--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h	2019-08-04 03:24:27 UTC (rev 248261)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h	2019-08-04 10:16:06 UTC (rev 248262)
@@ -41,6 +41,9 @@
 public:
     TableFormattingContext(const Box& formattingContextRoot, TableFormattingState&);
     void layout() const override;
+
+private:
+    IntrinsicWidthConstraints computedIntrinsicWidthConstraints() const override;
 };
 
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to