FormattingContext.cpp [plain text]
#include "config.h"
#include "FormattingContext.h"
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "DisplayBox.h"
#include "LayoutBox.h"
#include "LayoutContainer.h"
#include "LayoutContext.h"
#include "LayoutDescendantIterator.h"
#include "Logging.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/text/TextStream.h>
namespace WebCore {
namespace Layout {
WTF_MAKE_ISO_ALLOCATED_IMPL(FormattingContext);
FormattingContext::FormattingContext(const Box& formattingContextRoot)
: m_root(makeWeakPtr(const_cast<Box&>(formattingContextRoot)))
{
}
FormattingContext::~FormattingContext()
{
}
void FormattingContext::computeFloatingHeightAndMargin(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
auto heightAndMargin = Geometry::floatingHeightAndMargin(layoutContext, layoutBox);
displayBox.setContentBoxHeight(heightAndMargin.height);
displayBox.moveVertically(heightAndMargin.margin.top);
ASSERT(!heightAndMargin.collapsedMargin);
displayBox.setVerticalMargin(heightAndMargin.margin);
displayBox.setVerticalNonCollapsedMargin(heightAndMargin.margin);
}
void FormattingContext::computeFloatingWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
auto widthAndMargin = Geometry::floatingWidthAndMargin(layoutContext, *this, layoutBox);
displayBox.setContentBoxWidth(widthAndMargin.width);
displayBox.moveHorizontally(widthAndMargin.margin.left);
displayBox.setHorizontalMargin(widthAndMargin.margin);
}
void FormattingContext::computeOutOfFlowHorizontalGeometry(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
auto horizontalGeometry = Geometry::outOfFlowHorizontalGeometry(layoutContext, *this, layoutBox);
displayBox.setLeft(horizontalGeometry.left + horizontalGeometry.widthAndMargin.margin.left);
displayBox.setContentBoxWidth(horizontalGeometry.widthAndMargin.width);
displayBox.setHorizontalMargin(horizontalGeometry.widthAndMargin.margin);
}
void FormattingContext::computeOutOfFlowVerticalGeometry(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
auto verticalGeometry = Geometry::outOfFlowVerticalGeometry(layoutContext, layoutBox);
displayBox.setTop(verticalGeometry.top + verticalGeometry.heightAndMargin.margin.top);
displayBox.setContentBoxHeight(verticalGeometry.heightAndMargin.height);
ASSERT(!verticalGeometry.heightAndMargin.collapsedMargin);
displayBox.setVerticalMargin(verticalGeometry.heightAndMargin.margin);
displayBox.setVerticalNonCollapsedMargin(verticalGeometry.heightAndMargin.margin);
}
void FormattingContext::computeBorderAndPadding(LayoutContext& layoutContext, const Box& layoutBox, Display::Box& displayBox) const
{
displayBox.setBorder(Geometry::computedBorder(layoutContext, layoutBox));
if (auto padding = Geometry::computedPadding(layoutContext, layoutBox))
displayBox.setPadding(*padding);
}
void FormattingContext::placeInFlowPositionedChildren(LayoutContext& layoutContext, const Container& container) const
{
if (container.establishesFormattingContext() && &container != &root())
return;
LOG_WITH_STREAM(FormattingContextLayout, stream << "Start: move in-flow positioned children -> context: " << &layoutContext << " parent: " << &container);
for (auto& layoutBox : childrenOfType<Box>(container)) {
if (!layoutBox.isInFlowPositioned())
continue;
computeInFlowPositionedPosition(layoutContext, layoutBox, *layoutContext.displayBoxForLayoutBox(layoutBox));
}
LOG_WITH_STREAM(FormattingContextLayout, stream << "End: move in-flow positioned children -> context: " << &layoutContext << " parent: " << &container);
}
void FormattingContext::layoutOutOfFlowDescendants(LayoutContext& layoutContext, const Box& layoutBox) const
{
if (!layoutBox.isPositioned() && !layoutBox.isInitialContainingBlock())
return;
if (!is<Container>(layoutBox))
return;
auto& container = downcast<Container>(layoutBox);
if (!container.hasChild())
return;
LOG_WITH_STREAM(FormattingContextLayout, stream << "Start: layout out-of-flow descendants -> context: " << &layoutContext << " root: " << &root());
for (auto& outOfFlowBox : container.outOfFlowDescendants()) {
auto& layoutBox = *outOfFlowBox;
auto& displayBox = layoutContext.createDisplayBox(layoutBox);
ASSERT(layoutBox.establishesFormattingContext());
auto formattingContext = layoutContext.formattingContext(layoutBox);
auto& establishedFormattingState = layoutContext.establishedFormattingState(layoutBox, *formattingContext);
computeBorderAndPadding(layoutContext, layoutBox, displayBox);
computeOutOfFlowHorizontalGeometry(layoutContext, layoutBox, displayBox);
formattingContext->layout(layoutContext, establishedFormattingState);
computeOutOfFlowVerticalGeometry(layoutContext, layoutBox, displayBox);
layoutOutOfFlowDescendants(layoutContext, layoutBox);
}
LOG_WITH_STREAM(FormattingContextLayout, stream << "End: layout out-of-flow descendants -> context: " << &layoutContext << " root: " << &root());
}
#ifndef NDEBUG
void FormattingContext::validateGeometryConstraintsAfterLayout(const LayoutContext& layoutContext) const
{
if (!is<Container>(root()))
return;
auto& formattingContextRoot = downcast<Container>(root());
for (auto& layoutBox : descendantsOfType<Box>(formattingContextRoot)) {
if (&layoutBox.formattingContextRoot() != &formattingContextRoot)
continue;
auto& containingBlockDisplayBox = *layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock());
auto* displayBox = layoutContext.displayBoxForLayoutBox(layoutBox);
ASSERT(displayBox);
if ((layoutBox.isBlockLevelBox() || layoutBox.isOutOfFlowPositioned()) && !layoutBox.replaced()) {
auto containingBlockWidth = containingBlockDisplayBox.contentBoxWidth();
ASSERT(displayBox->marginLeft() + displayBox->borderLeft() + displayBox->paddingLeft() + displayBox->contentBoxWidth()
+ displayBox->paddingRight() + displayBox->borderRight() + displayBox->marginRight() == containingBlockWidth);
}
if (layoutBox.isOutOfFlowPositioned() && !layoutBox.replaced()) {
auto containingBlockHeight = containingBlockDisplayBox.contentBoxHeight();
ASSERT(displayBox->top() + displayBox->marginTop() + displayBox->borderTop() + displayBox->paddingTop() + displayBox->contentBoxHeight()
+ displayBox->paddingBottom() + displayBox->borderBottom() + displayBox->marginBottom() == containingBlockHeight);
}
}
}
#endif
}
}
#endif