2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6 * Copyright (C) 2012 University of Szeged
7 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
27 #include "core/svg/SVGUseElement.h"
29 #include "XLinkNames.h"
30 #include "bindings/v8/ExceptionStatePlaceholder.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/ElementTraversal.h"
33 #include "core/events/Event.h"
34 #include "core/dom/shadow/ElementShadow.h"
35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/fetch/FetchRequest.h"
37 #include "core/fetch/ResourceFetcher.h"
38 #include "core/rendering/svg/RenderSVGResource.h"
39 #include "core/rendering/svg/RenderSVGTransformableContainer.h"
40 #include "core/svg/SVGElementInstance.h"
41 #include "core/svg/SVGGElement.h"
42 #include "core/svg/SVGLengthContext.h"
43 #include "core/svg/SVGSVGElement.h"
44 #include "core/xml/parser/XMLDocumentParser.h"
48 inline SVGUseElement::SVGUseElement(Document& document, bool wasInsertedByParser)
49 : SVGGraphicsElement(SVGNames::useTag, document)
50 , SVGURIReference(this)
51 , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
52 , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
53 , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths))
54 , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths))
55 , m_wasInsertedByParser(wasInsertedByParser)
56 , m_haveFiredLoadEvent(false)
57 , m_needsShadowTreeRecreation(false)
58 , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
60 ASSERT(hasCustomStyleCallbacks());
61 ScriptWrappable::init(this);
63 addToPropertyMap(m_x);
64 addToPropertyMap(m_y);
65 addToPropertyMap(m_width);
66 addToPropertyMap(m_height);
69 PassRefPtr<SVGUseElement> SVGUseElement::create(Document& document, bool wasInsertedByParser)
71 // Always build a user agent #shadow-root for SVGUseElement.
72 RefPtr<SVGUseElement> use = adoptRef(new SVGUseElement(document, wasInsertedByParser));
73 use->ensureUserAgentShadowRoot();
77 SVGUseElement::~SVGUseElement()
79 setDocumentResource(0);
81 clearResourceReferences();
85 SVGElementInstance* SVGUseElement::instanceRoot()
87 // If there is no element instance tree, force immediate SVGElementInstance tree
88 // creation by asking the document to invoke our recalcStyle function - as we can't
89 // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
90 // object right after creating the element on-the-fly
91 if (!m_targetElementInstance)
92 document().updateRenderTreeIfNeeded();
94 return m_targetElementInstance.get();
97 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
99 // FIXME: Implement me.
103 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
105 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
106 if (supportedAttributes.isEmpty()) {
107 SVGURIReference::addSupportedAttributes(supportedAttributes);
108 supportedAttributes.add(SVGNames::xAttr);
109 supportedAttributes.add(SVGNames::yAttr);
110 supportedAttributes.add(SVGNames::widthAttr);
111 supportedAttributes.add(SVGNames::heightAttr);
113 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
116 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
118 SVGParsingError parseError = NoError;
120 if (!isSupportedAttribute(name)) {
121 SVGGraphicsElement::parseAttribute(name, value);
122 } else if (name == SVGNames::xAttr) {
123 m_x->setBaseValueAsString(value, parseError);
124 } else if (name == SVGNames::yAttr) {
125 m_y->setBaseValueAsString(value, parseError);
126 } else if (name == SVGNames::widthAttr) {
127 m_width->setBaseValueAsString(value, parseError);
128 } else if (name == SVGNames::heightAttr) {
129 m_height->setBaseValueAsString(value, parseError);
130 } else if (SVGURIReference::parseAttribute(name, value, parseError)) {
132 ASSERT_NOT_REACHED();
135 reportAttributeParsingError(parseError, name, value);
139 static inline bool isWellFormedDocument(Document* document)
141 if (document->isXMLDocument())
142 return static_cast<XMLDocumentParser*>(document->parser())->wellFormed();
147 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* rootParent)
149 // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
150 SVGGraphicsElement::insertedInto(rootParent);
151 if (!rootParent->inDocument())
152 return InsertionDone;
153 ASSERT(!m_targetElementInstance || !isWellFormedDocument(&document()));
154 ASSERT(!hasPendingResources() || !isWellFormedDocument(&document()));
155 if (!m_wasInsertedByParser) {
156 buildPendingResource();
158 if (!isStructurallyExternal()) {
159 sendSVGLoadEventIfPossibleAsynchronously();
162 return InsertionDone;
165 void SVGUseElement::removedFrom(ContainerNode* rootParent)
167 SVGGraphicsElement::removedFrom(rootParent);
168 if (rootParent->inDocument())
169 clearResourceReferences();
172 TreeScope* SVGUseElement::referencedScope() const
174 if (!isExternalURIReference(hrefString(), document()))
176 return externalDocument();
179 Document* SVGUseElement::externalDocument() const
181 if (m_resource && m_resource->isLoaded()) {
182 // Gracefully handle error condition.
183 if (m_resource->errorOccurred())
185 ASSERT(m_resource->document());
186 return m_resource->document();
191 void transferUseWidthAndHeightIfNeeded(const SVGUseElement& use, SVGElement* shadowElement, const SVGElement& originalElement)
193 ASSERT(shadowElement);
194 if (isSVGSymbolElement(*shadowElement)) {
195 // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
196 // If attributes width and/or height are provided on the 'use' element, then these attributes
197 // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
198 // the generated 'svg' element will use values of 100% for these attributes.
199 shadowElement->setAttribute(SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : "100%");
200 shadowElement->setAttribute(SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : "100%");
201 } else if (isSVGSVGElement(*shadowElement)) {
202 // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
203 // values will override the corresponding attributes on the 'svg' in the generated tree.
204 if (use.width()->isSpecified())
205 shadowElement->setAttribute(SVGNames::widthAttr, AtomicString(use.width()->currentValue()->valueAsString()));
207 shadowElement->setAttribute(SVGNames::widthAttr, originalElement.getAttribute(SVGNames::widthAttr));
208 if (use.height()->isSpecified())
209 shadowElement->setAttribute(SVGNames::heightAttr, AtomicString(use.height()->currentValue()->valueAsString()));
211 shadowElement->setAttribute(SVGNames::heightAttr, originalElement.getAttribute(SVGNames::heightAttr));
215 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
217 if (!isSupportedAttribute(attrName)) {
218 SVGGraphicsElement::svgAttributeChanged(attrName);
222 SVGElement::InvalidationGuard invalidationGuard(this);
224 RenderObject* renderer = this->renderer();
225 if (attrName == SVGNames::xAttr
226 || attrName == SVGNames::yAttr
227 || attrName == SVGNames::widthAttr
228 || attrName == SVGNames::heightAttr) {
229 updateRelativeLengthsInformation();
230 if (m_targetElementInstance) {
231 ASSERT(m_targetElementInstance->correspondingElement());
232 transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance->shadowTreeElement(), *m_targetElementInstance->correspondingElement());
235 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
239 if (SVGURIReference::isKnownAttribute(attrName)) {
240 bool isExternalReference = isExternalURIReference(hrefString(), document());
241 if (isExternalReference) {
242 KURL url = document().completeURL(hrefString());
243 if (url.hasFragmentIdentifier()) {
244 FetchRequest request(ResourceRequest(url.string()), localName());
245 setDocumentResource(document().fetcher()->fetchSVGDocument(request));
248 setDocumentResource(0);
251 if (!m_wasInsertedByParser)
252 buildPendingResource();
260 ASSERT_NOT_REACHED();
263 static bool isDisallowedElement(Node* node)
265 // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
266 // (i.e., "instanced") in the SVG document via a 'use' element."
267 // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
268 // Excluded are anything that is used by reference or that only make sense to appear once in a document.
269 // We must also allow the shadow roots of other use elements.
270 if (node->isShadowRoot() || node->isTextNode())
273 if (!node->isSVGElement())
276 Element* element = toElement(node);
278 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ());
279 if (allowedElementTags.isEmpty()) {
280 allowedElementTags.add(SVGNames::aTag);
281 allowedElementTags.add(SVGNames::circleTag);
282 allowedElementTags.add(SVGNames::descTag);
283 allowedElementTags.add(SVGNames::ellipseTag);
284 allowedElementTags.add(SVGNames::gTag);
285 allowedElementTags.add(SVGNames::imageTag);
286 allowedElementTags.add(SVGNames::lineTag);
287 allowedElementTags.add(SVGNames::metadataTag);
288 allowedElementTags.add(SVGNames::pathTag);
289 allowedElementTags.add(SVGNames::polygonTag);
290 allowedElementTags.add(SVGNames::polylineTag);
291 allowedElementTags.add(SVGNames::rectTag);
292 allowedElementTags.add(SVGNames::svgTag);
293 allowedElementTags.add(SVGNames::switchTag);
294 allowedElementTags.add(SVGNames::symbolTag);
295 allowedElementTags.add(SVGNames::textTag);
296 allowedElementTags.add(SVGNames::textPathTag);
297 allowedElementTags.add(SVGNames::titleTag);
298 allowedElementTags.add(SVGNames::tspanTag);
299 allowedElementTags.add(SVGNames::useTag);
301 return !allowedElementTags.contains<SVGAttributeHashTranslator>(element->tagQName());
304 static bool subtreeContainsDisallowedElement(Node* start)
306 if (isDisallowedElement(start))
309 for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
310 if (subtreeContainsDisallowedElement(cur))
317 void SVGUseElement::scheduleShadowTreeRecreation()
319 if (!referencedScope() || inUseShadowTree())
321 m_needsShadowTreeRecreation = true;
322 document().scheduleUseShadowTreeUpdate(*this);
325 void SVGUseElement::clearResourceReferences()
327 if (m_targetElementInstance) {
328 m_targetElementInstance->detach();
329 m_targetElementInstance = nullptr;
332 // FIXME: We should try to optimize this, to at least allow partial reclones.
333 if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
334 shadowTreeRootElement->removeChildren();
336 m_needsShadowTreeRecreation = false;
337 document().unscheduleUseShadowTreeUpdate(*this);
339 document().accessSVGExtensions().removeAllTargetReferencesForElement(this);
342 void SVGUseElement::buildPendingResource()
344 if (!referencedScope() || inUseShadowTree())
346 clearResourceReferences();
351 Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id, externalDocument());
352 if (!target || !target->inDocument()) {
353 // If we can't find the target of an external element, just give up.
354 // We can't observe if the target somewhen enters the external document, nor should we do it.
355 if (externalDocument())
360 referencedScope()->document().accessSVGExtensions().addPendingResource(id, this);
361 ASSERT(hasPendingResources());
365 if (target->isSVGElement()) {
366 buildShadowAndInstanceTree(toSVGElement(target));
367 invalidateDependentShadowTrees();
370 ASSERT(!m_needsShadowTreeRecreation);
373 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
375 ASSERT(!m_targetElementInstance);
377 // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use>
378 // elements living in a user agent shadow tree because they will get expanded in a second
379 // pass -- see expandUseElementsInShadowTree().
380 if (inUseShadowTree())
383 // Do not allow self-referencing.
384 // 'target' may be null, if it's a non SVG namespaced element.
385 if (!target || target == this)
388 // Why a seperated instance/shadow tree? SVG demands it:
389 // The instance tree is accesable from JavaScript, and has to
390 // expose a 1:1 copy of the referenced tree, whereas internally we need
391 // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
393 // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
395 // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
396 // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
397 // is the SVGRectElement that corresponds to the referenced 'rect' element.
398 m_targetElementInstance = SVGElementInstance::create(this, this, target);
400 // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
401 bool foundProblem = false;
402 buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false);
404 if (instanceTreeIsLoading(m_targetElementInstance.get()))
407 // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
408 // Non-appearing <use> content is easier to debug, then half-appearing content.
410 clearResourceReferences();
414 // Assure instance tree building was successfull
415 ASSERT(m_targetElementInstance);
416 ASSERT(!m_targetElementInstance->shadowTreeElement());
417 ASSERT(m_targetElementInstance->correspondingUseElement() == this);
418 ASSERT(m_targetElementInstance->directUseElement() == this);
419 ASSERT(m_targetElementInstance->correspondingElement() == target);
421 ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
422 ASSERT(shadowTreeRootElement);
424 // Build shadow tree from instance tree
425 // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
426 buildShadowTree(target, m_targetElementInstance.get(), shadowTreeRootElement);
428 // Expand all <use> elements in the shadow tree.
429 // Expand means: replace the actual <use> element by what it references.
430 expandUseElementsInShadowTree(shadowTreeRootElement);
432 // Expand all <symbol> elements in the shadow tree.
433 // Expand means: replace the actual <symbol> element by the <svg> element.
434 expandSymbolElementsInShadowTree(shadowTreeRootElement);
436 // If no shadow tree element is present, this means that the reference root
437 // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
438 // Do NOT leave an inconsistent instance tree around, instead destruct it.
439 Node* shadowTreeTargetNode = shadowTreeRootElement->firstChild();
440 if (!shadowTreeTargetNode) {
441 clearResourceReferences();
445 // Now that the shadow tree is completly expanded, we can associate
446 // shadow tree elements <-> instances in the instance tree.
447 associateInstancesWithShadowTreeElements(shadowTreeTargetNode, m_targetElementInstance.get());
449 SVGElement* shadowTreeTargetElement = toSVGElement(shadowTreeTargetNode);
450 ASSERT(shadowTreeTargetElement->correspondingElement());
451 transferUseWidthAndHeightIfNeeded(*this, shadowTreeTargetElement, *shadowTreeTargetElement->correspondingElement());
453 ASSERT(shadowTreeTargetElement->parentNode() == shadowTreeRootElement);
455 // Transfer event listeners assigned to the referenced element to our shadow tree elements.
456 transferEventListenersToShadowTree(shadowTreeTargetElement);
458 // Update relative length information.
459 updateRelativeLengthsInformation();
462 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
464 return new RenderSVGTransformableContainer(this);
467 static bool isDirectReference(const Node& node)
469 return isSVGPathElement(node)
470 || isSVGRectElement(node)
471 || isSVGCircleElement(node)
472 || isSVGEllipseElement(node)
473 || isSVGPolygonElement(node)
474 || isSVGPolylineElement(node)
475 || isSVGTextElement(node);
478 void SVGUseElement::toClipPath(Path& path)
480 ASSERT(path.isEmpty());
482 Node* n = userAgentShadowRoot()->firstChild();
486 if (n->isSVGElement() && toSVGElement(n)->isSVGGraphicsElement()) {
487 if (!isDirectReference(*n)) {
488 // Spec: Indirect references are an error (14.3.5)
489 document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>");
491 toSVGGraphicsElement(n)->toClipPath(path);
492 // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
493 SVGLengthContext lengthContext(this);
494 path.translate(FloatSize(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)));
495 path.transform(animatedLocalTransform());
500 RenderObject* SVGUseElement::rendererClipChild() const
502 if (Node* n = userAgentShadowRoot()->firstChild()) {
503 if (n->isSVGElement() && isDirectReference(*n))
504 return toSVGElement(n)->renderer();
510 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem, bool foundUse)
513 ASSERT(targetInstance);
515 // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
516 // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
517 bool targetIsUseElement = isSVGUseElement(*target);
518 SVGElement* newTarget = 0;
519 if (targetIsUseElement) {
520 foundProblem = hasCycleUseReferencing(toSVGUseElement(target), targetInstance, newTarget);
524 // We only need to track first degree <use> dependencies. Indirect references are handled
525 // as the invalidation bubbles up the dependency chain.
527 document().accessSVGExtensions().addElementReferencingTarget(this, target);
530 } else if (isDisallowedElement(target)) {
535 // A general description from the SVG spec, describing what buildInstanceTree() actually does.
537 // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
538 // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
539 // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
540 // its correspondingElement that is an SVGRectElement object.
542 for (SVGElement* element = Traversal<SVGElement>::firstChild(*target); element; element = Traversal<SVGElement>::nextSibling(*element)) {
543 // Skip any disallowed element.
544 if (isDisallowedElement(element))
547 // Create SVGElementInstance object, for both container/non-container nodes.
548 RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, 0, element);
549 SVGElementInstance* instancePtr = instance.get();
550 targetInstance->appendChild(instance.release());
552 // Enter recursion, appending new instance tree nodes to the "instance" object.
553 buildInstanceTree(element, instancePtr, foundProblem, foundUse);
558 if (!targetIsUseElement || !newTarget)
561 RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, toSVGUseElement(target), newTarget);
562 SVGElementInstance* newInstancePtr = newInstance.get();
563 targetInstance->appendChild(newInstance.release());
564 buildInstanceTree(newTarget, newInstancePtr, foundProblem, foundUse);
567 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, SVGElement*& newTarget)
569 ASSERT(referencedScope());
570 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope());
572 if (targetElement && targetElement->isSVGElement())
573 newTarget = toSVGElement(targetElement);
578 // Shortcut for self-references
579 if (newTarget == this)
582 AtomicString targetId = newTarget->getIdAttribute();
583 SVGElementInstance* instance = targetInstance->parentNode();
585 SVGElement* element = instance->correspondingElement();
587 if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
590 instance = instance->parentNode();
595 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
597 ASSERT(!subtree.inDocument());
598 Element* element = ElementTraversal::firstWithin(subtree);
600 if (isDisallowedElement(element)) {
601 Element* next = ElementTraversal::nextSkippingChildren(*element, &subtree);
602 // The subtree is not in document so this won't generate events that could mutate the tree.
603 element->parentNode()->removeChild(element);
606 element = ElementTraversal::next(*element, &subtree);
611 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance, ShadowRoot* shadowTreeRootElement)
613 // For instance <use> on <foreignObject> (direct case).
614 if (isDisallowedElement(target))
617 RefPtr<Element> newChild = targetInstance->correspondingElement()->cloneElementWithChildren();
619 // We don't walk the target tree element-by-element, and clone each element,
620 // but instead use cloneElementWithChildren(). This is an optimization for the common
621 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
622 // Though if there are disallowed elements in the subtree, we have to remove them.
623 // For instance: <use> on <g> containing <foreignObject> (indirect case).
624 if (subtreeContainsDisallowedElement(newChild.get()))
625 removeDisallowedElementsFromSubtree(*newChild);
627 shadowTreeRootElement->appendChild(newChild.release());
630 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
633 // Why expand the <use> elements in the shadow tree here, and not just
634 // do this directly in buildShadowTree, if we encounter a <use> element?
636 // Short answer: Because we may miss to expand some elements. For example, if a <symbol>
637 // contains <use> tags, we'd miss them. So once we're done with setting up the
638 // actual shadow tree (after the special case modification for svg/symbol) we have
639 // to walk it completely and expand all <use> elements.
640 if (isSVGUseElement(*element)) {
641 SVGUseElement* use = toSVGUseElement(element);
642 ASSERT(!use->resourceIsStillLoading());
644 ASSERT(referencedScope());
645 Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope());
646 SVGElement* target = 0;
647 if (targetElement && targetElement->isSVGElement())
648 target = toSVGElement(targetElement);
650 // Don't ASSERT(target) here, it may be "pending", too.
651 // Setup sub-shadow tree root node
652 RefPtr<SVGGElement> cloneParent = SVGGElement::create(referencedScope()->document());
653 use->cloneChildNodes(cloneParent.get());
655 // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
656 // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
657 transferUseAttributesToReplacedElement(use, cloneParent.get());
659 if (target && !isDisallowedElement(target)) {
660 RefPtr<Element> newChild = target->cloneElementWithChildren();
661 ASSERT(newChild->isSVGElement());
662 transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()), *target);
663 cloneParent->appendChild(newChild.release());
666 // We don't walk the target tree element-by-element, and clone each element,
667 // but instead use cloneElementWithChildren(). This is an optimization for the common
668 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
669 // Though if there are disallowed elements in the subtree, we have to remove them.
670 // For instance: <use> on <g> containing <foreignObject> (indirect case).
671 if (subtreeContainsDisallowedElement(cloneParent.get()))
672 removeDisallowedElementsFromSubtree(*cloneParent);
674 RefPtr<Node> replacingElement(cloneParent.get());
676 // Replace <use> with referenced content.
677 ASSERT(use->parentNode());
678 use->parentNode()->replaceChild(cloneParent.release(), use);
680 // Expand the siblings because the *element* is replaced and we will
681 // lose the sibling chain when we are back from recursion.
682 element = replacingElement.get();
683 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
684 expandUseElementsInShadowTree(sibling.get());
687 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
688 expandUseElementsInShadowTree(child.get());
691 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
694 if (isSVGSymbolElement(*element)) {
695 // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
696 // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
697 // always have explicit values for attributes width and height. If attributes width and/or
698 // height are provided on the 'use' element, then these attributes will be transferred to
699 // the generated 'svg'. If attributes width and/or height are not specified, the generated
700 // 'svg' element will use values of 100% for these attributes.
701 ASSERT(referencedScope());
702 RefPtr<SVGSVGElement> svgElement = SVGSVGElement::create(referencedScope()->document());
704 // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
705 svgElement->cloneDataFromElement(*toElement(element));
707 // Only clone symbol children, and add them to the new <svg> element
708 for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
709 RefPtr<Node> newChild = child->cloneNode(true);
710 svgElement->appendChild(newChild.release());
713 // We don't walk the target tree element-by-element, and clone each element,
714 // but instead use cloneNode(deep=true). This is an optimization for the common
715 // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
716 // Though if there are disallowed elements in the subtree, we have to remove them.
717 // For instance: <use> on <g> containing <foreignObject> (indirect case).
718 if (subtreeContainsDisallowedElement(svgElement.get()))
719 removeDisallowedElementsFromSubtree(*svgElement);
721 RefPtr<Node> replacingElement(svgElement.get());
723 // Replace <symbol> with <svg>.
724 element->parentNode()->replaceChild(svgElement.release(), element);
726 // Expand the siblings because the *element* is replaced and we will
727 // lose the sibling chain when we are back from recursion.
728 element = replacingElement.get();
729 for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
730 expandSymbolElementsInShadowTree(sibling.get());
733 for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
734 expandSymbolElementsInShadowTree(child.get());
737 void SVGUseElement::transferEventListenersToShadowTree(SVGElement* shadowTreeTargetElement)
739 if (!shadowTreeTargetElement)
742 SVGElement* originalElement = shadowTreeTargetElement->correspondingElement();
743 ASSERT(originalElement);
744 if (EventTargetData* data = originalElement->eventTargetData())
745 data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(shadowTreeTargetElement);
747 for (SVGElement* child = Traversal<SVGElement>::firstChild(*shadowTreeTargetElement); child; child = Traversal<SVGElement>::nextSibling(*child))
748 transferEventListenersToShadowTree(child);
751 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
753 if (!target || !targetInstance)
756 SVGElement* originalElement = targetInstance->correspondingElement();
757 ASSERT(originalElement);
758 if (isSVGUseElement(*originalElement)) {
759 // <use> gets replaced by <g>
760 ASSERT(AtomicString(target->nodeName()) == SVGNames::gTag);
761 } else if (isSVGSymbolElement(*originalElement)) {
762 // <symbol> gets replaced by <svg>
763 ASSERT(AtomicString(target->nodeName()) == SVGNames::svgTag);
765 ASSERT(AtomicString(target->nodeName()) == originalElement->nodeName());
768 SVGElement* element = 0;
769 if (target->isSVGElement())
770 element = toSVGElement(target);
772 ASSERT(!targetInstance->shadowTreeElement());
773 targetInstance->setShadowTreeElement(element);
774 element->setCorrespondingElement(originalElement);
776 SVGElement* child = Traversal<SVGElement>::firstChild(*target);
777 for (SVGElementInstance* instance = targetInstance->firstChild(); child && instance; instance = instance->nextSibling()) {
778 associateInstancesWithShadowTreeElements(child, instance);
779 child = Traversal<SVGElement>::nextSibling(*child);
783 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
785 if (!m_targetElementInstance) {
786 ASSERT(!inDocument());
790 return instanceForShadowTreeElement(element, m_targetElementInstance.get());
793 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
798 // We're dispatching a mutation event during shadow tree construction
799 // this instance hasn't yet been associated to a shadowTree element.
800 if (!instance->shadowTreeElement())
803 if (element == instance->shadowTreeElement())
806 for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
807 if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
814 void SVGUseElement::invalidateShadowTree()
816 if (!inActiveDocument() || m_needsShadowTreeRecreation)
818 scheduleShadowTreeRecreation();
819 invalidateDependentShadowTrees();
822 void SVGUseElement::invalidateDependentShadowTrees()
824 // Recursively invalidate dependent <use> shadow trees
825 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = instancesForElement();
826 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
827 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
828 if (SVGUseElement* element = (*it)->correspondingUseElement()) {
829 ASSERT(element->inDocument());
830 element->invalidateShadowTree();
835 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
840 to->cloneDataFromElement(*from);
842 to->removeAttribute(SVGNames::xAttr);
843 to->removeAttribute(SVGNames::yAttr);
844 to->removeAttribute(SVGNames::widthAttr);
845 to->removeAttribute(SVGNames::heightAttr);
846 to->removeAttribute(XLinkNames::hrefAttr);
849 bool SVGUseElement::selfHasRelativeLengths() const
851 if (m_x->currentValue()->isRelative()
852 || m_y->currentValue()->isRelative()
853 || m_width->currentValue()->isRelative()
854 || m_height->currentValue()->isRelative())
857 if (!m_targetElementInstance)
860 SVGElement* element = m_targetElementInstance->correspondingElement();
864 return element->hasRelativeLengths();
867 void SVGUseElement::notifyFinished(Resource* resource)
872 invalidateShadowTree();
873 if (resource->errorOccurred())
874 dispatchEvent(Event::create(EventTypeNames::error));
875 else if (!resource->wasCanceled()) {
876 if (m_wasInsertedByParser && m_haveFiredLoadEvent)
878 if (!isStructurallyExternal())
881 ASSERT(!m_haveFiredLoadEvent);
882 m_haveFiredLoadEvent = true;
883 sendSVGLoadEventIfPossible();
887 bool SVGUseElement::resourceIsStillLoading()
889 if (m_resource && m_resource->isLoading())
894 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInstance)
896 for (SVGElementInstance* instance = targetElementInstance->firstChild(); instance; instance = instance->nextSibling()) {
897 if (SVGUseElement* use = instance->correspondingUseElement()) {
898 if (use->resourceIsStillLoading())
901 if (instance->hasChildren())
902 instanceTreeIsLoading(instance);
907 void SVGUseElement::finishParsingChildren()
909 SVGGraphicsElement::finishParsingChildren();
910 if (m_wasInsertedByParser) {
911 buildPendingResource();
912 m_wasInsertedByParser = false;
916 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
918 if (m_resource == resource)
922 m_resource->removeClient(this);
924 m_resource = resource;
926 m_resource->addClient(this);
929 void SVGUseElement::trace(Visitor* visitor)
931 visitor->trace(m_targetElementInstance);
932 SVGGraphicsElement::trace(visitor);