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