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