LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset(LayoutUnit offsetInFlowThread) const { LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread(); unsigned columnIndex = columnIndexAtOffset(offsetInFlowThread); LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); flowThread->flipForWritingMode(portionRect); LayoutRect columnRect(columnRectAt(columnIndex)); m_columnSet.flipForWritingMode(columnRect); LayoutSize translationRelativeToGroup = columnRect.location() - portionRect.location(); LayoutSize enclosingTranslation; if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlowThread()) { // Translation that would map points in the coordinate space of the outermost flow thread to // visual points in the first column in the first fragmentainer group (row) in our multicol // container. LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadTranslationAtOffset(flowThread->blockOffsetInEnclosingFragmentationContext()); // Translation that would map points in the coordinate space of the outermost flow thread to // visual points in the first column in this fragmentainer group. enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffset(blockOffsetInEnclosingFragmentationContext()); // What we ultimately return from this method is a translation that maps points in the // coordinate space of our flow thread to a visual point in a certain column in this // fragmentainer group. We had to go all the way up to the outermost flow thread, since this // fragmentainer group may be in a different outer column than the first outer column that // this multicol container lives in. It's the visual distance between the first // fragmentainer group and this fragmentainer group that we need to add to the translation. enclosingTranslation -= enclosingTranslationOrigin; } return enclosingTranslation + translationRelativeToGroup + offsetFromColumnSet() + m_columnSet.topLeftLocationOffset() - flowThread->topLeftLocationOffset(); }
LayoutUnit MultiColumnFragmentainerGroup::calculateMaxColumnHeight() const { LayoutBlockFlow* multicolBlock = m_columnSet.multiColumnBlockFlow(); const ComputedStyle& multicolStyle = multicolBlock->styleRef(); LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread(); LayoutUnit availableHeight = flowThread->columnHeightAvailable(); LayoutUnit maxColumnHeight = availableHeight ? availableHeight : LayoutUnit::max(); if (!multicolStyle.logicalMaxHeight().isMaxSizeNone()) { LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(MaxSize, multicolStyle.logicalMaxHeight(), -1); if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight) maxColumnHeight = logicalMaxHeight; } LayoutUnit maxHeight = heightAdjustedForRowOffset(maxColumnHeight); if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlowThread()) { if (enclosingFlowThread->isPageLogicalHeightKnown()) { // We're nested inside another fragmentation context whose fragmentainer heights are // known. This constrains the max height. LayoutUnit remainingOuterLogicalHeight = enclosingFlowThread->pageRemainingLogicalHeightForOffset(blockOffsetInEnclosingFlowThread(), LayoutBlock::AssociateWithLatterPage); ASSERT(remainingOuterLogicalHeight > 0); if (maxHeight > remainingOuterLogicalHeight) maxHeight = remainingOuterLogicalHeight; } } return maxHeight; }
void MultiColumnFragmentainerGroup::resetColumnHeight() { // Nuke previously stored minimum column height. Contents may have changed for all we know. m_minimumColumnHeight = 0; m_maxColumnHeight = calculateMaxColumnHeight(); LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread(); LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlowThread(); if (enclosingFlowThread && enclosingFlowThread->isPageLogicalHeightKnown()) { // TODO(mstensho): Do this better. If height is auto here, we shouldn't set a // height, or forced breaks and pagination struts might mess up column balancing. LayoutUnit columnHeight = heightIsAuto() ? m_maxColumnHeight : heightAdjustedForRowOffset(flowThread->columnHeightAvailable()); setAndConstrainColumnHeight(columnHeight); } else if (heightIsAuto()) { m_columnHeight = LayoutUnit(); } else { setAndConstrainColumnHeight(heightAdjustedForRowOffset(flowThread->columnHeightAvailable())); } }
LayoutSize MultiColumnFragmentainerGroup::flowThreadTranslationAtOffset( LayoutUnit offsetInFlowThread, LayoutBox::PageBoundaryRule rule, CoordinateSpaceConversion mode) const { LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread(); // A column out of range doesn't have a flow thread portion, so we need to // clamp to make sure that we stay within the actual columns. This means that // content in the overflow area will be mapped to the last actual column, // instead of being mapped to an imaginary column further ahead. unsigned columnIndex = offsetInFlowThread >= logicalBottomInFlowThread() ? actualColumnCount() - 1 : columnIndexAtOffset(offsetInFlowThread, rule); LayoutRect portionRect(flowThreadPortionRectAt(columnIndex)); flowThread->flipForWritingMode(portionRect); portionRect.moveBy(flowThread->topLeftLocation()); LayoutRect columnRect(columnRectAt(columnIndex)); columnRect.move(offsetFromColumnSet()); m_columnSet.flipForWritingMode(columnRect); columnRect.moveBy(m_columnSet.topLeftLocation()); LayoutSize translationRelativeToFlowThread = columnRect.location() - portionRect.location(); if (mode == CoordinateSpaceConversion::Containing) return translationRelativeToFlowThread; LayoutSize enclosingTranslation; if (LayoutMultiColumnFlowThread* enclosingFlowThread = flowThread->enclosingFlowThread()) { const MultiColumnFragmentainerGroup& firstRow = flowThread->firstMultiColumnSet()->firstFragmentainerGroup(); // Translation that would map points in the coordinate space of the // outermost flow thread to visual points in the first column in the first // fragmentainer group (row) in our multicol container. LayoutSize enclosingTranslationOrigin = enclosingFlowThread->flowThreadTranslationAtOffset( firstRow.blockOffsetInEnclosingFragmentationContext(), LayoutBox::AssociateWithLatterPage, mode); // Translation that would map points in the coordinate space of the // outermost flow thread to visual points in the first column in this // fragmentainer group. enclosingTranslation = enclosingFlowThread->flowThreadTranslationAtOffset( blockOffsetInEnclosingFragmentationContext(), LayoutBox::AssociateWithLatterPage, mode); // What we ultimately return from this method is a translation that maps // points in the coordinate space of our flow thread to a visual point in a // certain column in this fragmentainer group. We had to go all the way up // to the outermost flow thread, since this fragmentainer group may be in a // different outer column than the first outer column that this multicol // container lives in. It's the visual distance between the first // fragmentainer group and this fragmentainer group that we need to add to // the translation. enclosingTranslation -= enclosingTranslationOrigin; } return enclosingTranslation + translationRelativeToFlowThread; }