| // 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::invalidatePaintOfSubtreesIfNeeded(const PaintInvalidationState& childPaintInvalidationState) |
| { |
| m_layoutObjectInFlowThread->invalidateTreeIfNeeded(childPaintInvalidationState); |
| LayoutBox::invalidatePaintOfSubtreesIfNeeded(childPaintInvalidationState); |
| } |
| |
| 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 |