[LFC] Implement BlockFormattingContext::layout logic and its dependencies
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Apr 2018 18:17:46 +0000 (18:17 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Apr 2018 18:17:46 +0000 (18:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185024

Reviewed by Antti Koivisto.

This patch implements the logic for block formatting context according to
https://www.w3.org/TR/CSS22/visuren.html#block-formatting

1. Traverse the tree iteratively (in post-order fashion) and compute the width/static position for the containers as
we visit the descendant nodes until we hit a leaf node.
2. Compute the position/geometry of the leaf node and move over to its sibling(s).
3. Finalize the container's height/final position as we climb back on the tree.
4. Run layout on the out-of-flow descendants.

Note that subtrees with a formatting context root need to be laid out completely before moving on to the next box.
The formatting root box is laid out in the formatting context it lives in, however its descendants get laid out
in a separate formatting context (excluding out-of-flow boxes that don't belong to the root).

* layout/FloatingContext.cpp:
(WebCore::Layout::FloatingContext::FloatingContext):
(WebCore::Layout::FloatingContext::computePosition):
* layout/FormattingContext.cpp:
(WebCore::Layout::FormattingContext::placeInFlowPositionedChildren const):
(WebCore::Layout::FormattingContext::layoutOutOfFlowDescendants const):
* layout/FormattingContext.h:
* layout/LayoutContext.cpp:
(WebCore::Layout::LayoutContext::updateLayout):
(WebCore::Layout::LayoutContext::establishedFormattingState):
* layout/LayoutContext.h:
* layout/blockformatting/BlockFormattingContext.cpp:
(WebCore::Layout::BlockFormattingContext::layout const):
(WebCore::Layout::BlockFormattingContext::layout): Deleted.
* layout/blockformatting/BlockFormattingContext.h:
* layout/inlineformatting/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::layout const):
(WebCore::Layout::InlineFormattingContext::layout): Deleted.
* layout/inlineformatting/InlineFormattingContext.h:

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

Source/WebCore/ChangeLog
Source/WebCore/layout/FloatingContext.cpp
Source/WebCore/layout/FormattingContext.cpp
Source/WebCore/layout/FormattingContext.h
Source/WebCore/layout/LayoutContext.cpp
Source/WebCore/layout/LayoutContext.h
Source/WebCore/layout/blockformatting/BlockFormattingContext.cpp
Source/WebCore/layout/blockformatting/BlockFormattingContext.h
Source/WebCore/layout/inlineformatting/InlineFormattingContext.cpp
Source/WebCore/layout/inlineformatting/InlineFormattingContext.h

index 742c8334a0f0c88e2be4366e03a8e20e95a05677..7d99846b09e828719ba00103ca32dcaf8aa80cd2 100644 (file)
@@ -1,3 +1,43 @@
+2018-04-27  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC] Implement BlockFormattingContext::layout logic and its dependencies
+        https://bugs.webkit.org/show_bug.cgi?id=185024
+
+        Reviewed by Antti Koivisto.
+
+        This patch implements the logic for block formatting context according to
+        https://www.w3.org/TR/CSS22/visuren.html#block-formatting
+
+        1. Traverse the tree iteratively (in post-order fashion) and compute the width/static position for the containers as
+        we visit the descendant nodes until we hit a leaf node.
+        2. Compute the position/geometry of the leaf node and move over to its sibling(s).
+        3. Finalize the container's height/final position as we climb back on the tree.
+        4. Run layout on the out-of-flow descendants.  
+
+        Note that subtrees with a formatting context root need to be laid out completely before moving on to the next box.
+        The formatting root box is laid out in the formatting context it lives in, however its descendants get laid out
+        in a separate formatting context (excluding out-of-flow boxes that don't belong to the root). 
+
+        * layout/FloatingContext.cpp:
+        (WebCore::Layout::FloatingContext::FloatingContext):
+        (WebCore::Layout::FloatingContext::computePosition):
+        * layout/FormattingContext.cpp:
+        (WebCore::Layout::FormattingContext::placeInFlowPositionedChildren const):
+        (WebCore::Layout::FormattingContext::layoutOutOfFlowDescendants const):
+        * layout/FormattingContext.h:
+        * layout/LayoutContext.cpp:
+        (WebCore::Layout::LayoutContext::updateLayout):
+        (WebCore::Layout::LayoutContext::establishedFormattingState):
+        * layout/LayoutContext.h:
+        * layout/blockformatting/BlockFormattingContext.cpp:
+        (WebCore::Layout::BlockFormattingContext::layout const):
+        (WebCore::Layout::BlockFormattingContext::layout): Deleted.
+        * layout/blockformatting/BlockFormattingContext.h:
+        * layout/inlineformatting/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::layout const):
+        (WebCore::Layout::InlineFormattingContext::layout): Deleted.
+        * layout/inlineformatting/InlineFormattingContext.h:
+
 2018-04-27  Youenn Fablet  <youenn@apple.com>
 
         Use NetworkLoadChecker for XHR/fetch loads
index 92872aa3a749c00d52efd6a18390d1a735aef8a1..f7430cda44b495894e6cb138376ff3f409a28e6b 100644 (file)
 
 #include "config.h"
 #include "FloatingContext.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(FloatingContext);
+
+FloatingContext::FloatingContext(FloatingState&)
+{
+}
+
+void FloatingContext::computePosition(const Box&)
+{
+}
+
+}
+}
+#endif
index dca0475ea58a7e8cf3288659ce551b16553b0c53..9840a3fb240e10438d57bfef08fcc5a360a3e915 100644 (file)
@@ -85,6 +85,14 @@ LayoutUnit FormattingContext::marginRight(const Box&) const
     return 0;
 }
 
+void FormattingContext::placeInFlowPositionedChildren(const Container&) const
+{
+}
+
+void FormattingContext::layoutOutOfFlowDescendants() const
+{
+}
+
 }
 }
 #endif
index bde31e212262915681ca7046050a08b0e404e760..c6c146143df5b7385e7a9e447495cf21ede6526a 100644 (file)
@@ -37,6 +37,7 @@ namespace WebCore {
 namespace Layout {
 
 class Box;
+class Container;
 class FormattingState;
 class LayoutContext;
 
@@ -46,7 +47,7 @@ public:
     FormattingContext(const Box& formattingContextRoot, LayoutContext&);
     virtual ~FormattingContext();
 
-    virtual void layout(FormattingState&) = 0;
+    virtual void layout(LayoutContext&, FormattingState&) const = 0;
     virtual std::unique_ptr<FormattingState> createFormattingState(Ref<FloatingState>&&) const = 0;
     virtual Ref<FloatingState> createOrFindFloatingState() const = 0;
 
@@ -66,6 +67,9 @@ protected:
     virtual LayoutUnit marginBottom(const Box&) const;
     virtual LayoutUnit marginRight(const Box&) const;
 
+    void placeInFlowPositionedChildren(const Container&) const;
+    void layoutOutOfFlowDescendants() const;
+
 private:
     WeakPtr<Box> m_root;
     LayoutContext& m_layoutContext;
index 4c9b6fd092a92efd8f88a2e005f68df486f2bc7d..9c2d4b71f9015956c79b04e87cb9870727f29569 100644 (file)
@@ -50,7 +50,7 @@ void LayoutContext::updateLayout()
 {
     auto context = formattingContext(*m_root);
     auto& state = establishedFormattingState(*m_root, *context);
-    context->layout(state);
+    context->layout(*this, state);
 }
 
 FormattingState& LayoutContext::formattingStateForBox(const Box& layoutBox) const
@@ -60,7 +60,7 @@ FormattingState& LayoutContext::formattingStateForBox(const Box& layoutBox) cons
     return *m_formattingStates.get(&root);
 }
 
-FormattingState& LayoutContext::establishedFormattingState(Box& formattingContextRoot, const FormattingContext& context)
+FormattingState& LayoutContext::establishedFormattingState(const Box& formattingContextRoot, const FormattingContext& context)
 {
     return *m_formattingStates.ensure(&formattingContextRoot, [this, &context] {
         return context.createFormattingState(context.createOrFindFloatingState());
index 6589e51940b35484661ec2e7ab56bfb3035411aa..5768bd2fe465ca2337abcd5f029bcffc1c28f4a4 100644 (file)
@@ -61,11 +61,10 @@ public:
     bool needsLayout(const Box&) const;
 
     FormattingState& formattingStateForBox(const Box&) const;
-
-private:
-    FormattingState& establishedFormattingState(Box& formattingContextRoot, const FormattingContext&);
+    FormattingState& establishedFormattingState(const Box& formattingContextRoot, const FormattingContext&);
     std::unique_ptr<FormattingContext> formattingContext(const Box& formattingContextRoot);
 
+private:
     WeakPtr<Box> m_root;
     HashMap<const Box*, std::unique_ptr<FormattingState>> m_formattingStates;
 };
index e80545b9f036b290aa67531fb15d3de46b5697ce..b57f1e7df247e579b17b9077e59c402bb6a5ad64 100644 (file)
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "BlockFormattingState.h"
+#include "FloatingContext.h"
 #include "FloatingState.h"
+#include "LayoutBox.h"
+#include "LayoutContainer.h"
+#include "LayoutContext.h"
 #include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
@@ -42,8 +46,63 @@ BlockFormattingContext::BlockFormattingContext(const Box& formattingContextRoot,
 {
 }
 
-void BlockFormattingContext::layout(FormattingState&)
+void BlockFormattingContext::layout(LayoutContext& layoutContext, FormattingState& formattingState) const
 {
+    // 9.4.1 Block formatting contexts
+    // In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block.
+    // The vertical distance between two sibling boxes is determined by the 'margin' properties.
+    // Vertical margins between adjacent block-level boxes in a block formatting context collapse.
+    if (!is<Container>(root()))
+        return;
+    auto& formattingRoot = downcast<Container>(root());
+    Vector<const Box*> layoutQueue;
+    FloatingContext floatingContext(formattingState.floatingState());
+    // This is a post-order tree traversal layout.
+    // The root container layout is done in the formatting context it lives in, not that one it creates, so let's start with the first child.
+    if (formattingRoot.hasInFlowOrFloatingChild())
+        layoutQueue.append(formattingRoot.firstInFlowOrFloatingChild());
+    // 1. Go all the way down to the leaf node
+    // 2. Compute static position and width as we traverse down
+    // 3. As we climb back on the tree, compute height and finialize position
+    // (Any subtrees with new formatting contexts need to layout synchronously)
+    while (!layoutQueue.isEmpty()) {
+        // Traverse down on the descendants and compute width/static position until we find a leaf node.
+        while (true) {
+            auto& layoutBox = *layoutQueue.last();
+            computeWidth(layoutBox);
+            computeStaticPosition(layoutBox);
+            if (layoutBox.establishesFormattingContext()) {
+                auto formattingContext = layoutContext.formattingContext(layoutBox);
+                formattingContext->layout(layoutContext, layoutContext.establishedFormattingState(layoutBox, *formattingContext));
+                break;
+            }
+            if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
+                break;
+            layoutQueue.append(downcast<Container>(layoutBox).firstInFlowOrFloatingChild());
+        }
+
+        // Climb back on the ancestors and compute height/final position.
+        while (!layoutQueue.isEmpty()) {
+            // All inflow descendants (if there are any) are laid out by now. Let's compute the box's height.
+            auto& layoutBox = *layoutQueue.takeLast();
+            computeHeight(layoutBox);
+            // Adjust position now that we have all the previous floats placed in this context -if needed.
+            floatingContext.computePosition(layoutBox);
+            if (!is<Container>(layoutBox))
+                continue;
+            auto& container = downcast<Container>(layoutBox);
+            // Move in-flow positioned children to their final position.
+            placeInFlowPositionedChildren(container);
+            if (auto* nextSibling = container.nextInFlowOrFloatingSibling()) {
+                layoutQueue.append(nextSibling);
+                break;
+            }
+        }
+    }
+    // Place the inflow positioned children.
+    placeInFlowPositionedChildren(formattingRoot);
+    // And take care of out-of-flow boxes as the final step.
+    layoutOutOfFlowDescendants();
 }
 
 std::unique_ptr<FormattingState> BlockFormattingContext::createFormattingState(Ref<FloatingState>&& floatingState) const
index 026398ba275d3b613b2473d32f9bdc0b7c0cef55..aade5a6556a36f4ffc56ff1b52fa660777f74aea 100644 (file)
@@ -45,7 +45,7 @@ class BlockFormattingContext : public FormattingContext {
 public:
     BlockFormattingContext(const Box& formattingContextRoot, LayoutContext&);
 
-    void layout(FormattingState&) override;
+    void layout(LayoutContext&, FormattingState&) const override;
     std::unique_ptr<FormattingState> createFormattingState(Ref<FloatingState>&&) const override;
     Ref<FloatingState> createOrFindFloatingState() const override;
 
index 22a4807b6dfeb9d5c9b77eb0ed04e79bf50a12db..2235266b707a20b166405219d9cb64c3eae256aa 100644 (file)
@@ -44,7 +44,7 @@ InlineFormattingContext::InlineFormattingContext(const Box& formattingContextRoo
 {
 }
 
-void InlineFormattingContext::layout(FormattingState&)
+void InlineFormattingContext::layout(LayoutContext&, FormattingState&) const
 {
 }
 
index 36580e1db4403e3645f771c3b1190585890309fb..f2587f40fc6de60da3a6f7aac05f83f46a7c5436 100644 (file)
@@ -43,7 +43,7 @@ class InlineFormattingContext : public FormattingContext {
 public:
     InlineFormattingContext(const Box& formattingContextRoot, LayoutContext&);
 
-    void layout(FormattingState&) override;
+    void layout(LayoutContext&, FormattingState&) const override;
     std::unique_ptr<FormattingState> createFormattingState(Ref<FloatingState>&&) const override;
     Ref<FloatingState> createOrFindFloatingState() const override;
 };