void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode mode) { if ((m_clients.isEmpty() && m_clientLayers.isEmpty()) || m_isInvalidating) return; if (m_invalidationMask & mode) return; m_invalidationMask |= mode; m_isInvalidating = true; bool needsLayout = mode == LayoutAndBoundariesInvalidation; bool markForInvalidation = mode != ParentOnlyInvalidation; HashSet<RenderObject*>::iterator end = m_clients.end(); for (HashSet<RenderObject*>::iterator it = m_clients.begin(); it != end; ++it) { RenderObject* client = *it; if (client->isSVGResourceContainer()) { toRenderSVGResourceContainer(client)->removeAllClientsFromCache(markForInvalidation); continue; } if (markForInvalidation) markClientForInvalidation(client, mode); RenderSVGResource::markForLayoutAndParentResourceInvalidation(client, needsLayout); } markAllClientLayersForInvalidation(); m_isInvalidating = false; }
void RenderLayerFilterInfo::updateReferenceFilterClients(const FilterOperations& operations) { removeReferenceFilterClients(); for (size_t i = 0; i < operations.size(); ++i) { RefPtr<FilterOperation> filterOperation = operations.operations().at(i); if (filterOperation->type() != FilterOperation::REFERENCE) continue; ReferenceFilterOperation* referenceFilterOperation = toReferenceFilterOperation(filterOperation.get()); DocumentResourceReference* documentReference = ReferenceFilterBuilder::documentResourceReference(referenceFilterOperation); DocumentResource* cachedSVGDocument = documentReference ? documentReference->document() : 0; if (cachedSVGDocument) { // Reference is external; wait for notifyFinished(). cachedSVGDocument->addClient(this); m_externalSVGReferences.append(cachedSVGDocument); } else { // Reference is internal; add layer as a client so we can trigger // filter paint invalidation on SVG attribute change. Element* filter = m_layer->renderer()->node()->document().getElementById(referenceFilterOperation->fragment()); if (!isSVGFilterElement(filter)) continue; if (filter->renderer()) toRenderSVGResourceContainer(filter->renderer())->addClientRenderLayer(m_layer); else toSVGFilterElement(filter)->addClient(m_layer->renderer()->node()); m_internalSVGReferences.append(filter); } } }
PassRefPtr<DisplayList> RenderSVGResourcePattern::asDisplayList(const FloatRect& tileBounds, const AffineTransform& tileTransform) const { ASSERT(!m_shouldCollectPatternAttributes); AffineTransform contentTransform; if (m_attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) contentTransform = tileTransform; // Draw the content into a DisplayList. GraphicsContext recordingContext(nullptr); recordingContext.beginRecording(FloatRect(FloatPoint(), tileBounds.size())); recordingContext.concatCTM(tileTransform); ASSERT(m_attributes.patternContentElement()); RenderSVGResourceContainer* patternRenderer = toRenderSVGResourceContainer(m_attributes.patternContentElement()->renderer()); ASSERT(patternRenderer); ASSERT(!patternRenderer->needsLayout()); SubtreeContentTransformScope contentTransformScope(contentTransform); for (RenderObject* child = patternRenderer->firstChild(); child; child = child->nextSibling()) SVGRenderingContext::renderSubtree(&recordingContext, child); return recordingContext.endRecording(); }
void SVGFilterElement::setFilterRes(unsigned filterResX, unsigned filterResY) { setFilterResXBaseValue(filterResX); setFilterResYBaseValue(filterResY); RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); if (renderer) renderer->invalidateCacheAndMarkForLayout(); }
void SVGResourcesCycleSolver::resolveCycles() { ASSERT(m_allResources.isEmpty()); #if DEBUG_CYCLE_DETECTION > 0 fprintf(stderr, "\nBefore cycle detection:\n"); m_resources.dump(&m_renderer); #endif // Stash all resources into a HashSet for the ease of traversing. HashSet<RenderSVGResourceContainer*> localResources; m_resources.buildSetOfResources(localResources); ASSERT(!localResources.isEmpty()); // Add all parent resource containers to the HashSet. HashSet<RenderSVGResourceContainer*> ancestorResources; for (auto& resource : ancestorsOfType<RenderSVGResourceContainer>(m_renderer)) ancestorResources.add(&resource); #if DEBUG_CYCLE_DETECTION > 0 fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); { fprintf(stderr, "Local resources:\n"); for (auto* resource : localResources) fprintf(stderr, "|> %s: object=%p (node=%p)\n", resource->renderName(), resource, resource->node()); fprintf(stderr, "Parent resources:\n"); for (auto* resource : ancestorResources) fprintf(stderr, "|> %s: object=%p (node=%p)\n", resource->renderName(), resource, resource->node()); } #endif // Build combined set of local and parent resources. m_allResources = localResources; for (auto* resource : ancestorResources) m_allResources.add(resource); // If we're a resource, add ourselves to the HashSet. if (m_renderer.isSVGResourceContainer()) m_allResources.add(&toRenderSVGResourceContainer(m_renderer)); ASSERT(!m_allResources.isEmpty()); // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. for (auto* resource : localResources) { if (ancestorResources.contains(resource) || resourceContainsCycles(*resource)) breakCycle(*resource); } #if DEBUG_CYCLE_DETECTION > 0 fprintf(stderr, "\nAfter cycle detection:\n"); m_resources.dump(m_renderer); #endif m_allResources.clear(); }
void SVGClipPathElement::svgAttributeChanged(const QualifiedName& attrName) { if (!isSupportedAttribute(attrName)) { SVGGraphicsElement::svgAttributeChanged(attrName); return; } SVGElement::InvalidationGuard invalidationGuard(this); RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); if (renderer) renderer->invalidateCacheAndMarkForLayout(); }
void RenderLayerFilterInfo::removeReferenceFilterClients() { for (size_t i = 0; i < m_externalSVGReferences.size(); ++i) m_externalSVGReferences.at(i)->removeClient(this); m_externalSVGReferences.clear(); for (size_t i = 0; i < m_internalSVGReferences.size(); ++i) { Element* filter = m_internalSVGReferences.at(i).get(); if (filter->renderer()) toRenderSVGResourceContainer(filter->renderer())->removeClientRenderLayer(m_layer); else toSVGFilterElement(filter)->removeClient(m_layer->renderer()->node()); } m_internalSVGReferences.clear(); }
void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName) { if (!isSupportedAttribute(attrName)) { SVGGradientElement::svgAttributeChanged(attrName); return; } SVGElement::InvalidationGuard invalidationGuard(this); updateRelativeLengthsInformation(); RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); if (renderer) renderer->invalidateCacheAndMarkForLayout(); }
void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderObject::styleDidChange(diff, oldStyle); if (!diff.hasDifference()) return; // <stop> elements should only be allowed to make renderers under gradient elements // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient. SVGGradientElement* gradient = gradientElement(); if (!gradient) return; RenderObject* renderer = gradient->renderer(); if (!renderer) return; RenderSVGResourceContainer* container = toRenderSVGResourceContainer(renderer); container->removeAllClientsFromCache(); }
void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName) { if (!isSupportedAttribute(attrName)) { SVGElement::svgAttributeChanged(attrName); return; } SVGElement::InvalidationGuard invalidationGuard(this); if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) updateRelativeLengthsInformation(); RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer()); if (renderer) renderer->invalidateCacheAndMarkForLayout(); }
void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope) { if (!inDocument()) return; ASSERT(!m_inRelativeLengthClientsInvalidation); #if ENABLE(ASSERT) TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true); #endif RenderObject* renderer = this->renderer(); if (renderer && selfHasRelativeLengths()) { if (renderer->isSVGResourceContainer()) toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope); else renderer->setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope); } WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator end = m_elementsWithRelativeLengths.end(); for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) { if (*it != this) (*it)->invalidateRelativeLengthClients(layoutScope); } }
void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* object, bool needsLayout) { ASSERT(object); ASSERT(object->node()); if (needsLayout && !object->documentBeingDestroyed()) object->setNeedsLayoutAndFullRepaint(); removeFromCacheAndInvalidateDependencies(object, needsLayout); // Invalidate resources in ancestor chain, if needed. RenderObject* current = object->parent(); while (current) { removeFromCacheAndInvalidateDependencies(current, needsLayout); if (current->isSVGResourceContainer()) { // This will process the rest of the ancestors. toRenderSVGResourceContainer(current)->removeAllClientsFromCache(); break; } current = current->parent(); } }
void SVGResourcesCycleSolver::resolveCycles() { ASSERT(m_allResources.isEmpty()); #if DEBUG_CYCLE_DETECTION > 0 fprintf(stderr, "\nBefore cycle detection:\n"); m_resources->dump(m_renderer); #endif // Stash all resources into a HashSet for the ease of traversing. HashSet<RenderSVGResourceContainer*> localResources; m_resources->buildSetOfResources(localResources); ASSERT(!localResources.isEmpty()); // Add all parent resource containers to the HashSet. HashSet<RenderSVGResourceContainer*> parentResources; RenderObject* parent = m_renderer->parent(); while (parent) { if (parent->isSVGResourceContainer()) parentResources.add(toRenderSVGResourceContainer(parent)); parent = parent->parent(); } #if DEBUG_CYCLE_DETECTION > 0 fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); { fprintf(stderr, "Local resources:\n"); HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); fprintf(stderr, "Parent resources:\n"); end = parentResources.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); } #endif // Build combined set of local and parent resources. m_allResources = localResources; HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it) m_allResources.add(*it); // If we're a resource, add ourselves to the HashSet. if (m_renderer->isSVGResourceContainer()) m_allResources.add(toRenderSVGResourceContainer(m_renderer)); ASSERT(!m_allResources.isEmpty()); // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. end = localResources.end(); for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) { RenderSVGResourceContainer* resource = *it; if (parentResources.contains(resource) || resourceContainsCycles(resource)) breakCycle(resource); } #if DEBUG_CYCLE_DETECTION > 0 fprintf(stderr, "\nAfter cycle detection:\n"); m_resources->dump(m_renderer); #endif m_allResources.clear(); }