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