19ce8648d858061572141c813f75b0629455bc7c
[WebKit-https.git] / WebCore / svg / SVGUseElement.cpp
1 /*
2     Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4
5     This file is part of the KDE project
6
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16
17     You should have received a copy of the GNU Library General Public License
18     along with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20     Boston, MA 02110-1301, USA.
21 */
22
23 #include "config.h"
24
25 // Dump SVGElementInstance object tree - useful to debug instanceRoot problems
26 // #define DUMP_INSTANCE_TREE
27
28 // Dump the deep-expanded shadow tree (where the renderes are built from)
29 // #define DUMP_SHADOW_TREE
30
31 #if ENABLE(SVG)
32 #include "SVGUseElement.h"
33
34 #include "CSSStyleSelector.h"
35 #include "CString.h"
36 #include "Document.h"
37 #include "Event.h"
38 #include "HTMLNames.h"
39 #include "RenderSVGTransformableContainer.h"
40 #include "SVGElementInstance.h"
41 #include "SVGElementInstanceList.h"
42 #include "SVGGElement.h"
43 #include "SVGLength.h"
44 #include "SVGNames.h"
45 #include "SVGPreserveAspectRatio.h"
46 #include "SVGSVGElement.h"
47 #include "SVGSymbolElement.h"
48 #include "XLinkNames.h"
49 #include "XMLSerializer.h"
50 #include <wtf/OwnPtr.h>
51
52 namespace WebCore {
53
54 SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document* doc)
55     : SVGStyledTransformableElement(tagName, doc)
56     , SVGTests()
57     , SVGLangSpace()
58     , SVGExternalResourcesRequired()
59     , SVGURIReference()
60     , m_x(this, LengthModeWidth)
61     , m_y(this, LengthModeHeight)
62     , m_width(this, LengthModeWidth)
63     , m_height(this, LengthModeHeight)
64 {
65 }
66
67 SVGUseElement::~SVGUseElement()
68 {
69 }
70
71 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, X, x, SVGNames::xAttr.localName(), m_x)
72 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Y, y, SVGNames::yAttr.localName(), m_y)
73 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr.localName(), m_width)
74 ANIMATED_PROPERTY_DEFINITIONS(SVGUseElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr.localName(), m_height)
75
76 SVGElementInstance* SVGUseElement::instanceRoot() const
77 {
78     return m_targetElementInstance.get();
79 }
80
81 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
82 {
83     // FIXME: Implement me.
84     return 0;
85 }
86  
87 void SVGUseElement::parseMappedAttribute(MappedAttribute* attr)
88 {
89     if (attr->name() == SVGNames::xAttr)
90         setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
91     else if (attr->name() == SVGNames::yAttr)
92         setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
93     else if (attr->name() == SVGNames::widthAttr) {
94         setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
95         if (width().value() < 0.0)
96             document()->accessSVGExtensions()->reportError("A negative value for use attribute <width> is not allowed");
97     } else if (attr->name() == SVGNames::heightAttr) {
98         setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
99         if (height().value() < 0.0)
100             document()->accessSVGExtensions()->reportError("A negative value for use attribute <height> is not allowed");
101     } else {
102         if (SVGTests::parseMappedAttribute(attr))
103             return;
104         if (SVGLangSpace::parseMappedAttribute(attr))
105             return;
106         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
107             return;
108         if (SVGURIReference::parseMappedAttribute(attr))
109             return;
110         SVGStyledTransformableElement::parseMappedAttribute(attr);
111     }
112 }
113
114 void SVGUseElement::insertedIntoDocument()
115 {
116     SVGElement::insertedIntoDocument();
117
118     String id = SVGURIReference::getTarget(href());
119     Element* targetElement = document()->getElementById(id);
120     if (!targetElement) {
121         document()->accessSVGExtensions()->addPendingResource(id, this);
122         return;
123     }
124
125     buildPendingResource();
126 }
127
128 void SVGUseElement::removedFromDocument()
129 {
130     SVGElement::removedFromDocument();
131
132     m_targetElementInstance = 0;
133     m_shadowTreeRootElement = 0;
134 }
135
136 void SVGUseElement::attributeChanged(Attribute* attr, bool preserveDecls)
137 {
138     // Avoid calling SVGStyledElement::attributeChanged(), as it always calls notifyAttributeChange.
139     SVGElement::attributeChanged(attr, preserveDecls);
140
141     if (!attached())
142        return;
143
144     // Only update the tree if x/y/width/height or xlink:href changed.
145     if (attr->name() == SVGNames::xAttr || attr->name() == SVGNames::yAttr ||
146         attr->name() == SVGNames::widthAttr || attr->name() == SVGNames::heightAttr ||
147         attr->name().matches(XLinkNames::hrefAttr))
148         buildPendingResource();
149     else if (m_shadowTreeRootElement)
150         m_shadowTreeRootElement->setChanged();
151 }
152
153 void SVGUseElement::notifyAttributeChange() const
154 {
155     if (!attached())
156         return;
157
158     // NOTE: A lot of room for improvments here. This is too slow.
159     // It has to be done correctly, by implementing attributeChanged().
160     const_cast<SVGUseElement*>(this)->buildPendingResource();
161
162     if (m_shadowTreeRootElement)
163         m_shadowTreeRootElement->setChanged();
164 }
165
166 void SVGUseElement::recalcStyle(StyleChange change)
167 {
168     SVGStyledElement::recalcStyle(change);
169
170     // The shadow tree root element is NOT a direct child element of us.
171     // So we have to take care it receives style updates, manually.
172     if (!m_shadowTreeRootElement || !m_shadowTreeRootElement->attached())
173         return;
174
175     // Mimic Element::recalcStyle(). The main difference is that we don't call attach() on the
176     // shadow tree root element, but call attachShadowTree() here. Calling attach() will crash
177     // as the shadow tree root element has no (direct) parent node. Yes, shadow trees are tricky.
178     if (change >= Inherit || m_shadowTreeRootElement->changed()) {
179         RenderStyle* newStyle = document()->styleSelector()->styleForElement(m_shadowTreeRootElement.get());
180         StyleChange ch = m_shadowTreeRootElement->diff(m_shadowTreeRootElement->renderStyle(), newStyle);
181         if (ch == Detach) {
182             ASSERT(m_shadowTreeRootElement->attached());
183             m_shadowTreeRootElement->detach();
184             attachShadowTree();
185
186             // attach recalulates the style for all children. No need to do it twice.
187             m_shadowTreeRootElement->setChanged(NoStyleChange);
188             m_shadowTreeRootElement->setHasChangedChild(false);
189             newStyle->deref(document()->renderArena());
190             return;
191         }
192
193         newStyle->deref(document()->renderArena());
194     }
195
196     // Only change==Detach needs special treatment, for anything else recalcStyle() works.
197     m_shadowTreeRootElement->recalcStyle(change);
198 }
199
200 #ifdef DUMP_INSTANCE_TREE
201 void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
202 {
203     SVGElement* element = targetInstance->correspondingElement();
204     ASSERT(element);
205
206     String elementId = element->getIDAttribute();
207     String elementNodeName = element->nodeName();
208     String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
209     String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
210
211     for (unsigned int i = 0; i < depth; ++i)
212         text += "  ";
213
214     text += String::format("SVGElementInstance (parentNode=%s, firstChild=%s, correspondingElement=%s, id=%s)\n",
215                            parentNodeName.latin1().data(), firstChildNodeName.latin1().data(), elementNodeName.latin1().data(), elementId.latin1().data());
216  
217     depth++;
218
219     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
220         dumpInstanceTree(depth, text, instance);
221
222     depth--;
223 }
224 #endif
225
226 static bool isDisallowedElement(Node* element)
227 {
228     // <foreignObject> should never be contained in a <use> tree. Too dangerous side effects possible.
229     if (element->hasTagName(SVGNames::foreignObjectTag))
230         return true;
231
232     return false;
233 }
234
235 static bool subtreeContainsDisallowedElement(Node* start)
236 {
237     if (isDisallowedElement(start))
238         return true;
239
240     for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
241         if (subtreeContainsDisallowedElement(cur))
242             return true;
243     }
244
245     return false;
246 }
247
248 void SVGUseElement::buildPendingResource()
249 {
250     // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
251     // The will be expanded soon anyway - see expandUseElementsInShadowTree().
252     Node* parent = parentNode();
253     while (parent) {
254         if (parent->isShadowNode())
255             return;
256
257         parent = parent->parentNode();
258     }
259
260     String id = SVGURIReference::getTarget(href());
261     Element* targetElement = document()->getElementById(id); 
262     SVGElement* target = 0;
263     if (targetElement && targetElement->isSVGElement())
264         target = static_cast<SVGElement*>(targetElement);
265
266     // Do not allow self-referencing.
267     // 'target' may be null, if it's a non SVG namespaced element.
268     if (!target || target == this) {
269         m_targetElementInstance = 0;
270         m_shadowTreeRootElement = 0;
271         return;
272     }
273
274     // Why a seperated instance/shadow tree? SVG demands it:
275     // The instance tree is accesable from JavaScript, and has to
276     // expose a 1:1 copy of the referenced tree, whereas internally we need
277     // to alter the tree for correct "use-on-symbol", "use-on-svg" support.  
278  
279     // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
280     //
281     // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
282     // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
283     // is the SVGRectElement that corresponds to the referenced 'rect' element.
284     m_targetElementInstance = new SVGElementInstance(this, target);
285
286     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
287     bool foundProblem = false;
288     buildInstanceTree(target, m_targetElementInstance.get(), foundProblem);
289
290     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
291     // Non-appearing <use> content is easier to debug, then half-appearing content.
292     if (foundProblem) {
293         m_targetElementInstance = 0;
294         m_shadowTreeRootElement = 0;
295         return;
296     }
297
298     // Assure instance tree building was successfull
299     ASSERT(m_targetElementInstance);
300     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
301
302     // Setup shadow tree root node
303     m_shadowTreeRootElement = new SVGGElement(SVGNames::gTag, document());
304     m_shadowTreeRootElement->setInDocument();
305     m_shadowTreeRootElement->setShadowParentNode(this);
306
307     // Spec: An additional transformation translate(x,y) is appended to the end
308     // (i.e., right-side) of the transform attribute on the generated 'g', where x
309     // and y represent the values of the x and y attributes on the 'use' element. 
310     if (x().value() != 0.0 || y().value() != 0.0) {
311         String transformString = String::format("translate(%f, %f)", x().value(), y().value());
312         m_shadowTreeRootElement->setAttribute(SVGNames::transformAttr, transformString);
313     }
314
315     // Build shadow tree from instance tree
316     // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
317     buildShadowTree(target, m_targetElementInstance.get());
318
319 #if ENABLE(SVG) && ENABLE(SVG_USE)
320     // Expand all <use> elements in the shadow tree.
321     // Expand means: replace the actual <use> element by what it references.
322     expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
323
324     // Expand all <symbol> elements in the shadow tree.
325     // Expand means: replace the actual <symbol> element by the <svg> element.
326     expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
327
328 #endif
329
330     // Now that the shadow tree is completly expanded, we can associate
331     // shadow tree elements <-> instances in the instance tree.
332     associateInstancesWithShadowTreeElements(m_shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
333
334     // Eventually dump instance tree
335 #ifdef DUMP_INSTANCE_TREE
336     String text;
337     unsigned int depth = 0;
338
339     dumpInstanceTree(depth, text, m_targetElementInstance.get());
340     fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
341 #endif
342
343     // Eventually dump shadow tree
344 #ifdef DUMP_SHADOW_TREE
345     ExceptionCode ec = 0;
346     OwnPtr<XMLSerializer> serializer(new XMLSerializer());
347
348     String markup = serializer->serializeToString(m_shadowTreeRootElement.get(), ec);
349     ASSERT(ec == 0);
350
351     fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
352 #endif
353
354     // The DOM side is setup properly. Now we have to attach the root shadow
355     // tree element manually - using attach() won't work for "shadow nodes".
356     attachShadowTree();
357 }
358
359 RenderObject* SVGUseElement::createRenderer(RenderArena* arena, RenderStyle*)
360 {
361     return new (arena) RenderSVGTransformableContainer(this);
362 }
363
364 void SVGUseElement::attach()
365 {
366     SVGStyledTransformableElement::attach();
367
368     // If we're a pending resource, this doesn't have any effect.
369     attachShadowTree();
370 }
371
372 void SVGUseElement::detach()
373 {
374     SVGStyledTransformableElement::detach();
375
376     if (m_shadowTreeRootElement)
377         m_shadowTreeRootElement->detach();
378 }
379
380 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem)
381 {
382     ASSERT(target);
383     ASSERT(targetInstance);
384
385     // A general description from the SVG spec, describing what buildInstanceTree() actually does.
386     //
387     // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
388     // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
389     // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
390     // its correspondingElement that is an SVGRectElement object.
391
392     for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
393         SVGElement* element = 0;
394         if (node->isSVGElement())
395             element = static_cast<SVGElement*>(node);
396
397         // Skip any non-svg nodes or any disallowed element.
398         if (!element || isDisallowedElement(element))
399             continue;
400
401         // Create SVGElementInstance object, for both container/non-container nodes.
402         SVGElementInstance* instancePtr = new SVGElementInstance(this, element);
403
404         RefPtr<SVGElementInstance> instance = instancePtr;
405         targetInstance->appendChild(instance.release());
406
407         // Enter recursion, appending new instance tree nodes to the "instance" object.
408         if (element->hasChildNodes())
409             buildInstanceTree(element, instancePtr, foundProblem);
410
411         // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
412         // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
413         if (element->hasTagName(SVGNames::useTag))
414             handleDeepUseReferencing(element, instancePtr, foundProblem);
415     }
416
417     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
418     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
419     if (target->hasTagName(SVGNames::useTag))
420         handleDeepUseReferencing(target, targetInstance, foundProblem);
421 }
422
423 void SVGUseElement::handleDeepUseReferencing(SVGElement* use, SVGElementInstance* targetInstance, bool& foundProblem)
424 {
425     String id = SVGURIReference::getTarget(use->href());
426     Element* targetElement = document()->getElementById(id); 
427     SVGElement* target = 0;
428     if (targetElement && targetElement->isSVGElement())
429         target = static_cast<SVGElement*>(targetElement);
430
431     if (!target)
432         return;
433
434     // Cycle detection first!
435     foundProblem = (target == this);
436
437     // Shortcut for self-references
438     if (foundProblem)
439         return;
440
441     SVGElementInstance* instance = targetInstance->parentNode();
442     while (instance) {
443         SVGElement* element = instance->correspondingElement();
444
445         if (element->getIDAttribute() == id) {
446             foundProblem = true;
447             return;
448         }
449     
450         instance = instance->parentNode();
451     }
452
453     // Create an instance object, even if we're dealing with a cycle
454     SVGElementInstance* newInstance = new SVGElementInstance(this, target);
455     targetInstance->appendChild(newInstance);
456
457     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
458     buildInstanceTree(target, newInstance, foundProblem);
459 }
460
461 void SVGUseElement::alterShadowTreeForSVGTag(SVGElement* target)
462 {
463     String widthString = String::number(width().value());
464     String heightString = String::number(height().value());
465
466     if (hasAttribute(SVGNames::widthAttr))
467         target->setAttribute(SVGNames::widthAttr, widthString);
468
469     if (hasAttribute(SVGNames::heightAttr))
470         target->setAttribute(SVGNames::heightAttr, heightString);
471 }
472
473 void SVGUseElement::removeDisallowedElementsFromSubtree(Node* element)
474 {
475     ExceptionCode ec = 0;
476
477     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) {
478         if (isDisallowedElement(child.get())) {
479             ASSERT(child->parent());
480             child->parent()->removeChild(child.get(), ec);
481             ASSERT(ec == 0);
482
483             continue;
484         }
485
486         if (child->hasChildNodes())
487             removeDisallowedElementsFromSubtree(child.get());
488     }
489 }
490
491 void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
492 {
493     // For instance <use> on <foreignObject> (direct case).
494     if (isDisallowedElement(target))
495         return;
496
497     RefPtr<Node> newChild = targetInstance->correspondingElement()->cloneNode(true);
498
499     // We don't walk the target tree element-by-element, and clone each element,
500     // but instead use cloneNode(deep=true). This is an optimization for the common
501     // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
502     // Though if there are disallowed elements in the subtree, we have to remove them.
503     // For instance: <use> on <g> containing <foreignObject> (indirect case).
504     if (subtreeContainsDisallowedElement(newChild.get()))
505         removeDisallowedElementsFromSubtree(newChild.get());
506
507     SVGElement* newChildPtr = 0;
508     if (newChild->isSVGElement())
509         newChildPtr = static_cast<SVGElement*>(newChild.get());
510     ASSERT(newChildPtr);
511
512     ExceptionCode ec = 0;
513     m_shadowTreeRootElement->appendChild(newChild.release(), ec);
514     ASSERT(ec == 0);
515
516     // Handle use referencing <svg> special case
517     if (target->hasTagName(SVGNames::svgTag))
518         alterShadowTreeForSVGTag(newChildPtr);
519 }
520
521 #if ENABLE(SVG) && ENABLE(SVG_USE)
522 void SVGUseElement::expandUseElementsInShadowTree(Node* element)
523 {
524     // Why expand the <use> elements in the shadow tree here, and not just
525     // do this directly in buildShadowTree, if we encounter a <use> element?
526     //
527     // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
528     // contains <use> tags, we'd miss them. So once we're done with settin' up the
529     // actual shadow tree (after the special case modification for svg/symbol) we have
530     // to walk it completely and expand all <use> elements.
531     if (element->hasTagName(SVGNames::useTag)) {
532         SVGUseElement* use = static_cast<SVGUseElement*>(element);
533
534         String id = SVGURIReference::getTarget(use->href());
535         Element* targetElement = document()->getElementById(id); 
536         SVGElement* target = 0;
537         if (targetElement && targetElement->isSVGElement())
538             target = static_cast<SVGElement*>(targetElement);
539
540         // Don't ASSERT(target) here, it may be "pending", too.
541         if (target) {
542             // Setup sub-shadow tree root node
543             RefPtr<SVGElement> cloneParent = new SVGGElement(SVGNames::gTag, document());
544
545             // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
546             // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
547             transferUseAttributesToReplacedElement(use, cloneParent.get());
548
549             // Spec: An additional transformation translate(x,y) is appended to the end
550             // (i.e., right-side) of the transform attribute on the generated 'g', where x
551             // and y represent the values of the x and y attributes on the 'use' element.
552             if (use->x().value() != 0.0 || use->y().value() != 0.0) {
553                 if (!cloneParent->hasAttribute(SVGNames::transformAttr)) {
554                     String transformString = String::format("translate(%f, %f)", use->x().value(), use->y().value());
555                     cloneParent->setAttribute(SVGNames::transformAttr, transformString);
556                 } else {
557                     String transformString = String::format(" translate(%f, %f)", use->x().value(), use->y().value());
558                     const AtomicString& transformAttribute = cloneParent->getAttribute(SVGNames::transformAttr);
559                     cloneParent->setAttribute(SVGNames::transformAttr, transformAttribute + transformString); 
560                 }
561             }
562
563             ExceptionCode ec = 0;
564  
565             // For instance <use> on <foreignObject> (direct case).
566             if (isDisallowedElement(target)) {
567                 // We still have to setup the <use> replacment (<g>). Otherwhise
568                 // associateInstancesWithShadowTreeElements() makes wrong assumptions.
569                 // Replace <use> with referenced content.
570                 ASSERT(use->parentNode()); 
571                 use->parentNode()->replaceChild(cloneParent.release(), use, ec);
572                 ASSERT(ec == 0);
573                 return;
574             }
575
576             RefPtr<Node> newChild = target->cloneNode(true);
577
578             // We don't walk the target tree element-by-element, and clone each element,
579             // but instead use cloneNode(deep=true). This is an optimization for the common
580             // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
581             // Though if there are disallowed elements in the subtree, we have to remove them.
582             // For instance: <use> on <g> containing <foreignObject> (indirect case).
583             if (subtreeContainsDisallowedElement(newChild.get()))
584                 removeDisallowedElementsFromSubtree(newChild.get());
585
586             SVGElement* newChildPtr = 0;
587             if (newChild->isSVGElement())
588                 newChildPtr = static_cast<SVGElement*>(newChild.get());
589             ASSERT(newChildPtr);
590
591             cloneParent->appendChild(newChild.release(), ec);
592             ASSERT(ec == 0);
593
594             // Replace <use> with referenced content.
595             ASSERT(use->parentNode()); 
596             use->parentNode()->replaceChild(cloneParent.release(), use, ec);
597             ASSERT(ec == 0);
598
599             // Handle use referencing <svg> special case
600             if (target->hasTagName(SVGNames::svgTag))
601                 alterShadowTreeForSVGTag(newChildPtr);
602
603             // Immediately stop here, and restart expanding.
604             expandUseElementsInShadowTree(m_shadowTreeRootElement.get());
605             return;
606         }
607     }
608
609     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
610         expandUseElementsInShadowTree(child.get());
611 }
612
613 void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
614 {
615     if (element->hasTagName(SVGNames::symbolTag)) {
616         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
617         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
618         // always have explicit values for attributes width and height. If attributes width and/or
619         // height are provided on the 'use' element, then these attributes will be transferred to
620         // the generated 'svg'. If attributes width and/or height are not specified, the generated
621         // 'svg' element will use values of 100% for these attributes.
622         RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
623
624         // Transfer all attributes from <symbol> to the new <svg> element
625         *svgElement->attributes() = *element->attributes();
626
627         // Explicitly re-set width/height values
628         String widthString = String::number(width().value());
629         String heightString = String::number(height().value()); 
630
631         svgElement->setAttribute(SVGNames::widthAttr, hasAttribute(SVGNames::widthAttr) ? widthString : "100%");
632         svgElement->setAttribute(SVGNames::heightAttr, hasAttribute(SVGNames::heightAttr) ? heightString : "100%");
633
634         ExceptionCode ec = 0;
635
636         // Only clone symbol children, and add them to the new <svg> element    
637         for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
638             RefPtr<Node> newChild = child->cloneNode(true);
639             svgElement->appendChild(newChild.release(), ec);
640             ASSERT(ec == 0);
641         }
642     
643         // We don't walk the target tree element-by-element, and clone each element,
644         // but instead use cloneNode(deep=true). This is an optimization for the common
645         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
646         // Though if there are disallowed elements in the subtree, we have to remove them.
647         // For instance: <use> on <g> containing <foreignObject> (indirect case).
648         if (subtreeContainsDisallowedElement(svgElement.get()))
649             removeDisallowedElementsFromSubtree(svgElement.get());
650
651         // Replace <symbol> with <svg>.
652         ASSERT(element->parentNode()); 
653         element->parentNode()->replaceChild(svgElement.release(), element, ec);
654         ASSERT(ec == 0);
655
656         // Immediately stop here, and restart expanding.
657         expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get());
658         return;
659     }
660
661     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
662         expandSymbolElementsInShadowTree(child.get());
663 }
664
665 #endif
666     
667 void SVGUseElement::attachShadowTree()
668 {
669     if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || !document()->shouldCreateRenderers() || !attached() || !renderer())
670         return;
671
672     // Inspired by RenderTextControl::createSubtreeIfNeeded(). 
673     if (renderer()->canHaveChildren() && childShouldCreateRenderer(m_shadowTreeRootElement.get())) {
674         RenderStyle* style = m_shadowTreeRootElement->styleForRenderer(renderer());
675
676         if (m_shadowTreeRootElement->rendererIsNeeded(style)) {
677             m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style));
678             if (RenderObject* shadowRenderer = m_shadowTreeRootElement->renderer()) {
679                 shadowRenderer->setStyle(style);
680                 renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer());
681                 m_shadowTreeRootElement->setAttached();
682             }
683         }
684
685         style->deref(document()->renderArena());
686
687         // This will take care of attaching all shadow tree child nodes.
688         for (Node* child = m_shadowTreeRootElement->firstChild(); child; child = child->nextSibling())
689             child->attach();
690     }
691 }
692
693 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
694 {
695     if (!target || !targetInstance)
696         return;
697
698     SVGElement* originalElement = targetInstance->correspondingElement();
699
700     if (originalElement->hasTagName(SVGNames::useTag)) {
701 #if ENABLE(SVG) && ENABLE(SVG_USE)
702         // <use> gets replaced by <g>
703         ASSERT(target->nodeName() == SVGNames::gTag);
704 #else 
705         ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag);
706 #endif
707     } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
708         // <symbol> gets replaced by <svg>
709         ASSERT(target->nodeName() == SVGNames::svgTag);
710     } else
711         ASSERT(target->nodeName() == originalElement->nodeName());
712
713     SVGElement* element = 0;
714     if (target->isSVGElement())
715         element = static_cast<SVGElement*>(target);
716
717     ASSERT(!targetInstance->shadowTreeElement());
718     targetInstance->setShadowTreeElement(element);
719
720     Node* node = target->firstChild();
721     for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
722         // Skip any non-svg elements in shadow tree
723         while (node && !node->isSVGElement())
724            node = node->nextSibling();
725
726         associateInstancesWithShadowTreeElements(node, instance);
727         node = node->nextSibling();
728     }
729 }
730
731 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
732 {
733     return instanceForShadowTreeElement(element, m_targetElementInstance.get());
734 }
735
736 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
737 {
738     ASSERT(element);
739     ASSERT(instance);
740     ASSERT(instance->shadowTreeElement());
741
742     if (element == instance->shadowTreeElement())
743         return instance;
744
745     for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
746         SVGElementInstance* search = instanceForShadowTreeElement(element, current);
747         if (search)
748             return search;
749     }
750
751     return 0;
752 }
753
754 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
755 {
756     ASSERT(from);
757     ASSERT(to);
758
759     *to->attributes() = *from->attributes();
760
761     ExceptionCode ec = 0;
762
763     to->removeAttribute(SVGNames::xAttr, ec);
764     ASSERT(ec == 0);
765
766     to->removeAttribute(SVGNames::yAttr, ec);
767     ASSERT(ec == 0);
768
769     to->removeAttribute(SVGNames::widthAttr, ec);
770     ASSERT(ec == 0);
771
772     to->removeAttribute(SVGNames::heightAttr, ec);
773     ASSERT(ec == 0);
774
775     to->removeAttribute(XLinkNames::hrefAttr, ec);
776     ASSERT(ec == 0);
777 }
778
779 }
780
781 #endif // ENABLE(SVG)
782
783 // vim:ts=4:noet