void InitialColumnHeightFinder::examineLine(const RootInlineBox& line) { LayoutUnit lineTop = line.lineTopWithLeading(); LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; LayoutUnit minimumLogialHeight = columnLogicalHeightRequirementForLine(line.block().styleRef(), line); m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, minimumLogialHeight); ASSERT( isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); if (isFirstAfterBreak(lineTopInFlowThread)) recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); }
void InitialColumnHeightFinder::examineBoxAfterEntering( const LayoutBox& box, LayoutUnit childLogicalHeight, EBreak previousBreakAfterValue) { if (m_lastBreakSeen > flowThreadOffset()) { // We have moved backwards. We're probably in a parallel flow, caused by // floats, sibling table cells, etc. m_lastBreakSeen = LayoutUnit(); } if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { if (box.needsForcedBreakBefore(previousBreakAfterValue)) { addContentRun(flowThreadOffset()); } else if (isFirstAfterBreak(flowThreadOffset()) && m_lastBreakSeen != flowThreadOffset()) { // This box is first after a soft break. m_lastBreakSeen = flowThreadOffset(); recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut()); } } if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) { m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, childLogicalHeight); return; } // Need to examine inner multicol containers to find their tallest unbreakable // piece of content. if (!box.isLayoutBlockFlow()) return; LayoutMultiColumnFlowThread* innerFlowThread = toLayoutBlockFlow(box).multiColumnFlowThread(); if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread()) return; LayoutUnit offsetInInnerFlowThread = flowThreadOffset() - innerFlowThread->blockOffsetInEnclosingFragmentationContext(); LayoutUnit innerUnbreakableHeight = innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread); m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight); }
void InitialColumnHeightFinder::examineBoxAfterEntering( const LayoutBox& box, EBreak previousBreakAfterValue) { if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { if (box.needsForcedBreakBefore(previousBreakAfterValue)) { addContentRun(flowThreadOffset()); } else { ASSERT(isFirstAfterBreak(flowThreadOffset()) || !box.paginationStrut()); if (isFirstAfterBreak(flowThreadOffset())) { // This box is first after a soft break. recordStrutBeforeOffset(flowThreadOffset(), box.paginationStrut()); } } } if (box.getPaginationBreakability() != LayoutBox::AllowAnyBreaks) { LayoutUnit unsplittableLogicalHeight = box.logicalHeight(); if (box.isFloating()) unsplittableLogicalHeight += box.marginBefore() + box.marginAfter(); m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight); return; } // Need to examine inner multicol containers to find their tallest unbreakable // piece of content. if (!box.isLayoutBlockFlow()) return; LayoutMultiColumnFlowThread* innerFlowThread = toLayoutBlockFlow(box).multiColumnFlowThread(); if (!innerFlowThread || innerFlowThread->isLayoutPagedFlowThread()) return; LayoutUnit offsetInInnerFlowThread = flowThreadOffset() - innerFlowThread->blockOffsetInEnclosingFragmentationContext(); LayoutUnit innerUnbreakableHeight = innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread); m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight); }
void MinimumSpaceShortageFinder::examineLine(const RootInlineBox& line) { LayoutUnit lineTop = line.lineTopWithLeading(); LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop; LayoutUnit lineHeight = line.lineBottomWithLeading() - lineTop; if (m_pendingStrut != LayoutUnit::min()) { // The previous break was before a breakable block. Here's the first line // after / inside that block. We want to record the distance from the top of // the column to the bottom of this box as space shortage. LayoutUnit logicalOffsetFromCurrentColumn = offsetFromColumnLogicalTop(lineTopInFlowThread); recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - m_pendingStrut); m_pendingStrut = LayoutUnit::min(); return; } ASSERT( isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut() || !isLogicalTopWithinBounds(lineTopInFlowThread - line.paginationStrut())); if (isFirstAfterBreak(lineTopInFlowThread)) recordSpaceShortage(lineHeight - line.paginationStrut()); // Even if the line box itself fits fine inside a column, some content may // overflow the line box bottom (due to restrictive line-height, for // instance). We should check if some portion of said overflow ends up in the // next column. That counts as space shortage. const MultiColumnFragmentainerGroup& group = groupAtOffset(lineTopInFlowThread); LayoutUnit lineBottomWithOverflow = lineTopInFlowThread + line.lineBottom() - lineTop; if (group.columnLogicalTopForOffset(lineTopInFlowThread) != group.columnLogicalTopForOffset(lineBottomWithOverflow)) { LayoutUnit shortage = lineBottomWithOverflow - group.columnLogicalTopForOffset(lineBottomWithOverflow); recordSpaceShortage(shortage); } }
void MinimumSpaceShortageFinder::examineBoxAfterEntering( const LayoutBox& box, LayoutUnit childLogicalHeight, EBreak previousBreakAfterValue) { LayoutBox::PaginationBreakability breakability = box.getPaginationBreakability(); // Look for breaks before the child box. if (isLogicalTopWithinBounds(flowThreadOffset() - box.paginationStrut())) { if (box.needsForcedBreakBefore(previousBreakAfterValue)) { m_forcedBreaksCount++; } else { if (isFirstAfterBreak(flowThreadOffset())) { // This box is first after a soft break. LayoutUnit strut = box.paginationStrut(); // Figure out how much more space we would need to prevent it from being // pushed to the next column. recordSpaceShortage(childLogicalHeight - strut); if (breakability != LayoutBox::ForbidBreaks && m_pendingStrut == LayoutUnit::min()) { // We now want to look for the first piece of unbreakable content // (e.g. a line or a block-displayed image) inside this block. That // ought to be a good candidate for minimum space shortage; a much // better one than reporting space shortage for the entire block // (which we'll also do (further down), in case we couldn't find // anything more suitable). m_pendingStrut = strut; } } } } if (breakability != LayoutBox::ForbidBreaks) { // See if this breakable box crosses column boundaries. LayoutUnit bottomInFlowThread = flowThreadOffset() + childLogicalHeight; const MultiColumnFragmentainerGroup& group = groupAtOffset(flowThreadOffset()); if (isFirstAfterBreak(flowThreadOffset()) || group.columnLogicalTopForOffset(flowThreadOffset()) != group.columnLogicalTopForOffset(bottomInFlowThread)) { // If the child crosses a column boundary, record space shortage, in case // nothing inside it has already done so. The column balancer needs to // know by how much it has to stretch the columns to make more content // fit. If no breaks are reported (but do occur), the balancer will have // no clue. Only measure the space after the last column boundary, in case // it crosses more than one. LayoutUnit spaceUsedInLastColumn = bottomInFlowThread - group.columnLogicalTopForOffset(bottomInFlowThread); recordSpaceShortage(spaceUsedInLastColumn); } } // If this is an inner multicol container, look for space shortage inside it. if (!box.isLayoutBlockFlow()) return; LayoutMultiColumnFlowThread* flowThread = toLayoutBlockFlow(box).multiColumnFlowThread(); if (!flowThread || flowThread->isLayoutPagedFlowThread()) return; for (const LayoutMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet()) { // Establish an inner shortage finder for this column set in the inner // multicol container. We need to let it walk through all fragmentainer // groups in one go, or we'd miss the column boundaries between each // fragmentainer group. We need to record space shortage there too. MinimumSpaceShortageFinder innerFinder( *columnSet, columnSet->logicalTopInFlowThread(), columnSet->logicalBottomInFlowThread()); recordSpaceShortage(innerFinder.minimumSpaceShortage()); } }