https://bugs.webkit.org/show_bug.cgi?id=187974
Reviewed by Antti Koivisto.
Add floating boxes to an empty floating context.
* layout/FloatingContext.cpp:
(WebCore::Layout::FloatingContext::FloatingContext):
(WebCore::Layout::FloatingContext::computePosition):
* layout/FloatingContext.h:
(WebCore::Layout::FloatingContext::floatingState const):
(WebCore::Layout::FloatingContext::layoutContext const):
* layout/FloatingState.cpp:
(WebCore::Layout::FloatingState::FloatingState):
(WebCore::Layout::FloatingState::append):
* layout/FloatingState.h:
(WebCore::Layout::FloatingState::create):
(WebCore::Layout::FloatingState::isEmpty const):
(WebCore::Layout::FloatingState::layoutContext const):
* layout/FormattingState.h:
* layout/LayoutContext.cpp:
(WebCore::Layout::LayoutContext::establishedFormattingState):
* layout/LayoutContext.h:
* layout/blockformatting/BlockFormattingContext.cpp:
(WebCore::Layout::BlockFormattingContext::layout const):
(WebCore::Layout::BlockFormattingContext::layoutFormattingContextRoot const):
(WebCore::Layout::BlockFormattingContext::computeFloatingPosition const):
* layout/blockformatting/BlockFormattingContext.h:
* layout/blockformatting/BlockInvalidation.cpp:
(WebCore::Layout::invalidationStopsAtFormattingContextBoundary):
* layout/layouttree/LayoutBox.cpp:
(WebCore::Layout::Box::isLeftFloatingPositioned const):
(WebCore::Layout::Box::isRightFloatingPositioned const):
* layout/layouttree/LayoutBox.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@234256
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
2018-07-26 Zalan Bujtas <zalan@apple.com>
+ [LFC][Floating] Add skeleton for basic positioning.
+ https://bugs.webkit.org/show_bug.cgi?id=187974
+
+ Reviewed by Antti Koivisto.
+
+ Add floating boxes to an empty floating context.
+
+ * layout/FloatingContext.cpp:
+ (WebCore::Layout::FloatingContext::FloatingContext):
+ (WebCore::Layout::FloatingContext::computePosition):
+ * layout/FloatingContext.h:
+ (WebCore::Layout::FloatingContext::floatingState const):
+ (WebCore::Layout::FloatingContext::layoutContext const):
+ * layout/FloatingState.cpp:
+ (WebCore::Layout::FloatingState::FloatingState):
+ (WebCore::Layout::FloatingState::append):
+ * layout/FloatingState.h:
+ (WebCore::Layout::FloatingState::create):
+ (WebCore::Layout::FloatingState::isEmpty const):
+ (WebCore::Layout::FloatingState::layoutContext const):
+ * layout/FormattingState.h:
+ * layout/LayoutContext.cpp:
+ (WebCore::Layout::LayoutContext::establishedFormattingState):
+ * layout/LayoutContext.h:
+ * layout/blockformatting/BlockFormattingContext.cpp:
+ (WebCore::Layout::BlockFormattingContext::layout const):
+ (WebCore::Layout::BlockFormattingContext::layoutFormattingContextRoot const):
+ (WebCore::Layout::BlockFormattingContext::computeFloatingPosition const):
+ * layout/blockformatting/BlockFormattingContext.h:
+ * layout/blockformatting/BlockInvalidation.cpp:
+ (WebCore::Layout::invalidationStopsAtFormattingContextBoundary):
+ * layout/layouttree/LayoutBox.cpp:
+ (WebCore::Layout::Box::isLeftFloatingPositioned const):
+ (WebCore::Layout::Box::isRightFloatingPositioned const):
+ * layout/layouttree/LayoutBox.h:
+
+2018-07-26 Zalan Bujtas <zalan@apple.com>
+
[LFC][BFC] Do not try to access containing block's height during descendant height computation
https://bugs.webkit.org/show_bug.cgi?id=187970
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+#include "LayoutBox.h"
+#include "LayoutContainer.h"
+#include "LayoutContext.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(FloatingContext);
-FloatingContext::FloatingContext(FloatingState&)
+FloatingContext::FloatingContext(FloatingState& floatingState)
+ : m_floatingState(floatingState)
{
}
-void FloatingContext::computePosition(const Box&, Display::Box&)
+Position FloatingContext::computePosition(const Box& layoutBox)
{
+ auto& layoutContext = m_floatingState.layoutContext();
+ // 1. No floating box on the context yet -> align it with the containing block's left/right edge.
+ if (m_floatingState.isEmpty()) {
+ // Push the box to the left/right edge.
+ auto* containingBlock = layoutBox.containingBlock();
+ auto* displayBox = layoutContext.displayBoxForLayoutBox(*containingBlock);
+
+ if (layoutBox.isLeftFloatingPositioned())
+ return { displayBox->contentBoxLeft(), displayBox->contentBoxTop() };
+
+ auto boxWidth = layoutContext.displayBoxForLayoutBox(layoutBox)->width();
+ return { displayBox->contentBoxRight() - boxWidth, displayBox->contentBoxTop() };
+ }
+
+ ASSERT_NOT_IMPLEMENTED_YET();
+ return { };
}
}
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
-#include "LayoutUnit.h"
+#include "FloatingState.h"
+#include "LayoutUnits.h"
#include <wtf/IsoMalloc.h>
namespace WebCore {
namespace Layout {
class Box;
-class FloatingState;
+class LayoutContext;
// FloatingContext is responsible for adjusting the position of a box in the current formatting context
// by taking the floating boxes into account.
public:
FloatingContext(FloatingState&);
- void computePosition(const Box&, Display::Box&);
- LayoutUnit left(LayoutUnit verticalPosition);
- LayoutUnit right(LayoutUnit verticalPosition);
- LayoutUnit bottom();
+ FloatingState& floatingState() const { return m_floatingState; }
+
+ Position computePosition(const Box&);
+
+private:
+ LayoutContext& layoutContext() const { return m_floatingState.layoutContext(); }
+
+ FloatingState& m_floatingState;
};
}
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+#include "LayoutBox.h"
+#include "LayoutContext.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(FloatingState);
-FloatingState::FloatingState()
+FloatingState::FloatingState(LayoutContext& layoutContext)
+ : m_layoutContext(layoutContext)
{
}
+void FloatingState::append(const Box& layoutBox)
+{
+ // Floating state should hold boxes with computed position/size.
+ ASSERT(m_layoutContext.displayBoxForLayoutBox(layoutBox));
+
+ if (layoutBox.isLeftFloatingPositioned()) {
+ m_leftFloatings.append(makeWeakPtr(const_cast<Box&>(layoutBox)));
+ return;
+ }
+
+ if (layoutBox.isRightFloatingPositioned()) {
+ m_rightFloatings.append(makeWeakPtr(const_cast<Box&>(layoutBox)));
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
}
}
#endif
#include <wtf/IsoMalloc.h>
#include <wtf/Ref.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
namespace Layout {
+class Box;
class FormattingState;
+class LayoutContext;
// FloatingState holds the floating boxes per formatting context.
class FloatingState : public RefCounted<FloatingState> {
WTF_MAKE_ISO_ALLOCATED(FloatingState);
public:
- static Ref<FloatingState> create() { return adoptRef(*new FloatingState()); }
+ static Ref<FloatingState> create(LayoutContext& layoutContext) { return adoptRef(*new FloatingState(layoutContext)); }
+
+ void append(const Box& layoutBox);
+
+ bool isEmpty() const { return m_leftFloatings.isEmpty() && m_rightFloatings.isEmpty(); }
private:
- FloatingState();
+ friend class FloatingContext;
+ FloatingState(LayoutContext&);
+
+ LayoutContext& layoutContext() const { return m_layoutContext; }
+
+ LayoutContext& m_layoutContext;
+
+ using FloatingList = Vector<WeakPtr<Box>>;
+ FloatingList m_leftFloatings;
+ FloatingList m_rightFloatings;
};
}
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "FloatingState.h"
+#include "FormattingContext.h"
#include "LayoutBox.h"
#include "LayoutContext.h"
#include "LayoutUnit.h"
// should not interfere with the content inside.
// <div style="float: left"></div><div style="overflow: hidden"> <- is a non-intrusive float, because overflow: hidden triggers new block formatting context.</div>
if (formattingRoot.establishesBlockFormattingContext())
- return std::make_unique<InlineFormattingState>(FloatingState::create(), *this);
+ return std::make_unique<InlineFormattingState>(FloatingState::create(*this), *this);
// Otherwise, the formatting context inherits the floats from the parent formatting context.
// Find the formatting state in which this formatting root lives, not the one it creates and use its floating state.
return *m_formattingStates.ensure(&formattingRoot, [&] {
// Block formatting context always establishes a new floating state.
- return std::make_unique<BlockFormattingState>(FloatingState::create(), *this);
+ return std::make_unique<BlockFormattingState>(FloatingState::create(*this), *this);
}).iterator->value;
}
CRASH();
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "FormattingContext.h"
+#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/IsoMalloc.h>
#include <wtf/OptionSet.h>
auto& displayBox = layoutPair.displayBox;
if (layoutBox.establishesFormattingContext()) {
- layoutFormattingContextRoot(layoutContext, formattingState, layoutBox, displayBox);
+ layoutFormattingContextRoot(layoutContext, floatingContext, formattingState, layoutBox, displayBox);
layoutQueue.removeLast();
// Since this box is a formatting context root, it takes care of its entire subtree.
// Continue with next sibling if exists.
computeStaticPosition(layoutContext, layoutBox, displayBox);
computeBorderAndPadding(layoutContext, layoutBox, displayBox);
computeWidthAndMargin(layoutContext, layoutBox, displayBox);
+ if (layoutBox.isFloatingPositioned())
+ computeFloatingPosition(floatingContext, layoutBox, displayBox);
if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
break;
auto& firstChild = *downcast<Container>(layoutBox).firstInFlowOrFloatingChild();
ASSERT(!layoutBox.establishesFormattingContext());
computeHeightAndMargin(layoutContext, layoutBox, displayBox);
- // Adjust position now that we have all the previous floats placed in this context -if needed.
- floatingContext.computePosition(layoutBox, displayBox);
if (!is<Container>(layoutBox))
continue;
auto& container = downcast<Container>(layoutBox);
LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> block formatting context -> layout context(" << &layoutContext << ") formatting root(" << &root() << ")");
}
-void BlockFormattingContext::layoutFormattingContextRoot(LayoutContext& layoutContext, FormattingState& formattingState, const Box& layoutBox, Display::Box& displayBox) const
+void BlockFormattingContext::layoutFormattingContextRoot(LayoutContext& layoutContext, FloatingContext& floatingContext, FormattingState&, const Box& layoutBox, Display::Box& displayBox) const
{
// Start laying out this formatting root in the formatting contenxt it lives in.
LOG_WITH_STREAM(FormattingContextLayout, stream << "[Compute] -> [Position][Border][Padding][Width][Margin] -> for layoutBox(" << &layoutBox << ")");
computeStaticPosition(layoutContext, layoutBox, displayBox);
computeBorderAndPadding(layoutContext, layoutBox, displayBox);
computeWidthAndMargin(layoutContext, layoutBox, displayBox);
+ if (layoutBox.isFloatingPositioned())
+ computeFloatingPosition(floatingContext, layoutBox, displayBox);
// Swich over to the new formatting context (the one that the root creates).
auto formattingContext = layoutContext.formattingContext(layoutBox);
formattingContext->layout(layoutContext, layoutContext.establishedFormattingState(layoutBox));
// Come back and finalize the root's geometry.
- FloatingContext(formattingState.floatingState()).computePosition(layoutBox, displayBox);
LOG_WITH_STREAM(FormattingContextLayout, stream << "[Compute] -> [Height][Margin] -> for layoutBox(" << &layoutBox << ")");
computeHeightAndMargin(layoutContext, layoutBox, displayBox);
// Now that we computed the root's height, we can go back and layout the out-of-flow descedants (if any).
displayBox.setTopLeft(Geometry::staticPosition(layoutContext, layoutBox));
}
+void BlockFormattingContext::computeFloatingPosition(FloatingContext& floatingContext, const Box& layoutBox, Display::Box& displayBox) const
+{
+ ASSERT(layoutBox.isFloatingPositioned());
+ displayBox.setTopLeft(floatingContext.computePosition(layoutBox));
+ floatingContext.floatingState().append(layoutBox);
+}
+
void BlockFormattingContext::computeInFlowPositionedPosition(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
displayBox.setTopLeft(Geometry::inFlowPositionedPosition(layoutContext, layoutBox));
class BlockFormattingState;
class Box;
+class FloatingContext;
// This class implements the layout logic for block formatting contexts.
// https://www.w3.org/TR/CSS22/visuren.html#block-formatting
void layout(LayoutContext&, FormattingState&) const override;
private:
- void layoutFormattingContextRoot(LayoutContext&, FormattingState&, const Box&, Display::Box&) const;
+ void layoutFormattingContextRoot(LayoutContext&, FloatingContext&, FormattingState&, const Box&, Display::Box&) const;
void computeWidthAndMargin(LayoutContext&, const Box&, Display::Box&) const;
void computeHeightAndMargin(LayoutContext&, const Box&, Display::Box&) const;
void computeStaticPosition(LayoutContext&, const Box&, Display::Box&) const override;
+ void computeFloatingPosition(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;
static bool invalidationStopsAtFormattingContextBoundary(const Container& formattingContextRoot, const Box&, StyleDiff)
{
+ UNUSED_PARAM(formattingContextRoot);
+
ASSERT(formattingContextRoot.establishesFormattingContext());
return true;
}
return m_style.floating() != Float::No;
}
+bool Box::isLeftFloatingPositioned() const
+{
+ return m_style.floating() == Float::Left;
+}
+
+bool Box::isRightFloatingPositioned() const
+{
+ return m_style.floating() == Float::Right;
+}
+
const Container* Box::containingBlock() const
{
// The containing block in which the root element lives is a rectangle called the initial containing block.
bool isAbsolutelyPositioned() const;
bool isFixedPositioned() const;
bool isFloatingPositioned() const;
+ bool isLeftFloatingPositioned() const;
+ bool isRightFloatingPositioned() const;
bool isFloatingOrOutOfFlowPositioned() const { return isFloatingPositioned() || isOutOfFlowPositioned(); }