void PartPainter::paintContents(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location(); Widget* widget = m_layoutPart.widget(); CHECK(widget); IntPoint paintLocation(roundedIntPoint( adjustedPaintOffset + m_layoutPart.replacedContentRect().location())); // Widgets don't support painting with a paint offset, but instead offset // themselves using the frame rect location. To paint widgets at our desired // location, we need to apply paint offset as a transform, with the frame rect // neutralized. IntSize widgetPaintOffset = paintLocation - widget->frameRect().location(); TransformRecorder transform( paintInfo.context, m_layoutPart, AffineTransform::translation(widgetPaintOffset.width(), widgetPaintOffset.height())); CullRect adjustedCullRect(paintInfo.cullRect(), -widgetPaintOffset); widget->paint(paintInfo.context, adjustedCullRect); }
void SVGImagePainter::paint(const PaintInfo& paintInfo) { if (paintInfo.phase != PaintPhaseForeground || m_layoutSVGImage.style()->visibility() != EVisibility::Visible || !m_layoutSVGImage.imageResource()->hasImage()) return; FloatRect boundingBox = m_layoutSVGImage.visualRectInLocalSVGCoordinates(); if (!paintInfo.cullRect().intersectsCullRect( m_layoutSVGImage.localToSVGParentTransform(), boundingBox)) return; PaintInfo paintInfoBeforeFiltering(paintInfo); // Images cannot have children so do not call updateCullRect. SVGTransformContext transformContext( paintInfoBeforeFiltering.context, m_layoutSVGImage, m_layoutSVGImage.localToSVGParentTransform()); { SVGPaintContext paintContext(m_layoutSVGImage, paintInfoBeforeFiltering); if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintContext.paintInfo().context, m_layoutSVGImage, paintContext.paintInfo().phase)) { LayoutObjectDrawingRecorder recorder( paintContext.paintInfo().context, m_layoutSVGImage, paintContext.paintInfo().phase, boundingBox); paintForeground(paintContext.paintInfo()); } } if (m_layoutSVGImage.style()->outlineWidth()) { PaintInfo outlinePaintInfo(paintInfoBeforeFiltering); outlinePaintInfo.phase = PaintPhaseSelfOutlineOnly; ObjectPainter(m_layoutSVGImage) .paintOutline(outlinePaintInfo, LayoutPoint(boundingBox.location())); } }
void SVGShapePainter::paint(const PaintInfo& paintInfo) { if (paintInfo.phase != PaintPhaseForeground || m_layoutSVGShape.style()->visibility() == HIDDEN || m_layoutSVGShape.isShapeEmpty()) return; FloatRect boundingBox = m_layoutSVGShape.paintInvalidationRectInLocalCoordinates(); if (!paintInfo.cullRect().intersectsCullRect(m_layoutSVGShape.localTransform(), boundingBox)) return; PaintInfo paintInfoBeforeFiltering(paintInfo); // Shapes cannot have children so do not call updateCullRect. TransformRecorder transformRecorder(paintInfoBeforeFiltering.context, m_layoutSVGShape, m_layoutSVGShape.localTransform()); { SVGPaintContext paintContext(m_layoutSVGShape, paintInfoBeforeFiltering); if (paintContext.applyClipMaskAndFilterIfNecessary() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintContext.paintInfo().context, m_layoutSVGShape, paintContext.paintInfo().phase, LayoutPoint())) { LayoutObjectDrawingRecorder recorder(paintContext.paintInfo().context, m_layoutSVGShape, paintContext.paintInfo().phase, boundingBox, LayoutPoint()); const SVGComputedStyle& svgStyle = m_layoutSVGShape.style()->svgStyle(); bool shouldAntiAlias = svgStyle.shapeRendering() != SR_CRISPEDGES; for (int i = 0; i < 3; i++) { switch (svgStyle.paintOrderType(i)) { case PT_FILL: { SkPaint fillPaint; if (!SVGPaintContext::paintForLayoutObject(paintContext.paintInfo(), m_layoutSVGShape.styleRef(), m_layoutSVGShape, ApplyToFillMode, fillPaint)) break; fillPaint.setAntiAlias(shouldAntiAlias); fillShape(paintContext.paintInfo().context, fillPaint, fillRuleFromStyle(paintContext.paintInfo(), svgStyle)); break; } case PT_STROKE: if (svgStyle.hasVisibleStroke()) { GraphicsContextStateSaver stateSaver(paintContext.paintInfo().context, false); AffineTransform nonScalingTransform; const AffineTransform* additionalPaintServerTransform = 0; if (m_layoutSVGShape.hasNonScalingStroke()) { nonScalingTransform = m_layoutSVGShape.nonScalingStrokeTransform(); if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) return; // Non-scaling stroke needs to reset the transform back to the host transform. additionalPaintServerTransform = &nonScalingTransform; } SkPaint strokePaint; if (!SVGPaintContext::paintForLayoutObject(paintContext.paintInfo(), m_layoutSVGShape.styleRef(), m_layoutSVGShape, ApplyToStrokeMode, strokePaint, additionalPaintServerTransform)) break; strokePaint.setAntiAlias(shouldAntiAlias); StrokeData strokeData; SVGLayoutSupport::applyStrokeStyleToStrokeData(strokeData, m_layoutSVGShape.styleRef(), m_layoutSVGShape, m_layoutSVGShape.dashScaleFactor()); strokeData.setupPaint(&strokePaint); strokeShape(paintContext.paintInfo().context, strokePaint); } break; case PT_MARKERS: paintMarkers(paintContext.paintInfo(), boundingBox); break; default: ASSERT_NOT_REACHED(); break; } } } } if (m_layoutSVGShape.style()->outlineWidth()) { PaintInfo outlinePaintInfo(paintInfoBeforeFiltering); outlinePaintInfo.phase = PaintPhaseSelfOutlineOnly; ObjectPainter(m_layoutSVGShape).paintOutline(outlinePaintInfo, LayoutPoint(boundingBox.location())); } }
void GridPainter::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { DCHECK(!m_layoutGrid.needsLayout()); LayoutRect localVisualRect = LayoutRect(paintInfo.cullRect().m_rect); localVisualRect.moveBy(-paintOffset); Vector<LayoutUnit> columnPositions = m_layoutGrid.columnPositions(); if (!m_layoutGrid.styleRef().isLeftToRightDirection()) { // Translate columnPositions in RTL as we need the physical coordinates of // the columns in order to call dirtiedGridAreas(). for (size_t i = 0; i < columnPositions.size(); i++) columnPositions[i] = m_layoutGrid.translateRTLCoordinate(columnPositions[i]); // We change the order of tracks in columnPositions, as in RTL the leftmost // track will be the last one. std::sort(columnPositions.begin(), columnPositions.end()); } GridSpan dirtiedColumns = dirtiedGridAreas( columnPositions, localVisualRect.x(), localVisualRect.maxX()); GridSpan dirtiedRows = dirtiedGridAreas( m_layoutGrid.rowPositions(), localVisualRect.y(), localVisualRect.maxY()); if (!m_layoutGrid.styleRef().isLeftToRightDirection()) { // As we changed the order of tracks previously, we need to swap the dirtied // columns in RTL. size_t lastLine = columnPositions.size() - 1; dirtiedColumns = GridSpan::translatedDefiniteGridSpan( lastLine - dirtiedColumns.endLine(), lastLine - dirtiedColumns.startLine()); } Vector<std::pair<LayoutBox*, size_t>> gridItemsToBePainted; for (const auto& row : dirtiedRows) { for (const auto& column : dirtiedColumns) { const Vector<LayoutBox*, 1>& children = m_layoutGrid.gridCell(row, column); for (auto* child : children) gridItemsToBePainted.append( std::make_pair(child, m_layoutGrid.paintIndexForGridItem(child))); } } for (auto* item : m_layoutGrid.itemsOverflowingGridArea()) { if (item->frameRect().intersects(localVisualRect)) gridItemsToBePainted.append( std::make_pair(item, m_layoutGrid.paintIndexForGridItem(item))); } std::stable_sort(gridItemsToBePainted.begin(), gridItemsToBePainted.end(), compareOrderModifiedDocumentOrder); LayoutBox* previous = 0; for (const auto& gridItemAndPaintIndex : gridItemsToBePainted) { // We might have duplicates because of spanning children are included in all // cells they span. Skip them here to avoid painting items several times. LayoutBox* current = gridItemAndPaintIndex.first; if (current == previous) continue; BlockPainter(m_layoutGrid) .paintAllChildPhasesAtomically(*current, paintInfo, paintOffset); previous = current; } }
void ListMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutListMarker.style()->visibility() != EVisibility::Visible) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutListMarker, paintInfo.phase)) return; LayoutPoint boxOrigin(paintOffset + m_layoutListMarker.location()); LayoutRect overflowRect(m_layoutListMarker.visualOverflowRect()); overflowRect.moveBy(boxOrigin); IntRect pixelSnappedOverflowRect = pixelSnappedIntRect(overflowRect); if (!paintInfo.cullRect().intersectsCullRect(overflowRect)) return; LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutListMarker, paintInfo.phase, pixelSnappedOverflowRect); LayoutRect box(boxOrigin, m_layoutListMarker.size()); IntRect marker = m_layoutListMarker.getRelativeMarkerRect(); marker.moveBy(roundedIntPoint(boxOrigin)); GraphicsContext& context = paintInfo.context; if (m_layoutListMarker.isImage()) { context.drawImage(m_layoutListMarker.image() ->image(m_layoutListMarker, marker.size(), m_layoutListMarker.styleRef().effectiveZoom()) .get(), marker); if (m_layoutListMarker.getSelectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context.fillRect( pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } return; } LayoutListMarker::ListStyleCategory styleCategory = m_layoutListMarker.getListStyleCategory(); if (styleCategory == LayoutListMarker::ListStyleCategory::None) return; Color color(m_layoutListMarker.resolveColor(CSSPropertyColor)); if (BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( m_layoutListMarker.styleRef(), m_layoutListMarker.listItem()->document())) color = TextPainter::textColorForWhiteBackground(color); // Apply the color to the list marker text. context.setFillColor(color); const EListStyleType listStyle = m_layoutListMarker.style()->listStyleType(); if (styleCategory == LayoutListMarker::ListStyleCategory::Symbol) { paintSymbol(context, color, marker, listStyle); return; } if (m_layoutListMarker.text().isEmpty()) return; const Font& font = m_layoutListMarker.style()->font(); TextRun textRun = constructTextRun(font, m_layoutListMarker.text(), m_layoutListMarker.styleRef()); GraphicsContextStateSaver stateSaver(context, false); if (!m_layoutListMarker.style()->isHorizontalWritingMode()) { marker.moveBy(roundedIntPoint(-boxOrigin)); marker = marker.transposedRect(); marker.moveBy( IntPoint(roundToInt(box.x()), roundToInt(box.y() - m_layoutListMarker.logicalHeight()))); stateSaver.save(); context.translate(marker.x(), marker.maxY()); context.rotate(static_cast<float>(deg2rad(90.))); context.translate(-marker.x(), -marker.maxY()); } TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = marker; const SimpleFontData* fontData = m_layoutListMarker.style()->font().primaryFont(); IntPoint textOrigin = IntPoint( marker.x(), marker.y() + (fontData ? fontData->getFontMetrics().ascent() : 0)); // Text is not arbitrary. We can judge whether it's RTL from the first // character, and we only need to handle the direction RightToLeft for now. bool textNeedsReversing = WTF::Unicode::direction(m_layoutListMarker.text()[0]) == WTF::Unicode::RightToLeft; StringBuilder reversedText; if (textNeedsReversing) { unsigned length = m_layoutListMarker.text().length(); reversedText.reserveCapacity(length); for (int i = length - 1; i >= 0; --i) reversedText.append(m_layoutListMarker.text()[i]); DCHECK(reversedText.length() == length); textRun.setText(reversedText.toString()); } const UChar suffix = ListMarkerText::suffix(listStyle, m_layoutListMarker.listItem()->value()); UChar suffixStr[2] = {suffix, static_cast<UChar>(' ')}; TextRun suffixRun = constructTextRun(font, suffixStr, 2, m_layoutListMarker.styleRef(), m_layoutListMarker.style()->direction()); TextRunPaintInfo suffixRunInfo(suffixRun); suffixRunInfo.bounds = marker; if (m_layoutListMarker.style()->isLeftToRightDirection()) { context.drawText(font, textRunPaintInfo, textOrigin); context.drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0)); } else { context.drawText(font, suffixRunInfo, textOrigin); context.drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0)); } }
void TableCellPainter::paintCollapsedBorders(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const CollapsedBorderValue& currentBorderValue) { if (m_layoutTableCell.style()->visibility() != VISIBLE) return; const ComputedStyle& styleForCellFlow = m_layoutTableCell.styleForCellFlow(); const CollapsedBorderValue* leftBorderValue = cachedCollapsedLeftBorder(styleForCellFlow); const CollapsedBorderValue* rightBorderValue = cachedCollapsedRightBorder(styleForCellFlow); const CollapsedBorderValue* topBorderValue = cachedCollapsedTopBorder(styleForCellFlow); const CollapsedBorderValue* bottomBorderValue = cachedCollapsedBottomBorder(styleForCellFlow); int displayItemType = DisplayItem::TableCollapsedBorderBase; int topWidth = 0; int bottomWidth = 0; int leftWidth = 0; int rightWidth = 0; if (topBorderValue) { if (topBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderTop; topWidth = topBorderValue->width(); } if (bottomBorderValue) { if (bottomBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderBottom; bottomWidth = bottomBorderValue->width(); } if (leftBorderValue) { if (leftBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderLeft; leftWidth = leftBorderValue->width(); } if (rightBorderValue) { if (rightBorderValue->shouldPaint(currentBorderValue)) displayItemType |= DisplayItem::TableCollapsedBorderRight; rightWidth = rightBorderValue->width(); } if (displayItemType == DisplayItem::TableCollapsedBorderBase) return; // Adjust our x/y/width/height so that we paint the collapsed borders at the correct location. LayoutRect paintRect = paintBounds(paintOffset, AddOffsetFromParent); IntRect borderRect = pixelSnappedIntRect(paintRect.x() - leftWidth / 2, paintRect.y() - topWidth / 2, paintRect.width() + leftWidth / 2 + (rightWidth + 1) / 2, paintRect.height() + topWidth / 2 + (bottomWidth + 1) / 2); if (!paintInfo.cullRect().intersectsCullRect(borderRect)) return; GraphicsContext& graphicsContext = paintInfo.context; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(graphicsContext, m_layoutTableCell, static_cast<DisplayItem::Type>(displayItemType))) return; LayoutObjectDrawingRecorder recorder(graphicsContext, m_layoutTableCell, static_cast<DisplayItem::Type>(displayItemType), borderRect); Color cellColor = m_layoutTableCell.resolveColor(CSSPropertyColor); // We never paint diagonals at the joins. We simply let the border with the highest // precedence paint on top of borders with lower precedence. if (displayItemType & DisplayItem::TableCollapsedBorderTop) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.y(), borderRect.maxX(), borderRect.y() + topWidth, BSTop, topBorderValue->color().resolve(cellColor), collapsedBorderStyle(topBorderValue->style()), 0, 0, true); } if (displayItemType & DisplayItem::TableCollapsedBorderBottom) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.maxY() - bottomWidth, borderRect.maxX(), borderRect.maxY(), BSBottom, bottomBorderValue->color().resolve(cellColor), collapsedBorderStyle(bottomBorderValue->style()), 0, 0, true); } if (displayItemType & DisplayItem::TableCollapsedBorderLeft) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.x(), borderRect.y(), borderRect.x() + leftWidth, borderRect.maxY(), BSLeft, leftBorderValue->color().resolve(cellColor), collapsedBorderStyle(leftBorderValue->style()), 0, 0, true); } if (displayItemType & DisplayItem::TableCollapsedBorderRight) { ObjectPainter::drawLineForBoxSide(graphicsContext, borderRect.maxX() - rightWidth, borderRect.y(), borderRect.maxX(), borderRect.maxY(), BSRight, rightBorderValue->color().resolve(cellColor), collapsedBorderStyle(rightBorderValue->style()), 0, 0, true); } }
void BlockPainter::paintOverflowControlsIfNeeded(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { PaintPhase phase = paintInfo.phase; if (m_layoutBlock.hasOverflowClip() && m_layoutBlock.style()->visibility() == VISIBLE && (phase == PaintPhaseSelfBlockBackground || phase == PaintPhaseBlockBackground) && paintInfo.shouldPaintWithinRoot(&m_layoutBlock) && !paintInfo.paintRootBackgroundOnly()) { Optional<ClipRecorder> clipRecorder; if (!m_layoutBlock.layer()->isSelfPaintingLayer()) { LayoutRect clipRect = m_layoutBlock.borderBoxRect(); clipRect.moveBy(paintOffset); clipRecorder.emplace(paintInfo.context, m_layoutBlock, DisplayItem::ClipScrollbarsToBoxBounds, clipRect); } ScrollableAreaPainter(*m_layoutBlock.layer()->scrollableArea()).paintOverflowControls(paintInfo.context, roundedIntPoint(paintOffset), paintInfo.cullRect(), false /* paintingOverlayControls */); } }
void PartPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (!m_layoutPart.shouldPaint(paintInfo, paintOffset)) return; LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location(); LayoutRect borderRect(adjustedPaintOffset, m_layoutPart.size()); if (m_layoutPart.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) BoxPainter(m_layoutPart).paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { BoxPainter(m_layoutPart).paintMask(paintInfo, adjustedPaintOffset); return; } if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && m_layoutPart.style()->hasOutline()) ObjectPainter(m_layoutPart).paintOutline(paintInfo, adjustedPaintOffset); if (paintInfo.phase != PaintPhaseForeground) return; { Optional<RoundedInnerRectClipper> clipper; if (m_layoutPart.style()->hasBorderRadius()) { if (borderRect.isEmpty()) return; FloatRoundedRect roundedInnerRect = m_layoutPart.style()->getRoundedInnerBorderFor(borderRect, LayoutRectOutsets( -(m_layoutPart.paddingTop() + m_layoutPart.borderTop()), -(m_layoutPart.paddingRight() + m_layoutPart.borderRight()), -(m_layoutPart.paddingBottom() + m_layoutPart.borderBottom()), -(m_layoutPart.paddingLeft() + m_layoutPart.borderLeft())), true, true); clipper.emplace(m_layoutPart, paintInfo, borderRect, roundedInnerRect, ApplyToDisplayList); } if (m_layoutPart.widget()) m_layoutPart.paintContents(paintInfo, paintOffset); } // Paint a partially transparent wash over selected widgets. if (isSelected() && !paintInfo.isPrinting() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutPart, paintInfo.phase, adjustedPaintOffset)) { LayoutRect rect = m_layoutPart.localSelectionRect(); rect.moveBy(adjustedPaintOffset); IntRect selectionRect = pixelSnappedIntRect(rect); LayoutObjectDrawingRecorder drawingRecorder(*paintInfo.context, m_layoutPart, paintInfo.phase, selectionRect, adjustedPaintOffset); paintInfo.context->fillRect(selectionRect, m_layoutPart.selectionBackgroundColor()); } if (m_layoutPart.canResize()) ScrollableAreaPainter(*m_layoutPart.layer()->scrollableArea()).paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.cullRect()); }
void TableSectionPainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutRect localPaintInvalidationRect = LayoutRect(paintInfo.cullRect().m_rect); localPaintInvalidationRect.moveBy(-paintOffset); LayoutRect tableAlignedRect = m_layoutTableSection.logicalRectForWritingModeAndDirection(localPaintInvalidationRect); CellSpan dirtiedRows = m_layoutTableSection.dirtiedRows(tableAlignedRect); CellSpan dirtiedColumns = m_layoutTableSection.dirtiedColumns(tableAlignedRect); if (dirtiedColumns.start() >= dirtiedColumns.end()) return; const HashSet<LayoutTableCell*>& overflowingCells = m_layoutTableSection.overflowingCells(); if (!m_layoutTableSection.hasMultipleCellLevels() && !overflowingCells.size()) { // Draw the dirty cells in the order that they appear. for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { const LayoutTableRow* row = m_layoutTableSection.rowLayoutObjectAt(r); if (row && !row->hasSelfPaintingLayer()) TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, paintOffset); for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) { const LayoutTableSection::CellStruct& current = m_layoutTableSection.cellAt(r, c); const LayoutTableCell* cell = current.primaryCell(); if (!cell || (r > dirtiedRows.start() && m_layoutTableSection.primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && m_layoutTableSection.primaryCellAt(r, c - 1) == cell)) continue; paintCell(*cell, paintInfo, paintOffset); } } } else { // The overflowing cells should be scarce to avoid adding a lot of cells to the HashSet. #if ENABLE(ASSERT) unsigned totalRows = m_layoutTableSection.numRows(); unsigned totalCols = m_layoutTableSection.table()->columns().size(); ASSERT(overflowingCells.size() < totalRows * totalCols * gMaxAllowedOverflowingCellRatioForFastPaintPath); #endif // To make sure we properly paint invalidate the section, we paint invalidated all the overflowing cells that we collected. Vector<LayoutTableCell*> cells; copyToVector(overflowingCells, cells); HashSet<LayoutTableCell*> spanningCells; for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { const LayoutTableRow* row = m_layoutTableSection.rowLayoutObjectAt(r); if (row && !row->hasSelfPaintingLayer()) TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, paintOffset); for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) { const LayoutTableSection::CellStruct& current = m_layoutTableSection.cellAt(r, c); if (!current.hasCells()) continue; for (unsigned i = 0; i < current.cells.size(); ++i) { if (overflowingCells.contains(current.cells[i])) continue; if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) { if (!spanningCells.add(current.cells[i]).isNewEntry) continue; } cells.append(current.cells[i]); } } } // Sort the dirty cells by paint order. if (!overflowingCells.size()) std::stable_sort(cells.begin(), cells.end(), compareCellPositions); else std::sort(cells.begin(), cells.end(), compareCellPositionsWithOverflowingCells); for (unsigned i = 0; i < cells.size(); ++i) paintCell(*cells[i], paintInfo, paintOffset); } }
void LineBoxListPainter::paint(const LayoutBoxModelObject& layoutObject, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const { ASSERT(!shouldPaintSelfOutline(paintInfo.phase) && !shouldPaintDescendantOutlines(paintInfo.phase)); // Only paint during the foreground/selection phases. if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && paintInfo.phase != PaintPhaseMask) return; ASSERT(layoutObject.isLayoutBlock() || (layoutObject.isLayoutInline() && layoutObject.hasLayer())); // The only way an inline could paint like this is if it has a layer. if (paintInfo.phase == PaintPhaseForeground && paintInfo.isPrinting()) addPDFURLRectsForInlineChildrenRecursively(layoutObject, paintInfo, paintOffset); // If we have no lines then we have no work to do. if (!m_lineBoxList.firstLineBox()) return; if (!m_lineBoxList.anyLineIntersectsRect(LineLayoutBoxModel(const_cast<LayoutBoxModelObject*>(&layoutObject)), paintInfo.cullRect(), paintOffset)) return; PaintInfo info(paintInfo); // See if our root lines intersect with the dirty rect. If so, then we paint // them. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. for (InlineFlowBox* curr = m_lineBoxList.firstLineBox(); curr; curr = curr->nextLineBox()) { if (m_lineBoxList.lineIntersectsDirtyRect(LineLayoutBoxModel(const_cast<LayoutBoxModelObject*>(&layoutObject)), curr, info.cullRect(), paintOffset)) { RootInlineBox& root = curr->root(); curr->paint(info, paintOffset, root.lineTop(), root.lineBottom()); } } }
void PartPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint adjustedPaintOffset = paintOffset + m_layoutPart.location(); if (!ReplacedPainter(m_layoutPart) .shouldPaint(paintInfo, adjustedPaintOffset)) return; LayoutRect borderRect(adjustedPaintOffset, m_layoutPart.size()); if (m_layoutPart.hasBoxDecorationBackground() && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) BoxPainter(m_layoutPart) .paintBoxDecorationBackground(paintInfo, adjustedPaintOffset); if (paintInfo.phase == PaintPhaseMask) { BoxPainter(m_layoutPart).paintMask(paintInfo, adjustedPaintOffset); return; } if (shouldPaintSelfOutline(paintInfo.phase)) ObjectPainter(m_layoutPart).paintOutline(paintInfo, adjustedPaintOffset); if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutPart.widget()) { // TODO(schenney) crbug.com/93805 Speculative release assert to verify that // the crashes we see in widget painting are due to a destroyed LayoutPart // object. CHECK(m_layoutPart.node()); Optional<RoundedInnerRectClipper> clipper; if (m_layoutPart.style()->hasBorderRadius()) { if (borderRect.isEmpty()) return; FloatRoundedRect roundedInnerRect = m_layoutPart.style()->getRoundedInnerBorderFor( borderRect, LayoutRectOutsets( -(m_layoutPart.paddingTop() + m_layoutPart.borderTop()), -(m_layoutPart.paddingRight() + m_layoutPart.borderRight()), -(m_layoutPart.paddingBottom() + m_layoutPart.borderBottom()), -(m_layoutPart.paddingLeft() + m_layoutPart.borderLeft())), true, true); clipper.emplace(m_layoutPart, paintInfo, borderRect, roundedInnerRect, ApplyToDisplayList); } m_layoutPart.paintContents(paintInfo, paintOffset); } // Paint a partially transparent wash over selected widgets. if (isSelected() && !paintInfo.isPrinting() && !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutPart, paintInfo.phase)) { LayoutRect rect = m_layoutPart.localSelectionRect(); rect.moveBy(adjustedPaintOffset); IntRect selectionRect = pixelSnappedIntRect(rect); LayoutObjectDrawingRecorder drawingRecorder(paintInfo.context, m_layoutPart, paintInfo.phase, selectionRect); paintInfo.context.fillRect(selectionRect, m_layoutPart.selectionBackgroundColor()); } if (m_layoutPart.canResize()) ScrollableAreaPainter(*m_layoutPart.layer()->getScrollableArea()) .paintResizer(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.cullRect()); }