55898ee34cac3e5cba2bccd92769b05af122a13d
[WebKit-https.git] / Source / WebCore / svg / SVGElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
4  * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
5  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6  * Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
7  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
8  * Copyright (C) 2014 Adobe Systems Incorporated. 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 "SVGElement.h"
28
29 #include "CSSPropertyParser.h"
30 #include "DeprecatedCSSOMValue.h"
31 #include "Document.h"
32 #include "ElementIterator.h"
33 #include "Event.h"
34 #include "EventNames.h"
35 #include "HTMLElement.h"
36 #include "HTMLNames.h"
37 #include "HTMLParserIdioms.h"
38 #include "RenderObject.h"
39 #include "RenderSVGResource.h"
40 #include "RenderSVGResourceFilter.h"
41 #include "RenderSVGResourceMasker.h"
42 #include "SVGDocumentExtensions.h"
43 #include "SVGElementRareData.h"
44 #include "SVGGraphicsElement.h"
45 #include "SVGImageElement.h"
46 #include "SVGNames.h"
47 #include "SVGRenderStyle.h"
48 #include "SVGRenderSupport.h"
49 #include "SVGSVGElement.h"
50 #include "SVGTitleElement.h"
51 #include "SVGUseElement.h"
52 #include "ShadowRoot.h"
53 #include "XLinkNames.h"
54 #include "XMLNames.h"
55 #include <wtf/Assertions.h>
56 #include <wtf/HashMap.h>
57 #include <wtf/IsoMallocInlines.h>
58 #include <wtf/NeverDestroyed.h>
59 #include <wtf/StdLibExtras.h>
60 #include <wtf/text/WTFString.h>
61
62
63 namespace WebCore {
64
65 WTF_MAKE_ISO_ALLOCATED_IMPL(SVGElement);
66
67 // Animated property definitions
68 DEFINE_ANIMATED_STRING(SVGElement, HTMLNames::classAttr, ClassName, className)
69
70 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGElement)
71     REGISTER_LOCAL_ANIMATED_PROPERTY(className)
72 END_REGISTER_ANIMATED_PROPERTIES
73
74 static NEVER_INLINE HashMap<AtomicStringImpl*, CSSPropertyID> createAttributeNameToCSSPropertyIDMap()
75 {
76     using namespace HTMLNames;
77     using namespace SVGNames;
78
79     // This list should include all base CSS and SVG CSS properties which are exposed as SVG XML attributes.
80     static const QualifiedName* const attributeNames[] = {
81         &alignment_baselineAttr.get(),
82         &baseline_shiftAttr.get(),
83         &buffered_renderingAttr.get(),
84         &clipAttr.get(),
85         &clip_pathAttr.get(),
86         &clip_ruleAttr.get(),
87         &SVGNames::colorAttr.get(),
88         &color_interpolationAttr.get(),
89         &color_interpolation_filtersAttr.get(),
90         &color_profileAttr.get(),
91         &color_renderingAttr.get(),
92         &cursorAttr.get(),
93         &cxAttr.get(),
94         &cyAttr.get(),
95         &SVGNames::directionAttr.get(),
96         &displayAttr.get(),
97         &dominant_baselineAttr.get(),
98         &enable_backgroundAttr.get(),
99         &fillAttr.get(),
100         &fill_opacityAttr.get(),
101         &fill_ruleAttr.get(),
102         &filterAttr.get(),
103         &flood_colorAttr.get(),
104         &flood_opacityAttr.get(),
105         &font_familyAttr.get(),
106         &font_sizeAttr.get(),
107         &font_stretchAttr.get(),
108         &font_styleAttr.get(),
109         &font_variantAttr.get(),
110         &font_weightAttr.get(),
111         &glyph_orientation_horizontalAttr.get(),
112         &glyph_orientation_verticalAttr.get(),
113         &image_renderingAttr.get(),
114         &SVGNames::heightAttr.get(),
115         &kerningAttr.get(),
116         &letter_spacingAttr.get(),
117         &lighting_colorAttr.get(),
118         &marker_endAttr.get(),
119         &marker_midAttr.get(),
120         &marker_startAttr.get(),
121         &maskAttr.get(),
122         &mask_typeAttr.get(),
123         &opacityAttr.get(),
124         &overflowAttr.get(),
125         &paint_orderAttr.get(),
126         &pointer_eventsAttr.get(),
127         &rAttr.get(),
128         &rxAttr.get(),
129         &ryAttr.get(),
130         &shape_renderingAttr.get(),
131         &stop_colorAttr.get(),
132         &stop_opacityAttr.get(),
133         &strokeAttr.get(),
134         &stroke_dasharrayAttr.get(),
135         &stroke_dashoffsetAttr.get(),
136         &stroke_linecapAttr.get(),
137         &stroke_linejoinAttr.get(),
138         &stroke_miterlimitAttr.get(),
139         &stroke_opacityAttr.get(),
140         &stroke_widthAttr.get(),
141         &text_anchorAttr.get(),
142         &text_decorationAttr.get(),
143         &text_renderingAttr.get(),
144         &unicode_bidiAttr.get(),
145         &vector_effectAttr.get(),
146         &visibilityAttr.get(),
147         &SVGNames::widthAttr.get(),
148         &word_spacingAttr.get(),
149         &writing_modeAttr.get(),
150         &xAttr.get(),
151         &yAttr.get(),
152     };
153
154     HashMap<AtomicStringImpl*, CSSPropertyID> map;
155
156     for (auto& name : attributeNames) {
157         const AtomicString& localName = name->localName();
158         map.add(localName.impl(), cssPropertyID(localName));
159     }
160
161     // FIXME: When CSS supports "transform-origin" this special case can be removed,
162     // and we can add transform_originAttr to the table above instead.
163     map.add(transform_originAttr->localName().impl(), CSSPropertyTransformOrigin);
164
165     return map;
166 }
167
168 static NEVER_INLINE HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType> createAttributeNameToAnimatedPropertyTypeMap()
169 {
170     using namespace HTMLNames;
171     using namespace SVGNames;
172
173     struct TableEntry {
174         const QualifiedName& attributeName;
175         AnimatedPropertyType type;
176     };
177
178     static const TableEntry table[] = {
179         { alignment_baselineAttr, AnimatedString },
180         { baseline_shiftAttr, AnimatedString },
181         { buffered_renderingAttr, AnimatedString },
182         { clipAttr, AnimatedRect },
183         { clip_pathAttr, AnimatedString },
184         { clip_ruleAttr, AnimatedString },
185         { SVGNames::colorAttr, AnimatedColor },
186         { color_interpolationAttr, AnimatedString },
187         { color_interpolation_filtersAttr, AnimatedString },
188         { color_profileAttr, AnimatedString },
189         { color_renderingAttr, AnimatedString },
190         { cursorAttr, AnimatedString },
191         { displayAttr, AnimatedString },
192         { dominant_baselineAttr, AnimatedString },
193         { fillAttr, AnimatedColor },
194         { fill_opacityAttr, AnimatedNumber },
195         { fill_ruleAttr, AnimatedString },
196         { filterAttr, AnimatedString },
197         { flood_colorAttr, AnimatedColor },
198         { flood_opacityAttr, AnimatedNumber },
199         { font_familyAttr, AnimatedString },
200         { font_sizeAttr, AnimatedLength },
201         { font_stretchAttr, AnimatedString },
202         { font_styleAttr, AnimatedString },
203         { font_variantAttr, AnimatedString },
204         { font_weightAttr, AnimatedString },
205         { image_renderingAttr, AnimatedString },
206         { kerningAttr, AnimatedLength },
207         { letter_spacingAttr, AnimatedLength },
208         { lighting_colorAttr, AnimatedColor },
209         { marker_endAttr, AnimatedString },
210         { marker_midAttr, AnimatedString },
211         { marker_startAttr, AnimatedString },
212         { maskAttr, AnimatedString },
213         { mask_typeAttr, AnimatedString },
214         { opacityAttr, AnimatedNumber },
215         { overflowAttr, AnimatedString },
216         { paint_orderAttr, AnimatedString },
217         { pointer_eventsAttr, AnimatedString },
218         { shape_renderingAttr, AnimatedString },
219         { stop_colorAttr, AnimatedColor },
220         { stop_opacityAttr, AnimatedNumber },
221         { strokeAttr, AnimatedColor },
222         { stroke_dasharrayAttr, AnimatedLengthList },
223         { stroke_dashoffsetAttr, AnimatedLength },
224         { stroke_linecapAttr, AnimatedString },
225         { stroke_linejoinAttr, AnimatedString },
226         { stroke_miterlimitAttr, AnimatedNumber },
227         { stroke_opacityAttr, AnimatedNumber },
228         { stroke_widthAttr, AnimatedLength },
229         { text_anchorAttr, AnimatedString },
230         { text_decorationAttr, AnimatedString },
231         { text_renderingAttr, AnimatedString },
232         { vector_effectAttr, AnimatedString },
233         { visibilityAttr, AnimatedString },
234         { word_spacingAttr, AnimatedLength },
235     };
236
237     HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType> map;
238     for (auto& entry : table)
239         map.add(entry.attributeName.impl(), entry.type);
240     return map;
241 }
242
243 static const HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>& attributeNameToAnimatedPropertyTypeMap()
244 {
245     static const auto map = makeNeverDestroyed(createAttributeNameToAnimatedPropertyTypeMap());
246     return map;
247 }
248
249 static NEVER_INLINE HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType> createCSSPropertyWithSVGDOMNameToAnimatedPropertyTypeMap()
250 {
251     using namespace HTMLNames;
252     using namespace SVGNames;
253
254     struct TableEntry {
255         const QualifiedName& attributeName;
256         AnimatedPropertyType type;
257     };
258
259     static const TableEntry table[] = {
260         { cxAttr, AnimatedLength },
261         { cyAttr, AnimatedLength },
262         { rAttr, AnimatedLength },
263         { rxAttr, AnimatedLength },
264         { ryAttr, AnimatedLength },
265         { SVGNames::heightAttr, AnimatedLength },
266         { SVGNames::widthAttr, AnimatedLength },
267         { xAttr, AnimatedLength },
268         { yAttr, AnimatedLength },
269     };
270
271     HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType> map;
272     for (auto& entry : table)
273         map.add(entry.attributeName.impl(), entry.type);
274     return map;
275 }
276
277 static inline const HashMap<QualifiedName::QualifiedNameImpl*, AnimatedPropertyType>& cssPropertyWithSVGDOMNameToAnimatedPropertyTypeMap()
278 {
279     static const auto map = makeNeverDestroyed(createCSSPropertyWithSVGDOMNameToAnimatedPropertyTypeMap());
280     return map;
281 }
282
283 SVGElement::SVGElement(const QualifiedName& tagName, Document& document)
284     : StyledElement(tagName, document, CreateSVGElement)
285 {
286     registerAnimatedPropertiesForSVGElement();
287 }
288
289 SVGElement::~SVGElement()
290 {
291     if (m_svgRareData) {
292         for (SVGElement* instance : m_svgRareData->instances())
293             instance->m_svgRareData->setCorrespondingElement(nullptr);
294         if (auto correspondingElement = makeRefPtr(m_svgRareData->correspondingElement()))
295             correspondingElement->m_svgRareData->instances().remove(this);
296
297         m_svgRareData = nullptr;
298     }
299     document().accessSVGExtensions().rebuildAllElementReferencesForTarget(*this);
300     document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
301 }
302
303 int SVGElement::tabIndex() const
304 {
305     if (supportsFocus())
306         return Element::tabIndex();
307     return -1;
308 }
309
310 void SVGElement::willRecalcStyle(Style::Change change)
311 {
312     if (!m_svgRareData || styleResolutionShouldRecompositeLayer())
313         return;
314     // If the style changes because of a regular property change (not induced by SMIL animations themselves)
315     // reset the "computed style without SMIL style properties", so the base value change gets reflected.
316     if (change > Style::NoChange || needsStyleRecalc())
317         m_svgRareData->setNeedsOverrideComputedStyleUpdate();
318 }
319
320 SVGElementRareData& SVGElement::ensureSVGRareData()
321 {
322     if (!m_svgRareData)
323         m_svgRareData = std::make_unique<SVGElementRareData>();
324     return *m_svgRareData;
325 }
326
327 bool SVGElement::isOutermostSVGSVGElement() const
328 {
329     if (!is<SVGSVGElement>(*this))
330         return false;
331
332     // If we're living in a shadow tree, we're a <svg> element that got created as replacement
333     // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
334     // we're always an inner <svg> element.
335     if (isInShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
336         return false;
337
338     // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
339     if (!parentNode())
340         return true;
341
342     // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
343     if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
344         return true;
345
346     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
347     return !parentNode()->isSVGElement();
348 }
349
350 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
351 {
352     if (error == NoError)
353         return;
354
355     String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
356     SVGDocumentExtensions& extensions = document().accessSVGExtensions();
357
358     if (error == NegativeValueForbiddenError) {
359         extensions.reportError("Invalid negative value for " + errorString);
360         return;
361     }
362
363     if (error == ParsingAttributeFailedError) {
364         extensions.reportError("Invalid value for " + errorString);
365         return;
366     }
367
368     ASSERT_NOT_REACHED();
369 }
370
371 void SVGElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
372 {
373     if (removalType.disconnectedFromDocument)
374         updateRelativeLengthsInformation(false, this);
375
376     StyledElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
377
378     if (removalType.disconnectedFromDocument) {
379         document().accessSVGExtensions().clearTargetDependencies(*this);
380         document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
381     }
382     invalidateInstances();
383 }
384
385 SVGSVGElement* SVGElement::ownerSVGElement() const
386 {
387     ContainerNode* node = parentOrShadowHostNode();
388     while (node) {
389         if (is<SVGSVGElement>(*node))
390             return downcast<SVGSVGElement>(node);
391
392         node = node->parentOrShadowHostNode();
393     }
394
395     return nullptr;
396 }
397
398 SVGElement* SVGElement::viewportElement() const
399 {
400     // This function needs shadow tree support - as RenderSVGContainer uses this function
401     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
402     ContainerNode* node = parentOrShadowHostNode();
403     while (node) {
404         if (is<SVGSVGElement>(*node) || is<SVGImageElement>(*node) || node->hasTagName(SVGNames::symbolTag))
405             return downcast<SVGElement>(node);
406
407         node = node->parentOrShadowHostNode();
408     }
409
410     return nullptr;
411 }
412  
413 const HashSet<SVGElement*>& SVGElement::instances() const
414 {
415     if (!m_svgRareData) {
416         static NeverDestroyed<HashSet<SVGElement*>> emptyInstances;
417         return emptyInstances;
418     }
419     return m_svgRareData->instances();
420 }
421
422 bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
423 {
424     if (is<SVGGraphicsElement>(*this)) {
425         rect = downcast<SVGGraphicsElement>(*this).getBBox(styleUpdateStrategy);
426         return true;
427     }
428     return false;
429 }
430
431 SVGElement* SVGElement::correspondingElement() const
432 {
433     return m_svgRareData ? m_svgRareData->correspondingElement() : nullptr;
434 }
435
436 RefPtr<SVGUseElement> SVGElement::correspondingUseElement() const
437 {
438     auto* root = containingShadowRoot();
439     if (!root)
440         return nullptr;
441     if (root->mode() != ShadowRootMode::UserAgent)
442         return nullptr;
443     auto* host = root->host();
444     if (!is<SVGUseElement>(host))
445         return nullptr;
446     return &downcast<SVGUseElement>(*host);
447 }
448
449 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
450 {
451     if (m_svgRareData) {
452         if (auto oldCorrespondingElement = makeRefPtr(m_svgRareData->correspondingElement()))
453             oldCorrespondingElement->m_svgRareData->instances().remove(this);
454     }
455     if (m_svgRareData || correspondingElement)
456         ensureSVGRareData().setCorrespondingElement(correspondingElement);
457     if (correspondingElement)
458         correspondingElement->ensureSVGRareData().instances().add(this);
459 }
460
461 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
462 {
463     if (name == HTMLNames::classAttr) {
464         setClassNameBaseValue(value);
465         return;
466     }
467
468     if (name == HTMLNames::tabindexAttr) {
469         if (value.isEmpty())
470             clearTabIndexExplicitlyIfNeeded();
471         else if (auto optionalTabIndex = parseHTMLInteger(value))
472             setTabIndexExplicitly(optionalTabIndex.value());
473         return;
474     }
475
476     auto& eventName = HTMLElement::eventNameForEventHandlerAttribute(name);
477     if (!eventName.isNull()) {
478         setAttributeEventListener(eventName, name, value);
479         return;
480     }
481
482     SVGLangSpace::parseAttribute(name, value);
483 }
484
485 Vector<AnimatedPropertyType> SVGElement::animatedPropertyTypesForAttribute(const QualifiedName& attributeName)
486 {
487     auto types = localAttributeToPropertyMap().types(attributeName);
488     if (!types.isEmpty())
489         return types;
490
491     {
492         auto& map = attributeNameToAnimatedPropertyTypeMap();
493         auto it = map.find(attributeName.impl());
494         if (it != map.end()) {
495             types.append(it->value);
496             return types;
497         }
498     }
499
500     {
501         auto& map = cssPropertyWithSVGDOMNameToAnimatedPropertyTypeMap();
502         auto it = map.find(attributeName.impl());
503         if (it != map.end()) {
504             types.append(it->value);
505             return types;
506         }
507     }
508
509     return types;
510 }
511
512 bool SVGElement::haveLoadedRequiredResources()
513 {
514     for (auto& child : childrenOfType<SVGElement>(*this)) {
515         if (!child.haveLoadedRequiredResources())
516             return false;
517     }
518     return true;
519 }
520
521 bool SVGElement::addEventListener(const AtomicString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
522 {   
523     // Add event listener to regular DOM element
524     if (!Node::addEventListener(eventType, listener.copyRef(), options))
525         return false;
526
527     if (containingShadowRoot())
528         return true;
529
530     // Add event listener to all shadow tree DOM element instances
531     ASSERT(!instanceUpdatesBlocked());
532     for (auto* instance : instances()) {
533         ASSERT(instance->correspondingElement() == this);
534         bool result = instance->Node::addEventListener(eventType, listener.copyRef(), options);
535         ASSERT_UNUSED(result, result);
536     }
537
538     return true;
539 }
540
541 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener& listener, const ListenerOptions& options)
542 {
543     if (containingShadowRoot())
544         return Node::removeEventListener(eventType, listener, options);
545
546     // EventTarget::removeEventListener creates a Ref around the given EventListener
547     // object when creating a temporary RegisteredEventListener object used to look up the
548     // event listener in a cache. If we want to be able to call removeEventListener() multiple
549     // times on different nodes, we have to delay its immediate destruction, which would happen
550     // after the first call below.
551     Ref<EventListener> protector(listener);
552
553     // Remove event listener from regular DOM element
554     if (!Node::removeEventListener(eventType, listener, options))
555         return false;
556
557     // Remove event listener from all shadow tree DOM element instances
558     ASSERT(!instanceUpdatesBlocked());
559     for (auto& instance : instances()) {
560         ASSERT(instance->correspondingElement() == this);
561
562         if (instance->Node::removeEventListener(eventType, listener, options))
563             continue;
564
565         // This case can only be hit for event listeners created from markup
566         ASSERT(listener.wasCreatedFromMarkup());
567
568         // If the event listener 'listener' has been created from markup and has been fired before
569         // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
570         // has been created (read: it's not 0 anymore). During shadow tree creation, the event
571         // listener DOM attribute has been cloned, and another event listener has been setup in
572         // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
573         // and tryRemoveEventListener() above will fail. Work around that very rare problem.
574         ASSERT(instance->eventTargetData());
575         instance->eventTargetData()->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
576     }
577
578     return true;
579 }
580
581 static bool hasLoadListener(Element* element)
582 {
583     if (element->hasEventListeners(eventNames().loadEvent))
584         return true;
585
586     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
587         if (element->hasCapturingEventListeners(eventNames().loadEvent))
588             return true;
589     }
590
591     return false;
592 }
593
594 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
595 {
596     if (!isConnected() || !document().frame())
597         return;
598
599     RefPtr<SVGElement> currentTarget = this;
600     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
601         RefPtr<Element> parent;
602         if (sendParentLoadEvents)
603             parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
604         if (hasLoadListener(currentTarget.get()))
605             currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
606         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
607         SVGElement* element = currentTarget.get();
608         if (!element || !element->isOutermostSVGSVGElement())
609             continue;
610
611         // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
612         // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
613         // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
614         ASSERT(sendParentLoadEvents);
615
616         // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
617         // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
618         // to be "ready to render", first.
619         if (!document().loadEventFinished())
620             break;
621     }
622 }
623
624 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
625 {
626     svgLoadEventTimer()->startOneShot(0_s);
627 }
628
629 void SVGElement::svgLoadEventTimerFired()
630 {
631     sendSVGLoadEventIfPossible();
632 }
633
634 Timer* SVGElement::svgLoadEventTimer()
635 {
636     ASSERT_NOT_REACHED();
637     return nullptr;
638 }
639
640 void SVGElement::finishParsingChildren()
641 {
642     StyledElement::finishParsingChildren();
643
644     // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
645     if (isOutermostSVGSVGElement())
646         return;
647
648     // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
649     // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
650     sendSVGLoadEventIfPossible();
651
652     // Notify all the elements which have references to this element to rebuild their shadow and render
653     // trees, e.g. a <use> element references a target element before this target element is defined.
654     invalidateInstances();
655 }
656
657 bool SVGElement::childShouldCreateRenderer(const Node& child) const
658 {
659     if (!child.isSVGElement())
660         return false;
661     auto& svgChild = downcast<SVGElement>(child);
662
663     static const QualifiedName* const invalidTextContent[] {
664 #if ENABLE(SVG_FONTS)
665         &SVGNames::altGlyphTag.get(),
666 #endif
667         &SVGNames::textPathTag.get(),
668         &SVGNames::trefTag.get(),
669         &SVGNames::tspanTag.get(),
670     };
671     auto& name = svgChild.localName();
672     for (auto* tag : invalidTextContent) {
673         if (name == tag->localName())
674             return false;
675     }
676
677     return svgChild.isValid();
678 }
679
680 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason)
681 {
682     StyledElement::attributeChanged(name, oldValue, newValue);
683
684     if (name == HTMLNames::idAttr)
685         document().accessSVGExtensions().rebuildAllElementReferencesForTarget(*this);
686
687     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
688     // so we don't want changes to the style attribute to result in extra work here.
689     if (name != HTMLNames::styleAttr)
690         svgAttributeChanged(name);
691 }
692
693 void SVGElement::synchronizeAllAnimatedSVGAttribute(SVGElement* svgElement)
694 {
695     ASSERT(svgElement->elementData());
696     ASSERT(svgElement->elementData()->animatedSVGAttributesAreDirty());
697
698     svgElement->localAttributeToPropertyMap().synchronizeProperties(*svgElement);
699     svgElement->elementData()->setAnimatedSVGAttributesAreDirty(false);
700 }
701
702 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
703 {
704     if (!elementData() || !elementData()->animatedSVGAttributesAreDirty())
705         return;
706
707     SVGElement* nonConstThis = const_cast<SVGElement*>(this);
708     if (name == anyQName())
709         synchronizeAllAnimatedSVGAttribute(nonConstThis);
710     else
711         nonConstThis->localAttributeToPropertyMap().synchronizeProperty(*nonConstThis, name);
712 }
713
714 void SVGElement::synchronizeRequiredFeatures(SVGElement* contextElement)
715 {
716     ASSERT(contextElement);
717     contextElement->synchronizeRequiredFeatures();
718 }
719
720 void SVGElement::synchronizeRequiredExtensions(SVGElement* contextElement)
721 {
722     ASSERT(contextElement);
723     contextElement->synchronizeRequiredExtensions();
724 }
725
726 void SVGElement::synchronizeSystemLanguage(SVGElement* contextElement)
727 {
728     ASSERT(contextElement);
729     contextElement->synchronizeSystemLanguage();
730 }
731
732 std::optional<ElementStyle> SVGElement::resolveCustomStyle(const RenderStyle& parentStyle, const RenderStyle*)
733 {
734     // If the element is in a <use> tree we get the style from the definition tree.
735     if (auto styleElement = makeRefPtr(this->correspondingElement())) {
736         std::optional<ElementStyle> style = styleElement->resolveStyle(&parentStyle);
737         StyleResolver::adjustSVGElementStyle(*this, *style->renderStyle);
738         return style;
739     }
740
741     return resolveStyle(&parentStyle);
742 }
743
744 MutableStyleProperties* SVGElement::animatedSMILStyleProperties() const
745 {
746     if (m_svgRareData)
747         return m_svgRareData->animatedSMILStyleProperties();
748     return 0;
749 }
750
751 MutableStyleProperties& SVGElement::ensureAnimatedSMILStyleProperties()
752 {
753     return ensureSVGRareData().ensureAnimatedSMILStyleProperties();
754 }
755
756 void SVGElement::setUseOverrideComputedStyle(bool value)
757 {
758     if (m_svgRareData)
759         m_svgRareData->setUseOverrideComputedStyle(value);
760 }
761
762 const RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
763 {
764     if (!m_svgRareData || !m_svgRareData->useOverrideComputedStyle())
765         return Element::computedStyle(pseudoElementSpecifier);
766
767     const RenderStyle* parentStyle = nullptr;
768     if (auto parent = makeRefPtr(parentOrShadowHostElement())) {
769         if (auto renderer = parent->renderer())
770             parentStyle = &renderer->style();
771     }
772
773     return m_svgRareData->overrideComputedStyle(*this, parentStyle);
774 }
775
776 QualifiedName SVGElement::animatableAttributeForName(const AtomicString& localName)
777 {
778     static const auto animatableAttributes = makeNeverDestroyed([] {
779         static const QualifiedName* const names[] = {
780             &HTMLNames::classAttr.get(),
781             &SVGNames::amplitudeAttr.get(),
782             &SVGNames::azimuthAttr.get(),
783             &SVGNames::baseFrequencyAttr.get(),
784             &SVGNames::biasAttr.get(),
785             &SVGNames::clipPathUnitsAttr.get(),
786             &SVGNames::cxAttr.get(),
787             &SVGNames::cyAttr.get(),
788             &SVGNames::diffuseConstantAttr.get(),
789             &SVGNames::divisorAttr.get(),
790             &SVGNames::dxAttr.get(),
791             &SVGNames::dyAttr.get(),
792             &SVGNames::edgeModeAttr.get(),
793             &SVGNames::elevationAttr.get(),
794             &SVGNames::exponentAttr.get(),
795             &SVGNames::externalResourcesRequiredAttr.get(),
796             &SVGNames::filterResAttr.get(),
797             &SVGNames::filterUnitsAttr.get(),
798             &SVGNames::fxAttr.get(),
799             &SVGNames::fyAttr.get(),
800             &SVGNames::gradientTransformAttr.get(),
801             &SVGNames::gradientUnitsAttr.get(),
802             &SVGNames::heightAttr.get(),
803             &SVGNames::in2Attr.get(),
804             &SVGNames::inAttr.get(),
805             &SVGNames::interceptAttr.get(),
806             &SVGNames::k1Attr.get(),
807             &SVGNames::k2Attr.get(),
808             &SVGNames::k3Attr.get(),
809             &SVGNames::k4Attr.get(),
810             &SVGNames::kernelMatrixAttr.get(),
811             &SVGNames::kernelUnitLengthAttr.get(),
812             &SVGNames::lengthAdjustAttr.get(),
813             &SVGNames::limitingConeAngleAttr.get(),
814             &SVGNames::markerHeightAttr.get(),
815             &SVGNames::markerUnitsAttr.get(),
816             &SVGNames::markerWidthAttr.get(),
817             &SVGNames::maskContentUnitsAttr.get(),
818             &SVGNames::maskUnitsAttr.get(),
819             &SVGNames::methodAttr.get(),
820             &SVGNames::modeAttr.get(),
821             &SVGNames::numOctavesAttr.get(),
822             &SVGNames::offsetAttr.get(),
823             &SVGNames::operatorAttr.get(),
824             &SVGNames::orderAttr.get(),
825             &SVGNames::orientAttr.get(),
826             &SVGNames::pathLengthAttr.get(),
827             &SVGNames::patternContentUnitsAttr.get(),
828             &SVGNames::patternTransformAttr.get(),
829             &SVGNames::patternUnitsAttr.get(),
830             &SVGNames::pointsAtXAttr.get(),
831             &SVGNames::pointsAtYAttr.get(),
832             &SVGNames::pointsAtZAttr.get(),
833             &SVGNames::preserveAlphaAttr.get(),
834             &SVGNames::preserveAspectRatioAttr.get(),
835             &SVGNames::primitiveUnitsAttr.get(),
836             &SVGNames::radiusAttr.get(),
837             &SVGNames::rAttr.get(),
838             &SVGNames::refXAttr.get(),
839             &SVGNames::refYAttr.get(),
840             &SVGNames::resultAttr.get(),
841             &SVGNames::rotateAttr.get(),
842             &SVGNames::rxAttr.get(),
843             &SVGNames::ryAttr.get(),
844             &SVGNames::scaleAttr.get(),
845             &SVGNames::seedAttr.get(),
846             &SVGNames::slopeAttr.get(),
847             &SVGNames::spacingAttr.get(),
848             &SVGNames::specularConstantAttr.get(),
849             &SVGNames::specularExponentAttr.get(),
850             &SVGNames::spreadMethodAttr.get(),
851             &SVGNames::startOffsetAttr.get(),
852             &SVGNames::stdDeviationAttr.get(),
853             &SVGNames::stitchTilesAttr.get(),
854             &SVGNames::surfaceScaleAttr.get(),
855             &SVGNames::tableValuesAttr.get(),
856             &SVGNames::targetAttr.get(),
857             &SVGNames::targetXAttr.get(),
858             &SVGNames::targetYAttr.get(),
859             &SVGNames::transformAttr.get(),
860             &SVGNames::typeAttr.get(),
861             &SVGNames::valuesAttr.get(),
862             &SVGNames::viewBoxAttr.get(),
863             &SVGNames::widthAttr.get(),
864             &SVGNames::x1Attr.get(),
865             &SVGNames::x2Attr.get(),
866             &SVGNames::xAttr.get(),
867             &SVGNames::xChannelSelectorAttr.get(),
868             &SVGNames::y1Attr.get(),
869             &SVGNames::y2Attr.get(),
870             &SVGNames::yAttr.get(),
871             &SVGNames::yChannelSelectorAttr.get(),
872             &SVGNames::zAttr.get(),
873             &XLinkNames::hrefAttr.get(),
874         };
875         HashMap<AtomicString, QualifiedName> map;
876         for (auto& name : names) {
877             auto addResult = map.add(name->localName(), *name);
878             ASSERT_UNUSED(addResult, addResult.isNewEntry);
879         }
880         return map;
881     }());
882     return animatableAttributes.get().get(localName);
883 }
884
885 #ifndef NDEBUG
886
887 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
888 {
889     if (animatableAttributeForName(name.localName()) == name)
890         return !filterOutAnimatableAttribute(name);
891     return false;
892 }
893
894 bool SVGElement::filterOutAnimatableAttribute(const QualifiedName&) const
895 {
896     return false;
897 }
898
899 #endif
900
901 String SVGElement::title() const
902 {
903     // According to spec, for stand-alone SVG documents we should not return a title when
904     // hovering over the rootmost SVG element (the first <title> element is the title of
905     // the document, not a tooltip) so we instantly return.
906     if (isOutermostSVGSVGElement() && document().topDocument().isSVGDocument())
907         return String();
908     auto firstTitle = childrenOfType<SVGTitleElement>(*this).first();
909     return firstTitle ? const_cast<SVGTitleElement*>(firstTitle)->innerText() : String();
910 }
911
912 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
913 {
914     // http://www.w3.org/TR/SVG/extend.html#PrivateData
915     // Prevent anything other than SVG renderers from appearing in our render tree
916     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
917     // with the SVG content. In general, the SVG user agent will include the unknown
918     // elements in the DOM but will otherwise ignore unknown elements.
919     if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement())
920         return StyledElement::rendererIsNeeded(style);
921
922     return false;
923 }
924
925 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
926 {
927     if (!attrName.namespaceURI().isNull())
928         return CSSPropertyInvalid;
929
930     static const auto properties = makeNeverDestroyed(createAttributeNameToCSSPropertyIDMap());
931     return properties.get().get(attrName.localName().impl());
932 }
933
934 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attributeName)
935 {
936     return attributeNameToAnimatedPropertyTypeMap().contains(attributeName.impl())
937         || cssPropertyWithSVGDOMNameToAnimatedPropertyTypeMap().contains(attributeName.impl());
938 }
939
940 bool SVGElement::isPresentationAttributeWithSVGDOM(const QualifiedName& attributeName)
941 {
942     return !localAttributeToPropertyMap().types(attributeName).isEmpty();
943 }
944
945 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
946 {
947     if (cssPropertyIdForSVGAttributeName(name) > 0)
948         return true;
949     return StyledElement::isPresentationAttribute(name);
950 }
951
952 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStyleProperties& style)
953 {
954     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
955     if (propertyID > 0)
956         addPropertyToPresentationAttributeStyle(style, propertyID, value);
957 }
958
959 bool SVGElement::isKnownAttribute(const QualifiedName& attrName)
960 {
961     return attrName == HTMLNames::idAttr;
962 }
963
964 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
965 {
966     CSSPropertyID propId = cssPropertyIdForSVGAttributeName(attrName);
967     if (propId > 0) {
968         invalidateInstances();
969         return;
970     }
971
972     if (attrName == HTMLNames::classAttr) {
973         classAttributeChanged(className());
974         invalidateInstances();
975         return;
976     }
977
978     if (attrName == HTMLNames::idAttr) {
979         auto renderer = this->renderer();
980         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
981         if (is<RenderSVGResourceContainer>(renderer))
982             downcast<RenderSVGResourceContainer>(*renderer).idChanged();
983         if (isConnected())
984             buildPendingResourcesIfNeeded();
985         invalidateInstances();
986         return;
987     }
988 }
989
990 Node::InsertedIntoAncestorResult SVGElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
991 {
992     StyledElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
993     updateRelativeLengthsInformation();
994     buildPendingResourcesIfNeeded();
995     return InsertedIntoAncestorResult::Done;
996 }
997
998 void SVGElement::buildPendingResourcesIfNeeded()
999 {
1000     if (!needsPendingResourceHandling() || !isConnected() || isInShadowTree())
1001         return;
1002
1003     SVGDocumentExtensions& extensions = document().accessSVGExtensions();
1004     String resourceId = getIdAttribute();
1005     if (!extensions.isIdOfPendingResource(resourceId))
1006         return;
1007
1008     // Mark pending resources as pending for removal.
1009     extensions.markPendingResourcesForRemoval(resourceId);
1010
1011     // Rebuild pending resources for each client of a pending resource that is being removed.
1012     while (auto clientElement = extensions.removeElementFromPendingResourcesForRemovalMap(resourceId)) {
1013         ASSERT(clientElement->hasPendingResources());
1014         if (clientElement->hasPendingResources()) {
1015             clientElement->buildPendingResource();
1016             extensions.clearHasPendingResourcesIfPossible(clientElement.get());
1017         }
1018     }
1019 }
1020
1021 void SVGElement::childrenChanged(const ChildChange& change)
1022 {
1023     StyledElement::childrenChanged(change);
1024
1025     if (change.source == ChildChangeSource::Parser)
1026         return;
1027     invalidateInstances();
1028 }
1029
1030 RefPtr<DeprecatedCSSOMValue> SVGElement::getPresentationAttribute(const String& name)
1031 {
1032     if (!hasAttributesWithoutUpdate())
1033         return 0;
1034
1035     QualifiedName attributeName(nullAtom(), name, nullAtom());
1036     const Attribute* attribute = findAttributeByName(attributeName);
1037     if (!attribute)
1038         return 0;
1039
1040     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create(SVGAttributeMode);
1041     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(attribute->name());
1042     style->setProperty(propertyID, attribute->value());
1043     auto cssValue = style->getPropertyCSSValue(propertyID);
1044     if (!cssValue)
1045         return nullptr;
1046     return cssValue->createDeprecatedCSSOMWrapper(style->ensureCSSStyleDeclaration());
1047 }
1048
1049 bool SVGElement::instanceUpdatesBlocked() const
1050 {
1051     return m_svgRareData && m_svgRareData->instanceUpdatesBlocked();
1052 }
1053
1054 void SVGElement::setInstanceUpdatesBlocked(bool value)
1055 {
1056     // Catch any callers that calls setInstanceUpdatesBlocked(true) twice in a row.
1057     // That probably indicates nested use of InstanceUpdateBlocker and a bug.
1058     ASSERT(!value || !instanceUpdatesBlocked());
1059
1060     if (m_svgRareData)
1061         m_svgRareData->setInstanceUpdatesBlocked(value);
1062 }
1063
1064 AffineTransform SVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
1065 {
1066     // To be overridden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
1067     return AffineTransform();
1068 }
1069
1070 void SVGElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement* element)
1071 {
1072     // If we're not yet in a document, this function will be called again from insertedIntoAncestor(). Do nothing now.
1073     if (!isConnected())
1074         return;
1075
1076     // An element wants to notify us that its own relative lengths state changed.
1077     // Register it in the relative length map, and register us in the parent relative length map.
1078     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
1079
1080     if (hasRelativeLengths)
1081         m_elementsWithRelativeLengths.add(element);
1082     else {
1083         if (!m_elementsWithRelativeLengths.contains(element)) {
1084             // We were never registered. Do nothing.
1085             return;
1086         }
1087
1088         m_elementsWithRelativeLengths.remove(element);
1089     }
1090
1091     if (!element->isSVGGraphicsElement())
1092         return;
1093
1094     // Find first styled parent node, and notify it that we've changed our relative length state.
1095     auto node = makeRefPtr(parentNode());
1096     while (node) {
1097         if (!node->isSVGElement())
1098             break;
1099
1100         // Register us in the parent element map.
1101         downcast<SVGElement>(*node).updateRelativeLengthsInformation(hasRelativeLengths, this);
1102         break;
1103     }
1104 }
1105
1106 bool SVGElement::hasFocusEventListeners() const
1107 {
1108     Element* eventTarget = const_cast<SVGElement*>(this);
1109     return eventTarget->hasEventListeners(eventNames().focusinEvent)
1110         || eventTarget->hasEventListeners(eventNames().focusoutEvent)
1111         || eventTarget->hasEventListeners(eventNames().focusEvent)
1112         || eventTarget->hasEventListeners(eventNames().blurEvent);
1113 }
1114
1115 bool SVGElement::isMouseFocusable() const
1116 {
1117     if (!isFocusable())
1118         return false;
1119     Element* eventTarget = const_cast<SVGElement*>(this);
1120     return hasFocusEventListeners()
1121         || eventTarget->hasEventListeners(eventNames().keydownEvent)
1122         || eventTarget->hasEventListeners(eventNames().keyupEvent)
1123         || eventTarget->hasEventListeners(eventNames().keypressEvent);
1124 }
1125     
1126 void SVGElement::accessKeyAction(bool sendMouseEvents)
1127 {
1128     dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
1129 }
1130
1131 void SVGElement::invalidateInstances()
1132 {
1133     if (instanceUpdatesBlocked())
1134         return;
1135
1136     auto& instances = this->instances();
1137     while (!instances.isEmpty()) {
1138         auto instance = makeRefPtr(*instances.begin());
1139         if (auto useElement = instance->correspondingUseElement())
1140             useElement->invalidateShadowTree();
1141         instance->setCorrespondingElement(nullptr);
1142     } while (!instances.isEmpty());
1143 }
1144
1145 }