void RenderSVGResourceContainer::registerResource() { SVGDocumentExtensions* extensions = svgExtensionsFromNode(node()); if (!extensions->hasPendingResources(m_id)) { extensions->addResource(m_id, this); return; } OwnPtr<SVGDocumentExtensions::SVGPendingElements> clients(extensions->removePendingResource(m_id)); // Cache us with the new id. extensions->addResource(m_id, this); // Update cached resources of pending clients. const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end(); for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) { ASSERT((*it)->hasPendingResources()); (*it)->clearHasPendingResourcesIfPossible(); RenderObject* renderer = (*it)->renderer(); if (!renderer) continue; SVGResourcesCache::clientUpdatedFromElement(renderer, renderer->style()); renderer->setNeedsLayout(true); } }
static inline SVGResourcesCache* resourcesCacheFromRenderObject(const RenderObject& renderer) { SVGDocumentExtensions* extensions = renderer.document().accessSVGExtensions(); ASSERT(extensions); SVGResourcesCache* cache = extensions->resourcesCache(); ASSERT(cache); return cache; }
void RenderSVGResourceContainer::idChanged() { // Invalidate all our current clients. removeAllClientsFromCache(); // Remove old id, that is guaranteed to be present in cache. SVGDocumentExtensions* extensions = svgExtensionsFromNode(node()); extensions->removeResource(m_id); m_id = static_cast<Element*>(node())->getIdAttribute(); registerResource(); }
static inline SVGResourcesCache* resourcesCacheFromRenderObject(RenderObject* renderer) { Document* document = renderer->document(); ASSERT(document); SVGDocumentExtensions* extensions = document->accessSVGExtensions(); ASSERT(extensions); SVGResourcesCache* cache = extensions->resourcesCache(); ASSERT(cache); return cache; }
void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer& resource) { SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource); // The resource itself may have clients, that need to be notified. cache->removeResourcesFromRenderer(resource); for (auto it = cache->m_cache.begin(), end = cache->m_cache.end(); it != end; ++it) { it->value->resourceDestroyed(resource); // Mark users of destroyed resources as pending resolution based on the id of the old resource. Element& resourceElement = resource.element(); Element* clientElement = toElement(it->key->node()); SVGDocumentExtensions* extensions = clientElement->document().accessSVGExtensions(); extensions->addPendingResource(resourceElement.getIdAttribute(), clientElement); } }
void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value) { if (error == NoError) return; String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\""; SVGDocumentExtensions* extensions = document().accessSVGExtensions(); if (error == NegativeValueForbiddenError) { extensions->reportError("Invalid negative value for " + errorString); return; } if (error == ParsingAttributeFailedError) { extensions->reportError("Invalid value for " + errorString); return; } ASSERT_NOT_REACHED(); }
void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource) { ASSERT(resource); SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource); // The resource itself may have clients, that need to be notified. cache->removeResourcesFromRenderObject(resource); HashMap<RenderObject*, SVGResources*>::iterator end = cache->m_cache.end(); for (HashMap<RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it) { it->second->resourceDestroyed(resource); // Mark users of destroyed resources as pending resolution based on the id of the old resource. Element* resourceElement = toElement(resource->node()); SVGStyledElement* clientElement = toSVGStyledElement(it->first->node()); SVGDocumentExtensions* extensions = clientElement->document()->accessSVGExtensions(); extensions->addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement); } }
void SVGElement::insertedIntoDocument() { StyledElement::insertedIntoDocument(); SVGDocumentExtensions* extensions = document()->accessSVGExtensions(); String resourceId = SVGURIReference::getTarget(id()); if (extensions->isPendingResource(resourceId)) { std::auto_ptr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(resourceId)); if (clients->isEmpty()) return; HashSet<SVGStyledElement*>::const_iterator it = clients->begin(); const HashSet<SVGStyledElement*>::const_iterator end = clients->end(); for (; it != end; ++it) (*it)->buildPendingResource(); SVGResource::invalidateClients(*clients); } }
void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement) { ASSERT(clientElement); // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now. if (!inDocument()) return; // An element wants to notify us that its own relative lengths state changed. // Register it in the relative length map, and register us in the parent relative length map. // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree. for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) { SVGElement* currentElement = toSVGElement(currentNode); ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation); bool hadRelativeLengths = currentElement->hasRelativeLengths(); if (clientHasRelativeLengths) currentElement->m_elementsWithRelativeLengths.add(clientElement); else currentElement->m_elementsWithRelativeLengths.remove(clientElement); // If the relative length state hasn't changed, we can stop propagating the notification. if (hadRelativeLengths == currentElement->hasRelativeLengths()) return; clientElement = currentElement; clientHasRelativeLengths = clientElement->hasRelativeLengths(); } // Register root SVG elements for top level viewport change notifications. if (clientElement->isSVGSVGElement()) { SVGDocumentExtensions* svgExtensions = accessDocumentSVGExtensions(); if (clientElement->hasRelativeLengths()) svgExtensions->addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement)); else svgExtensions->removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement)); } }
void SVGElement::buildPendingResourcesIfNeeded() { Document& document = this->document(); if (!needsPendingResourceHandling() || !inDocument() || isInShadowTree()) return; SVGDocumentExtensions* extensions = document.accessSVGExtensions(); AtomicString resourceId = getIdAttribute(); if (!extensions->hasPendingResource(resourceId)) return; // Mark pending resources as pending for removal. extensions->markPendingResourcesForRemoval(resourceId); // Rebuild pending resources for each client of a pending resource that is being removed. while (Element* clientElement = extensions->removeElementFromPendingResourcesForRemoval(resourceId)) { ASSERT(clientElement->hasPendingResources()); if (clientElement->hasPendingResources()) { clientElement->buildPendingResource(); extensions->clearHasPendingResourcesIfPossible(clientElement); } } }
static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement& element) { extensions.addPendingResource(id, &element); }