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