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; }
ClipPathHelper(GraphicsContext* context, const DeprecatedPaintLayer& paintLayer, const DeprecatedPaintLayerPaintingInfo& paintingInfo, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed, const LayoutPoint& offsetFromRoot, PaintLayerFlags paintFlags) : m_resourceClipper(0), m_paintLayer(paintLayer), m_context(context) { const ComputedStyle& style = paintLayer.layoutObject()->styleRef(); // Clip-path, like border radius, must not be applied to the contents of a composited-scrolling container. // It must, however, still be applied to the mask layer, so that the compositor can properly mask the // scrolling contents and scrollbars. if (!paintLayer.layoutObject()->hasClipPath() || (paintLayer.needsCompositedScrolling() && !(paintFlags & PaintLayerPaintingChildClippingMaskPhase))) return; m_clipperState = SVGClipPainter::ClipperNotApplied; ASSERT(style.clipPath()); if (style.clipPath()->type() == ClipPathOperation::SHAPE) { ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style.clipPath()); if (clipPath->isValid()) { if (!rootRelativeBoundsComputed) { rootRelativeBounds = paintLayer.physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot); rootRelativeBoundsComputed = true; } m_clipPathRecorder.emplace(*context, *paintLayer.layoutObject(), clipPath->path(rootRelativeBounds)); } } else if (style.clipPath()->type() == ClipPathOperation::REFERENCE) { ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style.clipPath()); Document& document = paintLayer.layoutObject()->document(); // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405) Element* element = document.getElementById(referenceClipPathOperation->fragment()); if (isSVGClipPathElement(element) && element->layoutObject()) { if (!rootRelativeBoundsComputed) { rootRelativeBounds = paintLayer.physicalBoundingBoxIncludingReflectionAndStackingChildren(paintingInfo.rootLayer, offsetFromRoot); rootRelativeBoundsComputed = true; } m_resourceClipper = toLayoutSVGResourceClipper(toLayoutSVGResourceContainer(element->layoutObject())); if (!SVGClipPainter(*m_resourceClipper).applyClippingToContext(*paintLayer.layoutObject(), rootRelativeBounds, paintingInfo.paintDirtyRect, context, m_clipperState)) { // No need to post-apply the clipper if this failed. m_resourceClipper = 0; } } } }