Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25
26 #include "core/svg/SVGElement.h"
27
28 #include "bindings/v8/ScriptEventListener.h"
29 #include "core/HTMLNames.h"
30 #include "core/SVGNames.h"
31 #include "core/XLinkNames.h"
32 #include "core/XMLNames.h"
33 #include "core/css/CSSCursorImageValue.h"
34 #include "core/css/parser/BisonCSSParser.h"
35 #include "core/dom/Document.h"
36 #include "core/dom/ElementTraversal.h"
37 #include "core/dom/shadow/ShadowRoot.h"
38 #include "core/events/Event.h"
39 #include "core/frame/Settings.h"
40 #include "core/html/HTMLElement.h"
41 #include "core/rendering/RenderObject.h"
42 #include "core/rendering/svg/RenderSVGResourceContainer.h"
43 #include "core/svg/SVGCursorElement.h"
44 #include "core/svg/SVGDocumentExtensions.h"
45 #include "core/svg/SVGElementRareData.h"
46 #include "core/svg/SVGGraphicsElement.h"
47 #include "core/svg/SVGSVGElement.h"
48 #include "core/svg/SVGTitleElement.h"
49 #include "core/svg/SVGUseElement.h"
50
51 #include "wtf/TemporaryChange.h"
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56 using namespace SVGNames;
57
58 void mapAttributeToCSSProperty(HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap, const QualifiedName& attrName)
59 {
60     // FIXME: when CSS supports "transform-origin" the special case for transform_originAttr can be removed.
61     // FIXME: It's not clear the above is strictly true, as -webkit-transform-origin has non-standard behavior.
62     CSSPropertyID propertyId = cssPropertyID(attrName.localName());
63     if (!propertyId && attrName == transform_originAttr) {
64         propertyId = CSSPropertyWebkitTransformOrigin; // cssPropertyID("-webkit-transform-origin")
65     } else if (propertyId == CSSPropertyTransformOrigin) {
66         propertyId = CSSPropertyWebkitTransformOrigin;
67     }
68     ASSERT(propertyId > 0);
69     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
70 }
71
72 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
73     : Element(tagName, &document, constructionType)
74 #if ASSERT_ENABLED
75     , m_inRelativeLengthClientsInvalidation(false)
76 #endif
77     // |m_isContextElement| must be initialized before |m_className|, as SVGAnimatedString tear-off c-tor currently set this to true.
78     , m_isContextElement(false)
79     , m_SVGRareData(nullptr)
80     , m_className(SVGAnimatedString::create(this, HTMLNames::classAttr, SVGString::create()))
81 {
82     ScriptWrappable::init(this);
83     addToPropertyMap(m_className);
84     setHasCustomStyleCallbacks();
85 }
86
87 SVGElement::~SVGElement()
88 {
89     ASSERT(inDocument() || !hasRelativeLengths());
90
91     // The below teardown is all handled by weak pointer processing in oilpan.
92 #if !ENABLE(OILPAN)
93     if (hasSVGRareData()) {
94         if (SVGCursorElement* cursorElement = svgRareData()->cursorElement())
95             cursorElement->removeReferencedElement(this);
96         if (CSSCursorImageValue* cursorImageValue = svgRareData()->cursorImageValue())
97             cursorImageValue->removeReferencedElement(this);
98         // Clear the rare data now so that we are in a consistent state when
99         // calling rebuildAllElementReferencesForTarget() below.
100         m_SVGRareData.clear();
101     }
102
103     // With Oilpan, either removedFrom has been called or the document is dead
104     // as well and there is no reason to clear out the references.
105     document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
106     document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
107 #endif
108 }
109
110 void SVGElement::detach(const AttachContext& context)
111 {
112     Element::detach(context);
113     if (SVGElement* element = correspondingElement())
114         element->removeInstanceMapping(this);
115 }
116
117 void SVGElement::attach(const AttachContext& context)
118 {
119     Element::attach(context);
120     if (SVGElement* element = correspondingElement())
121         element->mapInstanceToElement(this);
122 }
123
124 short SVGElement::tabIndex() const
125 {
126     if (supportsFocus())
127         return Element::tabIndex();
128     return -1;
129 }
130
131 void SVGElement::willRecalcStyle(StyleRecalcChange change)
132 {
133     if (!hasSVGRareData())
134         return;
135     // If the style changes because of a regular property change (not induced by SMIL animations themselves)
136     // reset the "computed style without SMIL style properties", so the base value change gets reflected.
137     if (change > NoChange || needsStyleRecalc())
138         svgRareData()->setNeedsOverrideComputedStyleUpdate();
139 }
140
141 void SVGElement::buildPendingResourcesIfNeeded()
142 {
143     Document& document = this->document();
144     if (!needsPendingResourceHandling() || !inDocument() || inUseShadowTree())
145         return;
146
147     SVGDocumentExtensions& extensions = document.accessSVGExtensions();
148     AtomicString resourceId = getIdAttribute();
149     if (!extensions.hasPendingResource(resourceId))
150         return;
151
152     // Mark pending resources as pending for removal.
153     extensions.markPendingResourcesForRemoval(resourceId);
154
155     // Rebuild pending resources for each client of a pending resource that is being removed.
156     while (Element* clientElement = extensions.removeElementFromPendingResourcesForRemoval(resourceId)) {
157         ASSERT(clientElement->hasPendingResources());
158         if (clientElement->hasPendingResources()) {
159             // FIXME: Ideally we'd always resolve pending resources async instead of inside
160             // insertedInto and svgAttributeChanged. For now we only do it for <use> since
161             // that would stamp out DOM.
162             if (isSVGUseElement(clientElement))
163                 toSVGUseElement(clientElement)->invalidateShadowTree();
164             else
165                 clientElement->buildPendingResource();
166             extensions.clearHasPendingResourcesIfPossible(clientElement);
167         }
168     }
169 }
170
171 bool SVGElement::rendererIsNeeded(const RenderStyle& style)
172 {
173     // http://www.w3.org/TR/SVG/extend.html#PrivateData
174     // Prevent anything other than SVG renderers from appearing in our render tree
175     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
176     // with the SVG content. In general, the SVG user agent will include the unknown
177     // elements in the DOM but will otherwise ignore unknown elements.
178     if (!parentOrShadowHostElement() || parentOrShadowHostElement()->isSVGElement())
179         return Element::rendererIsNeeded(style);
180
181     return false;
182 }
183
184 SVGElementRareData* SVGElement::ensureSVGRareData()
185 {
186     if (hasSVGRareData())
187         return svgRareData();
188
189     m_SVGRareData = adoptPtrWillBeNoop(new SVGElementRareData(this));
190     return m_SVGRareData.get();
191 }
192
193 bool SVGElement::isOutermostSVGSVGElement() const
194 {
195     if (!isSVGSVGElement(*this))
196         return false;
197
198     // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
199     if (!parentNode())
200         return true;
201
202     // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
203     if (isSVGForeignObjectElement(*parentNode()))
204         return true;
205
206     // If we're living in a shadow tree, we're a <svg> element that got created as replacement
207     // for a <symbol> element or a cloned <svg> element in the referenced tree. In that case
208     // we're always an inner <svg> element.
209     if (inUseShadowTree() && parentOrShadowHostElement() && parentOrShadowHostElement()->isSVGElement())
210         return false;
211
212     // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
213     return !parentNode()->isSVGElement();
214 }
215
216 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
217 {
218     if (error == NoError)
219         return;
220
221     String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
222     SVGDocumentExtensions& extensions = document().accessSVGExtensions();
223
224     if (error == NegativeValueForbiddenError) {
225         extensions.reportError("Invalid negative value for " + errorString);
226         return;
227     }
228
229     if (error == ParsingAttributeFailedError) {
230         extensions.reportError("Invalid value for " + errorString);
231         return;
232     }
233
234     ASSERT_NOT_REACHED();
235 }
236
237 String SVGElement::title() const
238 {
239     // According to spec, we should not return titles when hovering over root <svg> elements (those
240     // <title> elements are the title of the document, not a tooltip) so we instantly return.
241     if (isOutermostSVGSVGElement())
242         return String();
243
244     if (inUseShadowTree()) {
245         String useTitle(shadowHost()->title());
246         if (!useTitle.isEmpty())
247             return useTitle;
248     }
249
250     // If we aren't an instance in a <use> or the <use> title was not found, then find the first
251     // <title> child of this element.
252     // If a title child was found, return the text contents.
253     if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this))
254         return titleElement->innerText();
255
256     // Otherwise return a null/empty string.
257     return String();
258 }
259
260 bool SVGElement::instanceUpdatesBlocked() const
261 {
262     return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked();
263 }
264
265 void SVGElement::setInstanceUpdatesBlocked(bool value)
266 {
267     if (hasSVGRareData())
268         svgRareData()->setInstanceUpdatesBlocked(value);
269 }
270
271 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const
272 {
273     // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
274     return AffineTransform();
275 }
276
277 const AtomicString& SVGElement::xmlbase() const
278 {
279     return fastGetAttribute(XMLNames::baseAttr);
280 }
281
282 void SVGElement::setXMLbase(const AtomicString& value)
283 {
284     setAttribute(XMLNames::baseAttr, value);
285 }
286
287 const AtomicString& SVGElement::xmllang() const
288 {
289     return fastGetAttribute(XMLNames::langAttr);
290 }
291
292 void SVGElement::setXMLlang(const AtomicString& value)
293 {
294     setAttribute(XMLNames::langAttr, value);
295 }
296
297 const AtomicString& SVGElement::xmlspace() const
298 {
299     return fastGetAttribute(XMLNames::spaceAttr);
300 }
301
302 void SVGElement::setXMLspace(const AtomicString& value)
303 {
304     setAttribute(XMLNames::spaceAttr, value);
305 }
306
307 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent)
308 {
309     Element::insertedInto(rootParent);
310     updateRelativeLengthsInformation();
311     buildPendingResourcesIfNeeded();
312     return InsertionDone;
313 }
314
315 void SVGElement::removedFrom(ContainerNode* rootParent)
316 {
317     bool wasInDocument = rootParent->inDocument();
318
319     if (wasInDocument && hasRelativeLengths()) {
320         // The root of the subtree being removed should take itself out from its parent's relative
321         // length set. For the other nodes in the subtree we don't need to do anything: they will
322         // get their own removedFrom() notification and just clear their sets.
323         if (rootParent->isSVGElement() && !parentNode()) {
324             ASSERT(toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
325             toSVGElement(rootParent)->updateRelativeLengthsInformation(false, this);
326         }
327
328         m_elementsWithRelativeLengths.clear();
329     }
330
331     ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
332
333     Element::removedFrom(rootParent);
334
335     if (wasInDocument) {
336         document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
337         document().accessSVGExtensions().removeAllElementReferencesForTarget(this);
338     }
339
340     invalidateInstances();
341 }
342
343 void SVGElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
344 {
345     Element::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
346
347     // Invalidate all instances associated with us.
348     if (!changedByParser)
349         invalidateInstances();
350 }
351
352 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
353 {
354     if (!attrName.namespaceURI().isNull())
355         return CSSPropertyInvalid;
356
357     static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
358     if (!propertyNameToIdMap) {
359         propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
360         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
361         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
362         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
363         mapAttributeToCSSProperty(propertyNameToIdMap, buffered_renderingAttr);
364         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
365         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
366         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
367         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::colorAttr);
368         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
369         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
370         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
371         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
372         mapAttributeToCSSProperty(propertyNameToIdMap, SVGNames::directionAttr);
373         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
374         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
375         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
376         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
377         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
378         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
379         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
380         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
381         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
382         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
383         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
384         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
385         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
386         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
387         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
388         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
389         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
390         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
391         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
392         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
393         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
394         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
395         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
396         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
397         mapAttributeToCSSProperty(propertyNameToIdMap, mask_typeAttr);
398         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
399         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
400         mapAttributeToCSSProperty(propertyNameToIdMap, paint_orderAttr);
401         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
402         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
403         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
404         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
405         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
406         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
407         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
408         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
409         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
410         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
411         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
412         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
413         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
414         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
415         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
416         mapAttributeToCSSProperty(propertyNameToIdMap, transform_originAttr);
417         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
418         mapAttributeToCSSProperty(propertyNameToIdMap, vector_effectAttr);
419         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
420         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
421         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
422     }
423
424     return propertyNameToIdMap->get(attrName.localName().impl());
425 }
426
427 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
428 {
429     ASSERT(clientElement);
430
431     // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
432     if (!inDocument())
433         return;
434
435     // An element wants to notify us that its own relative lengths state changed.
436     // Register it in the relative length map, and register us in the parent relative length map.
437     // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
438     for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) {
439         SVGElement* currentElement = toSVGElement(currentNode);
440         ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation);
441
442         bool hadRelativeLengths = currentElement->hasRelativeLengths();
443         if (clientHasRelativeLengths)
444             currentElement->m_elementsWithRelativeLengths.add(clientElement);
445         else
446             currentElement->m_elementsWithRelativeLengths.remove(clientElement);
447
448         // If the relative length state hasn't changed, we can stop propagating the notification.
449         if (hadRelativeLengths == currentElement->hasRelativeLengths())
450             return;
451
452         clientElement = currentElement;
453         clientHasRelativeLengths = clientElement->hasRelativeLengths();
454     }
455
456     // Register root SVG elements for top level viewport change notifications.
457     if (isSVGSVGElement(*clientElement)) {
458         SVGDocumentExtensions& svgExtensions = accessDocumentSVGExtensions();
459         if (clientElement->hasRelativeLengths())
460             svgExtensions.addSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
461         else
462             svgExtensions.removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
463     }
464 }
465
466 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
467 {
468     if (!inDocument())
469         return;
470
471     ASSERT(!m_inRelativeLengthClientsInvalidation);
472 #if ASSERT_ENABLED
473     TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
474 #endif
475
476     RenderObject* renderer = this->renderer();
477     if (renderer && selfHasRelativeLengths()) {
478         if (renderer->isSVGResourceContainer())
479             toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
480         else
481             renderer->setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope);
482     }
483
484     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator end = m_elementsWithRelativeLengths.end();
485     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
486         if (*it != this)
487             (*it)->invalidateRelativeLengthClients(layoutScope);
488     }
489 }
490
491 SVGSVGElement* SVGElement::ownerSVGElement() const
492 {
493     ContainerNode* n = parentOrShadowHostNode();
494     while (n) {
495         if (isSVGSVGElement(*n))
496             return toSVGSVGElement(n);
497
498         n = n->parentOrShadowHostNode();
499     }
500
501     return 0;
502 }
503
504 SVGElement* SVGElement::viewportElement() const
505 {
506     // This function needs shadow tree support - as RenderSVGContainer uses this function
507     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
508     ContainerNode* n = parentOrShadowHostNode();
509     while (n) {
510         if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n))
511             return toSVGElement(n);
512
513         n = n->parentOrShadowHostNode();
514     }
515
516     return 0;
517 }
518
519 SVGDocumentExtensions& SVGElement::accessDocumentSVGExtensions()
520 {
521     // This function is provided for use by SVGAnimatedProperty to avoid
522     // global inclusion of core/dom/Document.h in SVG code.
523     return document().accessSVGExtensions();
524 }
525
526 void SVGElement::mapInstanceToElement(SVGElement* instance)
527 {
528     ASSERT(instance);
529     ASSERT(instance->inUseShadowTree());
530
531     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = ensureSVGRareData()->elementInstances();
532     ASSERT(!instances.contains(instance));
533
534     instances.add(instance);
535 }
536
537 void SVGElement::removeInstanceMapping(SVGElement* instance)
538 {
539     ASSERT(instance);
540     ASSERT(instance->inUseShadowTree());
541
542     if (!hasSVGRareData())
543         return;
544
545     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = svgRareData()->elementInstances();
546     ASSERT(instances.contains(instance));
547
548     instances.remove(instance);
549 }
550
551 static WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& emptyInstances()
552 {
553 #if ENABLE(OILPAN)
554     DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<WeakMember<SVGElement> > >, emptyInstances, (new HeapHashSet<WeakMember<SVGElement> >));
555     return *emptyInstances;
556 #else
557     DEFINE_STATIC_LOCAL(HashSet<RawPtr<SVGElement> >, emptyInstances, ());
558     return emptyInstances;
559 #endif
560 }
561
562 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& SVGElement::instancesForElement() const
563 {
564     if (!hasSVGRareData())
565         return emptyInstances();
566     return svgRareData()->elementInstances();
567 }
568
569 bool SVGElement::getBoundingBox(FloatRect& rect)
570 {
571     if (!isSVGGraphicsElement())
572         return false;
573
574     rect = toSVGGraphicsElement(this)->getBBox();
575     return true;
576 }
577
578 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
579 {
580     SVGElementRareData* rareData = ensureSVGRareData();
581     if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
582         if (cursorElement == oldCursorElement)
583             return;
584         oldCursorElement->removeReferencedElement(this);
585     }
586     rareData->setCursorElement(cursorElement);
587 }
588
589 #if !ENABLE(OILPAN)
590 void SVGElement::cursorElementRemoved()
591 {
592     svgRareData()->setCursorElement(0);
593 }
594 #endif
595
596 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
597 {
598     SVGElementRareData* rareData = ensureSVGRareData();
599 #if !ENABLE(OILPAN)
600     if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
601         if (cursorImageValue == oldCursorImageValue)
602             return;
603         oldCursorImageValue->removeReferencedElement(this);
604     }
605 #endif
606     rareData->setCursorImageValue(cursorImageValue);
607 }
608
609 #if !ENABLE(OILPAN)
610 void SVGElement::cursorImageValueRemoved()
611 {
612     svgRareData()->setCursorImageValue(0);
613 }
614 #endif
615
616 SVGElement* SVGElement::correspondingElement()
617 {
618     ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
619     return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
620 }
621
622 SVGUseElement* SVGElement::correspondingUseElement() const
623 {
624     if (ShadowRoot* root = containingShadowRoot()) {
625         if (isSVGUseElement(root->host()) && (root->type() == ShadowRoot::UserAgentShadowRoot))
626             return toSVGUseElement(root->host());
627     }
628     return 0;
629 }
630
631 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
632 {
633     ensureSVGRareData()->setCorrespondingElement(correspondingElement);
634 }
635
636 bool SVGElement::inUseShadowTree() const
637 {
638     return correspondingUseElement();
639 }
640
641 bool SVGElement::supportsSpatialNavigationFocus() const
642 {
643     // This function checks whether the element satisfies the extended criteria
644     // for the element to be focusable, introduced by spatial navigation feature,
645     // i.e. checks if click or keyboard event handler is specified.
646     // This is the way to make it possible to navigate to (focus) elements
647     // which web designer meant for being active (made them respond to click events).
648
649     if (!document().settings() || !document().settings()->spatialNavigationEnabled())
650         return false;
651     return hasEventListeners(EventTypeNames::click)
652         || hasEventListeners(EventTypeNames::keydown)
653         || hasEventListeners(EventTypeNames::keypress)
654         || hasEventListeners(EventTypeNames::keyup)
655         || hasEventListeners(EventTypeNames::focus)
656         || hasEventListeners(EventTypeNames::blur)
657         || hasEventListeners(EventTypeNames::focusin)
658         || hasEventListeners(EventTypeNames::focusout);
659 }
660
661 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
662 {
663     if (name == HTMLNames::classAttr) {
664         // SVG animation has currently requires special storage of values so we set
665         // the className here. svgAttributeChanged actually causes the resulting
666         // style updates (instead of Element::parseAttribute). We don't
667         // tell Element about the change to avoid parsing the class list twice
668         SVGParsingError parseError = NoError;
669         m_className->setBaseValueAsString(value, parseError);
670         reportAttributeParsingError(parseError, name, value);
671     } else if (name.matches(XMLNames::langAttr) || name.matches(XMLNames::spaceAttr)) {
672     } else if (name == tabindexAttr) {
673         Element::parseAttribute(name, value);
674     } else {
675         // standard events
676         const AtomicString& eventName = HTMLElement::eventNameForAttributeName(name);
677         if (!eventName.isNull())
678             setAttributeEventListener(eventName, createAttributeEventListener(this, name, value, eventParameterName()));
679         else
680             Element::parseAttribute(name, value);
681     }
682 }
683
684 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap;
685 AnimatedPropertyType SVGElement::animatedPropertyTypeForCSSAttribute(const QualifiedName& attributeName)
686 {
687     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, cssPropertyMap, ());
688
689     if (cssPropertyMap.isEmpty()) {
690         // Fill the map for the first use.
691         cssPropertyMap.set(alignment_baselineAttr, AnimatedString);
692         cssPropertyMap.set(baseline_shiftAttr, AnimatedString);
693         cssPropertyMap.set(buffered_renderingAttr, AnimatedString);
694         cssPropertyMap.set(clipAttr, AnimatedRect);
695         cssPropertyMap.set(clip_pathAttr, AnimatedString);
696         cssPropertyMap.set(clip_ruleAttr, AnimatedString);
697         cssPropertyMap.set(SVGNames::colorAttr, AnimatedColor);
698         cssPropertyMap.set(color_interpolationAttr, AnimatedString);
699         cssPropertyMap.set(color_interpolation_filtersAttr, AnimatedString);
700         cssPropertyMap.set(color_renderingAttr, AnimatedString);
701         cssPropertyMap.set(cursorAttr, AnimatedString);
702         cssPropertyMap.set(displayAttr, AnimatedString);
703         cssPropertyMap.set(dominant_baselineAttr, AnimatedString);
704         cssPropertyMap.set(fillAttr, AnimatedColor);
705         cssPropertyMap.set(fill_opacityAttr, AnimatedNumber);
706         cssPropertyMap.set(fill_ruleAttr, AnimatedString);
707         cssPropertyMap.set(filterAttr, AnimatedString);
708         cssPropertyMap.set(flood_colorAttr, AnimatedColor);
709         cssPropertyMap.set(flood_opacityAttr, AnimatedNumber);
710         cssPropertyMap.set(font_familyAttr, AnimatedString);
711         cssPropertyMap.set(font_sizeAttr, AnimatedLength);
712         cssPropertyMap.set(font_stretchAttr, AnimatedString);
713         cssPropertyMap.set(font_styleAttr, AnimatedString);
714         cssPropertyMap.set(font_variantAttr, AnimatedString);
715         cssPropertyMap.set(font_weightAttr, AnimatedString);
716         cssPropertyMap.set(image_renderingAttr, AnimatedString);
717         cssPropertyMap.set(letter_spacingAttr, AnimatedLength);
718         cssPropertyMap.set(lighting_colorAttr, AnimatedColor);
719         cssPropertyMap.set(marker_endAttr, AnimatedString);
720         cssPropertyMap.set(marker_midAttr, AnimatedString);
721         cssPropertyMap.set(marker_startAttr, AnimatedString);
722         cssPropertyMap.set(maskAttr, AnimatedString);
723         cssPropertyMap.set(mask_typeAttr, AnimatedString);
724         cssPropertyMap.set(opacityAttr, AnimatedNumber);
725         cssPropertyMap.set(overflowAttr, AnimatedString);
726         cssPropertyMap.set(paint_orderAttr, AnimatedString);
727         cssPropertyMap.set(pointer_eventsAttr, AnimatedString);
728         cssPropertyMap.set(shape_renderingAttr, AnimatedString);
729         cssPropertyMap.set(stop_colorAttr, AnimatedColor);
730         cssPropertyMap.set(stop_opacityAttr, AnimatedNumber);
731         cssPropertyMap.set(strokeAttr, AnimatedColor);
732         cssPropertyMap.set(stroke_dasharrayAttr, AnimatedLengthList);
733         cssPropertyMap.set(stroke_dashoffsetAttr, AnimatedLength);
734         cssPropertyMap.set(stroke_linecapAttr, AnimatedString);
735         cssPropertyMap.set(stroke_linejoinAttr, AnimatedString);
736         cssPropertyMap.set(stroke_miterlimitAttr, AnimatedNumber);
737         cssPropertyMap.set(stroke_opacityAttr, AnimatedNumber);
738         cssPropertyMap.set(stroke_widthAttr, AnimatedLength);
739         cssPropertyMap.set(text_anchorAttr, AnimatedString);
740         cssPropertyMap.set(text_decorationAttr, AnimatedString);
741         cssPropertyMap.set(text_renderingAttr, AnimatedString);
742         cssPropertyMap.set(vector_effectAttr, AnimatedString);
743         cssPropertyMap.set(visibilityAttr, AnimatedString);
744         cssPropertyMap.set(word_spacingAttr, AnimatedLength);
745     }
746
747     if (cssPropertyMap.contains(attributeName))
748         return cssPropertyMap.get(attributeName);
749
750     return AnimatedUnknown;
751 }
752
753 void SVGElement::addToPropertyMap(PassRefPtr<SVGAnimatedPropertyBase> passProperty)
754 {
755     RefPtr<SVGAnimatedPropertyBase> property(passProperty);
756     QualifiedName attributeName = property->attributeName();
757     m_newAttributeToPropertyMap.set(attributeName, property.release());
758 }
759
760 PassRefPtr<SVGAnimatedPropertyBase> SVGElement::propertyFromAttribute(const QualifiedName& attributeName)
761 {
762     return m_newAttributeToPropertyMap.get(attributeName);
763 }
764
765 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName)
766 {
767     return animatedPropertyTypeForCSSAttribute(attrName) != AnimatedUnknown;
768 }
769
770 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
771 {
772     return cssPropertyIdForSVGAttributeName(name) > 0;
773 }
774
775 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
776 {
777     CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
778     if (propertyID > 0)
779         addPropertyToPresentationAttributeStyle(style, propertyID, value);
780 }
781
782 bool SVGElement::haveLoadedRequiredResources()
783 {
784     for (SVGElement* child = Traversal<SVGElement>::firstChild(*this); child; child = Traversal<SVGElement>::nextSibling(*child)) {
785         if (!child->haveLoadedRequiredResources())
786             return false;
787     }
788     return true;
789 }
790
791 static inline void collectInstancesForSVGElement(SVGElement* element, WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances)
792 {
793     ASSERT(element);
794     if (element->containingShadowRoot())
795         return;
796
797     ASSERT(!element->instanceUpdatesBlocked());
798
799     instances = element->instancesForElement();
800 }
801
802 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
803 {
804     RefPtr<EventListener> listener = prpListener;
805
806     // Add event listener to regular DOM element
807     if (!Node::addEventListener(eventType, listener, useCapture))
808         return false;
809
810     // Add event listener to all shadow tree DOM element instances
811     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
812     collectInstancesForSVGElement(this, instances);
813     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
814     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
815         bool result = (*it)->Node::addEventListener(eventType, listener, useCapture);
816         ASSERT_UNUSED(result, result);
817     }
818
819     return true;
820 }
821
822 bool SVGElement::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
823 {
824     WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
825     collectInstancesForSVGElement(this, instances);
826     if (instances.isEmpty())
827         return Node::removeEventListener(eventType, listener, useCapture);
828
829     // EventTarget::removeEventListener creates a PassRefPtr around the given EventListener
830     // object when creating a temporary RegisteredEventListener object used to look up the
831     // event listener in a cache. If we want to be able to call removeEventListener() multiple
832     // times on different nodes, we have to delay its immediate destruction, which would happen
833     // after the first call below.
834     RefPtr<EventListener> protector(listener);
835
836     // Remove event listener from regular DOM element
837     if (!Node::removeEventListener(eventType, listener, useCapture))
838         return false;
839
840     // Remove event listener from all shadow tree DOM element instances
841     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
842     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
843         SVGElement* shadowTreeElement = *it;
844         ASSERT(shadowTreeElement);
845
846         shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture);
847     }
848
849     return true;
850 }
851
852 static bool hasLoadListener(Element* element)
853 {
854     if (element->hasEventListeners(EventTypeNames::load))
855         return true;
856
857     for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
858         const EventListenerVector& entry = element->getEventListeners(EventTypeNames::load);
859         for (size_t i = 0; i < entry.size(); ++i) {
860             if (entry[i].useCapture)
861                 return true;
862         }
863     }
864
865     return false;
866 }
867
868 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
869 {
870     RefPtrWillBeRawPtr<SVGElement> currentTarget = this;
871     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
872         RefPtrWillBeRawPtr<Element> parent = nullptr;
873         if (sendParentLoadEvents)
874             parent = currentTarget->parentOrShadowHostElement(); // save the next parent to dispatch too incase dispatching the event changes the tree
875         if (hasLoadListener(currentTarget.get())
876             && (currentTarget->isStructurallyExternal() || isSVGSVGElement(*currentTarget)))
877             currentTarget->dispatchEvent(Event::create(EventTypeNames::load));
878         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : nullptr;
879         SVGElement* element = currentTarget.get();
880         if (!element || !element->isOutermostSVGSVGElement())
881             continue;
882
883         // Consider <svg onload="foo()"><image xlink:href="foo.png" externalResourcesRequired="true"/></svg>.
884         // If foo.png is not yet loaded, the first SVGLoad event will go to the <svg> element, sent through
885         // Document::implicitClose(). Then the SVGLoad event will fire for <image>, once its loaded.
886         ASSERT(sendParentLoadEvents);
887
888         // If the load event was not sent yet by Document::implicitClose(), but the <image> from the example
889         // above, just appeared, don't send the SVGLoad event to the outermost <svg>, but wait for the document
890         // to be "ready to render", first.
891         if (!document().loadEventFinished())
892             break;
893     }
894 }
895
896 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
897 {
898     svgLoadEventTimer()->startOneShot(0, FROM_HERE);
899 }
900
901 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
902 {
903     sendSVGLoadEventIfPossible();
904 }
905
906 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
907 {
908     ASSERT_NOT_REACHED();
909     return 0;
910 }
911
912 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
913 {
914     Element::attributeChanged(name, newValue);
915
916     if (isIdAttributeName(name))
917         document().accessSVGExtensions().rebuildAllElementReferencesForTarget(this);
918
919     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
920     // so we don't want changes to the style attribute to result in extra work here.
921     if (name != HTMLNames::styleAttr)
922         svgAttributeChanged(name);
923 }
924
925 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
926 {
927     CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName);
928     if (propId > 0) {
929         invalidateInstances();
930         return;
931     }
932
933     if (attrName == HTMLNames::classAttr) {
934         classAttributeChanged(AtomicString(m_className->currentValue()->value()));
935         invalidateInstances();
936         return;
937     }
938
939     if (isIdAttributeName(attrName)) {
940         RenderObject* object = renderer();
941         // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
942         if (object && object->isSVGResourceContainer())
943             toRenderSVGResourceContainer(object)->idChanged();
944         if (inDocument())
945             buildPendingResourcesIfNeeded();
946         invalidateInstances();
947         return;
948     }
949 }
950
951 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
952 {
953     if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
954         return;
955
956     if (name == anyQName()) {
957         AttributeToPropertyMap::const_iterator::Values it = m_newAttributeToPropertyMap.values().begin();
958         AttributeToPropertyMap::const_iterator::Values end = m_newAttributeToPropertyMap.values().end();
959         for (; it != end; ++it) {
960             if ((*it)->needsSynchronizeAttribute())
961                 (*it)->synchronizeAttribute();
962         }
963
964         elementData()->m_animatedSVGAttributesAreDirty = false;
965     } else {
966         RefPtr<SVGAnimatedPropertyBase> property = m_newAttributeToPropertyMap.get(name);
967         if (property && property->needsSynchronizeAttribute())
968             property->synchronizeAttribute();
969     }
970 }
971
972 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
973 {
974     if (!correspondingElement())
975         return document().ensureStyleResolver().styleForElement(this);
976
977     RenderStyle* style = 0;
978     if (Element* parent = parentOrShadowHostElement()) {
979         if (RenderObject* renderer = parent->renderer())
980             style = renderer->style();
981     }
982
983     return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
984 }
985
986 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
987 {
988     if (hasSVGRareData())
989         return svgRareData()->animatedSMILStyleProperties();
990     return 0;
991 }
992
993 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
994 {
995     return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
996 }
997
998 void SVGElement::setUseOverrideComputedStyle(bool value)
999 {
1000     if (hasSVGRareData())
1001         svgRareData()->setUseOverrideComputedStyle(value);
1002 }
1003
1004 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
1005 {
1006     if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
1007         return Element::computedStyle(pseudoElementSpecifier);
1008
1009     RenderStyle* parentStyle = 0;
1010     if (Element* parent = parentOrShadowHostElement()) {
1011         if (RenderObject* renderer = parent->renderer())
1012             parentStyle = renderer->style();
1013     }
1014
1015     return svgRareData()->overrideComputedStyle(this, parentStyle);
1016 }
1017
1018 bool SVGElement::hasFocusEventListeners() const
1019 {
1020     return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout)
1021         || hasEventListeners(EventTypeNames::focus) || hasEventListeners(EventTypeNames::blur);
1022 }
1023
1024 void SVGElement::invalidateInstances()
1025 {
1026     if (!inDocument())
1027         return;
1028
1029     if (instanceUpdatesBlocked())
1030         return;
1031
1032     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& set = instancesForElement();
1033     if (set.isEmpty())
1034         return;
1035
1036     // Mark all use elements referencing 'element' for rebuilding
1037     const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = set.end();
1038     for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = set.begin(); it != end; ++it) {
1039         (*it)->setCorrespondingElement(0);
1040
1041         if (SVGUseElement* element = (*it)->correspondingUseElement()) {
1042             ASSERT(element->inDocument());
1043             element->invalidateShadowTree();
1044         }
1045     }
1046
1047     svgRareData()->elementInstances().clear();
1048
1049     document().updateRenderTreeIfNeeded();
1050 }
1051
1052 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
1053     : m_targetElement(targetElement)
1054 {
1055     if (m_targetElement)
1056         m_targetElement->setInstanceUpdatesBlocked(true);
1057 }
1058
1059 SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker()
1060 {
1061     if (m_targetElement)
1062         m_targetElement->setInstanceUpdatesBlocked(false);
1063 }
1064
1065 #ifndef NDEBUG
1066 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
1067 {
1068     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
1069
1070     if (animatableAttributes.isEmpty()) {
1071         animatableAttributes.add(XLinkNames::hrefAttr);
1072         animatableAttributes.add(SVGNames::amplitudeAttr);
1073         animatableAttributes.add(SVGNames::azimuthAttr);
1074         animatableAttributes.add(SVGNames::baseFrequencyAttr);
1075         animatableAttributes.add(SVGNames::biasAttr);
1076         animatableAttributes.add(SVGNames::clipPathUnitsAttr);
1077         animatableAttributes.add(SVGNames::cxAttr);
1078         animatableAttributes.add(SVGNames::cyAttr);
1079         animatableAttributes.add(SVGNames::diffuseConstantAttr);
1080         animatableAttributes.add(SVGNames::divisorAttr);
1081         animatableAttributes.add(SVGNames::dxAttr);
1082         animatableAttributes.add(SVGNames::dyAttr);
1083         animatableAttributes.add(SVGNames::edgeModeAttr);
1084         animatableAttributes.add(SVGNames::elevationAttr);
1085         animatableAttributes.add(SVGNames::exponentAttr);
1086         animatableAttributes.add(SVGNames::filterResAttr);
1087         animatableAttributes.add(SVGNames::filterUnitsAttr);
1088         animatableAttributes.add(SVGNames::fxAttr);
1089         animatableAttributes.add(SVGNames::fyAttr);
1090         animatableAttributes.add(SVGNames::gradientTransformAttr);
1091         animatableAttributes.add(SVGNames::gradientUnitsAttr);
1092         animatableAttributes.add(SVGNames::heightAttr);
1093         animatableAttributes.add(SVGNames::in2Attr);
1094         animatableAttributes.add(SVGNames::inAttr);
1095         animatableAttributes.add(SVGNames::interceptAttr);
1096         animatableAttributes.add(SVGNames::k1Attr);
1097         animatableAttributes.add(SVGNames::k2Attr);
1098         animatableAttributes.add(SVGNames::k3Attr);
1099         animatableAttributes.add(SVGNames::k4Attr);
1100         animatableAttributes.add(SVGNames::kernelMatrixAttr);
1101         animatableAttributes.add(SVGNames::kernelUnitLengthAttr);
1102         animatableAttributes.add(SVGNames::lengthAdjustAttr);
1103         animatableAttributes.add(SVGNames::limitingConeAngleAttr);
1104         animatableAttributes.add(SVGNames::markerHeightAttr);
1105         animatableAttributes.add(SVGNames::markerUnitsAttr);
1106         animatableAttributes.add(SVGNames::markerWidthAttr);
1107         animatableAttributes.add(SVGNames::maskContentUnitsAttr);
1108         animatableAttributes.add(SVGNames::maskUnitsAttr);
1109         animatableAttributes.add(SVGNames::methodAttr);
1110         animatableAttributes.add(SVGNames::modeAttr);
1111         animatableAttributes.add(SVGNames::numOctavesAttr);
1112         animatableAttributes.add(SVGNames::offsetAttr);
1113         animatableAttributes.add(SVGNames::operatorAttr);
1114         animatableAttributes.add(SVGNames::orderAttr);
1115         animatableAttributes.add(SVGNames::orientAttr);
1116         animatableAttributes.add(SVGNames::pathLengthAttr);
1117         animatableAttributes.add(SVGNames::patternContentUnitsAttr);
1118         animatableAttributes.add(SVGNames::patternTransformAttr);
1119         animatableAttributes.add(SVGNames::patternUnitsAttr);
1120         animatableAttributes.add(SVGNames::pointsAtXAttr);
1121         animatableAttributes.add(SVGNames::pointsAtYAttr);
1122         animatableAttributes.add(SVGNames::pointsAtZAttr);
1123         animatableAttributes.add(SVGNames::preserveAlphaAttr);
1124         animatableAttributes.add(SVGNames::preserveAspectRatioAttr);
1125         animatableAttributes.add(SVGNames::primitiveUnitsAttr);
1126         animatableAttributes.add(SVGNames::radiusAttr);
1127         animatableAttributes.add(SVGNames::rAttr);
1128         animatableAttributes.add(SVGNames::refXAttr);
1129         animatableAttributes.add(SVGNames::refYAttr);
1130         animatableAttributes.add(SVGNames::resultAttr);
1131         animatableAttributes.add(SVGNames::rotateAttr);
1132         animatableAttributes.add(SVGNames::rxAttr);
1133         animatableAttributes.add(SVGNames::ryAttr);
1134         animatableAttributes.add(SVGNames::scaleAttr);
1135         animatableAttributes.add(SVGNames::seedAttr);
1136         animatableAttributes.add(SVGNames::slopeAttr);
1137         animatableAttributes.add(SVGNames::spacingAttr);
1138         animatableAttributes.add(SVGNames::specularConstantAttr);
1139         animatableAttributes.add(SVGNames::specularExponentAttr);
1140         animatableAttributes.add(SVGNames::spreadMethodAttr);
1141         animatableAttributes.add(SVGNames::startOffsetAttr);
1142         animatableAttributes.add(SVGNames::stdDeviationAttr);
1143         animatableAttributes.add(SVGNames::stitchTilesAttr);
1144         animatableAttributes.add(SVGNames::surfaceScaleAttr);
1145         animatableAttributes.add(SVGNames::tableValuesAttr);
1146         animatableAttributes.add(SVGNames::targetAttr);
1147         animatableAttributes.add(SVGNames::targetXAttr);
1148         animatableAttributes.add(SVGNames::targetYAttr);
1149         animatableAttributes.add(SVGNames::transformAttr);
1150         animatableAttributes.add(SVGNames::typeAttr);
1151         animatableAttributes.add(SVGNames::valuesAttr);
1152         animatableAttributes.add(SVGNames::viewBoxAttr);
1153         animatableAttributes.add(SVGNames::widthAttr);
1154         animatableAttributes.add(SVGNames::x1Attr);
1155         animatableAttributes.add(SVGNames::x2Attr);
1156         animatableAttributes.add(SVGNames::xAttr);
1157         animatableAttributes.add(SVGNames::xChannelSelectorAttr);
1158         animatableAttributes.add(SVGNames::y1Attr);
1159         animatableAttributes.add(SVGNames::y2Attr);
1160         animatableAttributes.add(SVGNames::yAttr);
1161         animatableAttributes.add(SVGNames::yChannelSelectorAttr);
1162         animatableAttributes.add(SVGNames::zAttr);
1163     }
1164
1165     if (name == classAttr)
1166         return true;
1167
1168     return animatableAttributes.contains(name);
1169 }
1170 #endif
1171
1172 void SVGElement::trace(Visitor* visitor)
1173 {
1174     visitor->trace(m_elementsWithRelativeLengths);
1175     visitor->trace(m_SVGRareData);
1176     Element::trace(visitor);
1177 }
1178
1179 const AtomicString& SVGElement::eventParameterName()
1180 {
1181     DEFINE_STATIC_LOCAL(const AtomicString, evtString, ("evt", AtomicString::ConstructFromLiteral));
1182     return evtString;
1183 }
1184
1185 }