static bool isValidColumnSpanner(RenderMultiColumnFlowThread* flowThread, RenderObject* descendant) { // We assume that we're inside the flow thread. This function is not to be called otherwise. ASSERT(descendant->isDescendantOf(flowThread)); // First make sure that the renderer itself has the right properties for becoming a spanner. RenderStyle& style = descendant->style(); if (style.columnSpan() != ColumnSpanAll || !descendant->isBox() || descendant->isFloatingOrOutOfFlowPositioned()) return false; RenderBlock* container = descendant->containingBlock(); if (!container->isRenderBlockFlow() || container->childrenInline()) { // Needs to be block-level. return false; } // This looks like a spanner, but if we're inside something unbreakable, it's not to be treated as one. for (RenderBox* ancestor = toRenderBox(descendant)->parentBox(); ancestor; ancestor = ancestor->parentBox()) { if (ancestor->isRenderFlowThread()) { // Don't allow any intervening non-multicol fragmentation contexts. The spec doesn't say // anything about disallowing this, but it's just going to be too complicated to // implement (not to mention specify behavior). return ancestor == flowThread; } ASSERT(ancestor->style().columnSpan() != ColumnSpanAll || !isValidColumnSpanner(flowThread, ancestor)); if (ancestor->isUnsplittableForPagination()) return false; } ASSERT_NOT_REACHED(); return false; }
LayoutState::LayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo, bool containingBlockLogicalWidthChanged) : m_containingBlockLogicalWidthChanged(containingBlockLogicalWidthChanged) , m_columnInfo(columnInfo) , m_next(renderer.view()->layoutState()) , m_renderer(renderer) { m_flowThread = renderer.isRenderFlowThread() ? toRenderFlowThread(&renderer) : m_next->flowThread(); renderer.view()->pushLayoutState(*this); bool fixed = renderer.isOutOfFlowPositioned() && renderer.style()->position() == FixedPosition; if (fixed) { // FIXME: This doesn't work correctly with transforms. FloatPoint fixedOffset = renderer.view()->localToAbsolute(FloatPoint(), IsFixed); m_layoutOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset; } else { m_layoutOffset = m_next->m_layoutOffset + offset; } if (renderer.isOutOfFlowPositioned() && !fixed) { if (RenderObject* container = renderer.container()) { if (container->style()->hasInFlowPosition() && container->isRenderInline()) m_layoutOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer); } } // If we establish a new page height, then cache the offset to the top of the first page. // We can compare this later on to figure out what part of the page we're actually on, if (pageLogicalHeight || m_columnInfo || renderer.isRenderFlowThread()) { m_pageLogicalHeight = pageLogicalHeight; bool isFlipped = renderer.style()->isFlippedBlocksWritingMode(); m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer.borderLeft() + renderer.paddingLeft() : renderer.borderRight() + renderer.paddingRight()), m_layoutOffset.height() + (!isFlipped ? renderer.borderTop() + renderer.paddingTop() : renderer.borderBottom() + renderer.paddingBottom())); m_pageLogicalHeightChanged = pageLogicalHeightChanged; m_isPaginated = true; } else { // If we don't establish a new page height, then propagate the old page height and offset down. m_pageLogicalHeight = m_next->m_pageLogicalHeight; m_pageLogicalHeightChanged = m_next->m_pageLogicalHeightChanged; m_pageOffset = m_next->m_pageOffset; // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and // writing mode roots. if (renderer.isUnsplittableForPagination()) { m_pageLogicalHeight = 0; m_isPaginated = false; } else { m_isPaginated = m_pageLogicalHeight || m_next->m_columnInfo || renderer.flowThreadContainingBlock(); } } if (!m_columnInfo) m_columnInfo = m_next->m_columnInfo; // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. }