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