FilterPainter::FilterPainter(DeprecatedPaintLayer& layer, GraphicsContext* context, const LayoutPoint& offsetFromRoot, const ClipRect& clipRect, DeprecatedPaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed) : m_filterInProgress(false) , m_context(context) , m_layoutObject(layer.layoutObject()) { if (!layer.filterEffectBuilder() || !layer.paintsWithFilters()) return; ASSERT(layer.filterInfo()); SkiaImageFilterBuilder builder; RefPtrWillBeRawPtr<FilterEffect> lastEffect = layer.filterEffectBuilder()->lastEffect(); lastEffect->determineFilterPrimitiveSubregion(MapRectForward); RefPtr<SkImageFilter> imageFilter = builder.build(lastEffect.get(), ColorSpaceDeviceRGB); if (!imageFilter) return; if (!rootRelativeBoundsComputed) { rootRelativeBounds = layer.physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot); rootRelativeBoundsComputed = true; } // We'll handle clipping to the dirty rect before filter rasterization. // Filter processing will automatically expand the clip rect and the offscreen to accommodate any filter outsets. // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved. // Subsequent code should not clip to the dirty rect, since we've already // done it above, and doing it later will defeat the outsets. paintingInfo.clipToDirtyRect = false; if (clipRect.rect() != paintingInfo.paintDirtyRect || clipRect.hasRadius()) { m_clipRecorder = adoptPtr(new LayerClipRecorder(*context, *layer.layoutObject(), DisplayItem::ClipLayerFilter, clipRect, &paintingInfo, LayoutPoint(), paintFlags)); } ASSERT(m_layoutObject); if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { ASSERT(context->displayItemList()); if (!context->displayItemList()->displayItemConstructionIsDisabled()) { FilterOperations filterOperations(layer.computeFilterOperations(m_layoutObject->styleRef())); OwnPtr<WebFilterOperations> webFilterOperations = adoptPtr(Platform::current()->compositorSupport()->createFilterOperations()); builder.buildFilterOperations(filterOperations, webFilterOperations.get()); // FIXME: It's possible to have empty WebFilterOperations here even // though the SkImageFilter produced above is non-null, since the // layer's FilterEffectBuilder can have a stale representation of // the layer's filter. See crbug.com/502026. if (webFilterOperations->isEmpty()) return; context->displayItemList()->createAndAppend<BeginFilterDisplayItem>(*m_layoutObject, imageFilter, rootRelativeBounds, webFilterOperations.release()); } } else { BeginFilterDisplayItem filterDisplayItem(*m_layoutObject, imageFilter, rootRelativeBounds); filterDisplayItem.replay(*context); } m_filterInProgress = true; }
LayerClipRecorder::LayerClipRecorder(GraphicsContext& graphicsContext, const LayoutBoxModelObject& layoutObject, DisplayItem::Type clipType, const ClipRect& clipRect, const PaintLayerPaintingInfo* localPaintingInfo, const LayoutPoint& fragmentOffset, PaintLayerFlags paintFlags, BorderRadiusClippingRule rule) : m_graphicsContext(graphicsContext) , m_layoutObject(layoutObject) , m_clipType(clipType) { IntRect snappedClipRect = pixelSnappedIntRect(clipRect.rect()); Vector<FloatRoundedRect> roundedRects; if (localPaintingInfo && clipRect.hasRadius()) { collectRoundedRectClips(*layoutObject.layer(), *localPaintingInfo, graphicsContext, fragmentOffset, paintFlags, rule, roundedRects); } m_graphicsContext.paintController().createAndAppend<ClipDisplayItem>(layoutObject, m_clipType, snappedClipRect, roundedRects); }
void RenderTreeAsText::writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLayer* layer, const LayoutRect& paintRect, int indent, RenderAsTextBehavior behavior) { // FIXME: Apply overflow to the root layer to not break every test. Complete hack. Sigh. LayoutRect paintDirtyRect(paintRect); if (rootLayer == layer) { paintDirtyRect.setWidth(max<LayoutUnit>(paintDirtyRect.width(), rootLayer->renderer()->layoutOverflowRect().maxX())); paintDirtyRect.setHeight(max<LayoutUnit>(paintDirtyRect.height(), rootLayer->renderer()->layoutOverflowRect().maxY())); } // Calculate the clip rects we should use. LayoutRect layerBounds; ClipRect damageRect; layer->clipper().calculateRects(ClipRectsContext(rootLayer, UncachedClipRects), paintDirtyRect, layerBounds, damageRect); // FIXME: Apply overflow to the root layer to not break every test. Complete hack. Sigh. if (rootLayer == layer) layerBounds.setSize(layer->size().expandedTo(pixelSnappedIntSize(layer->renderer()->maxLayoutOverflow(), LayoutPoint(0, 0)))); // Ensure our lists are up-to-date. layer->stackingNode()->updateLayerListsIfNeeded(); bool shouldPaint = (behavior & RenderAsTextShowAllLayers) ? true : layer->intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer); if (shouldPaint) write(ts, *layer, layerBounds, damageRect.rect(), indent, behavior); if (Vector<RenderLayerStackingNode*>* normalFlowList = layer->stackingNode()->normalFlowList()) { int currIndent = indent; if (behavior & RenderAsTextShowLayerNesting) { writeIndent(ts, indent); ts << " normal flow list(" << normalFlowList->size() << ")\n"; ++currIndent; } for (unsigned i = 0; i != normalFlowList->size(); ++i) writeLayers(ts, rootLayer, normalFlowList->at(i)->layer(), paintDirtyRect, currIndent, behavior); } if (Vector<RenderLayerStackingNode*>* posList = layer->stackingNode()->zOrderList()) { int currIndent = indent; if (behavior & RenderAsTextShowLayerNesting) { writeIndent(ts, indent); ts << " positive z-order list(" << posList->size() << ")\n"; ++currIndent; } for (unsigned i = 0; i != posList->size(); ++i) writeLayers(ts, rootLayer, posList->at(i)->layer(), paintDirtyRect, currIndent, behavior); } }
LayoutRect RenderLayerClipper::localClipRect() const { // FIXME: border-radius not accounted for. RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect; ClipRectsContext context(clippingRootLayer, PaintingClipRects); calculateRects(context, PaintInfo::infiniteRect(), layerBounds, backgroundRect); LayoutRect clipRect = backgroundRect.rect(); if (clipRect == PaintInfo::infiniteRect()) return clipRect; LayoutPoint clippingRootOffset; m_renderer.layer()->convertToLayerCoords(clippingRootLayer, clippingRootOffset); clipRect.moveBy(-clippingRootOffset); return clipRect; }
LayoutRect PaintLayerClipper::localClipRect( const PaintLayer* clippingRootLayer) const { ClipRectsContext context(clippingRootLayer, PaintingClipRects); if (m_geometryMapper) { ClipRect clipRect = applyOverflowClipToBackgroundRectWithGeometryMapper( context, clipRectWithGeometryMapper(context, false)); // The rect now needs to be transformed to the local space of this // PaintLayer. bool success = false; FloatRect clippedRectInLocalSpace = m_geometryMapper->mapRectToDestinationSpace( FloatRect(clipRect.rect()), clippingRootLayer->layoutObject() ->paintProperties() ->localBorderBoxProperties() ->propertyTreeState, m_layer.layoutObject() ->paintProperties() ->localBorderBoxProperties() ->propertyTreeState, success); DCHECK(success); return LayoutRect(clippedRectInLocalSpace); } LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect; calculateRects(context, LayoutRect(LayoutRect::infiniteIntRect()), layerBounds, backgroundRect, foregroundRect); LayoutRect clipRect = backgroundRect.rect(); // TODO(chrishtr): avoid converting to IntRect and back. if (clipRect == LayoutRect(LayoutRect::infiniteIntRect())) return clipRect; LayoutPoint clippingRootOffset; m_layer.convertToLayerCoords(clippingRootLayer, clippingRootOffset); clipRect.moveBy(-clippingRootOffset); return clipRect; }
ClipRect PaintLayerClipper::applyOverflowClipToBackgroundRectWithGeometryMapper( const ClipRectsContext& context, const ClipRect& clip) const { const LayoutObject& layoutObject = *m_layer.layoutObject(); FloatRect clipRect(clip.rect()); if (shouldClipOverflow(context)) { LayoutRect layerBoundsWithVisualOverflow = layoutObject.isLayoutView() ? toLayoutView(layoutObject).viewRect() : toLayoutBox(layoutObject).visualOverflowRect(); toLayoutBox(layoutObject) .flipForWritingMode( // PaintLayer are in physical coordinates, so the overflow has to be // flipped. layerBoundsWithVisualOverflow); mapLocalToRootWithGeometryMapper(context, layerBoundsWithVisualOverflow); clipRect.intersect(FloatRect(layerBoundsWithVisualOverflow)); } return ClipRect(LayoutRect(clipRect)); }
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); }
bool PaintLayerPainter::needsToClip(const PaintLayerPaintingInfo& localPaintingInfo, const ClipRect& clipRect) { return clipRect.rect() != localPaintingInfo.paintDirtyRect || clipRect.hasRadius(); }