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()); if (isFirstAfterBreak(lineTopInFlowThread)) recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut()); }
void LayoutState::computeLineGridPaginationOrigin(RenderBox* renderer) { // We need to cache a line grid pagination origin so that we understand how to reset the line grid // at the top of each column. // Get the current line grid and offset. if (!lineGrid() || lineGrid()->style().writingMode() != renderer->style().writingMode()) return; // Get the hypothetical line box used to establish the grid. RootInlineBox* lineGridBox = lineGrid()->lineGridBox(); if (!lineGridBox) return; bool isHorizontalWritingMode = lineGrid()->isHorizontalWritingMode(); LayoutUnit lineGridBlockOffset = isHorizontalWritingMode ? lineGridOffset().height() : lineGridOffset().width(); // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple // as established by the line box. // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume // the grid should honor line-box-contain. LayoutUnit gridLineHeight = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading(); if (!gridLineHeight) return; LayoutUnit firstLineTopWithLeading = lineGridBlockOffset + lineGridBox->lineTopWithLeading(); if (isPaginated() && pageLogicalHeight()) { LayoutUnit pageLogicalTop = renderer->isHorizontalWritingMode() ? m_pageOffset.height() : m_pageOffset.width(); if (pageLogicalTop > firstLineTopWithLeading) { // Shift to the next highest line grid multiple past the page logical top. Cache the delta // between this new value and the page logical top as the pagination origin. LayoutUnit remainder = roundToInt(pageLogicalTop - firstLineTopWithLeading) % roundToInt(gridLineHeight); LayoutUnit paginationDelta = gridLineHeight - remainder; if (isHorizontalWritingMode) m_lineGridPaginationOrigin.setHeight(paginationDelta); else m_lineGridPaginationOrigin.setWidth(paginationDelta); } } }
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 = lineTopInFlowThread - group().columnLogicalTopForOffset(lineTopInFlowThread); recordSpaceShortage(logicalOffsetFromCurrentColumn + lineHeight - m_pendingStrut); m_pendingStrut = LayoutUnit::min(); return; } ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut()); if (isFirstAfterBreak(lineTopInFlowThread)) recordSpaceShortage(lineHeight - line.paginationStrut()); }
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); } }
LayoutUnit RootInlineBox::lineSnapAdjustment(LayoutUnit delta) const { // If our block doesn't have snapping turned on, do nothing. // FIXME: Implement bounds snapping. if (blockFlow().style().lineSnap() == LineSnapNone) return 0; // Get the current line grid and offset. LayoutState* layoutState = blockFlow().view().layoutState(); RenderBlockFlow* lineGrid = layoutState->lineGrid(); LayoutSize lineGridOffset = layoutState->lineGridOffset(); if (!lineGrid || lineGrid->style().writingMode() != blockFlow().style().writingMode()) return 0; // Get the hypothetical line box used to establish the grid. RootInlineBox* lineGridBox = lineGrid->lineGridBox(); if (!lineGridBox) return 0; LayoutUnit lineGridBlockOffset = lineGrid->isHorizontalWritingMode() ? lineGridOffset.height() : lineGridOffset.width(); LayoutUnit blockOffset = blockFlow().isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width(); // Now determine our position on the grid. Our baseline needs to be adjusted to the nearest baseline multiple // as established by the line box. // FIXME: Need to handle crazy line-box-contain values that cause the root line box to not be considered. I assume // the grid should honor line-box-contain. LayoutUnit gridLineHeight = lineGridBox->lineBottomWithLeading() - lineGridBox->lineTopWithLeading(); if (!gridLineHeight) return 0; LayoutUnit lineGridFontAscent = lineGrid->style().fontMetrics().ascent(baselineType()); LayoutUnit lineGridFontHeight = lineGridBox->logicalHeight(); LayoutUnit firstTextTop = lineGridBlockOffset + lineGridBox->logicalTop(); LayoutUnit firstLineTopWithLeading = lineGridBlockOffset + lineGridBox->lineTopWithLeading(); LayoutUnit firstBaselinePosition = firstTextTop + lineGridFontAscent; LayoutUnit currentTextTop = blockOffset + logicalTop() + delta; LayoutUnit currentFontAscent = blockFlow().style().fontMetrics().ascent(baselineType()); LayoutUnit currentBaselinePosition = currentTextTop + currentFontAscent; LayoutUnit lineGridPaginationOrigin = isHorizontal() ? layoutState->lineGridPaginationOrigin().height() : layoutState->lineGridPaginationOrigin().width(); // If we're paginated, see if we're on a page after the first one. If so, the grid resets on subsequent pages. // FIXME: If the grid is an ancestor of the pagination establisher, then this is incorrect. LayoutUnit pageLogicalTop = 0; if (layoutState->isPaginated() && layoutState->pageLogicalHeight()) { pageLogicalTop = blockFlow().pageLogicalTopForOffset(lineTopWithLeading() + delta); if (pageLogicalTop > firstLineTopWithLeading) firstTextTop = pageLogicalTop + lineGridBox->logicalTop() - lineGrid->borderAndPaddingBefore() + lineGridPaginationOrigin; } if (blockFlow().style().lineSnap() == LineSnapContain) { // Compute the desired offset from the text-top of a grid line. // Look at our height (logicalHeight()). // Look at the total available height. It's going to be (textBottom - textTop) + (n-1)*(multiple with leading) // where n is number of grid lines required to enclose us. if (logicalHeight() <= lineGridFontHeight) firstTextTop += (lineGridFontHeight - logicalHeight()) / 2; else { LayoutUnit numberOfLinesWithLeading = ceilf(static_cast<float>(logicalHeight() - lineGridFontHeight) / gridLineHeight); LayoutUnit totalHeight = lineGridFontHeight + numberOfLinesWithLeading * gridLineHeight; firstTextTop += (totalHeight - logicalHeight()) / 2; } firstBaselinePosition = firstTextTop + currentFontAscent; } else firstBaselinePosition = firstTextTop + lineGridFontAscent; // If we're above the first line, just push to the first line. if (currentBaselinePosition < firstBaselinePosition) return delta + firstBaselinePosition - currentBaselinePosition; // Otherwise we're in the middle of the grid somewhere. Just push to the next line. LayoutUnit baselineOffset = currentBaselinePosition - firstBaselinePosition; LayoutUnit remainder = roundToInt(baselineOffset) % roundToInt(gridLineHeight); LayoutUnit result = delta; if (remainder) result += gridLineHeight - remainder; // If we aren't paginated we can return the result. if (!layoutState->isPaginated() || !layoutState->pageLogicalHeight() || result == delta) return result; // We may end up shifted to a new page. We need to do a re-snap when that happens. LayoutUnit newPageLogicalTop = blockFlow().pageLogicalTopForOffset(lineBottomWithLeading() + result); if (newPageLogicalTop == pageLogicalTop) return result; // Put ourselves at the top of the next page to force a snap onto the new grid established by that page. return lineSnapAdjustment(newPageLogicalTop - (blockOffset + lineTopWithLeading())); }