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