void BlockFlowPainter::paintSelection(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    ASSERT(paintInfo.phase == PaintPhaseForeground);
    if (!m_layoutBlockFlow.shouldPaintSelectionGaps())
        return;

    LayoutUnit lastTop = 0;
    LayoutUnit lastLeft = m_layoutBlockFlow.logicalLeftSelectionOffset(&m_layoutBlockFlow, lastTop);
    LayoutUnit lastRight = m_layoutBlockFlow.logicalRightSelectionOffset(&m_layoutBlockFlow, lastTop);

    LayoutRect bounds = m_layoutBlockFlow.visualOverflowRect();
    bounds.moveBy(paintOffset);

    // Only create a DrawingRecorder and ClipScope if skipRecording is false. This logic is needed
    // because selectionGaps(...) needs to be called even when we do not record.
    bool skipRecording = LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutBlockFlow, DisplayItem::SelectionGap, paintOffset);
    Optional<LayoutObjectDrawingRecorder> drawingRecorder;
    Optional<ClipScope> clipScope;
    if (!skipRecording) {
        drawingRecorder.emplace(paintInfo.context, m_layoutBlockFlow, DisplayItem::SelectionGap, FloatRect(bounds), paintOffset);
        clipScope.emplace(paintInfo.context);
    }

    LayoutRect gapRectsBounds = m_layoutBlockFlow.selectionGaps(&m_layoutBlockFlow, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight,
        skipRecording ? nullptr : &paintInfo,
        skipRecording ? nullptr : &(*clipScope));
    // TODO(wkorman): Rework below to process paint invalidation rects during layout rather than paint.
    if (!gapRectsBounds.isEmpty()) {
        PaintLayer* layer = m_layoutBlockFlow.enclosingLayer();
        gapRectsBounds.moveBy(-paintOffset);
        if (!m_layoutBlockFlow.hasLayer()) {
            LayoutRect localBounds(gapRectsBounds);
            m_layoutBlockFlow.flipForWritingMode(localBounds);
            gapRectsBounds = LayoutRect(m_layoutBlockFlow.localToAncestorQuad(FloatRect(localBounds), layer->layoutObject()).enclosingBoundingBox());
            if (layer->layoutObject()->hasOverflowClip())
                gapRectsBounds.move(layer->layoutBox()->scrolledContentOffset());
        }
        layer->addBlockSelectionGapsBounds(gapRectsBounds);
    }
}
PaintLayerPainter::PaintResult PaintLayerPainter::paintChildren(unsigned childrenToVisit, GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
    PaintResult result = FullyPainted;
    if (!m_paintLayer.hasSelfPaintingLayerDescendant())
        return result;

#if ENABLE(ASSERT)
    LayerListMutationDetector mutationChecker(m_paintLayer.stackingNode());
#endif

    PaintLayerStackingNodeIterator iterator(*m_paintLayer.stackingNode(), childrenToVisit);
    PaintLayerStackingNode* child = iterator.next();
    if (!child)
        return result;

    IntSize scrollOffsetAccumulationForChildren = paintingInfo.scrollOffsetAccumulation;
    if (m_paintLayer.layoutObject()->hasOverflowClip())
        scrollOffsetAccumulationForChildren += m_paintLayer.layoutBox()->scrolledContentOffset();

    for (; child; child = iterator.next()) {
        PaintLayerPainter childPainter(*child->layer());
        // If this Layer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents()
        // and CompositedLayerMapping::doPaintTask().
        if (!childPainter.shouldPaintLayerInSoftwareMode(paintingInfo.globalPaintFlags(), paintFlags))
            continue;

        PaintLayerPaintingInfo childPaintingInfo = paintingInfo;
        childPaintingInfo.scrollOffsetAccumulation = scrollOffsetAccumulationForChildren;
        // Rare case: accumulate scroll offset of non-stacking-context ancestors up to m_paintLayer.
        for (PaintLayer* parentLayer = child->layer()->parent(); parentLayer != &m_paintLayer; parentLayer = parentLayer->parent()) {
            if (parentLayer->layoutObject()->hasOverflowClip())
                childPaintingInfo.scrollOffsetAccumulation += parentLayer->layoutBox()->scrolledContentOffset();
        }

        if (childPainter.paintLayer(context, childPaintingInfo, paintFlags) == MayBeClippedByPaintDirtyRect)
            result = MayBeClippedByPaintDirtyRect;
    }

    return result;
}
Example #3
0
PaintLayerPainter::PaintResult PaintLayerPainter::paintChildren(unsigned childrenToVisit, GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags)
{
    PaintResult result = FullyPainted;
    if (!m_paintLayer.hasSelfPaintingLayerDescendant())
        return result;

#if ENABLE(ASSERT)
    LayerListMutationDetector mutationChecker(m_paintLayer.stackingNode());
#endif

    PaintLayerStackingNodeIterator iterator(*m_paintLayer.stackingNode(), childrenToVisit);
    PaintLayerStackingNode* child = iterator.next();
    if (!child)
        return result;

    DisplayItem::Type subsequenceType;
    if (childrenToVisit == NegativeZOrderChildren) {
        subsequenceType = DisplayItem::SubsequenceNegativeZOrder;
    } else {
        ASSERT(childrenToVisit == (NormalFlowChildren | PositiveZOrderChildren));
        subsequenceType = DisplayItem::SubsequenceNormalFlowAndPositiveZOrder;
    }

    Optional<SubsequenceRecorder> subsequenceRecorder;
    if (!paintingInfo.disableSubsequenceCache
        && !(paintingInfo.globalPaintFlags() & GlobalPaintFlattenCompositingLayers)
        && !(paintFlags & PaintLayerPaintingReflection)
        && !(paintFlags & PaintLayerPaintingRootBackgroundOnly)) {
        if (!m_paintLayer.needsRepaint()
            && paintingInfo.scrollOffsetAccumulation == m_paintLayer.previousScrollOffsetAccumulationForPainting()
            && SubsequenceRecorder::useCachedSubsequenceIfPossible(*context, m_paintLayer, subsequenceType))
            return result;
        subsequenceRecorder.emplace(*context, m_paintLayer, subsequenceType);
    }

    IntSize scrollOffsetAccumulationForChildren = paintingInfo.scrollOffsetAccumulation;
    if (m_paintLayer.layoutObject()->hasOverflowClip())
        scrollOffsetAccumulationForChildren += m_paintLayer.layoutBox()->scrolledContentOffset();

    bool disableChildSubsequenceCache = !RuntimeEnabledFeatures::slimmingPaintV2Enabled()
        && (m_paintLayer.layoutObject()->hasOverflowClip() || m_paintLayer.layoutObject()->hasClip());

    for (; child; child = iterator.next()) {
        PaintLayerPainter childPainter(*child->layer());
        // If this Layer should paint into its own backing or a grouped backing, that will be done via CompositedLayerMapping::paintContents()
        // and CompositedLayerMapping::doPaintTask().
        if (!childPainter.shouldPaintLayerInSoftwareMode(paintingInfo.globalPaintFlags(), paintFlags))
            continue;

        PaintLayerPaintingInfo childPaintingInfo = paintingInfo;
        childPaintingInfo.disableSubsequenceCache = disableChildSubsequenceCache;
        childPaintingInfo.scrollOffsetAccumulation = scrollOffsetAccumulationForChildren;
        // Rare case: accumulate scroll offset of non-stacking-context ancestors up to m_paintLayer.
        for (PaintLayer* parentLayer = child->layer()->parent(); parentLayer != &m_paintLayer; parentLayer = parentLayer->parent()) {
            if (parentLayer->layoutObject()->hasOverflowClip())
                childPaintingInfo.scrollOffsetAccumulation += parentLayer->layoutBox()->scrolledContentOffset();
        }

        if (childPainter.paintLayer(context, childPaintingInfo, paintFlags) == MaybeNotFullyPainted)
            result = MaybeNotFullyPainted;
    }

    // Set subsequence not cacheable if the bounding box of this layer and descendants is not fully contained
    // by paintRect, because later paintRect changes may expose new contents which will need repainting.
    if (result == MaybeNotFullyPainted && subsequenceRecorder)
        subsequenceRecorder->setUncacheable();

    return result;
}