void SVGResourcesCache::addResourcesFromLayoutObject(LayoutObject* object, const ComputedStyle& style) { ASSERT(object); ASSERT(!m_cache.contains(object)); const SVGComputedStyle& svgStyle = style.svgStyle(); // Build a list of all resources associated with the passed LayoutObject OwnPtr<SVGResources> newResources = SVGResources::buildResources(object, svgStyle); if (!newResources) return; // Put object in cache. SVGResources* resources = m_cache.set(object, newResources.release()).storedValue->value.get(); // Run cycle-detection _afterwards_, so self-references can be caught as well. SVGResourcesCycleSolver solver(object, resources); solver.resolveCycles(); // Walk resources and register the layout object at each resources. HashSet<LayoutSVGResourceContainer*> resourceSet; resources->buildSetOfResources(resourceSet); for (auto* resourceContainer : resourceSet) resourceContainer->addClient(object); }
void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* object, FloatRect& repaintRect) { ASSERT(object); RenderStyle* style = object->style(); ASSERT(style); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); RenderObject* renderer = const_cast<RenderObject*>(object); SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (!resources) { if (const ShadowData* shadow = svgStyle->shadow()) shadow->adjustRectForShadow(repaintRect); return; } #if ENABLE(FILTERS) if (RenderSVGResourceFilter* filter = resources->filter()) repaintRect = filter->resourceBoundingBox(renderer); #endif if (RenderSVGResourceClipper* clipper = resources->clipper()) repaintRect.intersect(clipper->resourceBoundingBox(renderer)); if (RenderSVGResourceMasker* masker = resources->masker()) repaintRect.intersect(masker->resourceBoundingBox(renderer)); if (const ShadowData* shadow = svgStyle->shadow()) shadow->adjustRectForShadow(repaintRect); }
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(object, paintInfo.context, ApplyToDefaultMode, /* path */0); paintInfo.context = savedContext; } } #endif if (style->opacity() < 1) paintInfo.context->endTransparencyLayer(); if (svgStyle->shadow()) paintInfo.context->endTransparencyLayer(); }
void SVGShapePainter::paintMarkers(const PaintInfo& paintInfo, const FloatRect& boundingBox) { const Vector<MarkerPosition>* markerPositions = m_layoutSVGShape.markerPositions(); if (!markerPositions || markerPositions->isEmpty()) return; SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_layoutSVGShape); if (!resources) return; LayoutSVGResourceMarker* markerStart = resources->markerStart(); LayoutSVGResourceMarker* markerMid = resources->markerMid(); LayoutSVGResourceMarker* markerEnd = resources->markerEnd(); if (!markerStart && !markerMid && !markerEnd) return; float strokeWidth = m_layoutSVGShape.strokeWidth(); unsigned size = markerPositions->size(); for (unsigned i = 0; i < size; ++i) { if (LayoutSVGResourceMarker* marker = SVGMarkerData::markerForType((*markerPositions)[i].type, markerStart, markerMid, markerEnd)) { SkPictureBuilder pictureBuilder(boundingBox, nullptr, &paintInfo.context); PaintInfo markerPaintInfo(pictureBuilder.context(), paintInfo); // It's expensive to track the transformed paint cull rect for each // marker so just disable culling. The shape paint call will already // be culled if it is outside the paint info cull rect. markerPaintInfo.m_cullRect.m_rect = LayoutRect::infiniteIntRect(); paintMarker(markerPaintInfo, *marker, (*markerPositions)[i], strokeWidth); pictureBuilder.endRecording()->playback(paintInfo.context.canvas()); } } }
bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const { ASSERT(renderer); // First (first loop iteration) operate on the resources of the given // renderer. // <marker id="a"> <path marker-start="url(#b)"/> ... // <marker id="b" marker-start="url(#a)"/> // Then operate on the child resources of the given renderer. // <marker id="a"> <path marker-start="url(#b)"/> ... // <marker id="b"> <path marker-start="url(#a)"/> ... for (RenderObject* child = renderer; child; child = child->nextInPreOrder(renderer)) { SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child); if (!childResources) continue; // A child of the given 'resource' contains resources. HashSet<RenderSVGResourceContainer*> childSet; childResources->buildSetOfResources(childSet); // Walk all child resources and check whether they reference any resource contained in the resources set. HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) { if (m_allResources.contains(*it)) return true; } } return false; }
FloatRect RenderSVGPath::calculateMarkerBoundsIfNeeded() { SVGElement* svgElement = static_cast<SVGElement*>(node()); ASSERT(svgElement && svgElement->document()); if (!svgElement->isStyled()) return FloatRect(); SVGStyledElement* styledElement = static_cast<SVGStyledElement*>(svgElement); if (!styledElement->supportsMarkers()) return FloatRect(); const SVGRenderStyle* svgStyle = style()->svgStyle(); ASSERT(svgStyle->hasMarkers()); SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources) return FloatRect(); RenderSVGResourceMarker* markerStart = resources->markerStart(); RenderSVGResourceMarker* markerMid = resources->markerMid(); RenderSVGResourceMarker* markerEnd = resources->markerEnd(); if (!markerStart && !markerMid && !markerEnd) return FloatRect(); return m_markerLayoutInfo.calculateBoundaries(markerStart, markerMid, markerEnd, svgStyle->strokeWidth().value(svgElement), m_path); }
void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style) { ASSERT(object); ASSERT(style); ASSERT(!m_cache.contains(object)); const SVGRenderStyle* svgStyle = style->svgStyle(); ASSERT(svgStyle); // Build a list of all resources associated with the passed RenderObject SVGResources* resources = new SVGResources; if (!resources->buildCachedResources(object, svgStyle)) { delete resources; return; } // Put object in cache. m_cache.set(object, resources); // Run cycle-detection _afterwards_, so self-references can be caught as well. SVGResourcesCycleSolver solver(object, resources); solver.resolveCycles(); // Walk resources and register the render object at each resources. HashSet<RenderSVGResourceContainer*> resourceSet; resources->buildSetOfResources(resourceSet); HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) (*it)->addClient(object); }
void SVGRenderSupport::layoutResourcesIfNeeded(const RenderObject* object) { ASSERT(object); SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (resources) resources->layoutIfNeeded(); }
void SVGResourcesCache::clientLayoutChanged(RenderObject* object) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources) return; resources->removeClientFromCache(object); }
void SVGResourcesCache::clientDestroyed(RenderElement& renderer) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (resources) resources->removeClientFromCache(renderer); SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); cache->removeResourcesFromRenderer(renderer); }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitly disabled it. if (paintInfo.context->paintingDisabled()) return; // SVG outlines are painted during PaintPhaseForeground. if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); if (svg->hasEmptyViewBox()) return; // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) return; } // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip if (shouldApplyViewportClip()) childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); } childPaintInfo.context->restore(); }
bool RenderSVGRoot::selfWillPaint() { #if ENABLE(FILTERS) SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); return resources && resources->filter(); #else return false; #endif }
bool SVGClipPainter::applyClippingToContext(const LayoutObject& target, const FloatRect& targetBoundingBox, const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperState& clipperState) { ASSERT(context); ASSERT(clipperState == ClipperNotApplied); ASSERT_WITH_SECURITY_IMPLICATION(!m_clip.needsLayout()); if (paintInvalidationRect.isEmpty() || m_clip.hasCycle()) return false; SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element())->calculateAnimatedLocalTransform(); // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor. // In this case, we need to apply the zoom scale explicitly - but only for clips with // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths). if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) { ASSERT(m_clip.style()); animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); } // First, try to apply the clip as a clipPath. if (m_clip.tryPathOnlyClipping(target, context, animatedLocalTransform, targetBoundingBox)) { clipperState = ClipperAppliedPath; return true; } // Fall back to masking. clipperState = ClipperAppliedMask; // Begin compositing the clip mask. CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcOver_Mode, 1, &paintInvalidationRect); { TransformRecorder recorder(*context, target, animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip); LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : 0; ClipperState clipPathClipperState = ClipperNotApplied; if (clipPathClipper && !SVGClipPainter(*clipPathClipper).applyClippingToContext(m_clip, targetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) { // End the clip mask's compositor. CompositingRecorder::endCompositing(*context, target); return false; } drawClipMaskContent(context, target, targetBoundingBox); if (clipPathClipper) SVGClipPainter(*clipPathClipper).postApplyStatefulResource(m_clip, context, clipPathClipperState); } // Masked content layer start. CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcIn_Mode, 1, &paintInvalidationRect); return true; }
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! float opacity = 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 (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 (RenderSVGResourceFilter* filter = resources->filter()) { if (!filter->applyResource(object, style, paintInfo.context, ApplyToDefaultMode)) return false; } #endif return true; }
bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, const FloatRect& targetBoundingBox, const FloatRect& repaintRect, GraphicsContext* context, ClipperContext& clipperContext) { ASSERT(target); ASSERT(context); ASSERT(clipperContext.state == ClipperContext::NotAppliedState); ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); if (repaintRect.isEmpty() || m_inClipExpansion) return false; TemporaryChange<bool> inClipExpansionChange(m_inClipExpansion, true); // First, try to apply the clip as a clipPath. AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->animatedLocalTransform(); if (tryPathOnlyClipping(context, animatedLocalTransform, targetBoundingBox)) { clipperContext.state = ClipperContext::AppliedPathState; return true; } // Fall back to masking. clipperContext.state = ClipperContext::AppliedMaskState; // Mask layer start context->beginTransparencyLayer(1, &repaintRect); { GraphicsContextStateSaver maskContentSaver(*context); context->concatCTM(animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); RenderSVGResourceClipper* clipPathClipper = 0; ClipperContext clipPathClipperContext; if (resources && (clipPathClipper = resources->clipper())) { if (!clipPathClipper->applyClippingToContext(this, targetBoundingBox, repaintRect, context, clipPathClipperContext)) { // FIXME: Awkward state micro-management. Ideally, GraphicsContextStateSaver should // a) pop saveLayers also // b) pop multiple states if needed (similarly to SkCanvas::restoreToCount()) // Then we should be able to replace this mess with a single, top-level GCSS. maskContentSaver.restore(); context->restoreLayer(); return false; } } drawClipMaskContent(context, targetBoundingBox); if (clipPathClipper) clipPathClipper->postApplyStatefulResource(this, context, clipPathClipperContext); } // Masked content layer start. context->beginLayer(1, CompositeSourceIn, &repaintRect); return true; }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitely disabled it. if (paintInfo.context->paintingDisabled()) return; Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip - not affected by overflow handling childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); } childPaintInfo.context->restore(); }
void SVGResourcesCache::clientDestroyed(LayoutObject* layoutObject) { ASSERT(layoutObject); SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(layoutObject); if (resources) resources->removeClientFromCache(layoutObject); SVGResourcesCache* cache = resourcesCacheFromLayoutObject(layoutObject); cache->removeResourcesFromLayoutObject(layoutObject); }
void SVGResourcesCache::clientLayoutChanged(LayoutObject* object) { SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(object); if (!resources) return; // Invalidate the resources if either the LayoutObject itself changed, // or we have filter resources, which could depend on the layout of children. if (object->selfNeedsLayout() || resources->filter()) resources->removeClientFromCache(object); }
void SVGResourcesCache::clientLayoutChanged(RenderElement& renderer) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (!resources) return; // Invalidate the resources if either the RenderElement itself changed, // or we have filter resources, which could depend on the layout of children. if (renderer.selfNeedsLayout()) resources->removeClientFromCache(renderer); }
bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext* context) { bool missingClipperData = !m_clipper.contains(object); if (missingClipperData) m_clipper.set(object, new ClipperData); bool shouldCreateClipData = false; AffineTransform animatedLocalTransform = static_cast<SVGClipPathElement*>(node())->animatedLocalTransform(); ClipperData* clipperData = m_clipper.get(object); if (!clipperData->clipMaskImage) { if (pathOnlyClipping(context, animatedLocalTransform, objectBoundingBox)) return true; shouldCreateClipData = true; } AffineTransform absoluteTransform; SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform); if (shouldCreateClipData && !repaintRect.isEmpty()) { if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated)) return false; GraphicsContext* maskContext = clipperData->clipMaskImage->context(); ASSERT(maskContext); maskContext->concatCTM(animatedLocalTransform); // clipPath can also be clipped by another clipPath. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); RenderSVGResourceClipper* clipper; bool succeeded; if (resources && (clipper = resources->clipper())) { GraphicsContextStateSaver stateSaver(*maskContext); if (!clipper->applyClippingToContext(this, objectBoundingBox, repaintRect, maskContext)) return false; succeeded = drawContentIntoMaskImage(clipperData, objectBoundingBox); // The context restore applies the clipping on non-CG platforms. } else succeeded = drawContentIntoMaskImage(clipperData, objectBoundingBox); if (!succeeded) clipperData->clipMaskImage.clear(); } if (!clipperData->clipMaskImage) return false; SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperData->clipMaskImage, missingClipperData); return true; }
bool SVGRenderSupport::pointInClippingArea(const RenderElement& renderer, const FloatPoint& point) { // We just take clippers into account to determine if a point is on the node. The Specification may // change later and we also need to check maskers. SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (!resources) return true; if (RenderSVGResourceClipper* clipper = resources->clipper()) return clipper->hitTestClipContent(renderer.objectBoundingBox(), point); return true; }
bool SVGRenderSupport::filtersForceContainerLayout(RenderObject* object) { // If any of this container's children need to be laid out, and a filter is applied // to the container, we need to repaint the entire container. if (!object->normalChildNeedsLayout()) return false; SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object); if (!resources || !resources->filter()) return false; return true; }
bool SVGLayoutSupport::pointInClippingArea(LayoutObject* object, const FloatPoint& point) { ASSERT(object); // We just take clippers into account to determine if a point is on the node. The Specification may // change later and we also need to check maskers. SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(object); if (!resources) return true; if (LayoutSVGResourceClipper* clipper = resources->clipper()) return clipper->hitTestClipContent(object->objectBoundingBox(), point); return true; }
void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle) { ASSERT(renderer); ASSERT(renderer->parent()); SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); cache->removeResourcesFromRenderObject(renderer); cache->addResourcesFromRenderObject(renderer, newStyle); #if ENABLE(FILTERS) SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (resources && resources->filter()) resources->removeClientFromCache(renderer); #endif }
void LayoutSVGResourceContainer::detachAllClients() { for (auto* client : m_clients) { // Unlink the resource from the client's SVGResources. (The actual // removal will be signaled after processing all the clients.) SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(client); ASSERT(resources); // Or else the client wouldn't be in the list in the first place. resources->resourceDestroyed(this); // Add a pending resolution based on the id of the old resource. Element* clientElement = toElement(client->node()); svgExtensionsFromElement(clientElement).addPendingResource(m_id, clientElement); } removeAllClientsFromCache(); }
void SVGRenderSupport::intersectRepaintRectWithResources(const RenderObject* renderer, FloatRect& repaintRect) { ASSERT(renderer); SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); if (!resources) return; if (RenderSVGResourceFilter* filter = resources->filter()) repaintRect = filter->resourceBoundingBox(renderer); if (RenderSVGResourceClipper* clipper = resources->clipper()) repaintRect.intersect(clipper->resourceBoundingBox(renderer)); if (RenderSVGResourceMasker* masker = resources->masker()) repaintRect.intersect(masker->resourceBoundingBox(renderer)); }
void SVGRenderSupport::intersectRepaintRectWithResources(const RenderElement& renderer, FloatRect& repaintRect) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(&renderer); if (!resources) return; #if ENABLE(FILTERS) if (RenderSVGResourceFilter* filter = resources->filter()) repaintRect = filter->resourceBoundingBox(renderer); #endif if (RenderSVGResourceClipper* clipper = resources->clipper()) repaintRect.intersect(clipper->resourceBoundingBox(renderer)); if (RenderSVGResourceMasker* masker = resources->masker()) repaintRect.intersect(masker->resourceBoundingBox(renderer)); }
void SVGLayoutSupport::intersectPaintInvalidationRectWithResources(const LayoutObject* layoutObject, FloatRect& paintInvalidationRect) { ASSERT(layoutObject); SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(layoutObject); if (!resources) return; if (LayoutSVGResourceFilter* filter = resources->filter()) paintInvalidationRect = filter->resourceBoundingBox(layoutObject); if (LayoutSVGResourceClipper* clipper = resources->clipper()) paintInvalidationRect.intersect(clipper->resourceBoundingBox(layoutObject)); if (LayoutSVGResourceMasker* masker = resources->masker()) paintInvalidationRect.intersect(masker->resourceBoundingBox(layoutObject)); }
void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object) { if (!m_cache.contains(object)) return; SVGResources* resources = m_cache.get(object); // Walk resources and register the render object at each resources. HashSet<RenderSVGResourceContainer*> resourceSet; resources->buildSetOfResources(resourceSet); HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) (*it)->removeClient(object); delete m_cache.take(object); }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& adjustedPaintOffset) { // An empty viewport disables rendering. if (borderBoxRect().isEmpty()) return; // Don't paint, if the context explicitely disabled it. if (paintInfo.context->paintingDisabled()) return; // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) return; } if (Frame* frame = this->frame()) { if (Page* page = frame->page()) page->addRelevantRepaintedObject(this, paintInfo.rect); } // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip - not affected by overflow handling childPaintInfo.context->clip(overflowClipRect(adjustedPaintOffset, paintInfo.renderRegion)); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x() - x(), adjustedPaintOffset.y() - y()) * localToParentTransform()); bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) continueRendering = SVGRenderSupport::prepareToRenderSVGContent(this, childPaintInfo); if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); if (childPaintInfo.phase == PaintPhaseForeground) SVGRenderSupport::finishRenderSVGContent(this, childPaintInfo, paintInfo.context); childPaintInfo.context->restore(); }