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