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