Example #1
0
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());
}
Example #2
0
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);
        }
    }
}
Example #3
0
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());
}
Example #4
0
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);
  }
}
Example #5
0
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()));
}