void SVGElementInstance::invalidateAllInstancesOfElement(SVGElement* element) { if (!element || !element->inDocument()) return; if (element->isSVGStyledElement() && toSVGStyledElement(element)->instanceUpdatesBlocked()) return; const HashSet<SVGElementInstance*>& set = element->instancesForElement(); if (set.isEmpty()) return; // Mark all use elements referencing 'element' for rebuilding const HashSet<SVGElementInstance*>::const_iterator end = set.end(); for (HashSet<SVGElementInstance*>::const_iterator it = set.begin(); it != end; ++it) { ASSERT((*it)->shadowTreeElement()); ASSERT((*it)->shadowTreeElement()->correspondingElement()); ASSERT((*it)->shadowTreeElement()->correspondingElement() == (*it)->correspondingElement()); ASSERT((*it)->correspondingElement() == element); (*it)->shadowTreeElement()->setCorrespondingElement(0); if (SVGUseElement* element = (*it)->correspondingUseElement()) { ASSERT(element->inDocument()); element->invalidateShadowTree(); } } element->document()->updateStyleIfNeeded(); }
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); } }
AffineTransform SVGLocatable::computeCTM(SVGElement* element, CTMScope mode, StyleUpdateStrategy styleUpdateStrategy) { ASSERT(element); if (styleUpdateStrategy == AllowStyleUpdate) element->document()->updateLayoutIgnorePendingStylesheets(); AffineTransform ctm; SVGElement* stopAtElement = mode == NearestViewportScope ? nearestViewportElement(element) : 0; for (Element* currentElement = element; currentElement; currentElement = currentElement->parentOrShadowHostElement()) { if (!currentElement->isSVGElement()) break; if (toSVGElement(currentElement)->isSVGStyledElement()) ctm = toSVGStyledElement(currentElement)->localCoordinateSpaceTransform(mode).multiply(ctm); // For getCTM() computation, stop at the nearest viewport element if (currentElement == stopAtElement) break; } return ctm; }
SVGElementInstance::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement) : m_targetElement(targetElement->isSVGStyledElement() ? toSVGStyledElement(targetElement) : 0) { if (m_targetElement) m_targetElement->setInstanceUpdatesBlocked(true); }
void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) { bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(start); bool hasSVGShadow = rendererHasSVGShadow(start); bool needsBoundariesUpdate = start->needsBoundariesUpdate(); HashSet<RenderObject*> notlayoutedObjects; for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { bool needsLayout = selfNeedsLayout; bool childEverHadLayout = child->everHadLayout(); if (needsBoundariesUpdate && hasSVGShadow) { // If we have a shadow, our shadow is baked into our children's cached boundaries, // so they need to update. child->setNeedsBoundariesUpdate(); needsLayout = true; } if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). if (child->isSVGText()) toRenderSVGText(child)->setNeedsTextMetricsUpdate(); needsLayout = true; } if (layoutSizeChanged) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { if (element->isSVGStyledElement() && toSVGStyledElement(element)->hasRelativeLengths()) { // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object if (child->isSVGShape()) toRenderSVGShape(child)->setNeedsShapeUpdate(); else if (child->isSVGText()) { toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); } needsLayout = true; } } } if (needsLayout) child->setNeedsLayout(true, MarkOnlyThis); if (child->needsLayout()) { child->layout(); // Renderers are responsible for repainting themselves when changing, except // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds. // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout) child->repaint(); } else if (layoutSizeChanged) notlayoutedObjects.add(child); ASSERT(!child->needsLayout()); } if (!layoutSizeChanged) { ASSERT(notlayoutedObjects.isEmpty()); return; } // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. HashSet<RenderObject*>::iterator end = notlayoutedObjects.end(); for (HashSet<RenderObject*>::iterator it = notlayoutedObjects.begin(); it != end; ++it) invalidateResourcesOfChildren(*it); }