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; }
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; } }