REGRESSION (r179101): SVGUseElement::expandUseElementsInShadowTree has an object...
[WebKit-https.git] / Source / WebCore / svg / SVGUseElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5  * Copyright (C) 2011 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
6  * Copyright (C) 2012 University of Szeged
7  * Copyright (C) 2012 Renata Hodovan <reni@webkit.org>
8  * Copyright (C) 2015 Apple Inc. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "SVGUseElement.h"
28
29 #include "CachedResourceLoader.h"
30 #include "CachedResourceRequest.h"
31 #include "CachedSVGDocument.h"
32 #include "Document.h"
33 #include "ElementIterator.h"
34 #include "Event.h"
35 #include "EventListener.h"
36 #include "HTMLNames.h"
37 #include "NodeRenderStyle.h"
38 #include "RegisteredEventListener.h"
39 #include "RenderSVGResource.h"
40 #include "RenderSVGTransformableContainer.h"
41 #include "ShadowRoot.h"
42 #include "SVGElementInstance.h"
43 #include "SVGElementRareData.h"
44 #include "SVGGElement.h"
45 #include "SVGLengthContext.h"
46 #include "SVGNames.h"
47 #include "SVGSMILElement.h"
48 #include "SVGSVGElement.h"
49 #include "SVGSymbolElement.h"
50 #include "StyleResolver.h"
51 #include "XLinkNames.h"
52 #include "XMLDocumentParser.h"
53 #include "XMLSerializer.h"
54 #include <wtf/NeverDestroyed.h>
55
56 namespace WebCore {
57
58 // Animated property definitions
59 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x)
60 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y)
61 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::widthAttr, Width, width)
62 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::heightAttr, Height, height)
63 DEFINE_ANIMATED_STRING(SVGUseElement, XLinkNames::hrefAttr, Href, href)
64 DEFINE_ANIMATED_BOOLEAN(SVGUseElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
65
66 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGUseElement)
67     REGISTER_LOCAL_ANIMATED_PROPERTY(x)
68     REGISTER_LOCAL_ANIMATED_PROPERTY(y)
69     REGISTER_LOCAL_ANIMATED_PROPERTY(width)
70     REGISTER_LOCAL_ANIMATED_PROPERTY(height)
71     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
72     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
73     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
74 END_REGISTER_ANIMATED_PROPERTIES
75
76 inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document, bool wasInsertedByParser)
77     : SVGGraphicsElement(tagName, document)
78     , m_x(LengthModeWidth)
79     , m_y(LengthModeHeight)
80     , m_width(LengthModeWidth)
81     , m_height(LengthModeHeight)
82     , m_wasInsertedByParser(wasInsertedByParser)
83     , m_haveFiredLoadEvent(false)
84     , m_needsShadowTreeRecreation(false)
85     , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired)
86 {
87     ASSERT(hasCustomStyleResolveCallbacks());
88     ASSERT(hasTagName(SVGNames::useTag));
89     registerAnimatedPropertiesForSVGUseElement();
90 }
91
92 Ref<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document, bool wasInsertedByParser)
93 {
94     // Always build a #shadow-root for SVGUseElement.
95     Ref<SVGUseElement> use = adoptRef(*new SVGUseElement(tagName, document, wasInsertedByParser));
96     use->ensureUserAgentShadowRoot();
97     return use;
98 }
99
100 SVGUseElement::~SVGUseElement()
101 {
102     setCachedDocument(0);
103
104     clearResourceReferences();
105 }
106
107 SVGElementInstance* SVGUseElement::instanceRoot()
108 {
109     // If there is no element instance tree, force immediate SVGElementInstance tree
110     // creation by asking the document to invoke our recalcStyle function - as we can't
111     // wait for the lazy creation to happen if e.g. JS wants to access the instanceRoot
112     // object right after creating the element on-the-fly
113     if (!m_targetElementInstance)
114         document().updateLayoutIgnorePendingStylesheets();
115
116     return m_targetElementInstance.get();
117 }
118
119 bool SVGUseElement::isSupportedAttribute(const QualifiedName& attrName)
120 {
121     static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes;
122     if (supportedAttributes.get().isEmpty()) {
123         SVGLangSpace::addSupportedAttributes(supportedAttributes);
124         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
125         SVGURIReference::addSupportedAttributes(supportedAttributes);
126         supportedAttributes.get().add(SVGNames::xAttr);
127         supportedAttributes.get().add(SVGNames::yAttr);
128         supportedAttributes.get().add(SVGNames::widthAttr);
129         supportedAttributes.get().add(SVGNames::heightAttr);
130     }
131     return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName);
132 }
133
134 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
135 {
136     SVGParsingError parseError = NoError;
137
138     if (!isSupportedAttribute(name))
139         SVGGraphicsElement::parseAttribute(name, value);
140     else if (name == SVGNames::xAttr)
141         setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
142     else if (name == SVGNames::yAttr)
143         setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
144     else if (name == SVGNames::widthAttr)
145         setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
146     else if (name == SVGNames::heightAttr)
147         setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
148     else if (SVGLangSpace::parseAttribute(name, value)
149              || SVGExternalResourcesRequired::parseAttribute(name, value)
150              || SVGURIReference::parseAttribute(name, value)) {
151     } else
152         ASSERT_NOT_REACHED();
153
154     reportAttributeParsingError(parseError, name, value);
155 }
156
157 #if !ASSERT_DISABLED
158 static inline bool isWellFormedDocument(Document& document)
159 {
160     if (document.isSVGDocument() || document.isXHTMLDocument())
161         return static_cast<XMLDocumentParser*>(document.parser())->wellFormed();
162     return true;
163 }
164 #endif
165
166 Node::InsertionNotificationRequest SVGUseElement::insertedInto(ContainerNode& rootParent)
167 {
168     // This functions exists to assure assumptions made in the code regarding SVGElementInstance creation/destruction are satisfied.
169     SVGGraphicsElement::insertedInto(rootParent);
170     if (!rootParent.inDocument())
171         return InsertionDone;
172     ASSERT(!m_targetElementInstance || !isWellFormedDocument(document()));
173     ASSERT(!hasPendingResources() || !isWellFormedDocument(document()));
174     SVGExternalResourcesRequired::insertedIntoDocument(this);
175     if (!m_wasInsertedByParser)
176         return InsertionShouldCallDidNotifySubtreeInsertions;
177     return InsertionDone;
178 }
179
180 void SVGUseElement::didNotifySubtreeInsertions(ContainerNode*)
181 {
182     buildPendingResource();
183 }
184
185 void SVGUseElement::removedFrom(ContainerNode& rootParent)
186 {
187     SVGGraphicsElement::removedFrom(rootParent);
188     if (rootParent.inDocument())
189         clearResourceReferences();
190 }
191
192 Document* SVGUseElement::referencedDocument() const
193 {
194     if (!isExternalURIReference(href(), document()))
195         return &document();
196     return externalDocument();
197 }
198
199 Document* SVGUseElement::externalDocument() const
200 {
201     if (m_cachedDocument && m_cachedDocument->isLoaded()) {
202         // Gracefully handle error condition.
203         if (m_cachedDocument->errorOccurred())
204             return 0;
205         ASSERT(m_cachedDocument->document());
206         return m_cachedDocument->document();
207     }
208     return 0;
209 }
210
211 void SVGUseElement::transferSizeAttributesToShadowTreeTargetClone(SVGElement& shadowElement) const
212 {
213     // FIXME: The check for valueInSpecifiedUnits being non-zero below is a workaround for the fact
214     // that we currently have no good way to tell whether a particular animatable attribute is a value
215     // indicating it was unspecified, or specified but could not be parsed. Would be nice to fix that some day.
216     if (is<SVGSymbolElement>(shadowElement)) {
217         // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
218         // If attributes width and/or height are provided on the 'use' element, then these attributes
219         // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
220         // the generated 'svg' element will use values of 100% for these attributes.
221         shadowElement.setAttribute(SVGNames::widthAttr, (widthIsValid() && width().valueInSpecifiedUnits()) ? AtomicString(width().valueAsString()) : "100%");
222         shadowElement.setAttribute(SVGNames::heightAttr, (heightIsValid() && height().valueInSpecifiedUnits()) ? AtomicString(height().valueAsString()) : "100%");
223     } else if (is<SVGSVGElement>(shadowElement)) {
224         // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
225         // values will override the corresponding attributes on the 'svg' in the generated tree.
226         shadowElement.setAttribute(SVGNames::widthAttr, (widthIsValid() && width().valueInSpecifiedUnits()) ? AtomicString(width().valueAsString()) : shadowElement.correspondingElement()->getAttribute(SVGNames::widthAttr));
227         shadowElement.setAttribute(SVGNames::heightAttr, (heightIsValid() && height().valueInSpecifiedUnits()) ? AtomicString(height().valueAsString()) : shadowElement.correspondingElement()->getAttribute(SVGNames::heightAttr));
228     }
229 }
230
231 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
232 {
233     if (!isSupportedAttribute(attrName)) {
234         SVGGraphicsElement::svgAttributeChanged(attrName);
235         return;
236     }
237
238     SVGElementInstance::InvalidationGuard invalidationGuard(this);
239
240     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
241         updateRelativeLengthsInformation();
242         if (m_targetElementInstance) {
243             // FIXME: It's unnecessarily inefficient to do this work any time we change "x" or "y".
244             // FIXME: It's unnecessarily inefficient to update both width and height each time either is changed.
245             ASSERT(m_targetElementInstance->shadowTreeElement());
246             transferSizeAttributesToShadowTreeTargetClone(*m_targetElementInstance->shadowTreeElement());
247         }
248         if (auto* renderer = this->renderer())
249             RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
250         return;
251     }
252
253     if (SVGExternalResourcesRequired::handleAttributeChange(this, attrName))
254         return;
255
256     if (SVGURIReference::isKnownAttribute(attrName)) {
257         bool isExternalReference = isExternalURIReference(href(), document());
258         if (isExternalReference) {
259             URL url = document().completeURL(href());
260             if (url.hasFragmentIdentifier()) {
261                 CachedResourceRequest request(ResourceRequest(url.string()));
262                 request.setInitiator(this);
263                 setCachedDocument(document().cachedResourceLoader()->requestSVGDocument(request));
264             }
265         } else
266             setCachedDocument(0);
267
268         if (!m_wasInsertedByParser)
269             buildPendingResource();
270
271         return;
272     }
273
274     if (SVGLangSpace::isKnownAttribute(attrName)
275         || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
276         invalidateShadowTree();
277         return;
278     }
279
280     ASSERT_NOT_REACHED();
281 }
282
283 void SVGUseElement::willAttachRenderers()
284 {
285     if (m_needsShadowTreeRecreation)
286         buildPendingResource();
287 }
288
289 static bool isDisallowedElement(const Element& element)
290 {
291     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
292     // (i.e., "instanced") in the SVG document via a 'use' element."
293     // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
294     // Excluded are anything that is used by reference or that only make sense to appear once in a document.
295
296     if (!element.isSVGElement())
297         return true;
298
299     static NeverDestroyed<HashSet<QualifiedName>> allowedElementTags;
300     if (allowedElementTags.get().isEmpty()) {
301         allowedElementTags.get().add(SVGNames::aTag);
302         allowedElementTags.get().add(SVGNames::circleTag);
303         allowedElementTags.get().add(SVGNames::descTag);
304         allowedElementTags.get().add(SVGNames::ellipseTag);
305         allowedElementTags.get().add(SVGNames::gTag);
306         allowedElementTags.get().add(SVGNames::imageTag);
307         allowedElementTags.get().add(SVGNames::lineTag);
308         allowedElementTags.get().add(SVGNames::metadataTag);
309         allowedElementTags.get().add(SVGNames::pathTag);
310         allowedElementTags.get().add(SVGNames::polygonTag);
311         allowedElementTags.get().add(SVGNames::polylineTag);
312         allowedElementTags.get().add(SVGNames::rectTag);
313         allowedElementTags.get().add(SVGNames::svgTag);
314         allowedElementTags.get().add(SVGNames::switchTag);
315         allowedElementTags.get().add(SVGNames::symbolTag);
316         allowedElementTags.get().add(SVGNames::textTag);
317         allowedElementTags.get().add(SVGNames::textPathTag);
318         allowedElementTags.get().add(SVGNames::titleTag);
319         allowedElementTags.get().add(SVGNames::trefTag);
320         allowedElementTags.get().add(SVGNames::tspanTag);
321         allowedElementTags.get().add(SVGNames::useTag);
322     }
323     return !allowedElementTags.get().contains<SVGAttributeHashTranslator>(element.tagQName());
324 }
325
326 void SVGUseElement::clearResourceReferences()
327 {
328     // FIXME: We should try to optimize this, to at least allow partial reclones.
329     if (ShadowRoot* root = userAgentShadowRoot())
330         root->removeChildren();
331
332     if (m_targetElementInstance) {
333         m_targetElementInstance->detach();
334         m_targetElementInstance = 0;
335     }
336
337     m_needsShadowTreeRecreation = false;
338
339     document().accessSVGExtensions().removeAllTargetReferencesForElement(this);
340 }
341
342 void SVGUseElement::buildPendingResource()
343 {
344     if (!referencedDocument() || isInShadowTree())
345         return;
346     clearResourceReferences();
347     if (!inDocument())
348         return;
349
350     String id;
351     Element* target = SVGURIReference::targetElementFromIRIString(href(), document(), &id, externalDocument());
352     if (!target || !target->inDocument()) {
353         // If we can't find the target of an external element, just give up.
354         // We can't observe if the target somewhen enters the external document, nor should we do it.
355         if (externalDocument())
356             return;
357         if (id.isEmpty())
358             return;
359
360         referencedDocument()->accessSVGExtensions().addPendingResource(id, this);
361         ASSERT(hasPendingResources());
362         return;
363     }
364
365     if (target->isSVGElement()) {
366         buildShadowAndInstanceTree(downcast<SVGElement>(*target));
367         invalidateDependentShadowTrees();
368     }
369
370     ASSERT(!m_needsShadowTreeRecreation);
371 }
372
373 SVGElement* SVGUseElement::shadowTreeTargetClone() const
374 {
375     auto* root = userAgentShadowRoot();
376     if (!root)
377         return nullptr;
378     return downcast<SVGElement>(root->firstChild());
379 }
380
381 void SVGUseElement::buildShadowAndInstanceTree(SVGElement& target)
382 {
383     ASSERT(!m_targetElementInstance);
384
385     // Do not build the shadow/instance tree for <use> elements living in a shadow tree.
386     // The will be expanded soon anyway - see expandUseElementsInShadowTree().
387     if (isInShadowTree())
388         return;
389
390     // Do not allow self-referencing.
391     if (&target == this)
392         return;
393
394     // Build instance tree.
395     // Spec: If the 'use' element references a simple graphics element such as a 'rect', then there is only a
396     // single SVGElementInstance object, and the correspondingElement attribute on this SVGElementInstance object
397     // is the SVGRectElement that corresponds to the referenced 'rect' element.
398     m_targetElementInstance = SVGElementInstance::create(this, this, &target);
399
400     // Eventually enter recursion to build SVGElementInstance objects for the sub-tree children
401     bool foundProblem = false;
402     buildInstanceTree(&target, m_targetElementInstance.get(), foundProblem, false);
403
404     if (instanceTreeIsLoading(m_targetElementInstance.get()))
405         return;
406
407     // SVG specification does not say a word about <use> and cycles. My view on this is: just ignore it!
408     // Non-appearing <use> content is easier to debug, then half-appearing content.
409     if (foundProblem) {
410         clearResourceReferences();
411         return;
412     }
413
414     // Assure instance tree building was successful.
415     ASSERT(m_targetElementInstance);
416     ASSERT(!m_targetElementInstance->shadowTreeElement());
417     ASSERT(m_targetElementInstance->correspondingUseElement() == this);
418     ASSERT(m_targetElementInstance->directUseElement() == this);
419     ASSERT(m_targetElementInstance->correspondingElement() == &target);
420
421     if (isDisallowedElement(target)) {
422         clearResourceReferences();
423         return;
424     }
425
426     buildShadowTree(target);
427     expandUseElementsInShadowTree();
428     expandSymbolElementsInShadowTree();
429
430     ASSERT(shadowTreeTargetClone());
431     SVGElement& shadowTreeTargetClone = *this->shadowTreeTargetClone();
432     associateInstancesWithShadowTreeElements(&shadowTreeTargetClone, m_targetElementInstance.get());
433
434     transferSizeAttributesToShadowTreeTargetClone(shadowTreeTargetClone);
435
436     transferEventListenersToShadowTree();
437     updateRelativeLengthsInformation();
438 }
439
440 RenderPtr<RenderElement> SVGUseElement::createElementRenderer(Ref<RenderStyle>&& style)
441 {
442     return createRenderer<RenderSVGTransformableContainer>(*this, WTF::move(style));
443 }
444
445 static bool isDirectReference(const SVGElement& element)
446 {
447     return element.hasTagName(SVGNames::pathTag)
448         || element.hasTagName(SVGNames::rectTag)
449         || element.hasTagName(SVGNames::circleTag)
450         || element.hasTagName(SVGNames::ellipseTag)
451         || element.hasTagName(SVGNames::polygonTag)
452         || element.hasTagName(SVGNames::polylineTag)
453         || element.hasTagName(SVGNames::textTag);
454 }
455
456 void SVGUseElement::toClipPath(Path& path)
457 {
458     ASSERT(path.isEmpty());
459
460     SVGElement* element = shadowTreeTargetClone();
461     if (is<SVGGraphicsElement>(element)) {
462         if (!isDirectReference(*element)) {
463             // Spec: Indirect references are an error (14.3.5)
464             document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>");
465         } else {
466             downcast<SVGGraphicsElement>(*element).toClipPath(path);
467             // FIXME: Avoid manual resolution of x/y here. Its potentially harmful.
468             SVGLengthContext lengthContext(this);
469             path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext)));
470             path.transform(animatedLocalTransform());
471         }
472     }
473 }
474
475 RenderElement* SVGUseElement::rendererClipChild() const
476 {
477     auto* element = shadowTreeTargetClone();
478     if (!element)
479         return nullptr;
480     if (!isDirectReference(*element))
481         return nullptr;
482     return element->renderer();
483 }
484
485 void SVGUseElement::buildInstanceTree(SVGElement* target, SVGElementInstance* targetInstance, bool& foundProblem, bool foundUse)
486 {
487     ASSERT(target);
488     ASSERT(targetInstance);
489
490     // Spec: If the referenced object is itself a 'use', or if there are 'use' subelements within the referenced
491     // object, the instance tree will contain recursive expansion of the indirect references to form a complete tree.
492     bool targetHasUseTag = target->hasTagName(SVGNames::useTag);
493     SVGElement* newTarget = nullptr;
494     if (targetHasUseTag) {
495         foundProblem = hasCycleUseReferencing(downcast<SVGUseElement>(target), targetInstance, newTarget);
496         if (foundProblem)
497             return;
498
499         // We only need to track first degree <use> dependencies. Indirect references are handled
500         // as the invalidation bubbles up the dependency chain.
501         if (!foundUse) {
502             document().accessSVGExtensions().addElementReferencingTarget(this, target);
503             foundUse = true;
504         }
505     } else if (isDisallowedElement(*target)) {
506         foundProblem = true;
507         return;
508     }
509
510     // A general description from the SVG spec, describing what buildInstanceTree() actually does.
511     //
512     // Spec: If the 'use' element references a 'g' which contains two 'rect' elements, then the instance tree
513     // contains three SVGElementInstance objects, a root SVGElementInstance object whose correspondingElement
514     // is the SVGGElement object for the 'g', and then two child SVGElementInstance objects, each of which has
515     // its correspondingElement that is an SVGRectElement object.
516
517     for (auto& element : childrenOfType<SVGElement>(*target)) {
518         // Skip any non-svg nodes or any disallowed element.
519         if (isDisallowedElement(element))
520             continue;
521
522         // Create SVGElementInstance object, for both container/non-container nodes.
523         RefPtr<SVGElementInstance> instance = SVGElementInstance::create(this, 0, &element);
524         SVGElementInstance* instancePtr = instance.get();
525         targetInstance->appendChild(instance.release());
526
527         // Enter recursion, appending new instance tree nodes to the "instance" object.
528         buildInstanceTree(&element, instancePtr, foundProblem, foundUse);
529         if (foundProblem)
530             return;
531     }
532
533     if (!targetHasUseTag || !newTarget)
534         return;
535
536     RefPtr<SVGElementInstance> newInstance = SVGElementInstance::create(this, downcast<SVGUseElement>(target), newTarget);
537     SVGElementInstance* newInstancePtr = newInstance.get();
538     targetInstance->appendChild(newInstance.release());
539     buildInstanceTree(newTarget, newInstancePtr, foundProblem, foundUse);
540 }
541
542 bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, SVGElementInstance* targetInstance, SVGElement*& newTarget)
543 {
544     ASSERT(referencedDocument());
545     Element* targetElement = SVGURIReference::targetElementFromIRIString(use->href(), *referencedDocument());
546     newTarget = nullptr;
547     if (targetElement && targetElement->isSVGElement())
548         newTarget = downcast<SVGElement>(targetElement);
549
550     if (!newTarget)
551         return false;
552
553     // Shortcut for self-references
554     if (newTarget == this)
555         return true;
556
557     AtomicString targetId = newTarget->getIdAttribute();
558     SVGElementInstance* instance = targetInstance->parentNode();
559     while (instance) {
560         SVGElement* element = instance->correspondingElement();
561
562         if (element->hasID() && element->getIdAttribute() == targetId && &element->document() == &newTarget->document())
563             return true;
564
565         instance = instance->parentNode();
566     }
567     return false;
568 }
569
570 static void removeDisallowedElementsFromSubtree(SVGElement& subtree)
571 {
572     // Remove disallowed elements after the fact rather than not cloning them in the first place.
573     // This optimizes for the normal case where none of those elements are present.
574
575     // This function is used only on elements in subtrees that are not yet in documents, so
576     // mutation events are not a factor; there are no event listeners to handle those events.
577     // Assert that it's not in a document to make sure callers are still using it this way.
578     ASSERT(!subtree.inDocument());
579
580     Vector<Element*> disallowedElements;
581     auto descendants = descendantsOfType<Element>(subtree);
582     auto end = descendants.end();
583     for (auto it = descendants.begin(); it != end; ) {
584         if (isDisallowedElement(*it)) {
585             disallowedElements.append(&*it);
586             it.traverseNextSkippingChildren();
587             continue;
588         }
589         ++it;
590     }
591     for (Element* element : disallowedElements)
592         element->parentNode()->removeChild(element);
593 }
594
595 void SVGUseElement::buildShadowTree(SVGElement& target)
596 {
597     Ref<SVGElement> clonedTarget = static_pointer_cast<SVGElement>(target.cloneElementWithChildren(document())).releaseNonNull();
598     removeDisallowedElementsFromSubtree(clonedTarget.get());
599     ensureUserAgentShadowRoot().appendChild(WTF::move(clonedTarget));
600 }
601
602 void SVGUseElement::expandUseElementsInShadowTree()
603 {
604     // Why expand the <use> elements in the shadow tree here, and not just
605     // do this directly in buildShadowTree, as we encounter each <use> element?
606     // Because we might miss expanding some elements if we did it then. If a <symbol>
607     // contained <use> elements, we'd miss those.
608
609     auto descendants = descendantsOfType<SVGUseElement>(*userAgentShadowRoot());
610     auto end = descendants.end();
611     for (auto it = descendants.begin(); it != end; ) {
612         Ref<SVGUseElement> original = *it;
613         it = end; // Efficiently quiets assertions due to the outstanding iterator.
614
615         ASSERT(!original->cachedDocumentIsStillLoading());
616
617         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
618         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
619
620         // FIXME: Is it right to use referencedDocument() here instead of just document()?
621         // Can a shadow tree within this document really contain elements that are in a
622         // different document?
623         ASSERT(referencedDocument());
624         auto replacement = SVGGElement::create(SVGNames::gTag, *referencedDocument());
625
626         original->transferAttributesToShadowTreeReplacement(replacement.get());
627         original->cloneChildNodes(replacement.ptr());
628
629         RefPtr<SVGElement> clonedTarget;
630         Element* targetCandidate = SVGURIReference::targetElementFromIRIString(original->href(), *referencedDocument());
631         if (is<SVGElement>(targetCandidate) && !isDisallowedElement(downcast<SVGElement>(*targetCandidate))) {
632             SVGElement& originalTarget = downcast<SVGElement>(*targetCandidate);
633             clonedTarget = static_pointer_cast<SVGElement>(originalTarget.cloneElementWithChildren(document()));
634             // Set the corresponding element here so transferSizeAttributesToShadowTreeTargetClone
635             // can use it. It will be set again later in associateInstancesWithShadowTreeElements,
636             // but it does no harm to set it twice.
637             clonedTarget->setCorrespondingElement(&originalTarget);
638             replacement->appendChild(clonedTarget);
639         }
640
641         removeDisallowedElementsFromSubtree(replacement.get());
642
643         // Replace <use> with the <g> element we created.
644         original->parentNode()->replaceChild(replacement.ptr(), original.ptr());
645
646         // Call transferSizeAttributesToShadowTreeTargetClone after putting the cloned elements into the
647         // shadow tree so it can use SVGElement::correspondingElement without triggering an assertion.
648         if (clonedTarget)
649             original->transferSizeAttributesToShadowTreeTargetClone(*clonedTarget);
650
651         // Continue iterating from the <g> element since the <use> element was replaced.
652         it = descendants.from(replacement.get());
653     }
654 }
655
656 void SVGUseElement::expandSymbolElementsInShadowTree()
657 {
658     auto descendants = descendantsOfType<SVGSymbolElement>(*userAgentShadowRoot());
659     auto end = descendants.end();
660     for (auto it = descendants.begin(); it != end; ) {
661         SVGSymbolElement& original = *it;
662         it = end; // Efficiently quiets assertions due to the outstanding iterator.
663
664         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
665         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
666         // always have explicit values for attributes width and height. If attributes width and/or
667         // height are provided on the 'use' element, then these attributes will be transferred to
668         // the generated 'svg'. If attributes width and/or height are not specified, the generated
669         // 'svg' element will use values of 100% for these attributes.
670
671         // FIXME: Is it right to use referencedDocument() here instead of just document()?
672         // Can a shadow tree within this document really contain elements that are in a
673         // different document?
674         ASSERT(referencedDocument());
675         auto replacement = SVGSVGElement::create(SVGNames::svgTag, *referencedDocument());
676         replacement->cloneDataFromElement(original);
677         original.cloneChildNodes(replacement.ptr());
678         removeDisallowedElementsFromSubtree(replacement.get());
679
680         // Replace <symbol> with the <svg> element we created.
681         original.parentNode()->replaceChild(replacement.ptr(), &original);
682
683         // Continue iterating from the <svg> element since the <symbol> element was replaced.
684         it = descendants.from(replacement.get());
685     }
686 }
687
688 void SVGUseElement::transferEventListenersToShadowTree()
689 {
690     ASSERT(userAgentShadowRoot());
691     for (auto& descendant : descendantsOfType<SVGElement>(*userAgentShadowRoot())) {
692         ASSERT(descendant.correspondingElement());
693         if (EventTargetData* data = descendant.correspondingElement()->eventTargetData())
694             data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(&descendant);
695     }
696 }
697
698 void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance)
699 {
700     if (!target || !targetInstance)
701         return;
702
703     SVGElement* originalElement = targetInstance->correspondingElement();
704
705     if (originalElement->hasTagName(SVGNames::useTag)) {
706         // <use> gets replaced by <g>
707         ASSERT(target->nodeName() == SVGNames::gTag);
708     } else if (originalElement->hasTagName(SVGNames::symbolTag)) {
709         // <symbol> gets replaced by <svg>
710         ASSERT(target->nodeName() == SVGNames::svgTag);
711     } else
712         ASSERT(target->nodeName() == originalElement->nodeName());
713
714     SVGElement* element = nullptr;
715     if (target->isSVGElement())
716         element = downcast<SVGElement>(target);
717
718     ASSERT(!targetInstance->shadowTreeElement());
719     targetInstance->setShadowTreeElement(element);
720     element->setCorrespondingElement(originalElement);
721
722     Node* node = target->firstChild();
723     for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) {
724         // Skip any non-svg elements in shadow tree
725         while (node && !node->isSVGElement())
726            node = node->nextSibling();
727
728         if (!node)
729             break;
730
731         associateInstancesWithShadowTreeElements(node, instance);
732         node = node->nextSibling();
733     }
734 }
735
736 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const
737 {
738     if (!m_targetElementInstance) {
739         ASSERT(!inDocument());
740         return 0;
741     }
742
743     return instanceForShadowTreeElement(element, m_targetElementInstance.get());
744 }
745
746 SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const
747 {
748     ASSERT(element);
749     ASSERT(instance);
750
751     // We're dispatching a mutation event during shadow tree construction
752     // this instance hasn't yet been associated to a shadowTree element.
753     if (!instance->shadowTreeElement())
754         return 0;
755
756     if (element == instance->shadowTreeElement())
757         return instance;
758
759     for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) {
760         if (SVGElementInstance* search = instanceForShadowTreeElement(element, current))
761             return search;
762     }
763
764     return 0;
765 }
766
767 void SVGUseElement::invalidateShadowTree()
768 {
769     if (m_needsShadowTreeRecreation)
770         return;
771     m_needsShadowTreeRecreation = true;
772     setNeedsStyleRecalc(ReconstructRenderTree);
773     invalidateDependentShadowTrees();
774 }
775
776 void SVGUseElement::invalidateDependentShadowTrees()
777 {
778     // Recursively invalidate dependent <use> shadow trees
779     const HashSet<SVGElementInstance*>& instances = instancesForElement();
780     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
781     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
782         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
783             ASSERT(element->inDocument());
784             element->invalidateShadowTree();
785         }
786     }
787 }
788
789 void SVGUseElement::transferAttributesToShadowTreeReplacement(SVGGElement& replacement) const
790 {
791     replacement.cloneDataFromElement(*this);
792
793     replacement.removeAttribute(SVGNames::xAttr);
794     replacement.removeAttribute(SVGNames::yAttr);
795     replacement.removeAttribute(SVGNames::widthAttr);
796     replacement.removeAttribute(SVGNames::heightAttr);
797     replacement.removeAttribute(XLinkNames::hrefAttr);
798 }
799
800 bool SVGUseElement::selfHasRelativeLengths() const
801 {
802     if (x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative())
803         return true;
804
805     auto* target = shadowTreeTargetClone();
806     return target && target->hasRelativeLengths();
807 }
808
809 void SVGUseElement::notifyFinished(CachedResource* resource)
810 {
811     if (!inDocument())
812         return;
813
814     invalidateShadowTree();
815     if (resource->errorOccurred())
816         dispatchEvent(Event::create(eventNames().errorEvent, false, false));
817     else if (!resource->wasCanceled())
818         SVGExternalResourcesRequired::dispatchLoadEvent(this);
819 }
820
821 bool SVGUseElement::cachedDocumentIsStillLoading()
822 {
823     if (m_cachedDocument && m_cachedDocument->isLoading())
824         return true;
825     return false;
826 }
827
828 bool SVGUseElement::instanceTreeIsLoading(SVGElementInstance* targetElementInstance)
829 {
830     for (SVGElementInstance* instance = targetElementInstance->firstChild(); instance; instance = instance->nextSibling()) {
831         if (SVGUseElement* use = instance->correspondingUseElement()) {
832              if (use->cachedDocumentIsStillLoading())
833                  return true;
834         }
835         if (instance->hasChildNodes())
836             instanceTreeIsLoading(instance);
837     }
838     return false;
839 }
840
841 void SVGUseElement::finishParsingChildren()
842 {
843     SVGGraphicsElement::finishParsingChildren();
844     SVGExternalResourcesRequired::finishParsingChildren();
845     if (m_wasInsertedByParser) {
846         buildPendingResource();
847         m_wasInsertedByParser = false;
848     }
849 }
850
851 void SVGUseElement::setCachedDocument(CachedResourceHandle<CachedSVGDocument> cachedDocument)
852 {
853     if (m_cachedDocument == cachedDocument)
854         return;
855
856     if (m_cachedDocument)
857         m_cachedDocument->removeClient(this);
858
859     m_cachedDocument = cachedDocument;
860     if (m_cachedDocument) {
861         // We don't need the SVG document to create a new frame because the new document belongs to the parent UseElement.
862         m_cachedDocument->setShouldCreateFrameForDocument(false);
863         m_cachedDocument->addClient(this);
864     }
865 }
866
867 }