void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded(LayoutUnit bottomOffsetInFlowThread) { if (!isPageLogicalHeightKnown()) { // If we have no clue about the height of the multicol container, bail. This situation // occurs initially when an auto-height multicol container is nested inside another // auto-height multicol container. We need at least an estimated height of the outer // multicol container before we can check what an inner fragmentainer group has room for. // Its height is indefinite for now. return; } // TODO(mstensho): bottomOffsetInFlowThread is an endpoint-exclusive offset, i.e. the offset // just after the bottom of some object. So, ideally, columnSetAtBlockOffset() should be // informed about this (i.e. take a PageBoundaryRule argument). This is not the only place with // this issue; see also pageRemainingLogicalHeightForOffset(). LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(bottomOffsetInFlowThread); if (columnSet->isInitialHeightCalculated()) { // We only insert additional fragmentainer groups in the initial layout pass. We only want // to balance columns in the last fragmentainer group (if we need to balance at all), so we // want that last fragmentainer group to be the same one in all layout passes that follow. return; } if (!columnSet->hasFragmentainerGroupForColumnAt(bottomOffsetInFlowThread)) { FragmentationContext* enclosingFragmentationContext = this->enclosingFragmentationContext(); if (!enclosingFragmentationContext) return; // Not nested. We'll never need more rows than the one we already have then. ASSERT(!isLayoutPagedFlowThread()); // We have run out of columns here, so we add another row to hold more columns. When we add // a new row, it implicitly means that we're inserting another column in our enclosing // multicol container. That in turn may mean that we've run out of columns there too. const MultiColumnFragmentainerGroup& newRow = columnSet->appendNewFragmentainerGroup(); if (LayoutMultiColumnFlowThread* enclosingFlowThread = enclosingFragmentationContext->associatedFlowThread()) enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOffsetInEnclosingFragmentationContext() + newRow.logicalHeight()); } }
void LayoutMultiColumnFlowThread::appendNewFragmentainerGroupIfNeeded(LayoutUnit offsetInFlowThread) { if (!isPageLogicalHeightKnown()) { // If we have no clue about the height of the multicol container, bail. This situation // occurs initially when an auto-height multicol container is nested inside another // auto-height multicol container. We need at least an estimated height of the outer // multicol container before we can check what an inner fragmentainer group has room for. // Its height is indefinite for now. return; } LayoutMultiColumnSet* columnSet = columnSetAtBlockOffset(offsetInFlowThread); if (columnSet->isInitialHeightCalculated()) { // We only insert additional fragmentainer groups in the initial layout pass. We only want // to balance columns in the last fragmentainer group (if we need to balance at all), so we // want that last fragmentainer group to be the same one in all layout passes that follow. return; } if (!columnSet->hasFragmentainerGroupForColumnAt(offsetInFlowThread)) { FragmentationContext* enclosingFragmentationContext = this->enclosingFragmentationContext(); if (!enclosingFragmentationContext) return; // Not nested. We'll never need more rows than the one we already have then. ASSERT(!isLayoutPagedFlowThread()); // We have run out of columns here, so we add another row to hold more columns. When we add // a new row, it implicitly means that we're inserting another column in our enclosing // multicol container. That in turn may mean that we've run out of columns there too. const MultiColumnFragmentainerGroup& newRow = columnSet->appendNewFragmentainerGroup(); if (LayoutMultiColumnFlowThread* enclosingFlowThread = enclosingFragmentationContext->associatedFlowThread()) enclosingFlowThread->appendNewFragmentainerGroupIfNeeded(newRow.blockOffsetInEnclosingFragmentationContext()); } }
bool MultiColumnFragmentainerGroup::recalculateColumnHeight( LayoutMultiColumnSet& columnSet) { LayoutUnit oldColumnHeight = m_columnHeight; m_maxColumnHeight = calculateMaxColumnHeight(); // Only the last row may have auto height, and thus be balanced. There are no // good reasons to balance the preceding rows, and that could potentially lead // to an insane number of layout passes as well. if (isLastGroup() && columnSet.heightIsAuto()) { LayoutUnit newColumnHeight; if (!columnSet.isInitialHeightCalculated()) { // Initial balancing: Start with the lowest imaginable column height. Also // calculate the height of the tallest piece of unbreakable content. // Columns should never get any shorter than that (unless constrained by // max-height). Propagate this to our containing column set, in case there // is an outer multicol container that also needs to balance. After having // calculated the initial column height, the multicol container needs // another layout pass with the column height that we just calculated. InitialColumnHeightFinder initialHeightFinder( columnSet, logicalTopInFlowThread(), logicalBottomInFlowThread()); LayoutUnit tallestUnbreakableLogicalHeight = initialHeightFinder.tallestUnbreakableLogicalHeight(); columnSet.propagateTallestUnbreakableLogicalHeight( tallestUnbreakableLogicalHeight); newColumnHeight = std::max(initialHeightFinder.initialMinimalBalancedHeight(), tallestUnbreakableLogicalHeight); } else { // Rebalancing: After having laid out again, we'll need to rebalance if // the height wasn't enough and we're allowed to stretch it, and then // re-lay out. There are further details on the column balancing // machinery in ColumnBalancer and its derivates. newColumnHeight = rebalanceColumnHeightIfNeeded(); } setAndConstrainColumnHeight(newColumnHeight); } else { // The position of the column set may have changed, in which case height // available for columns may have changed as well. setAndConstrainColumnHeight(m_columnHeight); } if (m_columnHeight == oldColumnHeight) return false; // No change. We're done. return true; // Need another pass. }