void PaintLayerPainter::paintForegroundForFragments(const PaintLayerFragments& layerFragments, GraphicsContext& context, const LayoutRect& transparencyPaintDirtyRect, const PaintLayerPaintingInfo& localPaintingInfo, bool selectionOnly, PaintLayerFlags paintFlags) { // Optimize clipping for the single fragment case. bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && !layerFragments[0].foregroundRect.isEmpty(); ClipState clipState = HasNotClipped; Optional<LayerClipRecorder> clipRecorder; if (shouldClip && needsToClip(localPaintingInfo, layerFragments[0].foregroundRect)) { clipRecorder.emplace(context, *m_paintLayer.layoutObject(), DisplayItem::ClipLayerForeground, layerFragments[0].foregroundRect, &localPaintingInfo, layerFragments[0].paginationOffset, paintFlags); clipState = HasClipped; } // We have to loop through every fragment multiple times, since we have to issue paint invalidations in each specific phase in order for // interleaving of the fragments to work properly. paintForegroundForFragmentsWithPhase(selectionOnly ? PaintPhaseSelection : PaintPhaseDescendantBlockBackgroundsOnly, layerFragments, context, localPaintingInfo, paintFlags, clipState); if (!selectionOnly) { if (m_paintLayer.needsPaintPhaseFloat()) paintForegroundForFragmentsWithPhase(PaintPhaseFloat, layerFragments, context, localPaintingInfo, paintFlags, clipState); paintForegroundForFragmentsWithPhase(PaintPhaseForeground, layerFragments, context, localPaintingInfo, paintFlags, clipState); if (m_paintLayer.needsPaintPhaseDescendantOutlines()) paintForegroundForFragmentsWithPhase(PaintPhaseDescendantOutlinesOnly, layerFragments, context, localPaintingInfo, paintFlags, clipState); } }
void PaintLayerPainter::paintOverflowControlsForFragments(const PaintLayerFragments& layerFragments, GraphicsContext* context, const PaintLayerPaintingInfo& localPaintingInfo, PaintLayerFlags paintFlags) { bool needsScope = layerFragments.size() > 1; for (auto& fragment : layerFragments) { Optional<ScopeRecorder> scopeRecorder; if (needsScope) scopeRecorder.emplace(*context); Optional<LayerClipRecorder> clipRecorder; if (needsToClip(localPaintingInfo, fragment.backgroundRect)) clipRecorder.emplace(*context, *m_paintLayer.layoutObject(), DisplayItem::ClipLayerOverflowControls, fragment.backgroundRect, &localPaintingInfo, fragment.paginationOffset, paintFlags); if (PaintLayerScrollableArea* scrollableArea = m_paintLayer.scrollableArea()) ScrollableAreaPainter(*scrollableArea).paintOverflowControls(context, roundedIntPoint(toPoint(fragment.layerBounds.location() - m_paintLayer.layoutBoxLocation())), pixelSnappedIntRect(fragment.backgroundRect.rect()), true); } }
void PaintLayerPainter::paintFragmentWithPhase(PaintPhase phase, const PaintLayerFragment& fragment, GraphicsContext& context, const ClipRect& clipRect, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, ClipState clipState) { ASSERT(m_paintLayer.isSelfPaintingLayer()); Optional<LayerClipRecorder> clipRecorder; if (clipState != HasClipped && paintingInfo.clipToDirtyRect && needsToClip(paintingInfo, clipRect)) { DisplayItem::Type clipType = DisplayItem::paintPhaseToClipLayerFragmentType(phase); LayerClipRecorder::BorderRadiusClippingRule clippingRule; switch (phase) { case PaintPhaseSelfBlockBackgroundOnly: // Background painting will handle clipping to self. case PaintPhaseSelfOutlineOnly: case PaintPhaseMask: // Mask painting will handle clipping to self. clippingRule = LayerClipRecorder::DoNotIncludeSelfForBorderRadius; break; default: clippingRule = LayerClipRecorder::IncludeSelfForBorderRadius; break; } clipRecorder.emplace(context, *m_paintLayer.layoutObject(), clipType, clipRect, &paintingInfo, fragment.paginationOffset, paintFlags, clippingRule); } LayoutRect newCullRect(clipRect.rect()); Optional<ScrollRecorder> scrollRecorder; LayoutPoint paintOffset = toPoint(fragment.layerBounds.location() - m_paintLayer.layoutBoxLocation()); if (!paintingInfo.scrollOffsetAccumulation.isZero()) { // As a descendant of the root layer, m_paintLayer's painting is not controlled by the ScrollRecorders // created by BlockPainter of the ancestor layers up to the root layer, so we need to issue ScrollRecorder // for this layer seperately, with the scroll offset accumulated from the root layer to the parent of this // layer, to get the same result as ScrollRecorder in BlockPainter. paintOffset += paintingInfo.scrollOffsetAccumulation; newCullRect.move(paintingInfo.scrollOffsetAccumulation); scrollRecorder.emplace(context, *m_paintLayer.layoutObject(), phase, paintingInfo.scrollOffsetAccumulation); } PaintInfo paintInfo(context, pixelSnappedIntRect(newCullRect), phase, paintingInfo.globalPaintFlags(), paintFlags, paintingInfo.rootLayer->layoutObject()); m_paintLayer.layoutObject()->paint(paintInfo, paintOffset); }
PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerWithTransform(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { TransformationMatrix layerTransform = m_paintLayer.renderableTransform(paintingInfo.globalPaintFlags()); // If the transform can't be inverted, then don't paint anything. if (!layerTransform.isInvertible()) return FullyPainted; // FIXME: We should make sure that we don't walk past paintingInfo.rootLayer here. // m_paintLayer may be the "root", and then we should avoid looking at its parent. PaintLayer* parentLayer = m_paintLayer.parent(); ClipRect ancestorBackgroundClipRect; if (parentLayer) { // Calculate the clip rectangle that the ancestors establish. ClipRectsContext clipRectsContext(paintingInfo.rootLayer, (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize); if (shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()) == IgnoreOverflowClip) clipRectsContext.setIgnoreOverflowClip(); ancestorBackgroundClipRect = m_paintLayer.clipper().backgroundClipRect(clipRectsContext); } PaintLayer* paginationLayer = m_paintLayer.enclosingPaginationLayer(); PaintLayerFragments fragments; if (paginationLayer) { // FIXME: This is a mess. Look closely at this code and the code in Layer and fix any // issues in it & refactor to make it obvious from code structure what it does and that it's // correct. ClipRectsCacheSlot cacheSlot = (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects; ShouldRespectOverflowClip respectOverflowClip = shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject()); // Calculate the transformed bounding box in the current coordinate space, to figure out // which fragmentainers (e.g. columns) we need to visit. LayoutRect transformedExtent = PaintLayer::transparencyClipBox(&m_paintLayer, paginationLayer, PaintLayer::PaintingTransparencyClipBox, PaintLayer::RootOfTransparencyClipBox, paintingInfo.subPixelAccumulation, paintingInfo.globalPaintFlags()); // FIXME: we don't check if paginationLayer is within paintingInfo.rootLayer here. paginationLayer->collectFragments(fragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, 0, paintingInfo.subPixelAccumulation, &transformedExtent); } else { // We don't need to collect any fragments in the regular way here. We have already // calculated a clip rectangle for the ancestry if it was needed, and clipping this // layer is something that can be done further down the path, when the transform has // been applied. PaintLayerFragment fragment; fragment.backgroundRect = paintingInfo.paintDirtyRect; fragments.append(fragment); } bool needsScope = fragments.size() > 1; PaintResult result = FullyPainted; for (const auto& fragment : fragments) { Optional<ScopeRecorder> scopeRecorder; if (needsScope) scopeRecorder.emplace(*context); Optional<LayerClipRecorder> clipRecorder; if (parentLayer) { ClipRect clipRectForFragment(ancestorBackgroundClipRect); clipRectForFragment.moveBy(fragment.paginationOffset); clipRectForFragment.intersect(fragment.backgroundRect); if (clipRectForFragment.isEmpty()) continue; if (needsToClip(paintingInfo, clipRectForFragment)) { if (m_paintLayer.layoutObject()->style()->position() != StaticPosition && clipRectForFragment.isClippedByClipCss()) UseCounter::count(m_paintLayer.layoutObject()->document(), UseCounter::ClipCssOfPositionedElement); clipRecorder.emplace(*context, *parentLayer->layoutObject(), DisplayItem::ClipLayerParent, clipRectForFragment, &paintingInfo, fragment.paginationOffset, paintFlags); } } if (paintFragmentByApplyingTransform(context, paintingInfo, paintFlags, fragment.paginationOffset) == MaybeNotFullyPainted) result = MaybeNotFullyPainted; } return result; }