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