LayoutRect MultiColumnFragmentainerGroup::flowThreadPortionOverflowRectAt(
    unsigned columnIndex) const {
  // This function determines the portion of the flow thread that paints for the
  // column. Along the inline axis, columns are unclipped at outside edges
  // (i.e., the first and last column in the set), and they clip to half the
  // column gap along interior edges.
  //
  // In the block direction, we will not clip overflow out of the top of the
  // first column, or out of the bottom of the last column. This applies only to
  // the true first column and last column across all column sets.
  //
  // FIXME: Eventually we will know overflow on a per-column basis, but we can't
  // do this until we have a painting mode that understands not to paint
  // contents from a previous column in the overflow area of a following column.
  bool isFirstColumnInRow = !columnIndex;
  bool isLastColumnInRow = columnIndex == actualColumnCount() - 1;
  bool isLTR = m_columnSet.style()->isLeftToRightDirection();
  bool isLeftmostColumn = isLTR ? isFirstColumnInRow : isLastColumnInRow;
  bool isRightmostColumn = isLTR ? isLastColumnInRow : isFirstColumnInRow;

  LayoutRect portionRect = flowThreadPortionRectAt(columnIndex);
  bool isFirstColumnInMulticolContainer =
      isFirstColumnInRow && this == &m_columnSet.firstFragmentainerGroup() &&
      !m_columnSet.previousSiblingMultiColumnSet();
  bool isLastColumnInMulticolContainer =
      isLastColumnInRow && this == &m_columnSet.lastFragmentainerGroup() &&
      !m_columnSet.nextSiblingMultiColumnSet();
  // Calculate the overflow rectangle, based on the flow thread's, clipped at
  // column logical top/bottom unless it's the first/last column.
  LayoutRect overflowRect = m_columnSet.overflowRectForFlowThreadPortion(
      portionRect, isFirstColumnInMulticolContainer,
      isLastColumnInMulticolContainer);

  // Avoid overflowing into neighboring columns, by clipping in the middle of
  // adjacent column gaps. Also make sure that we avoid rounding errors.
  LayoutUnit columnGap = m_columnSet.columnGap();
  if (m_columnSet.isHorizontalWritingMode()) {
    if (!isLeftmostColumn)
      overflowRect.shiftXEdgeTo(portionRect.x() - columnGap / 2);
    if (!isRightmostColumn)
      overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + columnGap -
                                   columnGap / 2);
  } else {
    if (!isLeftmostColumn)
      overflowRect.shiftYEdgeTo(portionRect.y() - columnGap / 2);
    if (!isRightmostColumn)
      overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + columnGap -
                                   columnGap / 2);
  }
  return overflowRect;
}
Exemple #2
0
LayoutRect RootInlineBox::paddedLayoutOverflowRect(LayoutUnit endPadding) const
{
    LayoutRect lineLayoutOverflow = layoutOverflowRect(lineTop(), lineBottom());
    if (!endPadding)
        return lineLayoutOverflow;
    
    // FIXME: Audit whether to use pixel snapped values when not using integers for layout: https://bugs.webkit.org/show_bug.cgi?id=63656
    if (isHorizontal()) {
        if (isLeftToRightDirection())
            lineLayoutOverflow.shiftMaxXEdgeTo(std::max<LayoutUnit>(lineLayoutOverflow.maxX(), pixelSnappedLogicalRight() + endPadding));
        else
            lineLayoutOverflow.shiftXEdgeTo(std::min<LayoutUnit>(lineLayoutOverflow.x(), pixelSnappedLogicalLeft() - endPadding));
    } else {
        if (isLeftToRightDirection())
            lineLayoutOverflow.shiftMaxYEdgeTo(std::max<LayoutUnit>(lineLayoutOverflow.maxY(), pixelSnappedLogicalRight() + endPadding));
        else
            lineLayoutOverflow.shiftYEdgeTo(std::min<LayoutUnit>(lineLayoutOverflow.y(), pixelSnappedLogicalLeft() - endPadding));
    }
    
    return lineLayoutOverflow;
}
LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, LayoutUnit colGap)
{
    // This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are
    // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column
    // gap along interior edges.
    //
    // In the block direction, we will not clip overflow out of the top of the first column, or out of the bottom of
    // the last column. This applies only to the true first column and last column across all column sets.
    //
    // FIXME: Eventually we will know overflow on a per-column basis, but we can't do this until we have a painting
    // mode that understands not to paint contents from a previous column in the overflow area of a following column.
    // This problem applies to regions and pages as well and is not unique to columns.
    
    RenderBlockFlow* parentFlow = toRenderBlockFlow(parent());
    bool progressionReversed = parentFlow->multiColumnFlowThread()->progressionIsReversed();
    
    bool isFirstColumn = !index;
    bool isLastColumn = index == colCount - 1;
    bool isLeftmostColumn = style().isLeftToRightDirection() ^ progressionReversed ? isFirstColumn : isLastColumn;
    bool isRightmostColumn = style().isLeftToRightDirection() ^ progressionReversed ? isLastColumn : isFirstColumn;

    // Calculate the overflow rectangle, based on the flow thread's, clipped at column logical
    // top/bottom unless it's the first/last column.
    LayoutRect overflowRect = overflowRectForFlowThreadPortion(portionRect, isFirstColumn && isFirstRegion(), isLastColumn && isLastRegion(), VisualOverflow);

    // Avoid overflowing into neighboring columns, by clipping in the middle of adjacent column
    // gaps. Also make sure that we avoid rounding errors.
    if (isHorizontalWritingMode()) {
        if (!isLeftmostColumn)
            overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2);
        if (!isRightmostColumn)
            overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap - colGap / 2);
    } else {
        if (!isLeftmostColumn)
            overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2);
        if (!isRightmostColumn)
            overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap - colGap / 2);
    }
    return overflowRect;
}
void RenderMathMLOperator::fillWithExtensionGlyph(PaintInfo& info, const LayoutPoint& from, const LayoutPoint& to)
{
    ASSERT(m_stretchyCharacter);
    ASSERT(m_stretchyCharacter->extensionGlyph);
    ASSERT(from.y() <= to.y());

    // If there is no space for the extension glyph, we don't need to do anything.
    if (from.y() == to.y())
        return;

    GraphicsContextStateSaver stateSaver(*info.context);

    FloatRect glyphBounds = glyphBoundsForCharacter(m_stretchyCharacter->extensionGlyph);

    // Clipping the extender region here allows us to draw the bottom extender glyph into the
    // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
    LayoutRect clipBounds = info.rect;
    clipBounds.shiftYEdgeTo(from.y());
    clipBounds.shiftMaxYEdgeTo(to.y());
    info.context->clip(clipBounds);

    // Trimming may remove up to two pixels from the top of the extender glyph, so we move it up by two pixels.
    float offsetToGlyphTop = glyphBounds.y() + 2;
    LayoutPoint glyphOrigin = LayoutPoint(from.x(), from.y() - offsetToGlyphTop);
    FloatRect lastPaintedGlyphRect(from, FloatSize());

    while (lastPaintedGlyphRect.maxY() < to.y()) {
        lastPaintedGlyphRect = paintCharacter(info, m_stretchyCharacter->extensionGlyph, glyphOrigin, TrimTopAndBottom);
        glyphOrigin.setY(glyphOrigin.y() + lastPaintedGlyphRect.height());

        // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
        // with trimming. In that case we just draw nothing.
        if (lastPaintedGlyphRect.isEmpty())
            break;
    }
}