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