1/*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5 * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6 * Copyright (C) 2012 University of Szeged
7 * Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB.  If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#include "config.h"
26
27#include "core/svg/SVGUseElement.h"
28
29#include "SVGNames.h"
30#include "XLinkNames.h"
31#include "bindings/v8/ExceptionStatePlaceholder.h"
32#include "core/dom/Document.h"
33#include "core/dom/Event.h"
34#include "core/dom/NodeTraversal.h"
35#include "core/dom/shadow/ElementShadow.h"
36#include "core/dom/shadow/ShadowRoot.h"
37#include "core/loader/cache/DocumentResource.h"
38#include "core/loader/cache/FetchRequest.h"
39#include "core/loader/cache/ResourceFetcher.h"
40#include "core/rendering/svg/RenderSVGResource.h"
41#include "core/rendering/svg/RenderSVGTransformableContainer.h"
42#include "core/svg/SVGElementInstance.h"
43#include "core/svg/SVGGElement.h"
44#include "core/svg/SVGLengthContext.h"
45#include "core/svg/SVGSVGElement.h"
46#include "core/xml/parser/XMLDocumentParser.h"
47
48// Dump SVGElementInstance object tree - useful to debug instanceRoot problems
49// #define DUMP_INSTANCE_TREE
50
51// Dump the deep-expanded shadow tree (where the renderers are built from)
52// #define DUMP_SHADOW_TREE
53
54namespace WebCore {
55
56// Animated property definitions
57DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x)
58DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y)
59DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::widthAttr, Width, width)
60DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::heightAttr, Height, height)
61DEFINE_ANIMATED_STRING(SVGUseElement, XLinkNames::hrefAttr, Href, href)
62DEFINE_ANIMATED_BOOLEAN(SVGUseElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
63
64BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGUseElement)
65    REGISTER_LOCAL_ANIMATED_PROPERTY(x)
66    REGISTER_LOCAL_ANIMATED_PROPERTY(y)
67    REGISTER_LOCAL_ANIMATED_PROPERTY(width)
68    REGISTER_LOCAL_ANIMATED_PROPERTY(height)
69    REGISTER_LOCAL_ANIMATED_PROPERTY(href)
70    REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
71    REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
72END_REGISTER_ANIMATED_PROPERTIES
73
74inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser)
75    : SVGGraphicsElement(tagName, document)
76    , m_x(LengthModeWidth)
77    , m_y(LengthModeHeight)
78    , m_width(LengthModeWidth)
79    , m_height(LengthModeHeight)
80    , m_wasInsertedByParser(wasInsertedByParser)
81    , m_haveFiredLoadEvent(false)
82    , m_needsShadowTreeRecreation(false)
83    , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
84{
85    ASSERT(hasCustomStyleCallbacks());
86    ASSERT(hasTagName(SVGNames::useTag));
87    ScriptWrappable::init(this);
88    registerAnimatedPropertiesForSVGUseElement();
89}
90
91PassRefPtr<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document* document, bool wasInsertedByParser)
92{
93    // Always build a #shadow-root for SVGUseElement.
94    RefPtr<SVGUseElement> use = adoptRef(new SVGUseElement(tagName, document, wasInsertedByParser));
95    use->ensureUserAgentShadowRoot();
96    return use.release();
97}
98
99SVGUseElement::~SVGUseElement()
100{
101    setDocumentResource(0);
102
103    clearResourceReferences();
104}
105
106SVGElementInstance* SVGUseElement::instanceRoot()
107{
108    // If there is no element instance tree, force immediate SVGElementInstance tree
109    // creation by asking the document to invoke our recalcStyle function - as we can't
110    // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
111    // object right after creating the element on-the-fly
112    if (!m_targetElementInstance)
113        document()->updateStyleIfNeeded();
114
115    return m_targetElementInstance.get();
116}
117
118SVGElementInstance* SVGUseElement::animatedInstanceRoot() const
119{
120    // FIXME: Implement me.
121    return 0;
122}
123
124bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
125{
126    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
127    if (supportedAttributes.isEmpty()) {
128        SVGLangSpace::addSupportedAttributes(supportedAttributes);
129        SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
130        SVGURIReference::addSupportedAttributes(supportedAttributes);
131        supportedAttributes.add(SVGNames::xAttr);
132        supportedAttributes.add(SVGNames::yAttr);
133        supportedAttributes.add(SVGNames::widthAttr);
134        supportedAttributes.add(SVGNames::heightAttr);
135    }
136    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
137}
138
139void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
140{
141    SVGParsingError parseError = NoError;
142
143    if (!isSupportedAttribute(name))
144        SVGGraphicsElement::parseAttribute(name, value);
145    else if (name == SVGNames::xAttr)
146        setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
147    else if (name == SVGNames::yAttr)
148        setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
149    else if (name == SVGNames::widthAttr)
150        setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
151    else if (name == SVGNames::heightAttr)
152        setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
153    else if (SVGLangSpace::parseAttribute(name, value)
154             || SVGExternalResourcesRequired::parseAttribute(name, value)
155             || SVGURIReference::parseAttribute(name, value)) {
156    } else
157        ASSERT_NOT_REACHED();
158
159    reportAttributeParsingError(parseError, name, value);
160}
161
162static inline bool isWellFormedDocument(Document* document)
163{
164    if (document->isSVGDocument() || document->isXHTMLDocument())
165        return static_cast<XMLDocumentParser*>(document->parser())->wellFormed();
166    return true;
167}
168
169Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode* rootParent)
170{
171    // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
172    SVGGraphicsElement::insertedInto(rootParent);
173    if (!rootParent->inDocument())
174        return InsertionDone;
175    ASSERT(!m_targetElementInstance || !isWellFormedDocument(document()));
176    ASSERT(!hasPendingResources() || !isWellFormedDocument(document()));
177    if (!m_wasInsertedByParser)
178        buildPendingResource();
179    SVGExternalResourcesRequired::insertedIntoDocument(this);
180    return InsertionDone;
181}
182
183void SVGUseElement::removedFrom(ContainerNode* rootParent)
184{
185    SVGGraphicsElement::removedFrom(rootParent);
186    if (rootParent->inDocument())
187        clearResourceReferences();
188}
189
190Document* SVGUseElement::referencedDocument() const
191{
192    if (!isExternalURIReference(hrefCurrentValue(), document()))
193        return document();
194    return externalDocument();
195}
196
197Document* SVGUseElement::externalDocument() const
198{
199    if (m_resource && m_resource->isLoaded()) {
200        // Gracefully handle error condition.
201        if (m_resource->errorOccurred())
202            return 0;
203        ASSERT(m_resource->document());
204        return m_resource->document();
205    }
206    return 0;
207}
208
209void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
210{
211    if (!isSupportedAttribute(attrName)) {
212        SVGGraphicsElement::svgAttributeChanged(attrName);
213        return;
214    }
215
216    SVGElementInstance::InvalidationGuard invalidationGuard(this);
217
218    RenderObject* renderer = this->renderer();
219    if (attrName == SVGNames::xAttr
220        || attrName == SVGNames::yAttr
221        || attrName == SVGNames::widthAttr
222        || attrName == SVGNames::heightAttr) {
223        updateRelativeLengthsInformation();
224        if (renderer)
225            RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
226        return;
227    }
228
229    if (SVGExternalResourcesRequired::handleAttributeChange(this, attrName))
230        return;
231
232    if (SVGURIReference::isKnownAttribute(attrName)) {
233        bool isExternalReference = isExternalURIReference(hrefCurrentValue(), document());
234        if (isExternalReference) {
235            KURL url = document()->completeURL(hrefCurrentValue());
236            if (url.hasFragmentIdentifier()) {
237                FetchRequest request(ResourceRequest(url.string()), localName());
238                setDocumentResource(document()->fetcher()->requestSVGDocument(request));
239            }
240        } else {
241            setDocumentResource(0);
242        }
243
244        if (!m_wasInsertedByParser)
245            buildPendingResource();
246
247        return;
248    }
249
250    if (!renderer)
251        return;
252
253    if (SVGLangSpace::isKnownAttribute(attrName)
254        || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
255        invalidateShadowTree();
256        return;
257    }
258
259    ASSERT_NOT_REACHED();
260}
261
262void SVGUseElement::willRecalcStyle(StyleChange)
263{
264    if (!m_wasInsertedByParser && m_needsShadowTreeRecreation && renderer() && needsStyleRecalc())
265        buildPendingResource();
266}
267
268#ifdef DUMP_INSTANCE_TREE
269static void dumpInstanceTree(unsigned int& depth, String& text, SVGElementInstance* targetInstance)
270{
271    SVGElement* element = targetInstance->correspondingElement();
272    ASSERT(element);
273
274    if (element->hasTagName(SVGNames::useTag)) {
275        if (toSVGUseElement(element)->resourceIsStillLoading())
276            return;
277    }
278
279    SVGElement* shadowTreeElement = targetInstance->shadowTreeElement();
280    ASSERT(shadowTreeElement);
281
282    SVGUseElement* directUseElement = targetInstance->directUseElement();
283    String directUseElementName = directUseElement ? directUseElement->nodeName() : "null";
284
285    String elementId = element->getIdAttribute();
286    String elementNodeName = element->nodeName();
287    String shadowTreeElementNodeName = shadowTreeElement->nodeName();
288    String parentNodeName = element->parentNode() ? element->parentNode()->nodeName() : "null";
289    String firstChildNodeName = element->firstChild() ? element->firstChild()->nodeName() : "null";
290
291    for (unsigned int i = 0; i < depth; ++i)
292        text += "  ";
293
294    text += String::format("SVGElementInstance this=%p, (parentNode=%s (%p), firstChild=%s (%p), correspondingElement=%s (%p), directUseElement=%s (%p), shadowTreeElement=%s (%p), id=%s)\n",
295                           targetInstance, parentNodeName.latin1().data(), element->parentNode(), firstChildNodeName.latin1().data(), element->firstChild(),
296                           elementNodeName.latin1().data(), element, directUseElementName.latin1().data(), directUseElement, shadowTreeElementNodeName.latin1().data(), shadowTreeElement, elementId.latin1().data());
297
298    for (unsigned int i = 0; i < depth; ++i)
299        text += "  ";
300
301    const HashSet<SVGElementInstance*>& elementInstances = element->instancesForElement();
302    text += "Corresponding element is associated with " + String::number(elementInstances.size()) + " instance(s):\n";
303
304    const HashSet<SVGElementInstance*>::const_iterator end = elementInstances.end();
305    for (HashSet<SVGElementInstance*>::const_iterator it = elementInstances.begin(); it != end; ++it) {
306        for (unsigned int i = 0; i < depth; ++i)
307            text += "  ";
308
309        text += String::format(" -> SVGElementInstance this=%p, (refCount: %i, shadowTreeElement in document? %i)\n",
310                               *it, (*it)->refCount(), (*it)->shadowTreeElement()->inDocument());
311    }
312
313    ++depth;
314
315    for (SVGElementInstance* instance = targetInstance->firstChild(); instance; instance = instance->nextSibling())
316        dumpInstanceTree(depth, text, instance);
317
318    --depth;
319}
320#endif
321
322static bool isDisallowedElement(Node* node)
323{
324    // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
325    // (i.e., "instanced") in the SVG document via a 'use' element."
326    // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
327    // Excluded are anything that is used by reference or that only make sense to appear once in a document.
328    // We must also allow the shadow roots of other use elements.
329    if (node->isShadowRoot() || node->isTextNode())
330        return false;
331
332    if (!node->isSVGElement())
333        return true;
334
335    Element* element = toElement(node);
336
337    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowedElementTags, ());
338    if (allowedElementTags.isEmpty()) {
339        allowedElementTags.add(SVGNames::aTag);
340        allowedElementTags.add(SVGNames::circleTag);
341        allowedElementTags.add(SVGNames::descTag);
342        allowedElementTags.add(SVGNames::ellipseTag);
343        allowedElementTags.add(SVGNames::gTag);
344        allowedElementTags.add(SVGNames::imageTag);
345        allowedElementTags.add(SVGNames::lineTag);
346        allowedElementTags.add(SVGNames::metadataTag);
347        allowedElementTags.add(SVGNames::pathTag);
348        allowedElementTags.add(SVGNames::polygonTag);
349        allowedElementTags.add(SVGNames::polylineTag);
350        allowedElementTags.add(SVGNames::rectTag);
351        allowedElementTags.add(SVGNames::svgTag);
352        allowedElementTags.add(SVGNames::switchTag);
353        allowedElementTags.add(SVGNames::symbolTag);
354        allowedElementTags.add(SVGNames::textTag);
355        allowedElementTags.add(SVGNames::textPathTag);
356        allowedElementTags.add(SVGNames::titleTag);
357        allowedElementTags.add(SVGNames::trefTag);
358        allowedElementTags.add(SVGNames::tspanTag);
359        allowedElementTags.add(SVGNames::useTag);
360    }
361    return !allowedElementTags.contains<SVGAttributeHashTranslator>(element->tagQName());
362}
363
364static bool subtreeContainsDisallowedElement(Node* start)
365{
366    if (isDisallowedElement(start))
367        return true;
368
369    for (Node* cur = start->firstChild(); cur; cur = cur->nextSibling()) {
370        if (subtreeContainsDisallowedElement(cur))
371            return true;
372    }
373
374    return false;
375}
376
377void SVGUseElement::clearResourceReferences()
378{
379    // FIXME: We should try to optimize this, to at least allow partial reclones.
380    if (ShadowRoot* shadowTreeRootElement = userAgentShadowRoot())
381        shadowTreeRootElement->removeChildren();
382
383    if (m_targetElementInstance) {
384        m_targetElementInstance->detach();
385        m_targetElementInstance = 0;
386    }
387
388    m_needsShadowTreeRecreation = false;
389
390    ASSERT(document());
391    document()->accessSVGExtensions()->removeAllTargetReferencesForElement(this);
392}
393
394void SVGUseElement::buildPendingResource()
395{
396    if (!referencedDocument() || isInShadowTree())
397        return;
398    clearResourceReferences();
399    if (!inDocument())
400        return;
401
402    String id;
403    Element* target = SVGURIReference::targetElementFromIRIString(hrefCurrentValue(), document(), &id, externalDocument());
404    if (!target || !target->inDocument()) {
405        // If we can't find the target of an external element, just give up.
406        // We can't observe if the target somewhen enters the external document, nor should we do it.
407        if (externalDocument())
408            return;
409        if (id.isEmpty())
410            return;
411
412        referencedDocument()->accessSVGExtensions()->addPendingResource(id, this);
413        ASSERT(hasPendingResources());
414        return;
415    }
416
417    if (target->isSVGElement()) {
418        buildShadowAndInstanceTree(toSVGElement(target));
419        invalidateDependentShadowTrees();
420    }
421
422    ASSERT(!m_needsShadowTreeRecreation);
423}
424
425void SVGUseElement::buildShadowAndInstanceTree(SVGElement* target)
426{
427    ASSERT(!m_targetElementInstance);
428
429    // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
430    // The will be expanded soon anyway - see expandUseElementsInShadowTree().
431    if (isInShadowTree())
432        return;
433
434    // Do not allow self-referencing.
435    // 'target' may be null, if it's a non SVG namespaced element.
436    if (!target || target == this)
437        return;
438
439    // Why a seperated instance/shadow tree? SVG demands it:
440    // The instance tree is accesable from JavaScript, and has to
441    // expose a 1:1 copy of the referenced tree, whereas internally we need
442    // to alter the tree for correct "use-on-symbol", "use-on-svg" support.
443
444    // Build instance tree. Create root SVGElementInstance object for the first sub-tree node.
445    //
446    // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
447    // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
448    // is the SVGRectElement that corresponds to the referenced 'rect' element.
449    m_targetElementInstance = SVGElementInstance::create(this, this, target);
450
451    // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
452    bool foundProblem = false;
453    buildInstanceTree(target, m_targetElementInstance.get(), foundProblem, false);
454
455    if (instanceTreeIsLoading(m_targetElementInstance.get()))
456        return;
457
458    // SVG specification does not say a word about <use> & cycles. My view on this is: just ignore it!
459    // Non-appearing <use> content is easier to debug, then half-appearing content.
460    if (foundProblem) {
461        clearResourceReferences();
462        return;
463    }
464
465    // Assure instance tree building was successfull
466    ASSERT(m_targetElementInstance);
467    ASSERT(!m_targetElementInstance->shadowTreeElement());
468    ASSERT(m_targetElementInstance->correspondingUseElement() == this);
469    ASSERT(m_targetElementInstance->directUseElement() == this);
470    ASSERT(m_targetElementInstance->correspondingElement() == target);
471
472    ShadowRoot* shadowTreeRootElement = userAgentShadowRoot();
473    ASSERT(shadowTreeRootElement);
474
475    // Build shadow tree from instance tree
476    // This also handles the special cases: <use> on <symbol>, <use> on <svg>.
477    buildShadowTree(target, m_targetElementInstance.get());
478
479    // Expand all <use> elements in the shadow tree.
480    // Expand means: replace the actual <use> element by what it references.
481    expandUseElementsInShadowTree(shadowTreeRootElement);
482
483    // Expand all <symbol> elements in the shadow tree.
484    // Expand means: replace the actual <symbol> element by the <svg> element.
485    expandSymbolElementsInShadowTree(shadowTreeRootElement);
486
487    // Now that the shadow tree is completly expanded, we can associate
488    // shadow tree elements <-> instances in the instance tree.
489    associateInstancesWithShadowTreeElements(shadowTreeRootElement->firstChild(), m_targetElementInstance.get());
490
491    // If no shadow tree element is present, this means that the reference root
492    // element was removed, as it is disallowed (ie. <use> on <foreignObject>)
493    // Do NOT leave an inconsistent instance tree around, instead destruct it.
494    if (!m_targetElementInstance->shadowTreeElement()) {
495        clearResourceReferences();
496        return;
497    }
498
499    ASSERT(m_targetElementInstance->shadowTreeElement()->parentNode() == shadowTreeRootElement);
500
501    // Transfer event listeners assigned to the referenced element to our shadow tree elements.
502    transferEventListenersToShadowTree(m_targetElementInstance.get());
503
504    // Update relative length information.
505    updateRelativeLengthsInformation();
506
507    // Eventually dump instance tree
508#ifdef DUMP_INSTANCE_TREE
509    String text;
510    unsigned int depth = 0;
511
512    dumpInstanceTree(depth, text, m_targetElementInstance.get());
513    fprintf(stderr, "\nDumping <use> instance tree:\n%s\n", text.latin1().data());
514#endif
515
516    // Eventually dump shadow tree
517#ifdef DUMP_SHADOW_TREE
518    RefPtr<XMLSerializer> serializer = XMLSerializer::create();
519    String markup = serializer->serializeToString(shadowTreeRootElement, ASSERT_NO_EXCEPTION);
520    fprintf(stderr, "Dumping <use> shadow tree markup:\n%s\n", markup.latin1().data());
521#endif
522}
523
524RenderObject* SVGUseElement::createRenderer(RenderStyle*)
525{
526    return new RenderSVGTransformableContainer(this);
527}
528
529static bool isDirectReference(const Node* node)
530{
531    return node->hasTagName(SVGNames::pathTag)
532           || node->hasTagName(SVGNames::rectTag)
533           || node->hasTagName(SVGNames::circleTag)
534           || node->hasTagName(SVGNames::ellipseTag)
535           || node->hasTagName(SVGNames::polygonTag)
536           || node->hasTagName(SVGNames::polylineTag)
537           || node->hasTagName(SVGNames::textTag);
538}
539
540void SVGUseElement::toClipPath(Path& path)
541{
542    ASSERT(path.isEmpty());
543
544    Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
545    if (!n)
546        return;
547
548    if (n->isSVGElement() && toSVGElement(n)->isSVGGraphicsElement()) {
549        if (!isDirectReference(n))
550            // Spec: Indirect references are an error (14.3.5)
551            document()->accessSVGExtensions()->reportError("Not allowed to use indirect reference in <clip-path>");
552        else {
553            toSVGGraphicsElement(n)->toClipPath(path);
554            // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
555            SVGLengthContext lengthContext(this);
556            path.translate(FloatSize(xCurrentValue().value(lengthContext), yCurrentValue().value(lengthContext)));
557            path.transform(animatedLocalTransform());
558        }
559    }
560}
561
562RenderObject* SVGUseElement::rendererClipChild() const
563{
564    Node* n = m_targetElementInstance ? m_targetElementInstance->shadowTreeElement() : 0;
565    if (!n)
566        return 0;
567
568    if (n->isSVGElement() && isDirectReference(n))
569        return toSVGElement(n)->renderer();
570
571    return 0;
572}
573
574void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem, bool foundUse)
575{
576    ASSERT(target);
577    ASSERT(targetInstance);
578
579    // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
580    // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
581    bool targetHasUseTag = target->hasTagName(SVGNames::useTag);
582    SVGElement* newTarget = 0;
583    if (targetHasUseTag) {
584        foundProblem = hasCycleUseReferencing(toSVGUseElement(target), targetInstance, newTarget);
585        if (foundProblem)
586            return;
587
588        // We only need to track first degree <use> dependencies. Indirect references are handled
589        // as the invalidation bubbles up the dependency chain.
590        if (!foundUse) {
591            ASSERT(document());
592            document()->accessSVGExtensions()->addElementReferencingTarget(this, target);
593            foundUse = true;
594        }
595    } else if (isDisallowedElement(target)) {
596        foundProblem = true;
597        return;
598    }
599
600    // A general description from the SVG spec, describing what buildInstanceTree() actually does.
601    //
602    // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
603    // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
604    // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
605    // its correspondingElement that is an SVGRectElement object.
606
607    for (Node* node = target->firstChild(); node; node = node->nextSibling()) {
608        SVGElement* element = 0;
609        if (node->isSVGElement())
610            element = toSVGElement(node);
611
612        // Skip any non-svg nodes or any disallowed element.
613        if (!element || isDisallowedElement(element))
614            continue;
615
616        // Create SVGElementInstance object, for both container/non-container nodes.
617        RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, 0, element);
618        SVGElementInstance* instancePtr = instance.get();
619        targetInstance->appendChild(instance.release());
620
621        // Enter recursion, appending new instance tree nodes to the "instance" object.
622        buildInstanceTree(element, instancePtr, foundProblem, foundUse);
623        if (foundProblem)
624            return;
625    }
626
627    if (!targetHasUseTag || !newTarget)
628        return;
629
630    RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, toSVGUseElement(target), newTarget);
631    SVGElementInstance* newInstancePtr = newInstance.get();
632    targetInstance->appendChild(newInstance.release());
633    buildInstanceTree(newTarget, newInstancePtr, foundProblem, foundUse);
634}
635
636bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, SVGElement*& newTarget)
637{
638    Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefCurrentValue(), referencedDocument());
639    newTarget = 0;
640    if (targetElement && targetElement->isSVGElement())
641        newTarget = toSVGElement(targetElement);
642
643    if (!newTarget)
644        return false;
645
646    // Shortcut for self-references
647    if (newTarget == this)
648        return true;
649
650    AtomicString targetId = newTarget->getIdAttribute();
651    SVGElementInstance* instance = targetInstance->parentNode();
652    while (instance) {
653        SVGElement* element = instance->correspondingElement();
654
655        if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
656            return true;
657
658        instance = instance->parentNode();
659    }
660    return false;
661}
662
663static inline void removeDisallowedElementsFromSubtree(Element* subtree)
664{
665    ASSERT(!subtree->inDocument());
666    Element* element = ElementTraversal::firstWithin(subtree);
667    while (element) {
668        if (isDisallowedElement(element)) {
669            Element* next = ElementTraversal::nextSkippingChildren(element, subtree);
670            // The subtree is not in document so this won't generate events that could mutate the tree.
671            element->parentNode()->removeChild(element);
672            element = next;
673        } else
674            element = ElementTraversal::next(element, subtree);
675    }
676}
677
678void SVGUseElement::buildShadowTree(SVGElement* target, SVGElementInstance* targetInstance)
679{
680    // For instance <use> on <foreignObject> (direct case).
681    if (isDisallowedElement(target))
682        return;
683
684    RefPtr<Element> newChild = targetInstance->correspondingElement()->cloneElementWithChildren();
685
686    // We don't walk the target tree element-by-element, and clone each element,
687    // but instead use cloneElementWithChildren(). This is an optimization for the common
688    // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
689    // Though if there are disallowed elements in the subtree, we have to remove them.
690    // For instance: <use> on <g> containing <foreignObject> (indirect case).
691    if (subtreeContainsDisallowedElement(newChild.get()))
692        removeDisallowedElementsFromSubtree(newChild.get());
693
694    userAgentShadowRoot()->appendChild(newChild.release());
695}
696
697void SVGUseElement::expandUseElementsInShadowTree(Node* element)
698{
699    // Why expand the <use> elements in the shadow tree here, and not just
700    // do this directly in buildShadowTree, if we encounter a <use> element?
701    //
702    // Short answer: Because we may miss to expand some elements. Ie. if a <symbol>
703    // contains <use> tags, we'd miss them. So once we're done with settin' up the
704    // actual shadow tree (after the special case modification for svg/symbol) we have
705    // to walk it completely and expand all <use> elements.
706    if (element->hasTagName(SVGNames::useTag)) {
707        SVGUseElement* use = toSVGUseElement(element);
708        ASSERT(!use->resourceIsStillLoading());
709
710        Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefCurrentValue(), referencedDocument());
711        SVGElement* target = 0;
712        if (targetElement && targetElement->isSVGElement())
713            target = toSVGElement(targetElement);
714
715        // Don't ASSERT(target) here, it may be "pending", too.
716        // Setup sub-shadow tree root node
717        RefPtr<SVGGElement> cloneParent = SVGGElement::create(SVGNames::gTag, referencedDocument());
718        use->cloneChildNodes(cloneParent.get());
719
720        // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
721        // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
722        transferUseAttributesToReplacedElement(use, cloneParent.get());
723
724        if (target && !isDisallowedElement(target)) {
725            RefPtr<Element> newChild = target->cloneElementWithChildren();
726            ASSERT(newChild->isSVGElement());
727            cloneParent->appendChild(newChild.release());
728        }
729
730        // We don't walk the target tree element-by-element, and clone each element,
731        // but instead use cloneElementWithChildren(). This is an optimization for the common
732        // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
733        // Though if there are disallowed elements in the subtree, we have to remove them.
734        // For instance: <use> on <g> containing <foreignObject> (indirect case).
735        if (subtreeContainsDisallowedElement(cloneParent.get()))
736            removeDisallowedElementsFromSubtree(cloneParent.get());
737
738        RefPtr<Node> replacingElement(cloneParent.get());
739
740        // Replace <use> with referenced content.
741        ASSERT(use->parentNode());
742        use->parentNode()->replaceChild(cloneParent.release(), use);
743
744        // Expand the siblings because the *element* is replaced and we will
745        // lose the sibling chain when we are back from recursion.
746        element = replacingElement.get();
747        for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
748            expandUseElementsInShadowTree(sibling.get());
749    }
750
751    for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
752        expandUseElementsInShadowTree(child.get());
753}
754
755void SVGUseElement::expandSymbolElementsInShadowTree(Node* element)
756{
757    if (element->hasTagName(SVGNames::symbolTag)) {
758        // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
759        // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
760        // always have explicit values for attributes width and height. If attributes width and/or
761        // height are provided on the 'use' element, then these attributes will be transferred to
762        // the generated 'svg'. If attributes width and/or height are not specified, the generated
763        // 'svg' element will use values of 100% for these attributes.
764        RefPtr<SVGSVGElement> svgElement = SVGSVGElement::create(SVGNames::svgTag, referencedDocument());
765
766        // Transfer all data (attributes, etc.) from <symbol> to the new <svg> element.
767        svgElement->cloneDataFromElement(*toElement(element));
768
769        // Only clone symbol children, and add them to the new <svg> element
770        for (Node* child = element->firstChild(); child; child = child->nextSibling()) {
771            RefPtr<Node> newChild = child->cloneNode(true);
772            svgElement->appendChild(newChild.release());
773        }
774
775        // We don't walk the target tree element-by-element, and clone each element,
776        // but instead use cloneNode(deep=true). This is an optimization for the common
777        // case where <use> doesn't contain disallowed elements (ie. <foreignObject>).
778        // Though if there are disallowed elements in the subtree, we have to remove them.
779        // For instance: <use> on <g> containing <foreignObject> (indirect case).
780        if (subtreeContainsDisallowedElement(svgElement.get()))
781            removeDisallowedElementsFromSubtree(svgElement.get());
782
783        RefPtr<Node> replacingElement(svgElement.get());
784
785        // Replace <symbol> with <svg>.
786        element->parentNode()->replaceChild(svgElement.release(), element);
787
788        // Expand the siblings because the *element* is replaced and we will
789        // lose the sibling chain when we are back from recursion.
790        element = replacingElement.get();
791        for (RefPtr<Node> sibling = element->nextSibling(); sibling; sibling = sibling->nextSibling())
792            expandSymbolElementsInShadowTree(sibling.get());
793    }
794
795    for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling())
796        expandSymbolElementsInShadowTree(child.get());
797}
798
799void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target)
800{
801    if (!target)
802        return;
803
804    SVGElement* originalElement = target->correspondingElement();
805    ASSERT(originalElement);
806
807    if (SVGElement* shadowTreeElement = target->shadowTreeElement()) {
808        if (EventTargetData* data = originalElement->eventTargetData())
809            data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(shadowTreeElement);
810    }
811
812    for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling())
813        transferEventListenersToShadowTree(instance);
814}
815
816void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
817{
818    if (!target || !targetInstance)
819        return;
820
821    SVGElement* originalElement = targetInstance->correspondingElement();
822
823    if (originalElement->hasTagName(SVGNames::useTag)) {
824        // <use> gets replaced by <g>
825        ASSERT(target->nodeName() == SVGNames::gTag);
826    } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
827        // <symbol> gets replaced by <svg>
828        ASSERT(target->nodeName() == SVGNames::svgTag);
829    } else
830        ASSERT(target->nodeName() == originalElement->nodeName());
831
832    SVGElement* element = 0;
833    if (target->isSVGElement())
834        element = toSVGElement(target);
835
836    ASSERT(!targetInstance->shadowTreeElement());
837    targetInstance->setShadowTreeElement(element);
838    element->setCorrespondingElement(originalElement);
839
840    Node* node = target->firstChild();
841    for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
842        // Skip any non-svg elements in shadow tree
843        while (node && !node->isSVGElement())
844           node = node->nextSibling();
845
846        if (!node)
847            break;
848
849        associateInstancesWithShadowTreeElements(node, instance);
850        node = node->nextSibling();
851    }
852}
853
854SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
855{
856    if (!m_targetElementInstance) {
857        ASSERT(!inDocument());
858        return 0;
859    }
860
861    return instanceForShadowTreeElement(element, m_targetElementInstance.get());
862}
863
864SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
865{
866    ASSERT(element);
867    ASSERT(instance);
868
869    // We're dispatching a mutation event during shadow tree construction
870    // this instance hasn't yet been associated to a shadowTree element.
871    if (!instance->shadowTreeElement())
872        return 0;
873
874    if (element == instance->shadowTreeElement())
875        return instance;
876
877    for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
878        if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
879            return search;
880    }
881
882    return 0;
883}
884
885void SVGUseElement::invalidateShadowTree()
886{
887    if (!renderer() || m_needsShadowTreeRecreation)
888        return;
889    m_needsShadowTreeRecreation = true;
890    setNeedsStyleRecalc();
891    invalidateDependentShadowTrees();
892}
893
894void SVGUseElement::invalidateDependentShadowTrees()
895{
896    // Recursively invalidate dependent <use> shadow trees
897    const HashSet<SVGElementInstance*>& instances = instancesForElement();
898    const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
899    for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
900        if (SVGUseElement* element = (*it)->correspondingUseElement()) {
901            ASSERT(element->inDocument());
902            element->invalidateShadowTree();
903        }
904    }
905}
906
907void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const
908{
909    ASSERT(from);
910    ASSERT(to);
911
912    to->cloneDataFromElement(*from);
913
914    to->removeAttribute(SVGNames::xAttr);
915    to->removeAttribute(SVGNames::yAttr);
916    to->removeAttribute(SVGNames::widthAttr);
917    to->removeAttribute(SVGNames::heightAttr);
918    to->removeAttribute(XLinkNames::hrefAttr);
919}
920
921bool SVGUseElement::selfHasRelativeLengths() const
922{
923    if (xCurrentValue().isRelative()
924        || yCurrentValue().isRelative()
925        || widthCurrentValue().isRelative()
926        || heightCurrentValue().isRelative())
927        return true;
928
929    if (!m_targetElementInstance)
930        return false;
931
932    SVGElement* element = m_targetElementInstance->correspondingElement();
933    if (!element)
934        return false;
935
936    return toSVGElement(element)->hasRelativeLengths();
937}
938
939void SVGUseElement::notifyFinished(Resource* resource)
940{
941    if (!inDocument())
942        return;
943
944    invalidateShadowTree();
945    if (resource->errorOccurred())
946        dispatchEvent(Event::create(eventNames().errorEvent, false, false));
947    else if (!resource->wasCanceled())
948        SVGExternalResourcesRequired::dispatchLoadEvent(this);
949}
950
951bool SVGUseElement::resourceIsStillLoading()
952{
953    if (m_resource && m_resource->isLoading())
954        return true;
955    return false;
956}
957
958bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInstance)
959{
960    for (SVGElementInstance* instance = targetElementInstance->firstChild(); instance; instance = instance->nextSibling()) {
961        if (SVGUseElement* use = instance->correspondingUseElement()) {
962            if (use->resourceIsStillLoading())
963                return true;
964        }
965        if (instance->hasChildNodes())
966            instanceTreeIsLoading(instance);
967    }
968    return false;
969}
970
971void SVGUseElement::finishParsingChildren()
972{
973    SVGGraphicsElement::finishParsingChildren();
974    SVGExternalResourcesRequired::finishParsingChildren();
975    if (m_wasInsertedByParser) {
976        buildPendingResource();
977        m_wasInsertedByParser = false;
978    }
979}
980
981void SVGUseElement::setDocumentResource(ResourcePtr<DocumentResource> resource)
982{
983    if (m_resource == resource)
984        return;
985
986    if (m_resource)
987        m_resource->removeClient(this);
988
989    m_resource = resource;
990    if (m_resource)
991        m_resource->addClient(this);
992}
993
994}
995