blob: 4ea37764cefc7d6fe9e92c633cbea3db757dbd83 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
#include "core/layout/LayoutMultiColumnFlowThread.h"
namespace blink {
static void copyMarginProperties(ComputedStyle& placeholderStyle,
const ComputedStyle& spannerStyle) {
// We really only need the block direction margins, but there are no setters
// for that in ComputedStyle. Just copy all margin sides. The inline ones
// don't matter anyway.
placeholderStyle.setMarginLeft(spannerStyle.marginLeft());
placeholderStyle.setMarginRight(spannerStyle.marginRight());
placeholderStyle.setMarginTop(spannerStyle.marginTop());
placeholderStyle.setMarginBottom(spannerStyle.marginBottom());
}
LayoutMultiColumnSpannerPlaceholder*
LayoutMultiColumnSpannerPlaceholder::createAnonymous(
const ComputedStyle& parentStyle,
LayoutBox& layoutObjectInFlowThread) {
LayoutMultiColumnSpannerPlaceholder* newSpanner =
new LayoutMultiColumnSpannerPlaceholder(&layoutObjectInFlowThread);
Document& document = layoutObjectInFlowThread.document();
newSpanner->setDocumentForAnonymous(&document);
RefPtr<ComputedStyle> newStyle =
ComputedStyle::createAnonymousStyleWithDisplay(parentStyle,
EDisplay::Block);
copyMarginProperties(*newStyle, layoutObjectInFlowThread.styleRef());
newSpanner->setStyle(newStyle);
return newSpanner;
}
LayoutMultiColumnSpannerPlaceholder::LayoutMultiColumnSpannerPlaceholder(
LayoutBox* layoutObjectInFlowThread)
: LayoutBox(nullptr),
m_layoutObjectInFlowThread(layoutObjectInFlowThread) {}
void LayoutMultiColumnSpannerPlaceholder::
layoutObjectInFlowThreadStyleDidChange(const ComputedStyle* oldStyle) {
LayoutBox* objectInFlowThread = m_layoutObjectInFlowThread;
if (flowThread()->removeSpannerPlaceholderIfNoLongerValid(
objectInFlowThread)) {
// No longer a valid spanner, due to style changes. |this| is now dead.
if (objectInFlowThread->style()->hasOutOfFlowPosition() &&
!oldStyle->hasOutOfFlowPosition()) {
// We went from being a spanner to being out-of-flow positioned. When an
// object becomes out-of-flow positioned, we need to lay out its parent,
// since that's where the now-out-of-flow object gets added to the right
// containing block for out-of-flow positioned objects. Since neither a
// spanner nor an out-of-flow object is guaranteed to have this parent in
// its containing block chain, we need to mark it here, or we risk that
// the object isn't laid out.
objectInFlowThread->parent()->setNeedsLayout(
LayoutInvalidationReason::ColumnsChanged);
}
return;
}
updateMarginProperties();
}
void LayoutMultiColumnSpannerPlaceholder::updateMarginProperties() {
RefPtr<ComputedStyle> newStyle = ComputedStyle::clone(styleRef());
copyMarginProperties(*newStyle, m_layoutObjectInFlowThread->styleRef());
setStyle(newStyle);
}
void LayoutMultiColumnSpannerPlaceholder::insertedIntoTree() {
LayoutBox::insertedIntoTree();
// The object may previously have been laid out as a non-spanner, but since
// it's a spanner now, it needs to be relaid out.
m_layoutObjectInFlowThread->setNeedsLayoutAndPrefWidthsRecalc(
LayoutInvalidationReason::ColumnsChanged);
}
void LayoutMultiColumnSpannerPlaceholder::willBeRemovedFromTree() {
if (m_layoutObjectInFlowThread) {
LayoutBox* exSpanner = m_layoutObjectInFlowThread;
m_layoutObjectInFlowThread->clearSpannerPlaceholder();
// Even if the placeholder is going away, the object in the flow thread
// might live on. Since it's not a spanner anymore, it needs to be relaid
// out.
exSpanner->setNeedsLayoutAndPrefWidthsRecalc(
LayoutInvalidationReason::ColumnsChanged);
}
LayoutBox::willBeRemovedFromTree();
}
bool LayoutMultiColumnSpannerPlaceholder::needsPreferredWidthsRecalculation()
const {
return m_layoutObjectInFlowThread->needsPreferredWidthsRecalculation();
}
LayoutUnit LayoutMultiColumnSpannerPlaceholder::minPreferredLogicalWidth()
const {
return m_layoutObjectInFlowThread->minPreferredLogicalWidth();
}
LayoutUnit LayoutMultiColumnSpannerPlaceholder::maxPreferredLogicalWidth()
const {
return m_layoutObjectInFlowThread->maxPreferredLogicalWidth();
}
void LayoutMultiColumnSpannerPlaceholder::layout() {
ASSERT(needsLayout());
// The placeholder, like any other block level object, has its logical top
// calculated and set before layout. Copy this to the actual column-span:all
// object before laying it out, so that it gets paginated correctly, in case
// we have an enclosing fragmentation context.
m_layoutObjectInFlowThread->setLogicalTop(logicalTop());
// Lay out the actual column-span:all element.
m_layoutObjectInFlowThread->layoutIfNeeded();
// The spanner has now been laid out, so its height is known. Time to update
// the placeholder's height as well, so that we take up the correct amount of
// space in the multicol container.
updateLogicalHeight();
// Take the overflow from the spanner, so that it gets propagated to the
// multicol container and beyond.
m_overflow.reset();
addContentsVisualOverflow(m_layoutObjectInFlowThread->visualOverflowRect());
addLayoutOverflow(m_layoutObjectInFlowThread->layoutOverflowRect());
clearNeedsLayout();
}
void LayoutMultiColumnSpannerPlaceholder::computeLogicalHeight(
LayoutUnit,
LayoutUnit logicalTop,
LogicalExtentComputedValues& computedValues) const {
computedValues.m_extent = m_layoutObjectInFlowThread->logicalHeight();
computedValues.m_position = logicalTop;
computedValues.m_margins.m_before = marginBefore();
computedValues.m_margins.m_after = marginAfter();
}
void LayoutMultiColumnSpannerPlaceholder::paint(
const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) const {
if (!m_layoutObjectInFlowThread->hasSelfPaintingLayer())
m_layoutObjectInFlowThread->paint(paintInfo, paintOffset);
}
bool LayoutMultiColumnSpannerPlaceholder::nodeAtPoint(
HitTestResult& result,
const HitTestLocation& locationInContainer,
const LayoutPoint& accumulatedOffset,
HitTestAction action) {
return !m_layoutObjectInFlowThread->hasSelfPaintingLayer() &&
m_layoutObjectInFlowThread->nodeAtPoint(result, locationInContainer,
accumulatedOffset, action);
}
} // namespace blink