void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target) { ASSERT(!m_targetElementInstance); ASSERT(!m_needsShadowTreeRecreation); // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use> // elements living in a user agent shadow tree because they will get expanded in a second // pass -- see expandUseElementsInShadowTree(). if (inUseShadowTree()) return; // Do not allow self-referencing. // 'target' may be null, if it's a non SVG namespaced element. if (!target || target == this || isDisallowedElement(target)) return; // Set up root SVG element in shadow tree. RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren(); m_targetElementInstance = toSVGElement(newChild.get()); ShadowRoot* shadowTreeRootElement = userAgentShadowRoot(); shadowTreeRootElement->appendChild(newChild.release()); // Clone the target subtree into the shadow tree, not handling <use> and <symbol> yet. // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it! // Non-appearing <use> content is easier to debug, then half-appearing content. if (!buildShadowTree(target, m_targetElementInstance.get(), false)) { clearShadowTree(); return; } if (instanceTreeIsLoading(m_targetElementInstance.get())) return; // Assure shadow tree building was successfull ASSERT(m_targetElementInstance); ASSERT(m_targetElementInstance->correspondingUseElement() == this); ASSERT(m_targetElementInstance->correspondingElement() == target); // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) { clearShadowTree(); return; } // Expand all <symbol> elements in the shadow tree. // Expand means: replace the actual <symbol> element by the <svg> element. expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild())); m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild()); transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement()); ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement); // Update relative length information. updateRelativeLengthsInformation(); }
bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInstance) { for (SVGElementInstance* instance = targetElementInstance->firstChild(); instance; instance = instance->nextSibling()) { if (SVGUseElement* use = instance->correspondingUseElement()) { if (use->cachedDocumentIsStillLoading()) return true; } if (instance->hasChildNodes()) instanceTreeIsLoading(instance); } return false; }
void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target) { ASSERT(!m_targetElementInstance); // Do not build the shadow/instance tree for <use> elements living in a shadow tree. // The will be expanded soon anyway - see expandUseElementsInShadowTree(). if (isInShadowTree()) return; // Do not allow self-referencing. // 'target' may be null, if it's a non SVG namespaced element. if (!target || target == this) return; // Why a seperated instance/shadow tree? SVG demands it: // The instance tree is accesable from JavaScript, and has to // expose a 1:1 copy of the referenced tree, whereas internally we need // to alter the tree for correct "use-on-symbol", "use-on-svg" support. // Build instance tree. Create root SVGElementInstance object for the first sub-tree node. // // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object // is the SVGRectElement that corresponds to the referenced 'rect' element. m_targetElementInstance = SVGElementInstance::create(this, this, target); // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children bool foundProblem = false; buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false); if (instanceTreeIsLoading(m_targetElementInstance.get())) return; // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it! // Non-appearing <use> content is easier to debug, then half-appearing content. if (foundProblem) { clearResourceReferences(); return; } // Assure instance tree building was successfull ASSERT(m_targetElementInstance); ASSERT(!m_targetElementInstance->shadowTreeElement()); ASSERT(m_targetElementInstance->correspondingUseElement() == this); ASSERT(m_targetElementInstance->directUseElement() == this); ASSERT(m_targetElementInstance->correspondingElement() == target); ShadowRoot* shadowTreeRootElement = shadowRoot(); ASSERT(shadowTreeRootElement); // Build shadow tree from instance tree // This also handles the special cases: <use> on <symbol>, <use> on <svg>. buildShadowTree(target, m_targetElementInstance.get()); // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. expandUseElementsInShadowTree(shadowTreeRootElement); // Expand all <symbol> elements in the shadow tree. // Expand means: replace the actual <symbol> element by the <svg> element. expandSymbolElementsInShadowTree(shadowTreeRootElement); // Now that the shadow tree is completly expanded, we can associate // shadow tree elements <-> instances in the instance tree. associateInstancesWithShadowTreeElements(shadowTreeRootElement->firstChild(), m_targetElementInstance.get()); // If no shadow tree element is present, this means that the reference root // element was removed, as it is disallowed (ie. <use> on <foreignObject>) // Do NOT leave an inconsistent instance tree around, instead destruct it. if (!m_targetElementInstance->shadowTreeElement()) { clearResourceReferences(); return; } ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowTreeRootElement); // Transfer event listeners assigned to the referenced element to our shadow tree elements. transferEventListenersToShadowTree(m_targetElementInstance.get()); // Update relative length information. updateRelativeLengthsInformation(); // Eventually dump instance tree #ifdef DUMP_INSTANCE_TREE String text; unsigned int depth = 0; dumpInstanceTree(depth, text, m_targetElementInstance.get()); fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data()); #endif // Eventually dump shadow tree #ifdef DUMP_SHADOW_TREE RefPtr<XMLSerializer> serializer = XMLSerializer::create(); String markup = serializer->serializeToString(shadowTreeRootElement, ASSERT_NO_EXCEPTION); fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data()); #endif }