SVG element should become focusable when focus and key event listeners are added
[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-2019 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 "SVGPropertyAnimatorFactory.h"
48 #include "SVGRenderStyle.h"
49 #include "SVGRenderSupport.h"
50 #include "SVGSVGElement.h"
51 #include "SVGTitleElement.h"
52 #include "SVGUseElement.h"
53 #include "ShadowRoot.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<AtomStringImpl*, 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<AtomStringImpl*, CSSPropertyID> map;
148
149     for (auto& name : attributeNames) {
150         const AtomString& 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 SVGElement::SVGElement(const QualifiedName& tagName, Document& document)
162     : StyledElement(tagName, document, CreateSVGElement)
163     , SVGLangSpace(this)
164     , m_propertyAnimatorFactory(makeUnique<SVGPropertyAnimatorFactory>())
165 {
166     static std::once_flag onceFlag;
167     std::call_once(onceFlag, [] {
168         PropertyRegistry::registerProperty<HTMLNames::classAttr, &SVGElement::m_className>();
169     });
170 }
171
172 SVGElement::~SVGElement()
173 {
174     if (m_svgRareData) {
175         for (SVGElement* instance : m_svgRareData->instances())
176             instance->m_svgRareData->setCorrespondingElement(nullptr);
177         if (auto correspondingElement = makeRefPtr(m_svgRareData->correspondingElement()))
178             correspondingElement->m_svgRareData->instances().remove(this);
179
180         m_svgRareData = nullptr;
181     }
182     document().accessSVGExtensions().rebuildAllElementReferencesForTarget(*this);
183     document().accessSVGExtensions().removeAllElementReferencesForTarget(*this);
184 }
185
186 void SVGElement::willRecalcStyle(Style::Change change)
187 {
188     if (!m_svgRareData || styleResolutionShouldRecompositeLayer())
189         return;
190     // If the style changes because of a regular property change (not induced by SMIL animations themselves)
191     // reset the "computed style without SMIL style properties", so the base value change gets reflected.
192     if (change > Style::NoChange || needsStyleRecalc())
193         m_svgRareData->setNeedsOverrideComputedStyleUpdate();
194 }
195
196 SVGElementRareData& SVGElement::ensureSVGRareData()
197 {
198     if (!m_svgRareData)
199         m_svgRareData = makeUnique<SVGElementRareData>();
200     return *m_svgRareData;
201 }
202
203 bool SVGElement::isOutermostSVGSVGElement() const
204 {
205     if (!is<SVGSVGElement>(*this))
206         return false;
207
208     // If we're living in a shadow tree, we're a <svg> element that got created as replacement
209     // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
210     // we're always an inner <svg> element.
211     if (isInShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
212         return false;
213
214     // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
215     if (!parentNode())
216         return true;
217
218     // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
219     if (parentNode()->hasTagName(SVGNames::foreignObjectTag))
220         return true;
221
222     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
223     return !parentNode()->isSVGElement();
224 }
225
226 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomString& value)
227 {
228     if (error == NoError)
229         return;
230
231     String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
232     SVGDocumentExtensions& extensions = document().accessSVGExtensions();
233
234     if (error == NegativeValueForbiddenError) {
235         extensions.reportError("Invalid negative value for " + errorString);
236         return;
237     }
238
239     if (error == ParsingAttributeFailedError) {
240         extensions.reportError("Invalid value for " + errorString);
241         return;
242     }
243
244     ASSERT_NOT_REACHED();
245 }
246
247 void SVGElement::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
248 {
249     if (removalType.disconnectedFromDocument)
250         updateRelativeLengthsInformation(false, this);
251
252     StyledElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
253
254     if (removalType.disconnectedFromDocument) {
255         document().accessSVGExtensions().clearTargetDependencies(*this);
256         document().accessSVGExtensions().removeAllElementReferencesForTarget(*this);
257     }
258     invalidateInstances();
259 }
260
261 SVGSVGElement* SVGElement::ownerSVGElement() const
262 {
263     ContainerNode* node = parentOrShadowHostNode();
264     while (node) {
265         if (is<SVGSVGElement>(*node))
266             return downcast<SVGSVGElement>(node);
267
268         node = node->parentOrShadowHostNode();
269     }
270
271     return nullptr;
272 }
273
274 SVGElement* SVGElement::viewportElement() const
275 {
276     // This function needs shadow tree support - as RenderSVGContainer uses this function
277     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
278     ContainerNode* node = parentOrShadowHostNode();
279     while (node) {
280         if (is<SVGSVGElement>(*node) || is<SVGImageElement>(*node) || node->hasTagName(SVGNames::symbolTag))
281             return downcast<SVGElement>(node);
282
283         node = node->parentOrShadowHostNode();
284     }
285
286     return nullptr;
287 }
288  
289 const HashSet<SVGElement*>& SVGElement::instances() const
290 {
291     if (!m_svgRareData) {
292         static NeverDestroyed<HashSet<SVGElement*>> emptyInstances;
293         return emptyInstances;
294     }
295     return m_svgRareData->instances();
296 }
297
298 bool SVGElement::getBoundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
299 {
300     if (is<SVGGraphicsElement>(*this)) {
301         rect = downcast<SVGGraphicsElement>(*this).getBBox(styleUpdateStrategy);
302         return true;
303     }
304     return false;
305 }
306
307 SVGElement* SVGElement::correspondingElement() const
308 {
309     return m_svgRareData ? m_svgRareData->correspondingElement() : nullptr;
310 }
311
312 RefPtr<SVGUseElement> SVGElement::correspondingUseElement() const
313 {
314     auto* root = containingShadowRoot();
315     if (!root)
316         return nullptr;
317     if (root->mode() != ShadowRootMode::UserAgent)
318         return nullptr;
319     auto* host = root->host();
320     if (!is<SVGUseElement>(host))
321         return nullptr;
322     return &downcast<SVGUseElement>(*host);
323 }
324
325 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
326 {
327     if (m_svgRareData) {
328         if (auto oldCorrespondingElement = makeRefPtr(m_svgRareData->correspondingElement()))
329             oldCorrespondingElement->m_svgRareData->instances().remove(this);
330     }
331     if (m_svgRareData || correspondingElement)
332         ensureSVGRareData().setCorrespondingElement(correspondingElement);
333     if (correspondingElement)
334         correspondingElement->ensureSVGRareData().instances().add(this);
335 }
336
337 void SVGElement::parseAttribute(const QualifiedName& name, const AtomString& value)
338 {
339     if (name == HTMLNames::classAttr) {
340         m_className->setBaseValInternal(value);
341         return;
342     }
343
344     if (name == HTMLNames::tabindexAttr) {
345         if (value.isEmpty())
346             clearTabIndexExplicitlyIfNeeded();
347         else if (auto optionalTabIndex = parseHTMLInteger(value))
348             setTabIndexExplicitly(optionalTabIndex.value());
349         return;
350     }
351
352     auto& eventName = HTMLElement::eventNameForEventHandlerAttribute(name);
353     if (!eventName.isNull()) {
354         setAttributeEventListener(eventName, name, value);
355         return;
356     }
357
358     SVGLangSpace::parseAttribute(name, value);
359 }
360
361 bool SVGElement::haveLoadedRequiredResources()
362 {
363     for (auto& child : childrenOfType<SVGElement>(*this)) {
364         if (!child.haveLoadedRequiredResources())
365             return false;
366     }
367     return true;
368 }
369
370 bool SVGElement::addEventListener(const AtomString& eventType, Ref<EventListener>&& listener, const AddEventListenerOptions& options)
371 {   
372     // Add event listener to regular DOM element
373     if (!Node::addEventListener(eventType, listener.copyRef(), options))
374         return false;
375
376     if (containingShadowRoot())
377         return true;
378
379     // Add event listener to all shadow tree DOM element instances
380     ASSERT(!instanceUpdatesBlocked());
381     for (auto* instance : instances()) {
382         ASSERT(instance->correspondingElement() == this);
383         bool result = instance->Node::addEventListener(eventType, listener.copyRef(), options);
384         ASSERT_UNUSED(result, result);
385     }
386
387     return true;
388 }
389
390 bool SVGElement::removeEventListener(const AtomString& eventType, EventListener& listener, const ListenerOptions& options)
391 {
392     if (containingShadowRoot())
393         return Node::removeEventListener(eventType, listener, options);
394
395     // EventTarget::removeEventListener creates a Ref around the given EventListener
396     // object when creating a temporary RegisteredEventListener object used to look up the
397     // event listener in a cache. If we want to be able to call removeEventListener() multiple
398     // times on different nodes, we have to delay its immediate destruction, which would happen
399     // after the first call below.
400     Ref<EventListener> protector(listener);
401
402     // Remove event listener from regular DOM element
403     if (!Node::removeEventListener(eventType, listener, options))
404         return false;
405
406     // Remove event listener from all shadow tree DOM element instances
407     ASSERT(!instanceUpdatesBlocked());
408     for (auto& instance : instances()) {
409         ASSERT(instance->correspondingElement() == this);
410
411         if (instance->Node::removeEventListener(eventType, listener, options))
412             continue;
413
414         // This case can only be hit for event listeners created from markup
415         ASSERT(listener.wasCreatedFromMarkup());
416
417         // If the event listener 'listener' has been created from markup and has been fired before
418         // then JSLazyEventListener::parseCode() has been called and m_jsFunction of that listener
419         // has been created (read: it's not 0 anymore). During shadow tree creation, the event
420         // listener DOM attribute has been cloned, and another event listener has been setup in
421         // the shadow tree. If that event listener has not been used yet, m_jsFunction is still 0,
422         // and tryRemoveEventListener() above will fail. Work around that very rare problem.
423         ASSERT(instance->eventTargetData());
424         instance->eventTargetData()->eventListenerMap.removeFirstEventListenerCreatedFromMarkup(eventType);
425     }
426
427     return true;
428 }
429
430 static bool hasLoadListener(Element* element)
431 {
432     if (element->hasEventListeners(eventNames().loadEvent))
433         return true;
434
435     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
436         if (element->hasCapturingEventListeners(eventNames().loadEvent))
437             return true;
438     }
439
440     return false;
441 }
442
443 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
444 {
445     if (!isConnected() || !document().frame())
446         return;
447
448     RefPtr<SVGElement> currentTarget = this;
449     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
450         RefPtr<Element> parent;
451         if (sendParentLoadEvents)
452             parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
453         if (hasLoadListener(currentTarget.get()))
454             currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, Event::CanBubble::No, Event::IsCancelable::No));
455         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
456         SVGElement* element = currentTarget.get();
457         if (!element || !element->isOutermostSVGSVGElement())
458             continue;
459
460         // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
461         // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
462         // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
463         ASSERT(sendParentLoadEvents);
464
465         // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
466         // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
467         // to be "ready to render", first.
468         if (!document().loadEventFinished())
469             break;
470     }
471 }
472
473 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
474 {
475     svgLoadEventTimer()->startOneShot(0_s);
476 }
477
478 void SVGElement::svgLoadEventTimerFired()
479 {
480     sendSVGLoadEventIfPossible();
481 }
482
483 Timer* SVGElement::svgLoadEventTimer()
484 {
485     ASSERT_NOT_REACHED();
486     return nullptr;
487 }
488
489 void SVGElement::finishParsingChildren()
490 {
491     StyledElement::finishParsingChildren();
492
493     // The outermost SVGSVGElement SVGLoad event is fired through Document::dispatchWindowLoadEvent.
494     if (isOutermostSVGSVGElement())
495         return;
496
497     // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
498     // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
499     sendSVGLoadEventIfPossible();
500
501     // Notify all the elements which have references to this element to rebuild their shadow and render
502     // trees, e.g. a <use> element references a target element before this target element is defined.
503     invalidateInstances();
504 }
505
506 bool SVGElement::childShouldCreateRenderer(const Node& child) const
507 {
508     if (!child.isSVGElement())
509         return false;
510     auto& svgChild = downcast<SVGElement>(child);
511
512     static const QualifiedName* const invalidTextContent[] {
513 #if ENABLE(SVG_FONTS)
514         &SVGNames::altGlyphTag.get(),
515 #endif
516         &SVGNames::textPathTag.get(),
517         &SVGNames::trefTag.get(),
518         &SVGNames::tspanTag.get(),
519     };
520     auto& name = svgChild.localName();
521     for (auto* tag : invalidTextContent) {
522         if (name == tag->localName())
523             return false;
524     }
525
526     return svgChild.isValid();
527 }
528
529 void SVGElement::attributeChanged(const QualifiedName& name, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason)
530 {
531     StyledElement::attributeChanged(name, oldValue, newValue);
532
533     if (name == HTMLNames::idAttr)
534         document().accessSVGExtensions().rebuildAllElementReferencesForTarget(*this);
535
536     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
537     // so we don't want changes to the style attribute to result in extra work here except invalidateInstances().
538     if (name == HTMLNames::styleAttr)
539         invalidateInstances();
540     else
541         svgAttributeChanged(name);
542 }
543
544 void SVGElement::synchronizeAttribute(const QualifiedName& name)
545 {
546     // If the value of the property has changed, serialize the new value to the attribute.
547     if (auto value = propertyRegistry().synchronize(name))
548         setSynchronizedLazyAttribute(name, *value);
549 }
550     
551 void SVGElement::synchronizeAllAttributes()
552 {
553     // SVGPropertyRegistry::synchronizeAllAttributes() returns the new values of
554     // the properties which have changed but not committed yet.
555     auto map = propertyRegistry().synchronizeAllAttributes();
556     for (const auto& entry : map)
557         setSynchronizedLazyAttribute(entry.key, entry.value);
558 }
559
560 void SVGElement::synchronizeAllAnimatedSVGAttribute(SVGElement& svgElement)
561 {
562     svgElement.synchronizeAllAttributes();
563 }
564
565 void SVGElement::commitPropertyChange(SVGProperty* property)
566 {
567     // We want to dirty the top-level property when a descendant changes. For example
568     // a change in an SVGLength item in SVGLengthList should set the dirty flag on
569     // SVGLengthList and not the SVGLength.
570     property->setDirty();
571
572     invalidateSVGAttributes();
573     svgAttributeChanged(propertyRegistry().propertyAttributeName(*property));
574 }
575
576 void SVGElement::commitPropertyChange(SVGAnimatedProperty& animatedProperty)
577 {
578     QualifiedName attributeName = propertyRegistry().animatedPropertyAttributeName(animatedProperty);
579     ASSERT(attributeName != nullQName());
580
581     // A change in a style property, e.g SVGRectElement::x should be serialized to
582     // the attribute immediately. Otherwise it is okay to be lazy in this regard.
583     if (!propertyRegistry().isAnimatedStylePropertyAttribute(attributeName))
584         animatedProperty.setDirty();
585     else
586         setSynchronizedLazyAttribute(attributeName, animatedProperty.baseValAsString());
587
588     invalidateSVGAttributes();
589     svgAttributeChanged(attributeName);
590 }
591
592 bool SVGElement::isAnimatedPropertyAttribute(const QualifiedName& attributeName) const
593 {
594     return propertyRegistry().isAnimatedPropertyAttribute(attributeName);
595 }
596
597 bool SVGElement::isAnimatedAttribute(const QualifiedName& attributeName) const
598 {
599     return SVGPropertyAnimatorFactory::isKnownAttribute(attributeName) || isAnimatedPropertyAttribute(attributeName);
600 }
601
602 bool SVGElement::isAnimatedStyleAttribute(const QualifiedName& attributeName) const
603 {
604     return SVGPropertyAnimatorFactory::isKnownAttribute(attributeName) || propertyRegistry().isAnimatedStylePropertyAttribute(attributeName);
605 }
606
607 std::unique_ptr<SVGAttributeAnimator> SVGElement::createAnimator(const QualifiedName& attributeName, AnimationMode animationMode, CalcMode calcMode, bool isAccumulated, bool isAdditive)
608 {
609     // Property animator, e.g. "fill" or "fill-opacity".
610     if (auto animator = propertyAnimatorFactory().createAnimator(attributeName, animationMode, calcMode, isAccumulated, isAdditive))
611         return animator;
612     
613     // Animated property animator.
614     auto animator = propertyRegistry().createAnimator(attributeName, animationMode, calcMode, isAccumulated, isAdditive);
615     if (!animator)
616         return animator;
617     for (auto* instance : instances())
618         instance->propertyRegistry().appendAnimatedInstance(attributeName, *animator);
619     return animator;
620 }
621     
622 void SVGElement::animatorWillBeDeleted(const QualifiedName& attributeName)
623 {
624     propertyAnimatorFactory().animatorWillBeDeleted(attributeName);
625 }
626
627 Optional<ElementStyle> SVGElement::resolveCustomStyle(const RenderStyle& parentStyle, const RenderStyle*)
628 {
629     // If the element is in a <use> tree we get the style from the definition tree.
630     if (auto styleElement = makeRefPtr(this->correspondingElement())) {
631         Optional<ElementStyle> style = styleElement->resolveStyle(&parentStyle);
632         StyleResolver::adjustSVGElementStyle(*this, *style->renderStyle);
633         return style;
634     }
635
636     return resolveStyle(&parentStyle);
637 }
638
639 MutableStyleProperties* SVGElement::animatedSMILStyleProperties() const
640 {
641     if (m_svgRareData)
642         return m_svgRareData->animatedSMILStyleProperties();
643     return 0;
644 }
645
646 MutableStyleProperties& SVGElement::ensureAnimatedSMILStyleProperties()
647 {
648     return ensureSVGRareData().ensureAnimatedSMILStyleProperties();
649 }
650
651 void SVGElement::setUseOverrideComputedStyle(bool value)
652 {
653     if (m_svgRareData)
654         m_svgRareData->setUseOverrideComputedStyle(value);
655 }
656
657 const RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
658 {
659     if (!m_svgRareData || !m_svgRareData->useOverrideComputedStyle())
660         return Element::computedStyle(pseudoElementSpecifier);
661
662     const RenderStyle* parentStyle = nullptr;
663     if (auto parent = makeRefPtr(parentOrShadowHostElement())) {
664         if (auto renderer = parent->renderer())
665             parentStyle = &renderer->style();
666     }
667
668     return m_svgRareData->overrideComputedStyle(*this, parentStyle);
669 }
670
671 QualifiedName SVGElement::animatableAttributeForName(const AtomString& localName)
672 {
673     static const auto animatableAttributes = makeNeverDestroyed([] {
674         static const QualifiedName* const names[] = {
675             &HTMLNames::classAttr.get(),
676             &SVGNames::amplitudeAttr.get(),
677             &SVGNames::azimuthAttr.get(),
678             &SVGNames::baseFrequencyAttr.get(),
679             &SVGNames::biasAttr.get(),
680             &SVGNames::clipPathUnitsAttr.get(),
681             &SVGNames::cxAttr.get(),
682             &SVGNames::cyAttr.get(),
683             &SVGNames::diffuseConstantAttr.get(),
684             &SVGNames::divisorAttr.get(),
685             &SVGNames::dxAttr.get(),
686             &SVGNames::dyAttr.get(),
687             &SVGNames::edgeModeAttr.get(),
688             &SVGNames::elevationAttr.get(),
689             &SVGNames::exponentAttr.get(),
690             &SVGNames::externalResourcesRequiredAttr.get(),
691             &SVGNames::filterUnitsAttr.get(),
692             &SVGNames::fxAttr.get(),
693             &SVGNames::fyAttr.get(),
694             &SVGNames::gradientTransformAttr.get(),
695             &SVGNames::gradientUnitsAttr.get(),
696             &SVGNames::heightAttr.get(),
697             &SVGNames::in2Attr.get(),
698             &SVGNames::inAttr.get(),
699             &SVGNames::interceptAttr.get(),
700             &SVGNames::k1Attr.get(),
701             &SVGNames::k2Attr.get(),
702             &SVGNames::k3Attr.get(),
703             &SVGNames::k4Attr.get(),
704             &SVGNames::kernelMatrixAttr.get(),
705             &SVGNames::kernelUnitLengthAttr.get(),
706             &SVGNames::lengthAdjustAttr.get(),
707             &SVGNames::limitingConeAngleAttr.get(),
708             &SVGNames::markerHeightAttr.get(),
709             &SVGNames::markerUnitsAttr.get(),
710             &SVGNames::markerWidthAttr.get(),
711             &SVGNames::maskContentUnitsAttr.get(),
712             &SVGNames::maskUnitsAttr.get(),
713             &SVGNames::methodAttr.get(),
714             &SVGNames::modeAttr.get(),
715             &SVGNames::numOctavesAttr.get(),
716             &SVGNames::offsetAttr.get(),
717             &SVGNames::operatorAttr.get(),
718             &SVGNames::orderAttr.get(),
719             &SVGNames::orientAttr.get(),
720             &SVGNames::pathLengthAttr.get(),
721             &SVGNames::patternContentUnitsAttr.get(),
722             &SVGNames::patternTransformAttr.get(),
723             &SVGNames::patternUnitsAttr.get(),
724             &SVGNames::pointsAtXAttr.get(),
725             &SVGNames::pointsAtYAttr.get(),
726             &SVGNames::pointsAtZAttr.get(),
727             &SVGNames::preserveAlphaAttr.get(),
728             &SVGNames::preserveAspectRatioAttr.get(),
729             &SVGNames::primitiveUnitsAttr.get(),
730             &SVGNames::radiusAttr.get(),
731             &SVGNames::rAttr.get(),
732             &SVGNames::refXAttr.get(),
733             &SVGNames::refYAttr.get(),
734             &SVGNames::resultAttr.get(),
735             &SVGNames::rotateAttr.get(),
736             &SVGNames::rxAttr.get(),
737             &SVGNames::ryAttr.get(),
738             &SVGNames::scaleAttr.get(),
739             &SVGNames::seedAttr.get(),
740             &SVGNames::slopeAttr.get(),
741             &SVGNames::spacingAttr.get(),
742             &SVGNames::specularConstantAttr.get(),
743             &SVGNames::specularExponentAttr.get(),
744             &SVGNames::spreadMethodAttr.get(),
745             &SVGNames::startOffsetAttr.get(),
746             &SVGNames::stdDeviationAttr.get(),
747             &SVGNames::stitchTilesAttr.get(),
748             &SVGNames::surfaceScaleAttr.get(),
749             &SVGNames::tableValuesAttr.get(),
750             &SVGNames::targetAttr.get(),
751             &SVGNames::targetXAttr.get(),
752             &SVGNames::targetYAttr.get(),
753             &SVGNames::transformAttr.get(),
754             &SVGNames::typeAttr.get(),
755             &SVGNames::valuesAttr.get(),
756             &SVGNames::viewBoxAttr.get(),
757             &SVGNames::widthAttr.get(),
758             &SVGNames::x1Attr.get(),
759             &SVGNames::x2Attr.get(),
760             &SVGNames::xAttr.get(),
761             &SVGNames::xChannelSelectorAttr.get(),
762             &SVGNames::y1Attr.get(),
763             &SVGNames::y2Attr.get(),
764             &SVGNames::yAttr.get(),
765             &SVGNames::yChannelSelectorAttr.get(),
766             &SVGNames::zAttr.get(),
767             &SVGNames::hrefAttr.get(),
768         };
769         HashMap<AtomString, QualifiedName> map;
770         for (auto& name : names) {
771             auto addResult = map.add(name->localName(), *name);
772             ASSERT_UNUSED(addResult, addResult.isNewEntry);
773         }
774         return map;
775     }());
776     return animatableAttributes.get().get(localName);
777 }
778
779 #ifndef NDEBUG
780
781 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
782 {
783     if (animatableAttributeForName(name.localName()) == name)
784         return !filterOutAnimatableAttribute(name);
785     return false;
786 }
787
788 bool SVGElement::filterOutAnimatableAttribute(const QualifiedName&) const
789 {
790     return false;
791 }
792
793 #endif
794
795 String SVGElement::title() const
796 {
797     // According to spec, for stand-alone SVG documents we should not return a title when
798     // hovering over the rootmost SVG element (the first <title> element is the title of
799     // the document, not a tooltip) so we instantly return.
800     if (isOutermostSVGSVGElement() && document().topDocument().isSVGDocument())
801         return String();
802     auto firstTitle = childrenOfType<SVGTitleElement>(*this).first();
803     return firstTitle ? const_cast<SVGTitleElement*>(firstTitle)->innerText() : String();
804 }
805
806 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
807 {
808     // http://www.w3.org/TR/SVG/extend.html#PrivateData
809     // Prevent anything other than SVG renderers from appearing in our render tree
810     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
811     // with the SVG content. In general, the SVG user agent will include the unknown
812     // elements in the DOM but will otherwise ignore unknown elements.
813     if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement())
814         return StyledElement::rendererIsNeeded(style);
815
816     return false;
817 }
818
819 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
820 {
821     if (!attrName.namespaceURI().isNull())
822         return CSSPropertyInvalid;
823
824     static const auto properties = makeNeverDestroyed(createAttributeNameToCSSPropertyIDMap());
825     return properties.get().get(attrName.localName().impl());
826 }
827
828 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
829 {
830     if (cssPropertyIdForSVGAttributeName(name) > 0)
831         return true;
832     return StyledElement::isPresentationAttribute(name);
833 }
834
835 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomString& value, MutableStyleProperties& style)
836 {
837     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
838     if (propertyID > 0)
839         addPropertyToPresentationAttributeStyle(style, propertyID, value);
840 }
841
842 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
843 {
844     CSSPropertyID propId = cssPropertyIdForSVGAttributeName(attrName);
845     if (propId > 0) {
846         invalidateInstances();
847         return;
848     }
849
850     if (attrName == HTMLNames::classAttr) {
851         classAttributeChanged(className());
852         invalidateInstances();
853         return;
854     }
855
856     if (attrName == HTMLNames::idAttr) {
857         auto renderer = this->renderer();
858         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
859         if (is<RenderSVGResourceContainer>(renderer))
860             downcast<RenderSVGResourceContainer>(*renderer).idChanged();
861         if (isConnected())
862             buildPendingResourcesIfNeeded();
863         invalidateInstances();
864         return;
865     }
866
867     SVGLangSpace::svgAttributeChanged(attrName);
868 }
869
870 Node::InsertedIntoAncestorResult SVGElement::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
871 {
872     StyledElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
873     updateRelativeLengthsInformation();
874     buildPendingResourcesIfNeeded();
875     return InsertedIntoAncestorResult::Done;
876 }
877
878 void SVGElement::buildPendingResourcesIfNeeded()
879 {
880     if (!needsPendingResourceHandling() || !isConnected() || isInShadowTree())
881         return;
882
883     SVGDocumentExtensions& extensions = document().accessSVGExtensions();
884     String resourceId = getIdAttribute();
885     if (!extensions.isIdOfPendingResource(resourceId))
886         return;
887
888     // Mark pending resources as pending for removal.
889     extensions.markPendingResourcesForRemoval(resourceId);
890
891     // Rebuild pending resources for each client of a pending resource that is being removed.
892     while (auto clientElement = extensions.removeElementFromPendingResourcesForRemovalMap(resourceId)) {
893         ASSERT(clientElement->hasPendingResources());
894         if (clientElement->hasPendingResources()) {
895             clientElement->buildPendingResource();
896             extensions.clearHasPendingResourcesIfPossible(*clientElement);
897         }
898     }
899 }
900
901 void SVGElement::childrenChanged(const ChildChange& change)
902 {
903     StyledElement::childrenChanged(change);
904
905     if (change.source == ChildChangeSource::Parser)
906         return;
907     invalidateInstances();
908 }
909
910 RefPtr<DeprecatedCSSOMValue> SVGElement::getPresentationAttribute(const String& name)
911 {
912     if (!hasAttributesWithoutUpdate())
913         return 0;
914
915     QualifiedName attributeName(nullAtom(), name, nullAtom());
916     const Attribute* attribute = findAttributeByName(attributeName);
917     if (!attribute)
918         return 0;
919
920     auto style = MutableStyleProperties::create(SVGAttributeMode);
921     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(attribute->name());
922     style->setProperty(propertyID, attribute->value());
923     auto cssValue = style->getPropertyCSSValue(propertyID);
924     if (!cssValue)
925         return nullptr;
926     return cssValue->createDeprecatedCSSOMWrapper(style->ensureCSSStyleDeclaration());
927 }
928
929 bool SVGElement::instanceUpdatesBlocked() const
930 {
931     return m_svgRareData && m_svgRareData->instanceUpdatesBlocked();
932 }
933
934 void SVGElement::setInstanceUpdatesBlocked(bool value)
935 {
936     // Catch any callers that calls setInstanceUpdatesBlocked(true) twice in a row.
937     // That probably indicates nested use of InstanceUpdateBlocker and a bug.
938     ASSERT(!value || !instanceUpdatesBlocked());
939
940     if (m_svgRareData)
941         m_svgRareData->setInstanceUpdatesBlocked(value);
942 }
943
944 AffineTransform SVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
945 {
946     // To be overridden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
947     return AffineTransform();
948 }
949
950 void SVGElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement* element)
951 {
952     // If we're not yet in a document, this function will be called again from insertedIntoAncestor(). Do nothing now.
953     if (!isConnected())
954         return;
955
956     // An element wants to notify us that its own relative lengths state changed.
957     // Register it in the relative length map, and register us in the parent relative length map.
958     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
959
960     if (hasRelativeLengths)
961         m_elementsWithRelativeLengths.add(element);
962     else {
963         if (!m_elementsWithRelativeLengths.contains(element)) {
964             // We were never registered. Do nothing.
965             return;
966         }
967
968         m_elementsWithRelativeLengths.remove(element);
969     }
970
971     if (!element->isSVGGraphicsElement())
972         return;
973
974     // Find first styled parent node, and notify it that we've changed our relative length state.
975     auto node = makeRefPtr(parentNode());
976     while (node) {
977         if (!node->isSVGElement())
978             break;
979
980         // Register us in the parent element map.
981         downcast<SVGElement>(*node).updateRelativeLengthsInformation(hasRelativeLengths, this);
982         break;
983     }
984 }
985
986 void SVGElement::accessKeyAction(bool sendMouseEvents)
987 {
988     dispatchSimulatedClick(0, sendMouseEvents ? SendMouseUpDownEvents : SendNoEvents);
989 }
990
991 void SVGElement::invalidateInstances()
992 {
993     if (instanceUpdatesBlocked())
994         return;
995
996     auto& instances = this->instances();
997     while (!instances.isEmpty()) {
998         auto instance = makeRefPtr(*instances.begin());
999         if (auto useElement = instance->correspondingUseElement())
1000             useElement->invalidateShadowTree();
1001         instance->setCorrespondingElement(nullptr);
1002     } while (!instances.isEmpty());
1003 }
1004
1005 }