void SVGRenderSupport::finishRenderSVGContent(RenderObject* object, PaintInfo& paintInfo, GraphicsContext* savedContext) { #if !ENABLE(FILTERS) UNUSED_PARAM(savedContext); #endif ASSERT(object); const RenderStyle* style = object->style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); #if ENABLE(FILTERS) SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (resources) { if (RenderSVGResourceFilter* filter = resources->filter()) { filter->postApplyResource(static_cast<RenderSVGShape*>(object), paintInfo.context, ApplyToDefaultMode, 0, 0); paintInfo.context = savedContext; } } #endif if (style->opacity() < 1 && !isRenderingMaskImage(object)) paintInfo.context->endTransparencyLayer(); if (svgStyle->shadow()) paintInfo.context->endTransparencyLayer(); }
void SVGRenderingContext::prepareToRenderSVGContent(RenderElement& renderer, PaintInfo& paintInfo, NeedsGraphicsContextSave needsGraphicsContextSave) { #ifndef NDEBUG // This function must not be called twice! ASSERT(!(m_renderingFlags & PrepareToRenderSVGContentWasCalled)); m_renderingFlags |= PrepareToRenderSVGContentWasCalled; #endif m_renderer = &renderer; m_paintInfo = &paintInfo; m_filter = 0; // We need to save / restore the context even if the initialization failed. if (needsGraphicsContextSave == SaveGraphicsContext) { m_paintInfo->context().save(); m_renderingFlags |= RestoreGraphicsContext; } auto& style = m_renderer->style(); const SVGRenderStyle& svgStyle = style.svgStyle(); // Setup transparency layers before setting up SVG resources! bool isRenderingMask = isRenderingMaskImage(*m_renderer); // RenderLayer takes care of root opacity. float opacity = (renderer.isSVGRoot() || isRenderingMask) ? 1 : style.opacity(); const ShadowData* shadow = svgStyle.shadow(); bool hasBlendMode = style.hasBlendMode(); bool hasIsolation = style.hasIsolation(); bool isolateMaskForBlending = false; #if ENABLE(CSS_COMPOSITING) if (svgStyle.hasMasker() && is<SVGGraphicsElement>(downcast<SVGElement>(*renderer.element()))) { SVGGraphicsElement& graphicsElement = downcast<SVGGraphicsElement>(*renderer.element()); isolateMaskForBlending = graphicsElement.shouldIsolateBlending(); } #endif if (opacity < 1 || shadow || hasBlendMode || isolateMaskForBlending || hasIsolation) { FloatRect repaintRect = m_renderer->repaintRectInLocalCoordinates(); m_paintInfo->context().clip(repaintRect); if (opacity < 1 || hasBlendMode || isolateMaskForBlending || hasIsolation) { if (hasBlendMode) m_paintInfo->context().setCompositeOperation(m_paintInfo->context().compositeOperation(), style.blendMode()); m_paintInfo->context().beginTransparencyLayer(opacity); if (hasBlendMode) m_paintInfo->context().setCompositeOperation(m_paintInfo->context().compositeOperation(), BlendModeNormal); m_renderingFlags |= EndOpacityLayer; } if (shadow) { m_paintInfo->context().setShadow(IntSize(roundToInt(shadow->x()), roundToInt(shadow->y())), shadow->radius(), shadow->color()); m_paintInfo->context().beginTransparencyLayer(1); m_renderingFlags |= EndShadowLayer; } } ClipPathOperation* clipPathOperation = style.clipPath(); if (is<ShapeClipPathOperation>(clipPathOperation)) { auto& clipPath = downcast<ShapeClipPathOperation>(*clipPathOperation); FloatRect referenceBox; if (clipPath.referenceBox() == Stroke) // FIXME: strokeBoundingBox() takes dasharray into account but shouldn't. referenceBox = renderer.strokeBoundingBox(); else if (clipPath.referenceBox() == ViewBox && renderer.element()) { FloatSize viewportSize; SVGLengthContext(downcast<SVGElement>(renderer.element())).determineViewport(viewportSize); referenceBox.setWidth(viewportSize.width()); referenceBox.setHeight(viewportSize.height()); } else referenceBox = renderer.objectBoundingBox(); m_paintInfo->context().clipPath(clipPath.pathForReferenceRect(referenceBox), clipPath.windRule()); } auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*m_renderer); if (!resources) { if (style.hasReferenceFilterOnly()) return; m_renderingFlags |= RenderingPrepared; return; } if (!isRenderingMask) { if (RenderSVGResourceMasker* masker = resources->masker()) { GraphicsContext* contextPtr = &m_paintInfo->context(); bool result = masker->applyResource(*m_renderer, style, contextPtr, ApplyToDefaultMode); m_paintInfo->setContext(*contextPtr); if (!result) return; } } RenderSVGResourceClipper* clipper = resources->clipper(); if (!clipPathOperation && clipper) { GraphicsContext* contextPtr = &m_paintInfo->context(); bool result = clipper->applyResource(*m_renderer, style, contextPtr, ApplyToDefaultMode); m_paintInfo->setContext(*contextPtr); if (!result) return; } if (!isRenderingMask) { m_filter = resources->filter(); if (m_filter) { m_savedContext = &m_paintInfo->context(); m_savedPaintRect = m_paintInfo->rect; // Return with false here may mean that we don't need to draw the content // (because it was either drawn before or empty) but we still need to apply the filter. m_renderingFlags |= EndFilterLayer; GraphicsContext* contextPtr = &m_paintInfo->context(); bool result = m_filter->applyResource(*m_renderer, style, contextPtr, ApplyToDefaultMode); m_paintInfo->setContext(*contextPtr); if (!result) return; // Since we're caching the resulting bitmap and do not invalidate it on repaint rect // changes, we need to paint the whole filter region. Otherwise, elements not visible // at the time of the initial paint (due to scrolling, window size, etc.) will never // be drawn. m_paintInfo->rect = IntRect(m_filter->drawingRegion(m_renderer)); } } m_renderingFlags |= RenderingPrepared; }
bool SVGRenderSupport::prepareToRenderSVGContent(RenderObject* object, PaintInfo& paintInfo) { ASSERT(object); RenderStyle* style = object->style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); // Setup transparency layers before setting up SVG resources! bool isRenderingMask = isRenderingMaskImage(object); float opacity = isRenderingMask ? 1 : style->opacity(); const ShadowData* shadow = svgStyle->shadow(); if (opacity < 1 || shadow) { FloatRect repaintRect = object->repaintRectInLocalCoordinates(); if (opacity < 1) { paintInfo.context->clip(repaintRect); paintInfo.context->beginTransparencyLayer(opacity); } if (shadow) { paintInfo.context->clip(repaintRect); paintInfo.context->setShadow(IntSize(shadow->x(), shadow->y()), shadow->blur(), shadow->color(), style->colorSpace()); paintInfo.context->beginTransparencyLayer(1); } } SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources) { #if ENABLE(FILTERS) if (svgStyle->hasFilter()) return false; #endif return true; } if (!isRenderingMask) { if (RenderSVGResourceMasker* masker = resources->masker()) { if (!masker->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } } if (RenderSVGResourceClipper* clipper = resources->clipper()) { if (!clipper->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } #if ENABLE(FILTERS) if (!isRenderingMask) { if (RenderSVGResourceFilter* filter = resources->filter()) { if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } } #endif return true; }