static void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance) { SVGElement* element = targetInstance->correspondingElement(); ASSERT(element); if (element->hasTagName(SVGNames::useTag)) { if (toSVGUseElement(element)->cachedDocumentIsStillLoading()) return; } SVGElement* shadowTreeElement = targetInstance->shadowTreeElement(); ASSERT(shadowTreeElement); SVGUseElement* directUseElement = targetInstance->directUseElement(); String directUseElementName = directUseElement ? directUseElement->nodeName() : "null"; String elementId = element->getIdAttribute(); String elementNodeName = element->nodeName(); String shadowTreeElementNodeName = shadowTreeElement->nodeName(); String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null"; String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null"; for (unsigned int i = 0; i < depth; ++i) text += " "; text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), directUseElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n", targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(), elementNodeName.latin1().data(), element, directUseElementName.latin1().data(), directUseElement, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data()); for (unsigned int i = 0; i < depth; ++i) text += " "; const HashSet<SVGElementInstance*>& elementInstances = element->instancesForElement(); text += "Corresponding element is associated with " + String::number(elementInstances.size()) + " instance(s):\n"; const HashSet<SVGElementInstance*>::const_iterator end = elementInstances.end(); for (HashSet<SVGElementInstance*>::const_iterator it = elementInstances.begin(); it != end; ++it) { for (unsigned int i = 0; i < depth; ++i) text += " "; text += String::format(" -> SVGElementInstance this=%p, (refCount: %i, shadowTreeElement in document? %i)\n", *it, (*it)->refCount(), (*it)->shadowTreeElement()->inDocument()); } ++depth; for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling()) dumpInstanceTree(depth, text, instance); --depth; }
void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target) { if (!target) return; SVGElement* originalElement = target->correspondingElement(); ASSERT(originalElement); if (SVGElement* shadowTreeElement = target->shadowTreeElement()) { if (EventTargetData* d = originalElement->eventTargetData()) { EventListenerMap& map = d->eventListenerMap; EventListenerMap::iterator end = map.end(); for (EventListenerMap::iterator it = map.begin(); it != end; ++it) { EventListenerVector& entry = *it->second; for (size_t i = 0; i < entry.size(); ++i) { // Event listeners created from markup have already been transfered to the shadow tree during cloning. if (entry[i].listener->wasCreatedFromMarkup()) continue; shadowTreeElement->addEventListener(it->first, entry[i].listener, entry[i].useCapture); } } } } for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling()) transferEventListenersToShadowTree(instance); }
void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem) { ASSERT(target); ASSERT(targetInstance); // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree. bool targetHasUseTag = target->hasTagName(SVGNames::useTag); SVGElement* newTarget = 0; if (targetHasUseTag) { foundProblem = hasCycleUseReferencing(static_cast<SVGUseElement*>(target), targetInstance, newTarget); if (foundProblem) return; } // A general description from the SVG spec, describing what buildInstanceTree() actually does. // // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has // its correspondingElement that is an SVGRectElement object. for (Node* node = target->firstChild(); node; node = node->nextSibling()) { SVGElement* element = 0; if (node->isSVGElement()) element = static_cast<SVGElement*>(node); // Skip any non-svg nodes or any disallowed element. if (!element || isDisallowedElement(element)) continue; // Create SVGElementInstance object, for both container/non-container nodes. RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, element); SVGElementInstance* instancePtr = instance.get(); targetInstance->appendChild(instance.release()); // Enter recursion, appending new instance tree nodes to the "instance" object. buildInstanceTree(element, instancePtr, foundProblem); if (foundProblem) return; } if (!targetHasUseTag || !newTarget) return; RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, newTarget); SVGElementInstance* newInstancePtr = newInstance.get(); targetInstance->appendChild(newInstance.release()); buildInstanceTree(newTarget, newInstancePtr, foundProblem); }
void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance) { SVGElement* element = targetInstance->correspondingElement(); ASSERT(element); String elementId = element->getIDAttribute(); String elementNodeName = element->nodeName(); String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null"; String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null"; for (unsigned int i = 0; i < depth; ++i) text += " "; text += String::format("SVGElementInstance (parentNode=%s, firstChild=%s, correspondingElement=%s, id=%s)\n", parentNodeName.latin1().data(), firstChildNodeName.latin1().data(), elementNodeName.latin1().data(), elementId.latin1().data()); depth++; for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling()) dumpInstanceTree(depth, text, instance); depth--; }
void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance) { if (!target || !targetInstance) return; SVGElement* originalElement = targetInstance->correspondingElement(); if (originalElement->hasTagName(SVGNames::useTag)) { #if ENABLE(SVG) && ENABLE(SVG_USE) // <use> gets replaced by <g> ASSERT(target->nodeName() == SVGNames::gTag); #else ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag); #endif } else if (originalElement->hasTagName(SVGNames::symbolTag)) { // <symbol> gets replaced by <svg> #if ENABLE(SVG) && ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) ASSERT(target->nodeName() == SVGNames::svgTag); #endif } else ASSERT(target->nodeName() == originalElement->nodeName()); SVGElement* element = 0; if (target->isSVGElement()) element = static_cast<SVGElement*>(target); ASSERT(!targetInstance->shadowTreeElement()); targetInstance->setShadowTreeElement(element); Node* node = target->firstChild(); for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) { // Skip any non-svg elements in shadow tree while (node && !node->isSVGElement()) node = node->nextSibling(); if (!node) break; associateInstancesWithShadowTreeElements(node, instance); node = node->nextSibling(); } }