[LFC][Floating] Decouple the incoming floats and floats already placed in the list
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2018 15:12:24 +0000 (15:12 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Aug 2018 15:12:24 +0000 (15:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188886

Reviewed by Antti Koivisto.

This is in preparation for the float avoidance feature where formatting context root boxes avoid existing floats.

1. Introduce FloatBox class for the incoming floats (This will need to be renamed when adding support for avoidance -incoming box is actually not a float).
2. Use the existing FloatState::FloatItem class for placed floats.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/LayoutUnits.h:
* layout/Verification.cpp:
(WebCore::Layout::LayoutContext::verifyAndOutputMismatchingLayoutTree const):
* layout/displaytree/DisplayBox.h:
* layout/floats/FloatBox.cpp: Added.
(WebCore::Layout::FloatBox::FloatBox):
(WebCore::Layout::FloatBox::initializePosition):
(WebCore::Layout::FloatBox::isLeftAligned const):
(WebCore::Layout::FloatBox::setLeft):
(WebCore::Layout::FloatBox::setTopLeft):
(WebCore::Layout::FloatBox::resetVertically):
(WebCore::Layout::FloatBox::resetHorizontally):
(WebCore::Layout::FloatBox::topLeftInContainingBlock const):
* layout/floats/FloatBox.h: Copied from Source/WebCore/layout/floats/FloatingContext.h.
(WebCore::Layout::FloatBox::top const):
(WebCore::Layout::FloatBox::left const):
(WebCore::Layout::FloatBox::marginTop const):
(WebCore::Layout::FloatBox::marginLeft const):
(WebCore::Layout::FloatBox::marginBottom const):
(WebCore::Layout::FloatBox::marginRight const):
(WebCore::Layout::FloatBox::rectWithMargin const):
(WebCore::Layout::FloatBox::setTop):
* layout/floats/FloatingContext.cpp:
(WebCore::Layout::FloatingPair::verticalPosition const):
(WebCore::Layout::begin):
(WebCore::Layout::FloatingContext::positionForFloat const):
(WebCore::Layout::FloatingContext::verticalPositionWithClearance const):
(WebCore::Layout::FloatingContext::floatingPosition const):
(WebCore::Layout::FloatingPair::horiztonalPosition const):
(WebCore::Layout::FloatingPair::bottom const):
(WebCore::Layout::Iterator::Iterator):
(WebCore::Layout::Iterator::operator++):
(WebCore::Layout::Iterator::set):
(WebCore::Layout::FloatingContext::initialVerticalPosition const): Deleted.
(WebCore::Layout::FloatingContext::alignWithContainingBlock const): Deleted.
(WebCore::Layout::FloatingContext::alignWithFloatings const): Deleted.
(WebCore::Layout::FloatingContext::toContainingBlock const): Deleted.
* layout/floats/FloatingContext.h:
* layout/floats/FloatingState.h:
(WebCore::Layout::FloatingState::root const):
(WebCore::Layout::FloatingState::layoutContext const):

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

Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/layout/LayoutUnits.h
Source/WebCore/layout/displaytree/DisplayBox.h
Source/WebCore/layout/floats/FloatBox.cpp [new file with mode: 0644]
Source/WebCore/layout/floats/FloatBox.h [new file with mode: 0644]
Source/WebCore/layout/floats/FloatingContext.cpp
Source/WebCore/layout/floats/FloatingContext.h
Source/WebCore/layout/floats/FloatingState.h

index a5b0128..f2d9feb 100644 (file)
@@ -1,3 +1,59 @@
+2018-08-23  Zalan Bujtas  <zalan@apple.com>
+
+        [LFC][Floating] Decouple the incoming floats and floats already placed in the list
+        https://bugs.webkit.org/show_bug.cgi?id=188886
+
+        Reviewed by Antti Koivisto.
+
+        This is in preparation for the float avoidance feature where formatting context root boxes avoid existing floats.
+
+        1. Introduce FloatBox class for the incoming floats (This will need to be renamed when adding support for avoidance -incoming box is actually not a float).
+        2. Use the existing FloatState::FloatItem class for placed floats.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/LayoutUnits.h:
+        * layout/Verification.cpp:
+        (WebCore::Layout::LayoutContext::verifyAndOutputMismatchingLayoutTree const):
+        * layout/displaytree/DisplayBox.h:
+        * layout/floats/FloatBox.cpp: Added.
+        (WebCore::Layout::FloatBox::FloatBox):
+        (WebCore::Layout::FloatBox::initializePosition):
+        (WebCore::Layout::FloatBox::isLeftAligned const):
+        (WebCore::Layout::FloatBox::setLeft):
+        (WebCore::Layout::FloatBox::setTopLeft):
+        (WebCore::Layout::FloatBox::resetVertically):
+        (WebCore::Layout::FloatBox::resetHorizontally):
+        (WebCore::Layout::FloatBox::topLeftInContainingBlock const):
+        * layout/floats/FloatBox.h: Copied from Source/WebCore/layout/floats/FloatingContext.h.
+        (WebCore::Layout::FloatBox::top const):
+        (WebCore::Layout::FloatBox::left const):
+        (WebCore::Layout::FloatBox::marginTop const):
+        (WebCore::Layout::FloatBox::marginLeft const):
+        (WebCore::Layout::FloatBox::marginBottom const):
+        (WebCore::Layout::FloatBox::marginRight const):
+        (WebCore::Layout::FloatBox::rectWithMargin const):
+        (WebCore::Layout::FloatBox::setTop):
+        * layout/floats/FloatingContext.cpp:
+        (WebCore::Layout::FloatingPair::verticalPosition const):
+        (WebCore::Layout::begin):
+        (WebCore::Layout::FloatingContext::positionForFloat const):
+        (WebCore::Layout::FloatingContext::verticalPositionWithClearance const):
+        (WebCore::Layout::FloatingContext::floatingPosition const):
+        (WebCore::Layout::FloatingPair::horiztonalPosition const):
+        (WebCore::Layout::FloatingPair::bottom const):
+        (WebCore::Layout::Iterator::Iterator):
+        (WebCore::Layout::Iterator::operator++):
+        (WebCore::Layout::Iterator::set):
+        (WebCore::Layout::FloatingContext::initialVerticalPosition const): Deleted.
+        (WebCore::Layout::FloatingContext::alignWithContainingBlock const): Deleted.
+        (WebCore::Layout::FloatingContext::alignWithFloatings const): Deleted.
+        (WebCore::Layout::FloatingContext::toContainingBlock const): Deleted.
+        * layout/floats/FloatingContext.h:
+        * layout/floats/FloatingState.h:
+        (WebCore::Layout::FloatingState::root const):
+        (WebCore::Layout::FloatingState::layoutContext const):
+
 2018-08-23  Zan Dobersek  <zdobersek@igalia.com>
 
         [CoordGraphics] Remove the remaining CoordinatedGraphicsLayerState cruft
index 819a5d2..a512eba 100644 (file)
@@ -1229,6 +1229,7 @@ layout/blockformatting/BlockFormattingState.cpp
 layout/blockformatting/BlockMarginCollapse.cpp
 layout/blockformatting/BlockInvalidation.cpp
 layout/displaytree/DisplayBox.cpp
+layout/floats/FloatBox.cpp
 layout/floats/FloatingContext.cpp
 layout/floats/FloatingState.cpp
 layout/inlineformatting/InlineFormattingContext.cpp
index b0c2b0c..2b84115 100644 (file)
                6F995A381A70833700A735F4 /* JSWebGLTransformFeedback.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F995A2E1A70833700A735F4 /* JSWebGLTransformFeedback.h */; };
                6F995A3A1A70833700A735F4 /* JSWebGLVertexArrayObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F995A301A70833700A735F4 /* JSWebGLVertexArrayObject.h */; };
                6FA4454E898F2FC168BC38C1 /* JSBeforeUnloadEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 29E04A27BED2F81F98E9022B /* JSBeforeUnloadEvent.h */; };
+               6FFDC442212EFF1700A9CA91 /* FloatBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FFDC440212EFF1600A9CA91 /* FloatBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
                709A01FE1E3D0BDD006B0D4C /* ModuleFetchFailureKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
                71025ECD1F99F0CE004A250C /* AnimationTimeline.h in Headers */ = {isa = PBXBuildFile; fileRef = 71025EC71F99F096004A250C /* AnimationTimeline.h */; settings = {ATTRIBUTES = (Private, ); }; };
                71025ED01F99F0CE004A250C /* DocumentTimeline.h in Headers */ = {isa = PBXBuildFile; fileRef = 71025EC51F99F096004A250C /* DocumentTimeline.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6FCD19C120F9727A00FD4529 /* TextContentProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextContentProvider.h; sourceTree = "<group>"; };
                6FCD19C720F9727D00FD4529 /* TextContentProvider.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TextContentProvider.cpp; sourceTree = "<group>"; };
                6FCF975220F02B3500214960 /* Runs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Runs.h; sourceTree = "<group>"; };
+               6FFDC43E212EFF1600A9CA91 /* FloatBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FloatBox.cpp; sourceTree = "<group>"; };
+               6FFDC440212EFF1600A9CA91 /* FloatBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatBox.h; sourceTree = "<group>"; };
                709A01FD1E3D0BCC006B0D4C /* ModuleFetchFailureKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleFetchFailureKind.h; sourceTree = "<group>"; };
                71004B9D1DC1398800A52A38 /* playback-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "playback-support.js"; sourceTree = "<group>"; };
                71025EC21F99F096004A250C /* WebAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAnimation.h; sourceTree = "<group>"; };
                6FCFC055212DACC2007695D2 /* floats */ = {
                        isa = PBXGroup;
                        children = (
+                               6FFDC43E212EFF1600A9CA91 /* FloatBox.cpp */,
+                               6FFDC440212EFF1600A9CA91 /* FloatBox.h */,
                                115CFA85208B9066001E6991 /* FloatingContext.cpp */,
                                115CFA84208B9066001E6991 /* FloatingContext.h */,
                                115CFA81208B8EDA001E6991 /* FloatingState.cpp */,
                                49ECEB701499790D00CDD3A4 /* FilterOperations.h in Headers */,
                                372C00D9129619F8005C9575 /* FindOptions.h in Headers */,
                                A8CFF04F0A154F09000A4234 /* FixedTableLayout.h in Headers */,
+                               6FFDC442212EFF1700A9CA91 /* FloatBox.h in Headers */,
                                BC073BAA0C399B1F000F5979 /* FloatConversion.h in Headers */,
                                115CFA86208B9066001E6991 /* FloatingContext.h in Headers */,
                                9A528E8417D7F52F00AA9518 /* FloatingObjects.h in Headers */,
index d39e50a..1b61edb 100644 (file)
@@ -46,6 +46,12 @@ struct Position {
     operator LayoutPoint() const { return { x, y }; }
 };
 
+// FIXME: Wrap these into structs.
+using PointInContextRoot = Position;
+using PointInContainingBlock = Position;
+using PositionInContextRoot = LayoutUnit;
+using PositionInContainingBlock = LayoutUnit;
+
 inline Position::Position(LayoutPoint point)
     : x(point.x())
     , y(point.y())
index f722a18..22851f7 100644 (file)
@@ -36,6 +36,7 @@ namespace WebCore {
 class RenderStyle;
 
 namespace Layout {
+class FloatBox;
 class BlockFormattingContext;
 class FormattingContext;
 class FloatingContext;
@@ -47,6 +48,7 @@ namespace Display {
 class Box {
     WTF_MAKE_ISO_ALLOCATED(Box);
 public:
+    friend class Layout::FloatBox;
     friend class Layout::BlockFormattingContext;
     friend class Layout::FormattingContext;
     friend class Layout::FloatingContext;
diff --git a/Source/WebCore/layout/floats/FloatBox.cpp b/Source/WebCore/layout/floats/FloatBox.cpp
new file mode 100644 (file)
index 0000000..d4010ce
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FloatBox.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "LayoutBox.h"
+#include "LayoutContainer.h"
+#include "LayoutContext.h"
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+namespace Layout {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(FloatBox);
+
+FloatBox::FloatBox(const Box& layoutBox, const FloatingState& floatingState, const LayoutContext& layoutContext)
+    : m_layoutBox(makeWeakPtr(const_cast<Box&>(layoutBox)))
+    , m_floatingState(floatingState)
+    , m_absoluteDisplayBox(FormattingContext::mapBoxToAncestor(layoutContext, layoutBox, downcast<Container>(floatingState.root())))
+    , m_containingBlockAbsoluteDisplayBox(FormattingContext::mapBoxToAncestor(layoutContext, *layoutBox.containingBlock(), downcast<Container>(floatingState.root())))
+{
+    initializePosition();
+}
+
+void FloatBox::initializePosition()
+{
+    resetVertically();
+    resetHorizontally();
+}
+
+bool FloatBox::isLeftAligned() const
+{
+    return m_layoutBox->isLeftFloatingPositioned();
+}
+
+void FloatBox::setLeft(PositionInContextRoot left)
+{
+    // Horizontal position is constrained by the containing block's content box.
+    // Compute the horizontal position for the new floating by taking both the contining block and the current left/right floats into account.
+    auto containingBlockContentBoxLeft = m_containingBlockAbsoluteDisplayBox.left() + m_containingBlockAbsoluteDisplayBox.contentBoxLeft();
+    auto containingBlockContentBoxRight = containingBlockContentBoxLeft + m_containingBlockAbsoluteDisplayBox.contentBoxWidth();
+
+    // Align it with the containing block's left edge first.
+    left = std::max(containingBlockContentBoxLeft + marginLeft(), left);
+    // Make sure it does not overflow the containing block on the right.
+    auto marginBoxSize = m_absoluteDisplayBox.marginBox().width();
+    left = std::min(left, containingBlockContentBoxRight - marginBoxSize + marginLeft());
+
+    m_absoluteDisplayBox.setLeft(left);
+}
+
+void FloatBox::setTopLeft(PointInContextRoot topLeft)
+{
+    setTop(topLeft.y);
+    setLeft(topLeft.x);
+}
+
+void FloatBox::resetVertically()
+{
+    // Incoming float cannot be placed higher than existing floats (margin box of the last float).
+    // Take the static position (where the box would go if it wasn't floating) and adjust it with the last float.
+    auto top = m_absoluteDisplayBox.rectWithMargin().top();
+    if (auto lastFloat = m_floatingState.last())
+        top = std::max(top, lastFloat->displayBox().rectWithMargin().top());
+    top += m_absoluteDisplayBox.marginTop();
+
+    m_absoluteDisplayBox.setTop(top);
+}
+
+void FloatBox::resetHorizontally()
+{
+    // Align the box with the containing block's content box.
+    auto containingBlockContentBoxLeft = m_containingBlockAbsoluteDisplayBox.left() + m_containingBlockAbsoluteDisplayBox.contentBoxLeft();
+    auto containingBlockContentBoxRight = containingBlockContentBoxLeft + m_containingBlockAbsoluteDisplayBox.contentBoxWidth();
+
+    auto left = isLeftAligned() ? containingBlockContentBoxLeft : containingBlockContentBoxRight - m_absoluteDisplayBox.marginBox().width();
+    left += m_absoluteDisplayBox.marginLeft();
+
+    m_absoluteDisplayBox.setLeft(left);
+}
+
+PointInContainingBlock FloatBox::topLeftInContainingBlock() const
+{
+    // From formatting root coordinate system back to containing block's.
+    if (m_layoutBox->containingBlock() == &m_floatingState.root())
+        return m_absoluteDisplayBox.topLeft();
+
+    return { m_absoluteDisplayBox.left() - m_containingBlockAbsoluteDisplayBox.left(), m_absoluteDisplayBox.top() - m_containingBlockAbsoluteDisplayBox.top() };
+}
+
+}
+}
+#endif
diff --git a/Source/WebCore/layout/floats/FloatBox.h b/Source/WebCore/layout/floats/FloatBox.h
new file mode 100644 (file)
index 0000000..9ba6f90
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "DisplayBox.h"
+#include "LayoutUnit.h"
+#include <wtf/IsoMalloc.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+namespace Layout {
+
+class Box;
+class FloatingState;
+class LayoutContext;
+
+class FloatBox {
+    WTF_MAKE_ISO_ALLOCATED(FloatBox);
+public:
+    FloatBox(const Box&, const FloatingState&, const LayoutContext&);
+
+    PositionInContextRoot top() const { return m_absoluteDisplayBox.top(); }
+    PositionInContextRoot left() const { return m_absoluteDisplayBox.left(); }
+    PointInContainingBlock topLeftInContainingBlock() const;
+
+    LayoutUnit marginTop() const { return m_absoluteDisplayBox.marginTop(); }
+    LayoutUnit marginLeft() const { return m_absoluteDisplayBox.marginLeft(); }
+    LayoutUnit marginBottom() const { return m_absoluteDisplayBox.marginBottom(); }
+    LayoutUnit marginRight() const { return m_absoluteDisplayBox.marginRight(); }
+
+    Display::Box::Rect rectWithMargin() const { return m_absoluteDisplayBox.rectWithMargin(); }
+
+    void setTop(PositionInContextRoot top) { m_absoluteDisplayBox.setTop(top); }
+    void setLeft(PositionInContextRoot);
+    void setTopLeft(PointInContextRoot);
+
+    void resetHorizontally();
+    void resetVertically();
+
+    bool isLeftAligned() const;
+
+private:
+    void initializePosition();
+
+    WeakPtr<Box> m_layoutBox;
+    const FloatingState& m_floatingState;
+
+    Display::Box m_absoluteDisplayBox;
+    Display::Box m_containingBlockAbsoluteDisplayBox;
+};
+
+}
+}
+#endif
index 4feaea2..5e462d4 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "DisplayBox.h"
+#include "FloatBox.h"
 #include "LayoutBox.h"
 #include "LayoutContainer.h"
 #include "LayoutContext.h"
@@ -66,8 +67,9 @@ public:
     const Display::Box* left() const;
     const Display::Box* right() const;
     bool intersects(const Display::Box::Rect&) const;
-    LayoutUnit verticalPosition() const { return m_verticalPosition; }
-    LayoutUnit bottom() const;
+    PositionInContextRoot verticalPosition() const { return m_verticalPosition; }
+    std::optional<PositionInContextRoot> horiztonalPosition(Float) const;
+    PositionInContextRoot bottom() const;
     bool operator==(const FloatingPair&) const;
 
 private:
@@ -78,12 +80,12 @@ private:
 
     std::optional<unsigned> m_leftIndex;
     std::optional<unsigned> m_rightIndex;
-    LayoutUnit m_verticalPosition;
+    PositionInContextRoot m_verticalPosition;
 };
 
 class Iterator {
 public:
-    Iterator(const FloatingState::FloatList&, std::optional<LayoutUnit> verticalPosition);
+    Iterator(const FloatingState::FloatList&, std::optional<PositionInContextRoot> verticalPosition);
 
     const FloatingPair& operator*() const { return m_current; }
     Iterator& operator++();
@@ -91,13 +93,13 @@ public:
     bool operator!=(const Iterator&) const;
 
 private:
-    void set(LayoutUnit verticalPosition);
+    void set(PositionInContextRoot verticalPosition);
 
     const FloatingState::FloatList& m_floats;
     FloatingPair m_current;
 };
 
-static Iterator begin(const FloatingState& floatingState, LayoutUnit initialVerticalPosition)
+static Iterator begin(const FloatingState& floatingState, PositionInContextRoot initialVerticalPosition)
 {
     // Start with the inner-most floating pair for the initial vertical position.
     return Iterator(floatingState.floats(), initialVerticalPosition);
@@ -113,25 +115,34 @@ FloatingContext::FloatingContext(FloatingState& floatingState)
 {
 }
 
-Position FloatingContext::positionForFloat(const Box& layoutBox) const
+PointInContainingBlock FloatingContext::positionForFloat(const Box& layoutBox) const
 {
     ASSERT(layoutBox.isFloatingPositioned());
-    FloatingState::FloatItem floatItem = { layoutBox, m_floatingState };
 
-    Position floatPosition;
     if (m_floatingState.isEmpty()) {
+        auto& displayBox = *layoutContext().displayBoxForLayoutBox(layoutBox);
+
+        auto alignWithContainingBlock = [&]() -> PositionInContainingBlock {
+            // If there is no floating to align with, push the box to the left/right edge of its containing block's content box.
+            auto& containingBlockDisplayBox = *layoutContext().displayBoxForLayoutBox(*layoutBox.containingBlock());
+
+            if (layoutBox.isLeftFloatingPositioned())
+                return containingBlockDisplayBox.contentBoxLeft() + displayBox.marginLeft();
+
+            return containingBlockDisplayBox.contentBoxRight() - displayBox.marginRight() - displayBox.width();
+        };
+
         // No float box on the context yet -> align it with the containing block's left/right edge.
-        auto& displayBox = floatItem.displayBox();
-        floatPosition = { alignWithContainingBlock(floatItem) + displayBox.marginLeft(), displayBox.top() };
-    } else {
-        // Find the top most position where the float box fits.
-        floatPosition = floatingPosition(floatItem);
+        return { alignWithContainingBlock(), displayBox.top() };
     }
 
-    return toContainingBlock(floatItem, floatPosition);
+    // Find the top most position where the float box fits.
+    FloatBox alignedBox = { layoutBox, m_floatingState, layoutContext() };
+    floatingPosition(alignedBox);
+    return alignedBox.topLeftInContainingBlock();
 }
 
-std::optional<LayoutUnit> FloatingContext::verticalPositionWithClearance(const Box& layoutBox) const
+std::optional<PositionInContainingBlock> FloatingContext::verticalPositionWithClearance(const Box& layoutBox) const
 {
     ASSERT(layoutBox.hasFloatClear());
     ASSERT(layoutBox.isBlockLevelBox());
@@ -139,7 +150,7 @@ std::optional<LayoutUnit> FloatingContext::verticalPositionWithClearance(const B
     if (m_floatingState.isEmpty())
         return { };
 
-    auto bottom = [&](std::optional<LayoutUnit> floatBottom) -> std::optional<LayoutUnit> {
+    auto bottom = [&](std::optional<PositionInContextRoot> floatBottom) -> std::optional<PositionInContainingBlock> {
         // 'bottom' is in the formatting root's coordinate system.
         if (!floatBottom)
             return { };
@@ -202,104 +213,40 @@ std::optional<LayoutUnit> FloatingContext::verticalPositionWithClearance(const B
     return { };
 }
 
-Position FloatingContext::floatingPosition(const FloatingState::FloatItem& floatItem) const
+void FloatingContext::floatingPosition(FloatBox& floatBox) const
 {
-    auto initialVerticalPosition = this->initialVerticalPosition(floatItem);
-    auto& displayBox = floatItem.displayBox();
-    auto marginBoxSize = displayBox.marginBox().size();
-
+    std::optional<PositionInContextRoot> bottomMost;
+    auto initialLeft = floatBox.left();
     auto end = Layout::end(m_floatingState);
-    auto top = initialVerticalPosition;
-    auto bottomMost = top;
-    for (auto iterator = begin(m_floatingState, initialVerticalPosition); iterator != end; ++iterator) {
+    for (auto iterator = begin(m_floatingState, floatBox.rectWithMargin().top()); iterator != end; ++iterator) {
         ASSERT(!(*iterator).isEmpty());
-
         auto floats = *iterator;
-        top = floats.verticalPosition();
 
-        // Move the box horizontally so that it aligns with the current floating pair.
-        auto left = alignWithFloatings(floats, floatItem);
-        // Check if the box fits at this vertical position.
-        if (!floats.intersects({ top, left, marginBoxSize.width(), marginBoxSize.height() }))
-            return { left + displayBox.marginLeft(), top + displayBox.marginTop() };
+        floatBox.setTop(floats.verticalPosition() + floatBox.marginTop());
+        // Move the box horizontally so that it either
+        // 1. aligns with the current floating pair
+        // 2. or with the containing block's content box if there's no float to align with at this vertical position.
+        if (auto horiztonalPosition = floats.horiztonalPosition(floatBox.isLeftAligned() ? Float::Left : Float::Right)) {
+            if (!floatBox.isLeftAligned())
+                horiztonalPosition = *horiztonalPosition - floatBox.rectWithMargin().width();
+            floatBox.setLeft(*horiztonalPosition + floatBox.marginLeft());
+        } else
+            floatBox.resetHorizontally();
+
+        // Check if the box fits at this position.
+        if (!floats.intersects(floatBox.rectWithMargin()))
+            return;
 
         bottomMost = floats.bottom();
         // Move to the next floating pair.
     }
 
-    // Passed all the floats and still does not fit?
-    return { alignWithContainingBlock(floatItem) + displayBox.marginLeft(), bottomMost + displayBox.marginTop() };
-}
-
-LayoutUnit FloatingContext::initialVerticalPosition(const FloatingState::FloatItem& floatItem) const
-{
-    // Incoming floating cannot be placed higher than existing floats.
-    // Take the static position (where the box would go if it wasn't floating) and adjust it with the last floating.
-    auto marginBoxTop = floatItem.displayBox().rectWithMargin().top();
-
-    if (auto lastFloat = m_floatingState.last())
-        return std::max(marginBoxTop, lastFloat->displayBox().rectWithMargin().top());
-
-    return marginBoxTop;
-}
-
-LayoutUnit FloatingContext::alignWithContainingBlock(const FloatingState::FloatItem& floatItem) const
-{
-    // If there is no floating to align with, push the box to the left/right edge of its containing block's content box.
-    // (Either there's no floats at all or this box does not fit at any vertical positions where the floats are.)
-    auto& containingBlockDisplayBox = floatItem.containingBlockDisplayBox();
-    auto containingBlockContentBoxLeft = containingBlockDisplayBox.left() + containingBlockDisplayBox.contentBoxLeft();
-
-    if (floatItem.layoutBox().isLeftFloatingPositioned())
-        return containingBlockContentBoxLeft;
-
-    return containingBlockContentBoxLeft + containingBlockDisplayBox.contentBoxWidth() - floatItem.displayBox().marginBox().width();
-}
-
-LayoutUnit FloatingContext::alignWithFloatings(const FloatingPair& floatingPair, const FloatingState::FloatItem& floatItem) const
-{
-    // Compute the horizontal position for the new floating by taking both the contining block and the current left/right floats into account.
-    auto& containingBlockDisplayBox = floatItem.containingBlockDisplayBox();
-    auto containingBlockContentBoxLeft = containingBlockDisplayBox.left() + containingBlockDisplayBox.contentBoxLeft();
-    auto containingBlockContentBoxRight = containingBlockDisplayBox.left() + containingBlockDisplayBox.contentBoxRight();
-    auto marginBoxWidth = floatItem.displayBox().marginBox().width();
-
-    auto leftAlignedBoxLeft = containingBlockContentBoxLeft;
-    auto rightAlignedBoxLeft = containingBlockContentBoxRight - marginBoxWidth;
-
-    if (floatingPair.isEmpty()) {
-        ASSERT_NOT_REACHED();
-        return floatItem.layoutBox().isLeftFloatingPositioned() ? leftAlignedBoxLeft : rightAlignedBoxLeft;
-    }
-
-    if (floatItem.layoutBox().isLeftFloatingPositioned()) {
-        if (auto* leftDisplayBox = floatingPair.left()) {
-            auto leftFloatingBoxRight = leftDisplayBox->rectWithMargin().right();
-            return std::min(std::max(leftAlignedBoxLeft, leftFloatingBoxRight), rightAlignedBoxLeft);
-        }
-        
-        return leftAlignedBoxLeft;
-    }
-
-    ASSERT(floatItem.layoutBox().isRightFloatingPositioned());
-
-    if (auto* rightDisplayBox = floatingPair.right()) {
-        auto rightFloatingBoxLeft = rightDisplayBox->rectWithMargin().left();
-        return std::max(std::min(rightAlignedBoxLeft, rightFloatingBoxLeft - marginBoxWidth), leftAlignedBoxLeft);
-    }
-
-    return rightAlignedBoxLeft;
-}
-
-// FIXME: find a better place for this.
-Position FloatingContext::toContainingBlock(const FloatingState::FloatItem& floatItem, Position position) const
-{
-    // From formatting root coordinate system back to containing block's.
-    if (&floatItem.containingBlock() == &m_floatingState.root())
-        return position;
+    // The candidate box is already below of all the floats.
+    if (!bottomMost)
+        return;
 
-    auto& containingBlockDisplayBox = floatItem.containingBlockDisplayBox();
-    return { position.x - containingBlockDisplayBox.left(), position.y - containingBlockDisplayBox.top() };
+    // Passed all the floats and still does not fit? Push it below the last float.
+    floatBox.setTopLeft({ initialLeft, *bottomMost + floatBox.marginTop() });
 }
 
 FloatingPair::FloatingPair(const FloatingState::FloatList& floats)
@@ -359,14 +306,25 @@ bool FloatingPair::operator ==(const FloatingPair& other) const
     return m_leftIndex == other.m_leftIndex && m_rightIndex == other.m_rightIndex;
 }
 
-LayoutUnit FloatingPair::bottom() const
+std::optional<PositionInContextRoot> FloatingPair::horiztonalPosition(Float floatType) const
+{
+    if (floatType == Float::Left && left())
+        return left()->rectWithMargin().right();
+
+    if (floatType == Float::Right && right())
+        return right()->rectWithMargin().left();
+
+    return { };
+}
+
+PositionInContextRoot FloatingPair::bottom() const
 {
     auto* left = this->left();
     auto* right = this->right();
     ASSERT(left || right);
 
-    auto leftBottom = left ? std::optional<LayoutUnit>(left->rectWithMargin().bottom()) : std::nullopt;
-    auto rightBottom = right ? std::optional<LayoutUnit>(right->rectWithMargin().bottom()) : std::nullopt;
+    auto leftBottom = left ? std::optional<PositionInContextRoot>(left->rectWithMargin().bottom()) : std::nullopt;
+    auto rightBottom = right ? std::optional<PositionInContextRoot>(right->rectWithMargin().bottom()) : std::nullopt;
 
     if (leftBottom && rightBottom)
         return std::max(*leftBottom, *rightBottom);
@@ -377,7 +335,7 @@ LayoutUnit FloatingPair::bottom() const
     return *rightBottom;
 }
 
-Iterator::Iterator(const FloatingState::FloatList& floats, std::optional<LayoutUnit> verticalPosition)
+Iterator::Iterator(const FloatingState::FloatList& floats, std::optional<PositionInContextRoot> verticalPosition)
     : m_floats(floats)
     , m_current(floats)
 {
@@ -435,8 +393,8 @@ Iterator& Iterator::operator++()
     // Ensure that the new floating's bottom edge is positioned lower than the current one -which essentially means skipping in-between floats that are positioned higher).
     // 3. Reset the vertical position and align it with the new left-right pair. These floats are now the inner-most boxes for the current vertical position.
     // As the result we have more horizontal space on the current vertical position.
-    auto leftBottom = m_current.left() ? std::optional<LayoutUnit>(m_current.left()->bottom()) : std::nullopt;
-    auto rightBottom = m_current.right() ? std::optional<LayoutUnit>(m_current.right()->bottom()) : std::nullopt;
+    auto leftBottom = m_current.left() ? std::optional<PositionInContextRoot>(m_current.left()->bottom()) : std::nullopt;
+    auto rightBottom = m_current.right() ? std::optional<PositionInContextRoot>(m_current.right()->bottom()) : std::nullopt;
 
     auto updateLeft = (leftBottom == rightBottom) || (!rightBottom || (leftBottom && leftBottom < rightBottom)); 
     auto updateRight = (leftBottom == rightBottom) || (!leftBottom || (rightBottom && leftBottom > rightBottom)); 
@@ -456,7 +414,7 @@ Iterator& Iterator::operator++()
     return *this;
 }
 
-void Iterator::set(LayoutUnit verticalPosition)
+void Iterator::set(PositionInContextRoot verticalPosition)
 {
     // Move the iterator to the initial vertical position by starting at the inner-most floating pair (last floats on left/right).
     // 1. Check if the inner-most pair covers the vertical position.
index d903a93..9988e5b 100644 (file)
@@ -35,6 +35,7 @@ namespace WebCore {
 
 namespace Layout {
 
+class FloatBox;
 class Box;
 class Container;
 class FloatingPair;
@@ -49,18 +50,13 @@ public:
 
     FloatingState& floatingState() const { return m_floatingState; }
 
-    Position positionForFloat(const Box&) const;
-    std::optional<LayoutUnit> verticalPositionWithClearance(const Box&) const;
+    PointInContainingBlock positionForFloat(const Box&) const;
+    std::optional<PositionInContainingBlock> verticalPositionWithClearance(const Box&) const;
 
 private:
     LayoutContext& layoutContext() const { return m_floatingState.layoutContext(); }
 
-    Position floatingPosition(const FloatingState::FloatItem&) const;
-
-    LayoutUnit initialVerticalPosition(const FloatingState::FloatItem&) const;
-    LayoutUnit alignWithContainingBlock(const FloatingState::FloatItem&) const;
-    LayoutUnit alignWithFloatings(const FloatingPair&, const FloatingState::FloatItem&) const;
-    Position toContainingBlock(const FloatingState::FloatItem&, Position) const;
+    void floatingPosition(FloatBox&) const;
 
     FloatingState& m_floatingState;
 };
index 9a7e2b4..77d7130 100644 (file)
@@ -52,6 +52,8 @@ public:
 
     bool isEmpty() const { return m_floats.isEmpty(); }
 
+    const Box& root() const { return *m_formattingContextRoot; }
+
     std::optional<LayoutUnit> leftBottom(const Box& formattingContextRoot) const;
     std::optional<LayoutUnit> rightBottom(const Box& formattingContextRoot) const;
     std::optional<LayoutUnit> bottom(const Box& formattingContextRoot) const;
@@ -82,7 +84,6 @@ private:
     FloatingState(LayoutContext&, const Box& formattingContextRoot);
 
     LayoutContext& layoutContext() const { return m_layoutContext; }
-    const Box& root() const { return *m_formattingContextRoot; }
 
     std::optional<LayoutUnit> bottom(const Box& formattingContextRoot, Clear) const;