Backport crash fix by Huzaifa Sidhpurwala <huzaifas@redhat.com>
[webkitgtk-obsolete:stable.git] / WebCore / svg / SVGUseElement.cpp
1 /*
2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4     Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5
6     This library is free software; you can redistribute it and/or
7     modify it under the terms of the GNU Library General Public
8     License as published by the Free Software Foundation; either
9     version 2 of the License, or (at your option) any later version.
10
11     This library is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Library General Public License for more details.
15
16     You should have received a copy of the GNU Library General Public License
17     along with this library; see the file COPYING.LIB.  If not, write to
18     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19     Boston, MA 02110-1301, USA.
20 */
21
22 #include "config.h"
23
24 #if ENABLE(SVG)
25 #include "SVGUseElement.h"
26
27 #include "CSSStyleSelector.h"
28 #include "CString.h"
29 #include "Document.h"
30 #include "Event.h"
31 #include "EventListener.h"
32 #include "HTMLNames.h"
33 #include "MappedAttribute.h"
34 #include "NodeRenderStyle.h"
35 #include "RegisteredEventListener.h"
36 #include "RenderSVGShadowTreeRootContainer.h"
37 #include "SVGElementInstance.h"
38 #include "SVGElementInstanceList.h"
39 #include "SVGGElement.h"
40 #include "SVGLength.h"
41 #include "SVGPreserveAspectRatio.h"
42 #include "SVGShadowTreeElements.h"
43 #include "SVGSMILElement.h"
44 #include "SVGSVGElement.h"
45 #include "SVGSymbolElement.h"
46 #include "XLinkNames.h"
47 #include "XMLSerializer.h"
48
49 // Dump SVGElementInstance object tree - useful to debug instanceRoot problems
50 // #define DUMP_INSTANCE_TREE
51
52 // Dump the deep-expanded shadow tree (where the renderers are built from)
53 // #define DUMP_SHADOW_TREE
54
55 namespace WebCore {
56
57 SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document* doc)
58     : SVGStyledTransformableElement(tagName, doc)
59     , SVGTests()
60     , SVGLangSpace()
61     , SVGExternalResourcesRequired()
62     , SVGURIReference()
63     , m_x(LengthModeWidth)
64     , m_y(LengthModeHeight)
65     , m_width(LengthModeWidth)
66     , m_height(LengthModeHeight)
67     , m_isPendingResource(false)
68     , m_needsShadowTreeRecreation(false)
69 {
70 }
71
72 SVGUseElement::~SVGUseElement()
73 {
74 }
75
76 SVGElementInstance* SVGUseElement::instanceRoot() const
77 {
78     // If there is no element instance tree, force immediate SVGElementInstance tree
79     // creation by asking the document to invoke our recalcStyle function - as we can't
80     // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
81     // object right after creating the element on-the-fly
82     if (!m_targetElementInstance)
83         document()->updateLayoutIgnorePendingStylesheets();
84
85     return m_targetElementInstance.get();
86 }
87
88 SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
89 {
90     // FIXME: Implement me.
91     return 0;
92 }
93  
94 void SVGUseElement::parseMappedAttribute(MappedAttribute* attr)
95 {
96     if (attr->name() == SVGNames::xAttr)
97         setXBaseValue(SVGLength(LengthModeWidth, attr->value()));
98     else if (attr->name() == SVGNames::yAttr)
99         setYBaseValue(SVGLength(LengthModeHeight, attr->value()));
100     else if (attr->name() == SVGNames::widthAttr) {
101         setWidthBaseValue(SVGLength(LengthModeWidth, attr->value()));
102         if (widthBaseValue().value(this) < 0.0)
103             document()->accessSVGExtensions()->reportError("A negative value for use attribute <width> is not allowed");
104     } else if (attr->name() == SVGNames::heightAttr) {
105         setHeightBaseValue(SVGLength(LengthModeHeight, attr->value()));
106         if (heightBaseValue().value(this) < 0.0)
107             document()->accessSVGExtensions()->reportError("A negative value for use attribute <height> is not allowed");
108     } else {
109         if (SVGTests::parseMappedAttribute(attr))
110             return;
111         if (SVGLangSpace::parseMappedAttribute(attr))
112             return;
113         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
114             return;
115         if (SVGURIReference::parseMappedAttribute(attr))
116             return;
117         SVGStyledTransformableElement::parseMappedAttribute(attr);
118     }
119 }
120
121 void SVGUseElement::insertedIntoDocument()
122 {
123     // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
124     SVGElement::insertedIntoDocument();
125     ASSERT(!m_targetElementInstance);
126     ASSERT(!m_isPendingResource);
127 }
128
129 void SVGUseElement::removedFromDocument()
130 {
131     m_targetElementInstance = 0;
132     SVGElement::removedFromDocument();
133 }
134
135 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
136 {
137     SVGStyledTransformableElement::svgAttributeChanged(attrName);
138
139     if (!renderer())
140         return;
141
142     if (SVGURIReference::isKnownAttribute(attrName)) {
143         if (m_isPendingResource) {
144             document()->accessSVGExtensions()->removePendingResource(m_resourceId);
145             m_resourceId = String();
146             m_isPendingResource = false;
147         }
148
149         invalidateShadowTree();
150         return;
151     }
152
153     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) {
154         updateContainerOffsets();
155         return;
156     }
157
158     if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
159         updateContainerSizes();
160         return;
161     }
162
163     // Be very careful here, if svgAttributeChanged() has been called because a SVG CSS property changed, we do NOT want to reclone the tree!
164     if (SVGStyledElement::isKnownAttribute(attrName)) {
165         setNeedsStyleRecalc();
166         return;
167     }
168
169     if (SVGTests::isKnownAttribute(attrName)
170         || SVGLangSpace::isKnownAttribute(attrName)
171         || SVGExternalResourcesRequired::isKnownAttribute(attrName)
172         || SVGStyledTransformableElement::isKnownAttribute(attrName)) {
173         invalidateShadowTree();
174     }
175 }
176
177 void SVGUseElement::synchronizeProperty(const QualifiedName& attrName)
178 {
179     SVGStyledTransformableElement::synchronizeProperty(attrName);
180
181     if (attrName == anyQName()) {
182         synchronizeX();
183         synchronizeY();
184         synchronizeWidth();
185         synchronizeHeight();
186         synchronizeExternalResourcesRequired();
187         synchronizeHref();
188         return;
189     }
190
191     if (attrName == SVGNames::xAttr)
192         synchronizeX();
193     else if (attrName == SVGNames::yAttr)
194         synchronizeY();
195     else if (attrName == SVGNames::widthAttr)
196         synchronizeWidth();
197     else if (attrName == SVGNames::heightAttr)
198         synchronizeHeight();
199     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
200         synchronizeExternalResourcesRequired();
201     else if (SVGURIReference::isKnownAttribute(attrName))
202         synchronizeHref();
203 }
204
205 static void updateContainerSize(SVGUseElement* useElement, SVGElementInstance* targetInstance)
206 {
207     // Depth-first used to write the method in early exit style, no particular other reason.
208     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
209         updateContainerSize(useElement, instance);
210
211     SVGElement* correspondingElement = targetInstance->correspondingElement();
212     ASSERT(correspondingElement);
213
214     bool isSymbolTag = correspondingElement->hasTagName(SVGNames::symbolTag);
215     if (!correspondingElement->hasTagName(SVGNames::svgTag) && !isSymbolTag)
216         return;
217
218     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
219     ASSERT(shadowTreeElement);
220     ASSERT(shadowTreeElement->hasTagName(SVGNames::svgTag));
221
222     // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
223     // If attributes width and/or height are provided on the 'use' element, then these attributes
224     // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
225     // the generated 'svg' element will use values of 100% for these attributes.
226     
227     // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
228     // values will override the corresponding attributes on the 'svg' in the generated tree.
229
230     if (useElement->hasAttribute(SVGNames::widthAttr))
231         shadowTreeElement->setAttribute(SVGNames::widthAttr, useElement->getAttribute(SVGNames::widthAttr));
232     else if (isSymbolTag && shadowTreeElement->hasAttribute(SVGNames::widthAttr))
233         shadowTreeElement->setAttribute(SVGNames::widthAttr, "100%");
234
235     if (useElement->hasAttribute(SVGNames::heightAttr))
236         shadowTreeElement->setAttribute(SVGNames::heightAttr, useElement->getAttribute(SVGNames::heightAttr));
237     else if (isSymbolTag && shadowTreeElement->hasAttribute(SVGNames::heightAttr))
238         shadowTreeElement->setAttribute(SVGNames::heightAttr, "100%");
239 }   
240
241 void SVGUseElement::updateContainerSizes()
242 {
243     if (!m_targetElementInstance)
244         return;
245
246     // Update whole subtree, scanning for shadow container elements, that correspond to <svg>/<symbol> tags
247     updateContainerSize(this, m_targetElementInstance.get());
248
249     if (renderer())
250         renderer()->setNeedsLayout(true);
251 }
252
253 static void updateContainerOffset(SVGElementInstance* targetInstance)
254 {
255     // Depth-first used to write the method in early exit style, no particular other reason.
256     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
257         updateContainerOffset(instance);
258
259     SVGElement* correspondingElement = targetInstance->correspondingElement();
260     ASSERT(correspondingElement);
261
262     if (!correspondingElement->hasTagName(SVGNames::useTag))
263         return;
264
265     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
266     ASSERT(shadowTreeElement);
267     ASSERT(shadowTreeElement->hasTagName(SVGNames::gTag));
268
269     if (!static_cast<SVGGElement*>(shadowTreeElement)->isShadowTreeContainerElement())
270         return;
271
272     // Spec: An additional transformation translate(x,y) is appended to the end
273     // (i.e., right-side) of the transform attribute on the generated 'g', where x
274     // and y represent the values of the x and y attributes on the 'use' element. 
275     SVGUseElement* useElement = static_cast<SVGUseElement*>(correspondingElement);
276     SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(shadowTreeElement);
277     containerElement->setContainerOffset(useElement->x(), useElement->y());
278 }
279
280 void SVGUseElement::updateContainerOffsets()
281 {
282     if (!m_targetElementInstance)
283         return;
284
285     // Update root container offset (not reachable through instance tree)
286     SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement();
287     ASSERT(shadowRoot);
288
289     Node* parentNode = shadowRoot->parentNode();
290     ASSERT(parentNode);
291     ASSERT(parentNode->isSVGElement());
292     ASSERT(parentNode->hasTagName(SVGNames::gTag));
293     ASSERT(static_cast<SVGGElement*>(parentNode)->isShadowTreeContainerElement());
294
295     SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(parentNode);
296     containerElement->setContainerOffset(x(), y());
297
298     // Update whole subtree, scanning for shadow container elements, marking a cloned use subtree
299     updateContainerOffset(m_targetElementInstance.get());
300
301     if (renderer())
302         renderer()->setNeedsLayout(true);
303 }
304
305 void SVGUseElement::recalcStyle(StyleChange change)
306 {
307     // Eventually mark shadow root element needing style recalc
308     if (needsStyleRecalc() && m_targetElementInstance) {
309         if (SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement())
310             shadowRoot->setNeedsStyleRecalc();
311     }
312
313     SVGStyledTransformableElement::recalcStyle(change);
314
315     bool needsStyleUpdate = !m_needsShadowTreeRecreation;
316     if (m_needsShadowTreeRecreation) {
317         static_cast<RenderSVGShadowTreeRootContainer*>(renderer())->markShadowTreeForRecreation();
318         m_needsShadowTreeRecreation = false;
319     }
320
321     RenderSVGShadowTreeRootContainer* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer());
322     if (!shadowRoot)
323         return;
324
325     shadowRoot->updateFromElement();
326
327     if (!needsStyleUpdate)
328         return;
329
330     shadowRoot->updateStyle(change);
331 }
332
333 #ifdef DUMP_INSTANCE_TREE
334 void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
335 {
336     SVGElement* element = targetInstance->correspondingElement();
337     ASSERT(element);
338
339     SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
340     ASSERT(shadowTreeElement);
341
342     String elementId = element->getIDAttribute();
343     String elementNodeName = element->nodeName();
344     String shadowTreeElementNodeName = shadowTreeElement->nodeName();
345     String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
346     String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
347
348     for (unsigned int i = 0; i < depth; ++i)
349         text += "  ";
350
351     text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n",
352                            targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(),
353                            elementNodeName.latin1().data(), element, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data());
354
355     for (unsigned int i = 0; i < depth; ++i)
356         text += "  ";
357
358     const HashSet<SVGElementInstance*>& elementInstances = element->instancesForElement();
359     text += String::format("Corresponding element is associated with %i instance(s):\n", elementInstances.size());
360
361     const HashSet<SVGElementInstance*>::const_iterator end = elementInstances.end();
362     for (HashSet<SVGElementInstance*>::const_iterator it = elementInstances.begin(); it != end; ++it) {
363         for (unsigned int i = 0; i < depth; ++i)
364             text += "  ";
365
366         text += String::format(" -> SVGElementInstance this=%p, (refCount: %i, shadowTreeElement in document? %i)\n",
367                                *it, (*it)->refCount(), (*it)->shadowTreeElement()->inDocument());
368     }
369
370     ++depth;
371
372     for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
373         dumpInstanceTree(depth, text, instance);
374
375     --depth;
376 }
377 #endif
378
379 static bool isDisallowedElement(Node* element)
380 {
381 #if ENABLE(SVG_FOREIGN_OBJECT)
382     // <foreignObject> should never be contained in a <use> tree. Too dangerous side effects possible.
383     if (element->hasTagName(SVGNames::foreignObjectTag))
384         return true;
385 #endif
386 #if ENABLE(SVG_ANIMATION)
387     if (SVGSMILElement::isSMILElement(element))
388         return true;
389 #endif
390
391     return false;
392 }
393
394 static bool subtreeContainsDisallowedElement(Node* start)
395 {
396     if (isDisallowedElement(start))
397         return true;
398
399     for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
400         if (subtreeContainsDisallowedElement(cur))
401             return true;
402     }
403
404     return false;
405 }
406
407 void SVGUseElement::buildPendingResource()
408 {
409     // If we're called the first time (during shadow tree root creation from RenderSVGShadowTreeRootContainer)
410     // we either determine that our target is available or not - then we add ourselves to the pending resource list
411     // Once the pending resource appears, it will call buildPendingResource(), so we're called a second time.
412     String id = SVGURIReference::getTarget(href());
413     Element* targetElement = document()->getElementById(id);
414     ASSERT(!m_targetElementInstance);
415
416     if (!targetElement) {
417         if (m_isPendingResource || id.isEmpty())
418             return;
419
420         m_isPendingResource = true;
421         m_resourceId = id;
422         document()->accessSVGExtensions()->addPendingResource(id, this);
423         return;
424     }
425
426     if (m_isPendingResource) {
427         ASSERT(!m_targetElementInstance);
428         m_isPendingResource = false;    
429         invalidateShadowTree();
430     }
431 }
432
433 void SVGUseElement::buildShadowAndInstanceTree(SVGShadowTreeRootElement* shadowRoot)
434 {
435     String id = SVGURIReference::getTarget(href());
436     Element* targetElement = document()->getElementById(id);
437     if (!targetElement) {
438         // The only time we should get here is when the use element has not been
439         // given a resource to target.
440         ASSERT(m_resourceId.isEmpty());
441         return;
442     }
443
444     // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
445     // The will be expanded soon anyway - see expandUseElementsInShadowTree().
446     Node* parent = parentNode();
447     while (parent) {
448         if (parent->isShadowNode())
449             return;
450
451         parent = parent->parentNode();
452     }
453  
454     SVGElement* target = 0;
455     if (targetElement && targetElement->isSVGElement())
456         target = static_cast<SVGElement*>(targetElement);
457
458     if (m_targetElementInstance)
459         m_targetElementInstance = 0;
460
461     // Do not allow self-referencing.
462     // 'target' may be null, if it's a non SVG namespaced element.
463     if (!target || target == this)
464         return;
465
466     // Why a seperated instance/shadow tree? SVG demands it:
467     // The instance tree is accesable from JavaScript, and has to
468     // expose a 1:1 copy of the referenced tree, whereas internally we need
469     // to alter the tree for correct "use-on-symbol", "use-on-svg" support.  
470  
471     // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
472     //
473     // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
474     // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
475     // is the SVGRectElement that corresponds to the referenced 'rect' element.
476     m_targetElementInstance = SVGElementInstance::create(this, target);
477
478     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
479     bool foundProblem = false;
480     buildInstanceTree(target, m_targetElementInstance.get(), foundProblem);
481
482     // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
483     // Non-appearing <use> content is easier to debug, then half-appearing content.
484     if (foundProblem) {
485         m_targetElementInstance = 0;
486         return;
487     }
488
489     // Assure instance tree building was successfull
490     ASSERT(m_targetElementInstance);
491     ASSERT(!m_targetElementInstance->shadowTreeElement());
492     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
493     ASSERT(m_targetElementInstance->correspondingElement() == target);
494
495     // Build shadow tree from instance tree
496     // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
497     buildShadowTree(shadowRoot, target, m_targetElementInstance.get());
498
499 #if ENABLE(SVG) && ENABLE(SVG_USE)
500     // Expand all <use> elements in the shadow tree.
501     // Expand means: replace the actual <use> element by what it references.
502     expandUseElementsInShadowTree(shadowRoot, shadowRoot);
503
504     // Expand all <symbol> elements in the shadow tree.
505     // Expand means: replace the actual <symbol> element by the <svg> element.
506     expandSymbolElementsInShadowTree(shadowRoot, shadowRoot);
507 #endif
508
509     // Now that the shadow tree is completly expanded, we can associate
510     // shadow tree elements <-> instances in the instance tree.
511     associateInstancesWithShadowTreeElements(shadowRoot->firstChild(), m_targetElementInstance.get());
512
513     // If no shadow tree element is present, this means that the reference root
514     // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
515     // Do NOT leave an inconsistent instance tree around, instead destruct it.
516     if (!m_targetElementInstance->shadowTreeElement()) {
517         shadowRoot->removeAllChildren();
518         m_targetElementInstance = 0;
519         return;
520     }
521
522     // Consistency checks - this is assumed in updateContainerOffset().
523     ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowRoot);
524
525     // Eventually dump instance tree
526 #ifdef DUMP_INSTANCE_TREE
527     String text;
528     unsigned int depth = 0;
529
530     dumpInstanceTree(depth, text, m_targetElementInstance.get());
531     fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
532 #endif
533
534     // Eventually dump shadow tree
535 #ifdef DUMP_SHADOW_TREE
536     ExceptionCode ec = 0;
537
538     PassRefPtr<XMLSerializer> serializer = XMLSerializer::create();
539
540     String markup = serializer->serializeToString(shadowRoot, ec);
541     ASSERT(!ec);
542
543     fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
544 #endif
545
546     // Transfer event listeners assigned to the referenced element to our shadow tree elements.
547     transferEventListenersToShadowTree(m_targetElementInstance.get());
548
549     // Update container offset/size
550     updateContainerOffsets();
551     updateContainerSizes();
552 }
553
554 RenderObject* SVGUseElement::createRenderer(RenderArena* arena, RenderStyle*)
555 {
556     return new (arena) RenderSVGShadowTreeRootContainer(this);
557 }
558
559 static void updateFromElementCallback(Node* node)
560 {
561     if (RenderObject* renderer = node->renderer())
562         renderer->updateFromElement();
563 }
564
565 void SVGUseElement::attach()
566 {
567     SVGStyledTransformableElement::attach();
568
569     if (renderer())
570         queuePostAttachCallback(updateFromElementCallback, this);
571 }
572
573 void SVGUseElement::detach()
574 {
575     m_targetElementInstance = 0;
576     SVGStyledTransformableElement::detach();
577 }
578
579 static bool isDirectReference(Node* n)
580 {
581     return n->hasTagName(SVGNames::pathTag) ||
582            n->hasTagName(SVGNames::rectTag) ||
583            n->hasTagName(SVGNames::circleTag) ||
584            n->hasTagName(SVGNames::ellipseTag) ||
585            n->hasTagName(SVGNames::polygonTag) ||
586            n->hasTagName(SVGNames::polylineTag) ||
587            n->hasTagName(SVGNames::textTag);
588 }
589
590 Path SVGUseElement::toClipPath() const
591 {
592     Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
593     if (!n)
594         return Path();
595
596     if (n->isSVGElement() && static_cast<SVGElement*>(n)->isStyledTransformable()) {
597         if (!isDirectReference(n))
598             // Spec: Indirect references are an error (14.3.5)
599             document()->accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>");
600         else {
601             Path clipPath = static_cast<SVGStyledTransformableElement*>(n)->toClipPath();
602             clipPath.translate(FloatSize(x().value(this), y().value(this)));
603             clipPath.transform(animatedLocalTransform());
604             return clipPath;
605         }
606     }
607
608     return Path();
609 }
610
611 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem)
612 {
613     ASSERT(target);
614     ASSERT(targetInstance);
615
616     // A general description from the SVG spec, describing what buildInstanceTree() actually does.
617     //
618     // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
619     // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
620     // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
621     // its correspondingElement that is an SVGRectElement object.
622
623     for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
624         SVGElement* element = 0;
625         if (node->isSVGElement())
626             element = static_cast<SVGElement*>(node);
627
628         // Skip any non-svg nodes or any disallowed element.
629         if (!element || isDisallowedElement(element))
630             continue;
631
632         // Create SVGElementInstance object, for both container/non-container nodes.
633         RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, element);
634         SVGElementInstance* instancePtr = instance.get();
635         targetInstance->appendChild(instance.release());
636
637         // Enter recursion, appending new instance tree nodes to the "instance" object.
638         buildInstanceTree(element, instancePtr, foundProblem);
639     }
640
641     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
642     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
643     if (target->hasTagName(SVGNames::useTag))
644         handleDeepUseReferencing(static_cast<SVGUseElement*>(target), targetInstance, foundProblem);
645 }
646
647 void SVGUseElement::handleDeepUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, bool& foundProblem)
648 {
649     String id = SVGURIReference::getTarget(use->href());
650     Element* targetElement = document()->getElementById(id); 
651     SVGElement* target = 0;
652     if (targetElement && targetElement->isSVGElement())
653         target = static_cast<SVGElement*>(targetElement);
654
655     if (!target)
656         return;
657
658     // Cycle detection first!
659     foundProblem = (target == this);
660
661     // Shortcut for self-references
662     if (foundProblem)
663         return;
664
665     SVGElementInstance* instance = targetInstance->parentNode();
666     while (instance) {
667         SVGElement* element = instance->correspondingElement();
668
669         if (element->getIDAttribute() == id) {
670             foundProblem = true;
671             return;
672         }
673     
674         instance = instance->parentNode();
675     }
676
677     // Create an instance object, even if we're dealing with a cycle
678     RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, target);
679     SVGElementInstance* newInstancePtr = newInstance.get();
680     targetInstance->appendChild(newInstance.release());
681
682     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
683     buildInstanceTree(target, newInstancePtr, foundProblem);
684 }
685
686 void SVGUseElement::removeDisallowedElementsFromSubtree(Node* subtree)
687 {
688     ASSERT(!subtree->inDocument());
689     ExceptionCode ec;
690     Node* node = subtree->firstChild();
691     while (node) {
692         if (isDisallowedElement(node)) {
693             Node* next = node->traverseNextSibling(subtree);
694             // The subtree is not in document so this won't generate events that could mutate the tree.
695             node->parent()->removeChild(node, ec);
696             node = next;
697         } else
698             node = node->traverseNextNode(subtree);
699     }
700 }
701
702 void SVGUseElement::buildShadowTree(SVGShadowTreeRootElement* shadowRoot, SVGElement* target, SVGElementInstance* targetInstance)
703 {
704     // For instance <use> on <foreignObject> (direct case).
705     if (isDisallowedElement(target))
706         return;
707
708     RefPtr<Element> newChild = targetInstance->correspondingElement()->cloneElementWithChildren();
709
710     // We don't walk the target tree element-by-element, and clone each element,
711     // but instead use cloneElementWithChildren(). This is an optimization for the common
712     // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
713     // Though if there are disallowed elements in the subtree, we have to remove them.
714     // For instance: <use> on <g> containing <foreignObject> (indirect case).
715     if (subtreeContainsDisallowedElement(newChild.get()))
716         removeDisallowedElementsFromSubtree(newChild.get());
717
718     SVGElement* newChildPtr = 0;
719     if (newChild->isSVGElement())
720         newChildPtr = static_cast<SVGElement*>(newChild.get());
721     ASSERT(newChildPtr);
722
723     ExceptionCode ec = 0;
724     shadowRoot->appendChild(newChild.release(), ec);
725     ASSERT(!ec);
726 }
727
728 #if ENABLE(SVG) && ENABLE(SVG_USE)
729 void SVGUseElement::expandUseElementsInShadowTree(SVGShadowTreeRootElement* shadowRoot, Node* element)
730 {
731     // Why expand the <use> elements in the shadow tree here, and not just
732     // do this directly in buildShadowTree, if we encounter a <use> element?
733     //
734     // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
735     // contains <use> tags, we'd miss them. So once we're done with settin' up the
736     // actual shadow tree (after the special case modification for svg/symbol) we have
737     // to walk it completely and expand all <use> elements.
738     if (element->hasTagName(SVGNames::useTag)) {
739         SVGUseElement* use = static_cast<SVGUseElement*>(element);
740
741         String id = SVGURIReference::getTarget(use->href());
742         Element* targetElement = document()->getElementById(id); 
743         SVGElement* target = 0;
744         if (targetElement && targetElement->isSVGElement())
745             target = static_cast<SVGElement*>(targetElement);
746
747         // Don't ASSERT(target) here, it may be "pending", too.
748         // Setup sub-shadow tree root node
749         RefPtr<SVGShadowTreeContainerElement> cloneParent = new SVGShadowTreeContainerElement(document());
750         use->cloneChildNodes(cloneParent.get());
751
752         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
753         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
754         transferUseAttributesToReplacedElement(use, cloneParent.get());
755
756         ExceptionCode ec = 0;
757         if (target && !isDisallowedElement(target)) {
758             RefPtr<Element> newChild = target->cloneElementWithChildren();
759
760             SVGElement* newChildPtr = 0;
761             if (newChild->isSVGElement())
762                 newChildPtr = static_cast<SVGElement*>(newChild.get());
763             ASSERT(newChildPtr);
764
765             cloneParent->appendChild(newChild.release(), ec);
766             ASSERT(!ec);
767         }
768
769         // We don't walk the target tree element-by-element, and clone each element,
770         // but instead use cloneElementWithChildren(). This is an optimization for the common
771         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
772         // Though if there are disallowed elements in the subtree, we have to remove them.
773         // For instance: <use> on <g> containing <foreignObject> (indirect case).
774         if (subtreeContainsDisallowedElement(cloneParent.get()))
775             removeDisallowedElementsFromSubtree(cloneParent.get());
776
777         // Replace <use> with referenced content.
778         ASSERT(use->parentNode()); 
779         use->parentNode()->replaceChild(cloneParent.release(), use, ec);
780         ASSERT(!ec);
781
782         // Immediately stop here, and restart expanding.
783         expandUseElementsInShadowTree(shadowRoot, shadowRoot);
784         return;
785     }
786
787     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
788         expandUseElementsInShadowTree(shadowRoot, child.get());
789 }
790
791 void SVGUseElement::expandSymbolElementsInShadowTree(SVGShadowTreeRootElement* shadowRoot, Node* element)
792 {
793     if (element->hasTagName(SVGNames::symbolTag)) {
794         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
795         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
796         // always have explicit values for attributes width and height. If attributes width and/or
797         // height are provided on the 'use' element, then these attributes will be transferred to
798         // the generated 'svg'. If attributes width and/or height are not specified, the generated
799         // 'svg' element will use values of 100% for these attributes.
800         RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document());
801
802         // Transfer all attributes from <symbol> to the new <svg> element
803         svgElement->attributes()->setAttributes(*element->attributes());
804
805         // Only clone symbol children, and add them to the new <svg> element    
806         ExceptionCode ec = 0;
807         for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
808             RefPtr<Node> newChild = child->cloneNode(true);
809             svgElement->appendChild(newChild.release(), ec);
810             ASSERT(!ec);
811         }
812     
813         // We don't walk the target tree element-by-element, and clone each element,
814         // but instead use cloneNode(deep=true). This is an optimization for the common
815         // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
816         // Though if there are disallowed elements in the subtree, we have to remove them.
817         // For instance: <use> on <g> containing <foreignObject> (indirect case).
818         if (subtreeContainsDisallowedElement(svgElement.get()))
819             removeDisallowedElementsFromSubtree(svgElement.get());
820
821         // Replace <symbol> with <svg>.
822         ASSERT(element->parentNode()); 
823         element->parentNode()->replaceChild(svgElement.release(), element, ec);
824         ASSERT(!ec);
825
826         // Immediately stop here, and restart expanding.
827         expandSymbolElementsInShadowTree(shadowRoot, shadowRoot);
828         return;
829     }
830
831     for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
832         expandSymbolElementsInShadowTree(shadowRoot, child.get());
833 }
834
835 #endif
836
837 void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target)
838 {
839     if (!target)
840         return;
841
842     SVGElement* originalElement = target->correspondingElement();
843     ASSERT(originalElement);
844
845     if (SVGElement* shadowTreeElement = target->shadowTreeElement()) {
846         if (EventTargetData* d = originalElement->eventTargetData()) {
847             EventListenerMap& map = d->eventListenerMap;
848             EventListenerMap::iterator end = map.end();
849             for (EventListenerMap::iterator it = map.begin(); it != end; ++it) {
850                 EventListenerVector& entry = *it->second;
851                 for (size_t i = 0; i < entry.size(); ++i) {
852                     // Event listeners created from markup have already been transfered to the shadow tree during cloning.
853                     if (entry[i].listener->wasCreatedFromMarkup())
854                         continue;
855                     shadowTreeElement->addEventListener(it->first, entry[i].listener, entry[i].useCapture);
856                 }
857             }
858         }
859     }
860
861     for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
862         transferEventListenersToShadowTree(instance);
863 }
864
865 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
866 {
867     if (!target || !targetInstance)
868         return;
869
870     SVGElement* originalElement = targetInstance->correspondingElement();
871
872     if (originalElement->hasTagName(SVGNames::useTag)) {
873 #if ENABLE(SVG) && ENABLE(SVG_USE)
874         // <use> gets replaced by <g>
875         ASSERT(target->nodeName() == SVGNames::gTag);
876 #else 
877         ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag);
878 #endif
879     } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
880         // <symbol> gets replaced by <svg>
881 #if ENABLE(SVG) && ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT)
882         ASSERT(target->nodeName() == SVGNames::svgTag);
883 #endif
884     } else
885         ASSERT(target->nodeName() == originalElement->nodeName());
886
887     SVGElement* element = 0;
888     if (target->isSVGElement())
889         element = static_cast<SVGElement*>(target);
890
891     ASSERT(!targetInstance->shadowTreeElement());
892     targetInstance->setShadowTreeElement(element);
893
894     Node* node = target->firstChild();
895     for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
896         // Skip any non-svg elements in shadow tree
897         while (node && !node->isSVGElement())
898            node = node->nextSibling();
899
900         associateInstancesWithShadowTreeElements(node, instance);
901         node = node->nextSibling();
902     }
903 }
904
905 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
906 {
907     if (!m_targetElementInstance) {
908         ASSERT(!inDocument());
909         return 0;
910     }
911
912     return instanceForShadowTreeElement(element, m_targetElementInstance.get());
913 }
914
915 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
916 {
917     ASSERT(element);
918     ASSERT(instance);
919
920     // We're dispatching a mutation event during shadow tree construction
921     // this instance hasn't yet been associated to a shadowTree element.
922     if (!instance->shadowTreeElement())
923         return 0;
924
925     if (element == instance->shadowTreeElement())
926         return instance;
927
928     for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
929         if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
930             return search;
931     }
932
933     return 0;
934 }
935
936 void SVGUseElement::invalidateShadowTree()
937 {
938     m_needsShadowTreeRecreation = true;
939     setNeedsStyleRecalc();
940 }
941
942 void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
943 {
944     ASSERT(from);
945     ASSERT(to);
946
947     to->attributes()->setAttributes(*from->attributes());
948
949     ExceptionCode ec = 0;
950
951     to->removeAttribute(SVGNames::xAttr, ec);
952     ASSERT(!ec);
953
954     to->removeAttribute(SVGNames::yAttr, ec);
955     ASSERT(!ec);
956
957     to->removeAttribute(SVGNames::widthAttr, ec);
958     ASSERT(!ec);
959
960     to->removeAttribute(SVGNames::heightAttr, ec);
961     ASSERT(!ec);
962
963     to->removeAttribute(XLinkNames::hrefAttr, ec);
964     ASSERT(!ec);
965 }
966
967 bool SVGUseElement::hasRelativeValues() const
968 {
969     return x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative();
970 }
971
972 }
973
974 #endif // ENABLE(SVG)