Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / SVGUseElement.cpp
1 /*
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>
8  *
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.
13  *
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.
18  *
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.
23  */
24
25 #include "config.h"
26
27 #include "core/svg/SVGUseElement.h"
28
29 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
30 #include "core/XLinkNames.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/RenderSVGTransformableContainer.h"
39 #include "core/svg/SVGGElement.h"
40 #include "core/svg/SVGLengthContext.h"
41 #include "core/svg/SVGSVGElement.h"
42 #include "core/xml/parser/XMLDocumentParser.h"
43
44 namespace blink {
45
46 inline SVGUseElement::SVGUseElement(Document& document)
47     : SVGGraphicsElement(SVGNames::useTag, document)
48     , SVGURIReference(this)
49     , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
50     , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
51     , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths))
52     , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths))
53     , m_haveFiredLoadEvent(false)
54     , m_needsShadowTreeRecreation(false)
55     , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
56 {
57     ASSERT(hasCustomStyleCallbacks());
58
59     addToPropertyMap(m_x);
60     addToPropertyMap(m_y);
61     addToPropertyMap(m_width);
62     addToPropertyMap(m_height);
63 }
64
65 PassRefPtrWillBeRawPtr<SVGUseElement> SVGUseElement::create(Document& document)
66 {
67     // Always build a user agent #shadow-root for SVGUseElement.
68     RefPtrWillBeRawPtr<SVGUseElement> use = adoptRefWillBeNoop(new SVGUseElement(document));
69     use->ensureUserAgentShadowRoot();
70     return use.release();
71 }
72
73 SVGUseElement::~SVGUseElement()
74 {
75     setDocumentResource(0);
76 #if !ENABLE(OILPAN)
77     clearResourceReferences();
78 #endif
79 }
80
81 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
82 {
83     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
84     if (supportedAttributes.isEmpty()) {
85         SVGURIReference::addSupportedAttributes(supportedAttributes);
86         supportedAttributes.add(SVGNames::xAttr);
87         supportedAttributes.add(SVGNames::yAttr);
88         supportedAttributes.add(SVGNames::widthAttr);
89         supportedAttributes.add(SVGNames::heightAttr);
90     }
91     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
92 }
93
94 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
95 {
96     parseAttributeNew(name, value);
97 }
98
99 #if ENABLE(ASSERT)
100 static inline bool isWellFormedDocument(Document* document)
101 {
102     if (document->isXMLDocument())
103         return static_cast<XMLDocumentParser*>(document->parser())->wellFormed();
104     return true;
105 }
106 #endif
107
108 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* rootParent)
109 {
110     // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
111     SVGGraphicsElement::insertedInto(rootParent);
112     if (!rootParent->inDocument())
113         return InsertionDone;
114     ASSERT(!m_targetElementInstance || !isWellFormedDocument(&document()));
115     ASSERT(!hasPendingResources() || !isWellFormedDocument(&document()));
116     invalidateShadowTree();
117     if (!isStructurallyExternal())
118         sendSVGLoadEventIfPossibleAsynchronously();
119     return InsertionDone;
120 }
121
122 void SVGUseElement::removedFrom(ContainerNode* rootParent)
123 {
124     SVGGraphicsElement::removedFrom(rootParent);
125     if (rootParent->inDocument())
126         clearResourceReferences();
127 }
128
129 TreeScope* SVGUseElement::referencedScope() const
130 {
131     if (!isExternalURIReference(hrefString(), document()))
132         return &treeScope();
133     return externalDocument();
134 }
135
136 Document* SVGUseElement::externalDocument() const
137 {
138     if (m_resource && m_resource->isLoaded()) {
139         // Gracefully handle error condition.
140         if (m_resource->errorOccurred())
141             return 0;
142         ASSERT(m_resource->document());
143         return m_resource->document();
144     }
145     return 0;
146 }
147
148 void transferUseWidthAndHeightIfNeeded(const SVGUseElement& use, SVGElement* shadowElement, const SVGElement& originalElement)
149 {
150     DEFINE_STATIC_LOCAL(const AtomicString, hundredPercentString, ("100%", AtomicString::ConstructFromLiteral));
151     ASSERT(shadowElement);
152     if (isSVGSymbolElement(*shadowElement)) {
153         // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
154         // If attributes width and/or height are provided on the 'use' element, then these attributes
155         // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
156         // the generated 'svg' element will use values of 100% for these attributes.
157         shadowElement->setAttribute(SVGNames::widthAttr, use.width()->isSpecified() ? AtomicString(use.width()->currentValue()->valueAsString()) : hundredPercentString);
158         shadowElement->setAttribute(SVGNames::heightAttr, use.height()->isSpecified() ? AtomicString(use.height()->currentValue()->valueAsString()) : hundredPercentString);
159     } else if (isSVGSVGElement(*shadowElement)) {
160         // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
161         // values will override the corresponding attributes on the 'svg' in the generated tree.
162         if (use.width()->isSpecified())
163             shadowElement->setAttribute(SVGNames::widthAttr, AtomicString(use.width()->currentValue()->valueAsString()));
164         else
165             shadowElement->setAttribute(SVGNames::widthAttr, originalElement.getAttribute(SVGNames::widthAttr));
166         if (use.height()->isSpecified())
167             shadowElement->setAttribute(SVGNames::heightAttr, AtomicString(use.height()->currentValue()->valueAsString()));
168         else
169             shadowElement->setAttribute(SVGNames::heightAttr, originalElement.getAttribute(SVGNames::heightAttr));
170     }
171 }
172
173 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
174 {
175     if (!isSupportedAttribute(attrName)) {
176         SVGGraphicsElement::svgAttributeChanged(attrName);
177         return;
178     }
179
180     SVGElement::InvalidationGuard invalidationGuard(this);
181
182     RenderObject* renderer = this->renderer();
183     if (attrName == SVGNames::xAttr
184         || attrName == SVGNames::yAttr
185         || attrName == SVGNames::widthAttr
186         || attrName == SVGNames::heightAttr) {
187         updateRelativeLengthsInformation();
188         if (m_targetElementInstance) {
189             ASSERT(m_targetElementInstance->correspondingElement());
190             transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
191         }
192         if (renderer)
193             markForLayoutAndParentResourceInvalidation(renderer);
194         return;
195     }
196
197     if (SVGURIReference::isKnownAttribute(attrName)) {
198         bool isExternalReference = isExternalURIReference(hrefString(), document());
199         if (isExternalReference) {
200             KURL url = document().completeURL(hrefString());
201             if (url.hasFragmentIdentifier()) {
202                 FetchRequest request(ResourceRequest(url), localName());
203                 setDocumentResource(document().fetcher()->fetchSVGDocument(request));
204             }
205         } else {
206             setDocumentResource(0);
207         }
208
209         invalidateShadowTree();
210
211         return;
212     }
213
214     if (!renderer)
215         return;
216
217     ASSERT_NOT_REACHED();
218 }
219
220 static bool isDisallowedElement(Node* node)
221 {
222     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
223     // (i.e., "instanced") in the SVG document via a 'use' element."
224     // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
225     // Excluded are anything that is used by reference or that only make sense to appear once in a document.
226     // We must also allow the shadow roots of other use elements.
227     if (node->isShadowRoot() || node->isTextNode())
228         return false;
229
230     if (!node->isSVGElement())
231         return true;
232
233     Element* element = toElement(node);
234
235     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ());
236     if (allowedElementTags.isEmpty()) {
237         allowedElementTags.add(SVGNames::aTag);
238         allowedElementTags.add(SVGNames::circleTag);
239         allowedElementTags.add(SVGNames::descTag);
240         allowedElementTags.add(SVGNames::ellipseTag);
241         allowedElementTags.add(SVGNames::gTag);
242         allowedElementTags.add(SVGNames::imageTag);
243         allowedElementTags.add(SVGNames::lineTag);
244         allowedElementTags.add(SVGNames::metadataTag);
245         allowedElementTags.add(SVGNames::pathTag);
246         allowedElementTags.add(SVGNames::polygonTag);
247         allowedElementTags.add(SVGNames::polylineTag);
248         allowedElementTags.add(SVGNames::rectTag);
249         allowedElementTags.add(SVGNames::svgTag);
250         allowedElementTags.add(SVGNames::switchTag);
251         allowedElementTags.add(SVGNames::symbolTag);
252         allowedElementTags.add(SVGNames::textTag);
253         allowedElementTags.add(SVGNames::textPathTag);
254         allowedElementTags.add(SVGNames::titleTag);
255         allowedElementTags.add(SVGNames::tspanTag);
256         allowedElementTags.add(SVGNames::useTag);
257     }
258     return !allowedElementTags.contains<SVGAttributeHashTranslator>(element->tagQName());
259 }
260
261 static bool subtreeContainsDisallowedElement(Node* start)
262 {
263     if (isDisallowedElement(start))
264         return true;
265
266     for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
267         if (subtreeContainsDisallowedElement(cur))
268             return true;
269     }
270
271     return false;
272 }
273
274 void SVGUseElement::scheduleShadowTreeRecreation()
275 {
276     if (!referencedScope() || inUseShadowTree())
277         return;
278     m_needsShadowTreeRecreation = true;
279     document().scheduleUseShadowTreeUpdate(*this);
280 }
281
282 void SVGUseElement::clearResourceReferences()
283 {
284     if (m_targetElementInstance)
285         m_targetElementInstance = nullptr;
286
287     // FIXME: We should try to optimize this, to at least allow partial reclones.
288     if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
289         shadowTreeRootElement->removeChildren();
290
291     m_needsShadowTreeRecreation = false;
292     document().unscheduleUseShadowTreeUpdate(*this);
293
294     removeAllOutgoingReferences();
295 }
296
297 void SVGUseElement::buildPendingResource()
298 {
299     if (!referencedScope() || inUseShadowTree())
300         return;
301     clearResourceReferences();
302     if (!inDocument())
303         return;
304
305     AtomicString id;
306     Element* target = SVGURIReference::targetElementFromIRIString(hrefString(), treeScope(), &id, externalDocument());
307     if (!target || !target->inDocument()) {
308         // If we can't find the target of an external element, just give up.
309         // We can't observe if the target somewhen enters the external document, nor should we do it.
310         if (externalDocument())
311             return;
312         if (id.isEmpty())
313             return;
314
315         referencedScope()->document().accessSVGExtensions().addPendingResource(id, this);
316         ASSERT(hasPendingResources());
317         return;
318     }
319
320     if (target->isSVGElement()) {
321         buildShadowAndInstanceTree(toSVGElement(target));
322         invalidateDependentShadowTrees();
323     }
324
325     ASSERT(!m_needsShadowTreeRecreation);
326 }
327
328 static PassRefPtrWillBeRawPtr<Node> cloneNodeAndAssociate(Node& toClone)
329 {
330     RefPtrWillBeRawPtr<Node> clone = toClone.cloneNode(false);
331     if (!clone->isSVGElement())
332         return clone.release();
333
334     SVGElement& svgElement = toSVGElement(toClone);
335     ASSERT(!svgElement.correspondingElement());
336     toSVGElement(clone.get())->setCorrespondingElement(&svgElement);
337     if (EventTargetData* data = toClone.eventTargetData())
338         data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(clone.get());
339     TrackExceptionState exceptionState;
340     for (Node* node = toClone.firstChild(); node && !exceptionState.hadException(); node = node->nextSibling())
341         clone->appendChild(cloneNodeAndAssociate(*node), exceptionState);
342     return clone.release();
343 }
344
345 void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
346 {
347     ASSERT(!m_targetElementInstance);
348
349     // <use> creates a "user agent" shadow root. Do not build the shadow/instance tree for <use>
350     // elements living in a user agent shadow tree because they will get expanded in a second
351     // pass -- see expandUseElementsInShadowTree().
352     if (inUseShadowTree())
353         return;
354
355     // Do not allow self-referencing.
356     // 'target' may be null, if it's a non SVG namespaced element.
357     if (!target || target == this)
358         return;
359
360     // Set up root SVG element in shadow tree.
361     RefPtrWillBeRawPtr<Element> newChild = target->cloneElementWithoutChildren();
362     m_targetElementInstance = toSVGElement(newChild.get());
363     ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
364     shadowTreeRootElement->appendChild(newChild.release());
365
366     // Clone the target subtree into the shadow tree, not handling <use> and <symbol> yet.
367
368     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
369     // Non-appearing <use> content is easier to debug, then half-appearing content.
370     if (!buildShadowTree(target, m_targetElementInstance.get(), false)) {
371         clearResourceReferences();
372         return;
373     }
374
375     if (instanceTreeIsLoading(m_targetElementInstance.get()))
376         return;
377
378     // Assure shadow tree building was successfull
379     ASSERT(m_targetElementInstance);
380     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
381     ASSERT(m_targetElementInstance->correspondingElement() == target);
382
383     // Expand all <use> elements in the shadow tree.
384     // Expand means: replace the actual <use> element by what it references.
385     if (!expandUseElementsInShadowTree(m_targetElementInstance.get())) {
386         clearResourceReferences();
387         return;
388     }
389
390     // Expand all <symbol> elements in the shadow tree.
391     // Expand means: replace the actual <symbol> element by the <svg> element.
392     expandSymbolElementsInShadowTree(toSVGElement(shadowTreeRootElement->firstChild()));
393
394     m_targetElementInstance = toSVGElement(shadowTreeRootElement->firstChild());
395     transferUseWidthAndHeightIfNeeded(*this, m_targetElementInstance.get(), *m_targetElementInstance->correspondingElement());
396
397     ASSERT(m_targetElementInstance->parentNode() == shadowTreeRootElement);
398
399     // Update relative length information.
400     updateRelativeLengthsInformation();
401 }
402
403 RenderObject* SVGUseElement::createRenderer(RenderStyle*)
404 {
405     return new RenderSVGTransformableContainer(this);
406 }
407
408 static bool isDirectReference(const SVGElement& element)
409 {
410     return isSVGPathElement(element)
411         || isSVGRectElement(element)
412         || isSVGCircleElement(element)
413         || isSVGEllipseElement(element)
414         || isSVGPolygonElement(element)
415         || isSVGPolylineElement(element)
416         || isSVGTextElement(element);
417 }
418
419 void SVGUseElement::toClipPath(Path& path)
420 {
421     ASSERT(path.isEmpty());
422
423     Node* n = userAgentShadowRoot()->firstChild();
424     if (!n || !n->isSVGElement())
425         return;
426     SVGElement& element = toSVGElement(*n);
427
428     if (element.isSVGGraphicsElement()) {
429         if (!isDirectReference(element)) {
430             // Spec: Indirect references are an error (14.3.5)
431             document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>");
432         } else {
433             toSVGGraphicsElement(element).toClipPath(path);
434             // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
435             SVGLengthContext lengthContext(this);
436             path.translate(FloatSize(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)));
437             path.transform(calculateAnimatedLocalTransform());
438         }
439     }
440 }
441
442 RenderObject* SVGUseElement::rendererClipChild() const
443 {
444     if (Node* n = userAgentShadowRoot()->firstChild()) {
445         if (n->isSVGElement() && isDirectReference(toSVGElement(*n)))
446             return n->renderer();
447     }
448
449     return 0;
450 }
451
452 bool SVGUseElement::buildShadowTree(SVGElement* target, SVGElement* targetInstance, bool foundUse)
453 {
454     ASSERT(target);
455     ASSERT(targetInstance);
456
457     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
458     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
459     if (isSVGUseElement(*target)) {
460         // We only need to track first degree <use> dependencies. Indirect references are handled
461         // as the invalidation bubbles up the dependency chain.
462         if (!foundUse && !isStructurallyExternal()) {
463             addReferenceTo(target);
464             foundUse = true;
465         }
466     } else if (isDisallowedElement(target)) {
467         return false;
468     }
469
470     targetInstance->setCorrespondingElement(target);
471     if (EventTargetData* data = target->eventTargetData())
472         data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(targetInstance);
473
474     for (Node* child = target->firstChild(); child; child = child->nextSibling()) {
475         // Skip any disallowed element.
476         if (isDisallowedElement(child))
477             continue;
478
479         RefPtrWillBeRawPtr<Node> newChild = child->cloneNode(false);
480         targetInstance->appendChild(newChild.get());
481         if (newChild->isSVGElement()) {
482             // Enter recursion, appending new instance tree nodes to the "instance" object.
483             if (!buildShadowTree(toSVGElement(child), toSVGElement(newChild), foundUse))
484                 return false;
485         }
486     }
487     return true;
488 }
489
490 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* targetInstance, SVGElement*& newTarget)
491 {
492     ASSERT(referencedScope());
493     Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope());
494     newTarget = 0;
495     if (targetElement && targetElement->isSVGElement())
496         newTarget = toSVGElement(targetElement);
497
498     if (!newTarget)
499         return false;
500
501     // Shortcut for self-references
502     if (newTarget == this)
503         return true;
504
505     AtomicString targetId = newTarget->getIdAttribute();
506     ContainerNode* instance = targetInstance->parentNode();
507     while (instance && instance->isSVGElement()) {
508         SVGElement* element = toSVGElement(instance);
509         if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
510             return true;
511
512         instance = instance->parentNode();
513     }
514     return false;
515 }
516
517 static inline void removeDisallowedElementsFromSubtree(Element& subtree)
518 {
519     ASSERT(!subtree.inDocument());
520     Element* element = ElementTraversal::firstWithin(subtree);
521     while (element) {
522         if (isDisallowedElement(element)) {
523             Element* next = ElementTraversal::nextSkippingChildren(*element, &subtree);
524             // The subtree is not in document so this won't generate events that could mutate the tree.
525             element->parentNode()->removeChild(element);
526             element = next;
527         } else {
528             element = ElementTraversal::next(*element, &subtree);
529         }
530     }
531 }
532
533 bool SVGUseElement::expandUseElementsInShadowTree(SVGElement* element)
534 {
535     ASSERT(element);
536     // Why expand the <use> elements in the shadow tree here, and not just
537     // do this directly in buildShadowTree, if we encounter a <use> element?
538     //
539     // Short answer: Because we may miss to expand some elements. For example, if a <symbol>
540     // contains <use> tags, we'd miss them. So once we're done with setting up the
541     // actual shadow tree (after the special case modification for svg/symbol) we have
542     // to walk it completely and expand all <use> elements.
543     if (isSVGUseElement(*element)) {
544         SVGUseElement* use = toSVGUseElement(element);
545         ASSERT(!use->resourceIsStillLoading());
546
547         SVGElement* target = 0;
548         if (hasCycleUseReferencing(toSVGUseElement(use->correspondingElement()), use, target))
549             return false;
550
551         if (target && isDisallowedElement(target))
552             return false;
553         // Don't ASSERT(target) here, it may be "pending", too.
554         // Setup sub-shadow tree root node
555         RefPtrWillBeRawPtr<SVGGElement> cloneParent = SVGGElement::create(referencedScope()->document());
556         cloneParent->setCorrespondingElement(use->correspondingElement());
557
558         // Move already cloned elements to the new <g> element
559         for (Node* child = use->firstChild(); child; ) {
560             Node* nextChild = child->nextSibling();
561             cloneParent->appendChild(child);
562             child = nextChild;
563         }
564
565         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
566         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
567         transferUseAttributesToReplacedElement(use, cloneParent.get());
568
569         if (target) {
570             RefPtrWillBeRawPtr<Node> newChild = cloneNodeAndAssociate(*target);
571             ASSERT(newChild->isSVGElement());
572             transferUseWidthAndHeightIfNeeded(*use, toSVGElement(newChild.get()), *target);
573             cloneParent->appendChild(newChild.release());
574         }
575
576         // We don't walk the target tree element-by-element, and clone each element,
577         // but instead use cloneElementWithChildren(). This is an optimization for the common
578         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
579         // Though if there are disallowed elements in the subtree, we have to remove them.
580         // For instance: <use> on <g> containing <foreignObject> (indirect case).
581         if (subtreeContainsDisallowedElement(cloneParent.get()))
582             removeDisallowedElementsFromSubtree(*cloneParent);
583
584         RefPtrWillBeRawPtr<SVGElement> replacingElement(cloneParent.get());
585
586         // Replace <use> with referenced content.
587         ASSERT(use->parentNode());
588         use->parentNode()->replaceChild(cloneParent.release(), use);
589
590         // Expand the siblings because the *element* is replaced and we will
591         // lose the sibling chain when we are back from recursion.
592         element = replacingElement.get();
593         for (RefPtrWillBeRawPtr<SVGElement> sibling = Traversal<SVGElement>::nextSibling(*element); sibling; sibling = Traversal<SVGElement>::nextSibling(*sibling)) {
594             if (!expandUseElementsInShadowTree(sibling.get()))
595                 return false;
596         }
597     }
598
599     for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child)) {
600         if (!expandUseElementsInShadowTree(child.get()))
601             return false;
602     }
603     return true;
604 }
605
606 void SVGUseElement::expandSymbolElementsInShadowTree(SVGElement* element)
607 {
608     ASSERT(element);
609     if (isSVGSymbolElement(*element)) {
610         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
611         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
612         // always have explicit values for attributes width and height. If attributes width and/or
613         // height are provided on the 'use' element, then these attributes will be transferred to
614         // the generated 'svg'. If attributes width and/or height are not specified, the generated
615         // 'svg' element will use values of 100% for these attributes.
616         ASSERT(referencedScope());
617         RefPtrWillBeRawPtr<SVGSVGElement> svgElement = SVGSVGElement::create(referencedScope()->document());
618         // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
619         svgElement->cloneDataFromElement(*element);
620         svgElement->setCorrespondingElement(element->correspondingElement());
621
622         // Move already cloned elements to the new <svg> element
623         for (Node* child = element->firstChild(); child; ) {
624             Node* nextChild = child->nextSibling();
625             svgElement->appendChild(child);
626             child = nextChild;
627         }
628
629         // We don't walk the target tree element-by-element, and clone each element,
630         // but instead use cloneNode(deep=true). This is an optimization for the common
631         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
632         // Though if there are disallowed elements in the subtree, we have to remove them.
633         // For instance: <use> on <g> containing <foreignObject> (indirect case).
634         if (subtreeContainsDisallowedElement(svgElement.get()))
635             removeDisallowedElementsFromSubtree(*svgElement);
636
637         RefPtrWillBeRawPtr<SVGElement> replacingElement(svgElement.get());
638
639         // Replace <symbol> with <svg>.
640         ASSERT(element->parentNode());
641         element->parentNode()->replaceChild(svgElement.release(), element);
642
643         // Expand the siblings because the *element* is replaced and we will
644         // lose the sibling chain when we are back from recursion.
645         element = replacingElement.get();
646     }
647
648     for (RefPtrWillBeRawPtr<SVGElement> child = Traversal<SVGElement>::firstChild(*element); child; child = Traversal<SVGElement>::nextSibling(*child))
649         expandSymbolElementsInShadowTree(child.get());
650 }
651
652 void SVGUseElement::invalidateShadowTree()
653 {
654     if (!inActiveDocument() || m_needsShadowTreeRecreation)
655         return;
656     scheduleShadowTreeRecreation();
657     invalidateDependentShadowTrees();
658 }
659
660 void SVGUseElement::invalidateDependentShadowTrees()
661 {
662     // Recursively invalidate dependent <use> shadow trees
663     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = instancesForElement();
664     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
665     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
666         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
667             ASSERT(element->inDocument());
668             element->invalidateShadowTree();
669         }
670     }
671 }
672
673 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
674 {
675     ASSERT(from);
676     ASSERT(to);
677
678     to->cloneDataFromElement(*from);
679
680     to->removeAttribute(SVGNames::xAttr);
681     to->removeAttribute(SVGNames::yAttr);
682     to->removeAttribute(SVGNames::widthAttr);
683     to->removeAttribute(SVGNames::heightAttr);
684     to->removeAttribute(XLinkNames::hrefAttr);
685 }
686
687 bool SVGUseElement::selfHasRelativeLengths() const
688 {
689     if (m_x->currentValue()->isRelative()
690         || m_y->currentValue()->isRelative()
691         || m_width->currentValue()->isRelative()
692         || m_height->currentValue()->isRelative())
693         return true;
694
695     if (!m_targetElementInstance)
696         return false;
697
698     return m_targetElementInstance->hasRelativeLengths();
699 }
700
701 void SVGUseElement::notifyFinished(Resource* resource)
702 {
703     if (!inDocument())
704         return;
705
706     invalidateShadowTree();
707     if (resource->errorOccurred())
708         dispatchEvent(Event::create(EventTypeNames::error));
709     else if (!resource->wasCanceled()) {
710         if (m_haveFiredLoadEvent)
711             return;
712         if (!isStructurallyExternal())
713             return;
714         ASSERT(!m_haveFiredLoadEvent);
715         m_haveFiredLoadEvent = true;
716         sendSVGLoadEventIfPossibleAsynchronously();
717     }
718 }
719
720 bool SVGUseElement::resourceIsStillLoading()
721 {
722     if (m_resource && m_resource->isLoading())
723         return true;
724     return false;
725 }
726
727 bool SVGUseElement::instanceTreeIsLoading(SVGElement* targetInstance)
728 {
729     for (SVGElement* element = Traversal<SVGElement>::firstChild(*targetInstance); element; element = Traversal<SVGElement>::nextSibling(*element)) {
730         if (SVGUseElement* use = element->correspondingUseElement()) {
731             if (use->resourceIsStillLoading())
732                 return true;
733         }
734         if (element->hasChildren() && instanceTreeIsLoading(element))
735             return true;
736     }
737     return false;
738 }
739
740 void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
741 {
742     if (m_resource == resource)
743         return;
744
745     if (m_resource)
746         m_resource->removeClient(this);
747
748     m_resource = resource;
749     if (m_resource)
750         m_resource->addClient(this);
751 }
752
753 void SVGUseElement::trace(Visitor* visitor)
754 {
755     visitor->trace(m_targetElementInstance);
756     SVGGraphicsElement::trace(visitor);
757 }
758
759 }