9b5ffb1e430c6d640d7bef9733a86db1594cf8eb
[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-2017 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 "CachedSVGDocument.h"
31 #include "ElementIterator.h"
32 #include "Event.h"
33 #include "EventNames.h"
34 #include "RenderSVGResource.h"
35 #include "RenderSVGTransformableContainer.h"
36 #include "SVGDocumentExtensions.h"
37 #include "SVGGElement.h"
38 #include "SVGSVGElement.h"
39 #include "SVGSymbolElement.h"
40 #include "ScriptDisallowedScope.h"
41 #include "ShadowRoot.h"
42 #include "XLinkNames.h"
43 #include <wtf/IsoMallocInlines.h>
44
45 namespace WebCore {
46
47 WTF_MAKE_ISO_ALLOCATED_IMPL(SVGUseElement);
48
49 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::xAttr, X, x)
50 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::yAttr, Y, y)
51 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::widthAttr, Width, width)
52 DEFINE_ANIMATED_LENGTH(SVGUseElement, SVGNames::heightAttr, Height, height)
53 DEFINE_ANIMATED_STRING(SVGUseElement, XLinkNames::hrefAttr, Href, href)
54 DEFINE_ANIMATED_BOOLEAN(SVGUseElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
55
56 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGUseElement)
57     REGISTER_LOCAL_ANIMATED_PROPERTY(x)
58     REGISTER_LOCAL_ANIMATED_PROPERTY(y)
59     REGISTER_LOCAL_ANIMATED_PROPERTY(width)
60     REGISTER_LOCAL_ANIMATED_PROPERTY(height)
61     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
62     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
63     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
64 END_REGISTER_ANIMATED_PROPERTIES
65
66 inline SVGUseElement::SVGUseElement(const QualifiedName& tagName, Document& document)
67     : SVGGraphicsElement(tagName, document)
68     , m_x(LengthModeWidth)
69     , m_y(LengthModeHeight)
70     , m_width(LengthModeWidth)
71     , m_height(LengthModeHeight)
72     , m_svgLoadEventTimer(*this, &SVGElement::svgLoadEventTimerFired)
73 {
74     ASSERT(hasCustomStyleResolveCallbacks());
75     ASSERT(hasTagName(SVGNames::useTag));
76     registerAnimatedPropertiesForSVGUseElement();
77 }
78
79 Ref<SVGUseElement> SVGUseElement::create(const QualifiedName& tagName, Document& document)
80 {
81     return adoptRef(*new SVGUseElement(tagName, document));
82 }
83
84 SVGUseElement::~SVGUseElement()
85 {
86     if (m_externalDocument)
87         m_externalDocument->removeClient(*this);
88 }
89
90 void SVGUseElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
91 {
92     SVGParsingError parseError = NoError;
93
94     if (name == SVGNames::xAttr)
95         setXBaseValue(SVGLengthValue::construct(LengthModeWidth, value, parseError));
96     else if (name == SVGNames::yAttr)
97         setYBaseValue(SVGLengthValue::construct(LengthModeHeight, value, parseError));
98     else if (name == SVGNames::widthAttr)
99         setWidthBaseValue(SVGLengthValue::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
100     else if (name == SVGNames::heightAttr)
101         setHeightBaseValue(SVGLengthValue::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
102
103     reportAttributeParsingError(parseError, name, value);
104
105     SVGExternalResourcesRequired::parseAttribute(name, value);
106     SVGGraphicsElement::parseAttribute(name, value);
107     SVGURIReference::parseAttribute(name, value);
108 }
109
110 Node::InsertedIntoAncestorResult SVGUseElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
111 {
112     SVGGraphicsElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
113     if (insertionType.connectedToDocument) {
114         if (m_shadowTreeNeedsUpdate)
115             document().addSVGUseElement(*this);
116         SVGExternalResourcesRequired::insertedIntoDocument(this);
117         invalidateShadowTree();
118         updateExternalDocument();
119     }
120     return InsertedIntoAncestorResult::Done;
121 }
122
123 void SVGUseElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
124 {
125     // Check m_shadowTreeNeedsUpdate before calling SVGElement::removedFromAncestor which calls SVGElement::invalidateInstances
126     // and SVGUseElement::updateExternalDocument which calls invalidateShadowTree().
127     if (removalType.disconnectedFromDocument) {
128         if (m_shadowTreeNeedsUpdate)
129             document().removeSVGUseElement(*this);
130     }
131     SVGGraphicsElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
132     if (removalType.disconnectedFromDocument) {
133         clearShadowTree();
134         updateExternalDocument();
135     }
136 }
137
138 inline Document* SVGUseElement::externalDocument() const
139 {
140     return m_externalDocument ? m_externalDocument->document() : nullptr;
141 }
142
143 void SVGUseElement::transferSizeAttributesToTargetClone(SVGElement& shadowElement) const
144 {
145     // FIXME: The check for valueInSpecifiedUnits being non-zero below is a workaround for the fact
146     // that we currently have no good way to tell whether a particular animatable attribute is a value
147     // indicating it was unspecified, or specified but could not be parsed. Would be nice to fix that some day.
148     if (is<SVGSymbolElement>(shadowElement)) {
149         // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height.
150         // If attributes width and/or height are provided on the 'use' element, then these attributes
151         // will be transferred to the generated 'svg'. If attributes width and/or height are not specified,
152         // the generated 'svg' element will use values of 100% for these attributes.
153         shadowElement.setAttribute(SVGNames::widthAttr, (widthIsValid() && width().valueInSpecifiedUnits()) ? AtomicString(width().valueAsString()) : "100%");
154         shadowElement.setAttribute(SVGNames::heightAttr, (heightIsValid() && height().valueInSpecifiedUnits()) ? AtomicString(height().valueAsString()) : "100%");
155     } else if (is<SVGSVGElement>(shadowElement)) {
156         // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these
157         // values will override the corresponding attributes on the 'svg' in the generated tree.
158         auto correspondingElement = makeRefPtr(shadowElement.correspondingElement());
159         shadowElement.setAttribute(SVGNames::widthAttr, (widthIsValid() && width().valueInSpecifiedUnits()) ? AtomicString(width().valueAsString()) : (correspondingElement ? correspondingElement->getAttribute(SVGNames::widthAttr) : nullAtom()));
160         shadowElement.setAttribute(SVGNames::heightAttr, (heightIsValid() && height().valueInSpecifiedUnits()) ? AtomicString(height().valueAsString()) : (correspondingElement ? correspondingElement->getAttribute(SVGNames::heightAttr) : nullAtom()));
161     }
162 }
163
164 void SVGUseElement::svgAttributeChanged(const QualifiedName& attrName)
165 {
166     InstanceInvalidationGuard guard(*this);
167
168     if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
169         updateRelativeLengthsInformation();
170         if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
171             // FIXME: It's unnecessarily inefficient to update both width and height each time either is changed.
172             if (auto targetClone = this->targetClone())
173                 transferSizeAttributesToTargetClone(*targetClone);
174         }
175         if (auto* renderer = this->renderer())
176             RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
177         return;
178     }
179
180     if (SVGExternalResourcesRequired::handleAttributeChange(this, attrName))
181         return;
182
183     if (SVGURIReference::isKnownAttribute(attrName)) {
184         updateExternalDocument();
185         invalidateShadowTree();
186         return;
187     }
188
189     if (SVGLangSpace::isKnownAttribute(attrName) || SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
190         invalidateShadowTree();
191         return;
192     }
193
194     SVGGraphicsElement::svgAttributeChanged(attrName);
195 }
196
197 static HashSet<AtomicString> createAllowedElementSet()
198 {
199     // Spec: "Any 'svg', 'symbol', 'g', graphics element or other 'use' is potentially a template object that can be re-used
200     // (i.e., "instanced") in the SVG document via a 'use' element."
201     // "Graphics Element" is defined as 'circle', 'ellipse', 'image', 'line', 'path', 'polygon', 'polyline', 'rect', 'text'
202     // Excluded are anything that is used by reference or that only make sense to appear once in a document.
203     using namespace SVGNames;
204     HashSet<AtomicString> set;
205     for (auto& tag : { aTag.get(), circleTag.get(), descTag.get(), ellipseTag.get(), gTag.get(), imageTag.get(), lineTag.get(), metadataTag.get(), pathTag.get(), polygonTag.get(), polylineTag.get(), rectTag.get(), svgTag.get(), switchTag.get(), symbolTag.get(), textTag.get(), textPathTag.get(), titleTag.get(), trefTag.get(), tspanTag.get(), useTag.get() })
206         set.add(tag.localName());
207     return set;
208 }
209
210 static inline bool isDisallowedElement(const SVGElement& element)
211 {
212     static NeverDestroyed<HashSet<AtomicString>> set = createAllowedElementSet();
213     return !set.get().contains(element.localName());
214 }
215
216 static inline bool isDisallowedElement(const Element& element)
217 {
218     return !element.isSVGElement() || isDisallowedElement(downcast<SVGElement>(element));
219 }
220
221 void SVGUseElement::clearShadowTree()
222 {
223     if (auto root = userAgentShadowRoot()) {
224         // Safe because SVG use element's shadow tree is never used to fire synchronous events during layout or DOM mutations.
225         ScriptDisallowedScope::EventAllowedScope scope(*root);
226         root->removeChildren();
227     }
228 }
229
230 void SVGUseElement::buildPendingResource()
231 {
232     invalidateShadowTree();
233 }
234
235 void SVGUseElement::updateShadowTree()
236 {
237     m_shadowTreeNeedsUpdate = false;
238
239     // FIXME: It's expensive to re-clone the entire tree every time. We should find a more efficient way to handle this.
240     clearShadowTree();
241
242     if (!isConnected())
243         return;
244     document().removeSVGUseElement(*this);
245
246     // FIXME: Enable SVG use elements in shadow trees.
247     if (isInShadowTree())
248         return;
249
250     String targetID;
251     auto* target = findTarget(&targetID);
252     if (!target) {
253         document().accessSVGExtensions().addPendingResource(targetID, this);
254         return;
255     }
256
257     {
258         auto& shadowRoot = ensureUserAgentShadowRoot();
259         cloneTarget(shadowRoot, *target);
260         expandUseElementsInShadowTree();
261         expandSymbolElementsInShadowTree();
262         updateRelativeLengthsInformation();
263     }
264
265     transferEventListenersToShadowTree();
266
267     // When we invalidate the other shadow trees, it's important that we don't
268     // follow any cycles and invalidate ourselves. To avoid that, we temporarily
269     // set m_shadowTreeNeedsUpdate to true so invalidateShadowTree will
270     // quickly return and do nothing.
271     ASSERT(!m_shadowTreeNeedsUpdate);
272     m_shadowTreeNeedsUpdate = true;
273     invalidateDependentShadowTrees();
274     m_shadowTreeNeedsUpdate = false;
275 }
276
277 RefPtr<SVGElement> SVGUseElement::targetClone() const
278 {
279     auto root = userAgentShadowRoot();
280     if (!root)
281         return nullptr;
282     return childrenOfType<SVGElement>(*root).first();
283 }
284
285 RenderPtr<RenderElement> SVGUseElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
286 {
287     return createRenderer<RenderSVGTransformableContainer>(*this, WTFMove(style));
288 }
289
290 static bool isDirectReference(const SVGElement& element)
291 {
292     using namespace SVGNames;
293     return element.hasTagName(circleTag)
294         || element.hasTagName(ellipseTag)
295         || element.hasTagName(pathTag)
296         || element.hasTagName(polygonTag)
297         || element.hasTagName(polylineTag)
298         || element.hasTagName(rectTag)
299         || element.hasTagName(textTag);
300 }
301
302 Path SVGUseElement::toClipPath()
303 {
304     auto targetClone = this->targetClone();
305     if (!is<SVGGraphicsElement>(targetClone))
306         return { };
307
308     if (!isDirectReference(*targetClone)) {
309         // Spec: Indirect references are an error (14.3.5)
310         document().accessSVGExtensions().reportError("Not allowed to use indirect reference in <clip-path>"_s);
311         return { };
312     }
313
314     Path path = downcast<SVGGraphicsElement>(*targetClone).toClipPath();
315     SVGLengthContext lengthContext(this);
316     // FIXME: Find a way to do this without manual resolution of x/y here. It's potentially incorrect.
317     path.translate(FloatSize(x().value(lengthContext), y().value(lengthContext)));
318     path.transform(animatedLocalTransform());
319     return path;
320 }
321
322 RenderElement* SVGUseElement::rendererClipChild() const
323 {
324     auto targetClone = this->targetClone();
325     if (!targetClone)
326         return nullptr;
327     if (!isDirectReference(*targetClone))
328         return nullptr;
329     return targetClone->renderer();
330 }
331
332 static inline void disassociateAndRemoveClones(const Vector<Element*>& clones)
333 {
334     for (auto& clone : clones) {
335         for (auto& descendant : descendantsOfType<SVGElement>(*clone))
336             descendant.setCorrespondingElement(nullptr);
337         clone->parentNode()->removeChild(*clone);
338     }
339 }
340
341 static void removeDisallowedElementsFromSubtree(SVGElement& subtree)
342 {
343     // Remove disallowed elements after the fact rather than not cloning them in the first place.
344     // This optimizes for the normal case where none of those elements are present.
345
346     // This function is used only on elements in subtrees that are not yet in documents, so
347     // mutation events are not a factor; there are no event listeners to handle those events.
348     // Assert that it's not in a document to make sure callers are still using it this way.
349     ASSERT(!subtree.isConnected());
350
351     Vector<Element*> disallowedElements;
352     auto descendants = descendantsOfType<Element>(subtree);
353     for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
354         if (isDisallowedElement(*it)) {
355             disallowedElements.append(&*it);
356             it.traverseNextSkippingChildren();
357             continue;
358         }
359         ++it;
360     }
361
362     disassociateAndRemoveClones(disallowedElements);
363 }
364
365 static void removeSymbolElementsFromSubtree(SVGElement& subtree)
366 {
367     // Symbol elements inside the subtree should not be cloned for two reasons: 1) They are invisible and
368     // don't need to be cloned to get correct rendering. 2) expandSymbolElementsInShadowTree will turn them
369     // into <svg> elements, which is correct for symbol elements directly referenced by use elements,
370     // but incorrect for ones that just happen to be in a subtree.
371     Vector<Element*> symbolElements;
372     for (auto& descendant : descendantsOfType<SVGSymbolElement>(subtree))
373         symbolElements.append(&descendant);
374     disassociateAndRemoveClones(symbolElements);
375 }
376
377 static void associateClonesWithOriginals(SVGElement& clone, SVGElement& original)
378 {
379     // This assertion checks that we don't call this with the arguments backwards.
380     // The clone is new and so it's not installed in a parent yet.
381     ASSERT(!clone.parentNode());
382
383     // The loop below works because we are associating these clones immediately, before
384     // doing transformations like removing disallowed elements or expanding elements.
385     clone.setCorrespondingElement(&original);
386     for (auto pair : descendantsOfType<SVGElement>(clone, original))
387         pair.first.setCorrespondingElement(&pair.second);
388 }
389
390 static void associateReplacementCloneWithOriginal(SVGElement& replacementClone, SVGElement& originalClone)
391 {
392     auto* correspondingElement = originalClone.correspondingElement();
393     ASSERT(correspondingElement);
394     originalClone.setCorrespondingElement(nullptr);
395     replacementClone.setCorrespondingElement(correspondingElement);
396 }
397
398 static void associateReplacementClonesWithOriginals(SVGElement& replacementClone, SVGElement& originalClone)
399 {
400     // This assertion checks that we don't call this with the arguments backwards.
401     // The replacement clone is new and so it's not installed in a parent yet.
402     ASSERT(!replacementClone.parentNode());
403
404     // The loop below works because we are associating these clones immediately, before
405     // doing transformations like removing disallowed elements or expanding elements.
406     associateReplacementCloneWithOriginal(replacementClone, originalClone);
407     for (auto pair : descendantsOfType<SVGElement>(replacementClone, originalClone))
408         associateReplacementCloneWithOriginal(pair.first, pair.second);
409 }
410
411 SVGElement* SVGUseElement::findTarget(String* targetID) const
412 {
413     auto* correspondingElement = this->correspondingElement();
414     auto& original = correspondingElement ? downcast<SVGUseElement>(*correspondingElement) : *this;
415
416     auto targetCandidate = makeRefPtr(targetElementFromIRIString(original.href(), original.document(), targetID, original.externalDocument()));
417     if (targetID && !targetID->isNull()) {
418         // If the reference is external, don't return the target ID to the caller.
419         // The caller would use the target ID to wait for a pending resource on the wrong document.
420         // If we ever want the change that and let the caller to wait on the external document,
421         // we should change this function so it returns the appropriate document to go with the ID.
422         if (isExternalURIReference(original.href(), original.document()))
423             *targetID = String();
424     }
425     if (!is<SVGElement>(targetCandidate))
426         return nullptr;
427     auto& target = downcast<SVGElement>(*targetCandidate);
428
429     if (!target.isConnected() || isDisallowedElement(target))
430         return nullptr;
431
432     // Reject any target that has already been cloned to create one of the ancestors of this element,
433     // already in the shadow tree. This is sufficient to prevent cycles.
434     if (correspondingElement) {
435         for (auto& ancestor : lineageOfType<SVGElement>(*this)) {
436             if (ancestor.correspondingElement() == &target)
437                 return nullptr;
438         }
439     }
440
441     return &target;
442 }
443
444 void SVGUseElement::cloneTarget(ContainerNode& container, SVGElement& target) const
445 {
446     Ref<SVGElement> targetClone = static_cast<SVGElement&>(target.cloneElementWithChildren(document()).get());
447     associateClonesWithOriginals(targetClone.get(), target);
448     removeDisallowedElementsFromSubtree(targetClone.get());
449     removeSymbolElementsFromSubtree(targetClone.get());
450     transferSizeAttributesToTargetClone(targetClone.get());
451     container.appendChild(targetClone);
452 }
453
454 static void cloneDataAndChildren(SVGElement& replacementClone, SVGElement& originalClone)
455 {
456     // This assertion checks that we don't call this with the arguments backwards.
457     // The replacement clone is new and so it's not installed in a parent yet.
458     ASSERT(!replacementClone.parentNode());
459
460     replacementClone.cloneDataFromElement(originalClone);
461     originalClone.cloneChildNodes(replacementClone);
462     associateReplacementClonesWithOriginals(replacementClone, originalClone);
463     removeDisallowedElementsFromSubtree(replacementClone);
464 }
465
466 void SVGUseElement::expandUseElementsInShadowTree() const
467 {
468     auto descendants = descendantsOfType<SVGUseElement>(*userAgentShadowRoot());
469     for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
470         SVGUseElement& originalClone = *it;
471         it = end; // Efficiently quiets assertions due to the outstanding iterator.
472
473         auto* target = originalClone.findTarget();
474
475         // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the
476         // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element.
477
478         auto replacementClone = SVGGElement::create(document());
479
480         cloneDataAndChildren(replacementClone.get(), originalClone);
481
482         replacementClone->removeAttribute(SVGNames::xAttr);
483         replacementClone->removeAttribute(SVGNames::yAttr);
484         replacementClone->removeAttribute(SVGNames::widthAttr);
485         replacementClone->removeAttribute(SVGNames::heightAttr);
486         replacementClone->removeAttribute(XLinkNames::hrefAttr);
487
488         if (target)
489             originalClone.cloneTarget(replacementClone.get(), *target);
490
491         originalClone.parentNode()->replaceChild(replacementClone, originalClone);
492
493         // Resume iterating, starting just inside the replacement clone.
494         it = descendants.from(replacementClone.get());
495     }
496 }
497
498 void SVGUseElement::expandSymbolElementsInShadowTree() const
499 {
500     auto descendants = descendantsOfType<SVGSymbolElement>(*userAgentShadowRoot());
501     for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
502         SVGSymbolElement& originalClone = *it;
503         it = end; // Efficiently quiets assertions due to the outstanding iterator.
504
505         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
506         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will
507         // always have explicit values for attributes width and height. If attributes width and/or
508         // height are provided on the 'use' element, then these attributes will be transferred to
509         // the generated 'svg'. If attributes width and/or height are not specified, the generated
510         // 'svg' element will use values of 100% for these attributes.
511
512         auto replacementClone = SVGSVGElement::create(document());
513         cloneDataAndChildren(replacementClone.get(), originalClone);
514
515         originalClone.parentNode()->replaceChild(replacementClone, originalClone);
516
517         // Resume iterating, starting just inside the replacement clone.
518         it = descendants.from(replacementClone.get());
519     }
520 }
521
522 void SVGUseElement::transferEventListenersToShadowTree() const
523 {
524     // FIXME: Don't directly add event listeners on each descendant. Copy event listeners on the use element instead.
525     for (auto& descendant : descendantsOfType<SVGElement>(*userAgentShadowRoot())) {
526         if (EventTargetData* data = descendant.correspondingElement()->eventTargetData())
527             data->eventListenerMap.copyEventListenersNotCreatedFromMarkupToTarget(&descendant);
528     }
529 }
530
531 void SVGUseElement::invalidateShadowTree()
532 {
533     if (m_shadowTreeNeedsUpdate)
534         return;
535     m_shadowTreeNeedsUpdate = true;
536     invalidateStyleAndRenderersForSubtree();
537     invalidateDependentShadowTrees();
538     if (isConnected())
539         document().addSVGUseElement(*this);
540 }
541
542 void SVGUseElement::invalidateDependentShadowTrees()
543 {
544     for (auto* instance : instances()) {
545         if (auto element = instance->correspondingUseElement())
546             element->invalidateShadowTree();
547     }
548 }
549
550 bool SVGUseElement::selfHasRelativeLengths() const
551 {
552     if (x().isRelative() || y().isRelative() || width().isRelative() || height().isRelative())
553         return true;
554
555     auto targetClone = this->targetClone();
556     return targetClone && targetClone->hasRelativeLengths();
557 }
558
559 void SVGUseElement::notifyFinished(CachedResource& resource)
560 {
561     invalidateShadowTree();
562     if (resource.errorOccurred())
563         dispatchEvent(Event::create(eventNames().errorEvent, false, false));
564     else if (!resource.wasCanceled())
565         SVGExternalResourcesRequired::dispatchLoadEvent(this);
566 }
567
568 void SVGUseElement::finishParsingChildren()
569 {
570     SVGGraphicsElement::finishParsingChildren();
571     SVGExternalResourcesRequired::finishParsingChildren();
572 }
573
574 void SVGUseElement::updateExternalDocument()
575 {
576     URL externalDocumentURL;
577     if (isConnected() && isExternalURIReference(href(), document())) {
578         externalDocumentURL = document().completeURL(href());
579         if (!externalDocumentURL.hasFragmentIdentifier())
580             externalDocumentURL = URL();
581     }
582
583     if (externalDocumentURL == (m_externalDocument ? m_externalDocument->url() : URL()))
584         return;
585
586     if (m_externalDocument)
587         m_externalDocument->removeClient(*this);
588
589     if (externalDocumentURL.isNull())
590         m_externalDocument = nullptr;
591     else {
592         ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
593         options.contentSecurityPolicyImposition = isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck;
594         options.mode = FetchOptions::Mode::SameOrigin;
595         CachedResourceRequest request { ResourceRequest { externalDocumentURL }, options };
596         request.setInitiator(*this);
597         m_externalDocument = document().cachedResourceLoader().requestSVGDocument(WTFMove(request)).value_or(nullptr);
598         if (m_externalDocument)
599             m_externalDocument->addClient(*this);
600     }
601
602     invalidateShadowTree();
603 }
604
605 bool SVGUseElement::isValid() const
606 {
607     return SVGTests::isValid();
608 }
609
610 bool SVGUseElement::haveLoadedRequiredResources()
611 {
612     return SVGExternalResourcesRequired::haveLoadedRequiredResources();
613 }
614
615 void SVGUseElement::setHaveFiredLoadEvent(bool haveFiredLoadEvent)
616 {
617     m_haveFiredLoadEvent = haveFiredLoadEvent;
618 }
619
620 bool SVGUseElement::haveFiredLoadEvent() const
621 {
622     return m_haveFiredLoadEvent;
623 }
624
625 Timer* SVGUseElement::svgLoadEventTimer()
626 {
627     return &m_svgLoadEventTimer;
628 }
629
630 }