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>
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.
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.
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.
26 #include "core/svg/SVGElement.h"
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"
52 #include "wtf/TemporaryChange.h"
56 using namespace HTMLNames;
57 using namespace SVGNames;
59 SVGElement::SVGElement(const QualifiedName& tagName, Document& document, ConstructionType constructionType)
60 : Element(tagName, &document, constructionType)
62 , m_inRelativeLengthClientsInvalidation(false)
64 , m_SVGRareData(nullptr)
65 , m_className(SVGAnimatedString::create(this, HTMLNames::classAttr, SVGString::create()))
67 addToPropertyMap(m_className);
68 setHasCustomStyleCallbacks();
71 SVGElement::~SVGElement()
73 ASSERT(inDocument() || !hasRelativeLengths());
75 // The below teardown is all handled by weak pointer processing in oilpan.
77 if (hasSVGRareData()) {
78 if (SVGCursorElement* cursorElement = svgRareData()->cursorElement())
79 cursorElement->removeReferencedElement(this);
80 if (CSSCursorImageValue* cursorImageValue = svgRareData()->cursorImageValue())
81 cursorImageValue->removeReferencedElement(this);
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();
91 void SVGElement::detach(const AttachContext& context)
93 Element::detach(context);
94 if (SVGElement* element = correspondingElement())
95 element->removeInstanceMapping(this);
98 void SVGElement::attach(const AttachContext& context)
100 Element::attach(context);
101 if (SVGElement* element = correspondingElement())
102 element->mapInstanceToElement(this);
105 short SVGElement::tabIndex() const
108 return Element::tabIndex();
112 void SVGElement::willRecalcStyle(StyleRecalcChange change)
114 if (!hasSVGRareData())
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();
122 void SVGElement::buildPendingResourcesIfNeeded()
124 Document& document = this->document();
125 if (!needsPendingResourceHandling() || !inDocument() || inUseShadowTree())
128 SVGDocumentExtensions& extensions = document.accessSVGExtensions();
129 AtomicString resourceId = getIdAttribute();
130 if (!extensions.hasPendingResource(resourceId))
133 // Mark pending resources as pending for removal.
134 extensions.markPendingResourcesForRemoval(resourceId);
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();
146 clientElement->buildPendingResource();
147 extensions.clearHasPendingResourcesIfPossible(clientElement);
152 SVGElementRareData* SVGElement::ensureSVGRareData()
154 if (hasSVGRareData())
155 return svgRareData();
157 m_SVGRareData = adoptPtrWillBeNoop(new SVGElementRareData(this));
158 return m_SVGRareData.get();
161 bool SVGElement::isOutermostSVGSVGElement() const
163 if (!isSVGSVGElement(*this))
166 // Element may not be in the document, pretend we're outermost for viewport(), getCTM(), etc.
170 // We act like an outermost SVG element, if we're a direct child of a <foreignObject> element.
171 if (isSVGForeignObjectElement(*parentNode()))
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())
180 // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
181 return !parentNode()->isSVGElement();
184 void SVGElement::reportAttributeParsingError(SVGParsingError error, const QualifiedName& name, const AtomicString& value)
186 if (error == NoError)
189 String errorString = "<" + tagName() + "> attribute " + name.toString() + "=\"" + value + "\"";
190 SVGDocumentExtensions& extensions = document().accessSVGExtensions();
192 if (error == NegativeValueForbiddenError) {
193 extensions.reportError("Invalid negative value for " + errorString);
197 if (error == ParsingAttributeFailedError) {
198 extensions.reportError("Invalid value for " + errorString);
202 ASSERT_NOT_REACHED();
205 String SVGElement::title() const
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())
212 if (inUseShadowTree()) {
213 String useTitle(shadowHost()->title());
214 if (!useTitle.isEmpty())
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();
224 // Otherwise return a null/empty string.
228 bool SVGElement::instanceUpdatesBlocked() const
230 return hasSVGRareData() && svgRareData()->instanceUpdatesBlocked();
233 void SVGElement::setInstanceUpdatesBlocked(bool value)
235 if (hasSVGRareData())
236 svgRareData()->setInstanceUpdatesBlocked(value);
239 AffineTransform SVGElement::localCoordinateSpaceTransform(CTMScope) const
241 // To be overriden by SVGGraphicsElement (or as special case SVGTextElement and SVGPatternElement)
242 return AffineTransform();
245 Node::InsertionNotificationRequest SVGElement::insertedInto(ContainerNode* rootParent)
247 Element::insertedInto(rootParent);
248 updateRelativeLengthsInformation();
249 buildPendingResourcesIfNeeded();
250 return InsertionDone;
253 void SVGElement::removedFrom(ContainerNode* rootParent)
255 bool wasInDocument = rootParent->inDocument();
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);
266 m_elementsWithRelativeLengths.clear();
269 ASSERT_WITH_SECURITY_IMPLICATION(!rootParent->isSVGElement() || !toSVGElement(rootParent)->m_elementsWithRelativeLengths.contains(this));
271 Element::removedFrom(rootParent);
274 rebuildAllIncomingReferences();
275 removeAllIncomingReferences();
278 invalidateInstances();
281 void SVGElement::childrenChanged(const ChildrenChange& change)
283 Element::childrenChanged(change);
285 // Invalidate all instances associated with us.
286 if (!change.byParser)
287 invalidateInstances();
290 CSSPropertyID SVGElement::cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
292 if (!attrName.namespaceURI().isNull())
293 return CSSPropertyInvalid;
295 static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0;
296 if (!propertyNameToIdMap) {
297 propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>;
298 // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
299 const QualifiedName* const attrNames[] = {
300 &alignment_baselineAttr,
302 &buffered_renderingAttr,
306 &SVGNames::colorAttr,
307 &color_interpolationAttr,
308 &color_interpolation_filtersAttr,
309 &color_renderingAttr,
311 &SVGNames::directionAttr,
313 &dominant_baselineAttr,
314 &enable_backgroundAttr,
327 &glyph_orientation_horizontalAttr,
328 &glyph_orientation_verticalAttr,
329 &image_renderingAttr,
341 &shape_renderingAttr,
345 &stroke_dasharrayAttr,
346 &stroke_dashoffsetAttr,
348 &stroke_linejoinAttr,
349 &stroke_miterlimitAttr,
353 &text_decorationAttr,
355 &transform_originAttr,
362 for (size_t i = 0; i < WTF_ARRAY_LENGTH(attrNames); i++) {
363 CSSPropertyID propertyId = cssPropertyID(attrNames[i]->localName());
364 ASSERT(propertyId > 0);
365 propertyNameToIdMap->set(attrNames[i]->localName().impl(), propertyId);
369 return propertyNameToIdMap->get(attrName.localName().impl());
372 void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
374 ASSERT(clientElement);
376 // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
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);
387 bool hadRelativeLengths = currentElement->hasRelativeLengths();
388 if (clientHasRelativeLengths)
389 currentElement->m_elementsWithRelativeLengths.add(clientElement);
391 currentElement->m_elementsWithRelativeLengths.remove(clientElement);
393 // If the relative length state hasn't changed, we can stop propagating the notification.
394 if (hadRelativeLengths == currentElement->hasRelativeLengths())
397 clientElement = currentElement;
398 clientHasRelativeLengths = clientElement->hasRelativeLengths();
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));
407 svgExtensions.removeSVGRootWithRelativeLengthDescendents(toSVGSVGElement(clientElement));
411 void SVGElement::invalidateRelativeLengthClients(SubtreeLayoutScope* layoutScope)
416 ASSERT(!m_inRelativeLengthClientsInvalidation);
418 TemporaryChange<bool> inRelativeLengthClientsInvalidationChange(m_inRelativeLengthClientsInvalidation, true);
421 RenderObject* renderer = this->renderer();
422 if (renderer && selfHasRelativeLengths()) {
423 if (renderer->isSVGResourceContainer())
424 toRenderSVGResourceContainer(renderer)->invalidateCacheAndMarkForLayout(layoutScope);
426 renderer->setNeedsLayoutAndFullPaintInvalidation(MarkContainingBlockChain, layoutScope);
429 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator end = m_elementsWithRelativeLengths.end();
430 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::iterator it = m_elementsWithRelativeLengths.begin(); it != end; ++it) {
432 (*it)->invalidateRelativeLengthClients(layoutScope);
436 SVGSVGElement* SVGElement::ownerSVGElement() const
438 ContainerNode* n = parentOrShadowHostNode();
440 if (isSVGSVGElement(*n))
441 return toSVGSVGElement(n);
443 n = n->parentOrShadowHostNode();
449 SVGElement* SVGElement::viewportElement() const
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();
455 if (isSVGSVGElement(*n) || isSVGImageElement(*n) || isSVGSymbolElement(*n))
456 return toSVGElement(n);
458 n = n->parentOrShadowHostNode();
464 SVGDocumentExtensions& SVGElement::accessDocumentSVGExtensions()
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();
471 void SVGElement::mapInstanceToElement(SVGElement* instance)
474 ASSERT(instance->inUseShadowTree());
476 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = ensureSVGRareData()->elementInstances();
477 ASSERT(!instances.contains(instance));
479 instances.add(instance);
482 void SVGElement::removeInstanceMapping(SVGElement* instance)
485 ASSERT(instance->inUseShadowTree());
487 if (!hasSVGRareData())
490 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances = svgRareData()->elementInstances();
492 instances.remove(instance);
495 static WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& emptyInstances()
497 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > >, emptyInstances, (adoptPtrWillBeNoop(new WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >())));
498 return *emptyInstances;
501 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& SVGElement::instancesForElement() const
503 if (!hasSVGRareData())
504 return emptyInstances();
505 return svgRareData()->elementInstances();
508 bool SVGElement::getBoundingBox(FloatRect& rect)
510 if (!isSVGGraphicsElement())
513 rect = toSVGGraphicsElement(this)->getBBox();
517 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
519 SVGElementRareData* rareData = ensureSVGRareData();
520 if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
521 if (cursorElement == oldCursorElement)
523 oldCursorElement->removeReferencedElement(this);
525 rareData->setCursorElement(cursorElement);
529 void SVGElement::cursorElementRemoved()
531 svgRareData()->setCursorElement(0);
535 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
537 SVGElementRareData* rareData = ensureSVGRareData();
539 if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
540 if (cursorImageValue == oldCursorImageValue)
542 oldCursorImageValue->removeReferencedElement(this);
545 rareData->setCursorImageValue(cursorImageValue);
549 void SVGElement::cursorImageValueRemoved()
551 svgRareData()->setCursorImageValue(0);
555 SVGElement* SVGElement::correspondingElement()
557 ASSERT(!hasSVGRareData() || !svgRareData()->correspondingElement() || containingShadowRoot());
558 return hasSVGRareData() ? svgRareData()->correspondingElement() : 0;
561 SVGUseElement* SVGElement::correspondingUseElement() const
563 if (ShadowRoot* root = containingShadowRoot()) {
564 if (isSVGUseElement(root->host()) && (root->type() == ShadowRoot::UserAgentShadowRoot))
565 return toSVGUseElement(root->host());
570 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
572 ensureSVGRareData()->setCorrespondingElement(correspondingElement);
575 bool SVGElement::inUseShadowTree() const
577 return correspondingUseElement();
580 void SVGElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
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);
595 const AtomicString& eventName = HTMLElement::eventNameForAttributeName(name);
596 if (!eventName.isNull())
597 setAttributeEventListener(eventName, createAttributeEventListener(this, name, value, eventParameterName()));
599 Element::parseAttribute(name, value);
603 void SVGElement::parseAttributeNew(const QualifiedName& name, const AtomicString& value)
605 RefPtr<SVGAnimatedPropertyBase> property = propertyFromAttribute(name);
607 SVGParsingError parseError = NoError;
608 property->setBaseValueAsString(value, parseError);
609 reportAttributeParsingError(parseError, name, value);
614 SVGElement::parseAttribute(name, value);
617 typedef HashMap<QualifiedName, AnimatedPropertyType> AttributeToPropertyTypeMap;
618 AnimatedPropertyType SVGElement::animatedPropertyTypeForCSSAttribute(const QualifiedName& attributeName)
620 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, cssPropertyMap, ());
622 if (cssPropertyMap.isEmpty()) {
623 // Fill the map for the first use.
624 struct AttrToTypeEntry {
625 const QualifiedName& attr;
626 const AnimatedPropertyType propType;
628 const AttrToTypeEntry attrToTypes[] = {
629 { alignment_baselineAttr, AnimatedString },
630 { baseline_shiftAttr, AnimatedString },
631 { buffered_renderingAttr, AnimatedString },
632 { clip_pathAttr, AnimatedString },
633 { clip_ruleAttr, AnimatedString },
634 { SVGNames::colorAttr, AnimatedColor },
635 { color_interpolationAttr, AnimatedString },
636 { color_interpolation_filtersAttr, AnimatedString },
637 { color_renderingAttr, AnimatedString },
638 { cursorAttr, AnimatedString },
639 { displayAttr, AnimatedString },
640 { dominant_baselineAttr, AnimatedString },
641 { fillAttr, AnimatedColor },
642 { fill_opacityAttr, AnimatedNumber },
643 { fill_ruleAttr, AnimatedString },
644 { filterAttr, AnimatedString },
645 { flood_colorAttr, AnimatedColor },
646 { flood_opacityAttr, AnimatedNumber },
647 { font_familyAttr, AnimatedString },
648 { font_sizeAttr, AnimatedLength },
649 { font_stretchAttr, AnimatedString },
650 { font_styleAttr, AnimatedString },
651 { font_variantAttr, AnimatedString },
652 { font_weightAttr, AnimatedString },
653 { image_renderingAttr, AnimatedString },
654 { letter_spacingAttr, AnimatedLength },
655 { lighting_colorAttr, AnimatedColor },
656 { marker_endAttr, AnimatedString },
657 { marker_midAttr, AnimatedString },
658 { marker_startAttr, AnimatedString },
659 { maskAttr, AnimatedString },
660 { mask_typeAttr, AnimatedString },
661 { opacityAttr, AnimatedNumber },
662 { overflowAttr, AnimatedString },
663 { paint_orderAttr, AnimatedString },
664 { pointer_eventsAttr, AnimatedString },
665 { shape_renderingAttr, AnimatedString },
666 { stop_colorAttr, AnimatedColor },
667 { stop_opacityAttr, AnimatedNumber },
668 { strokeAttr, AnimatedColor },
669 { stroke_dasharrayAttr, AnimatedLengthList },
670 { stroke_dashoffsetAttr, AnimatedLength },
671 { stroke_linecapAttr, AnimatedString },
672 { stroke_linejoinAttr, AnimatedString },
673 { stroke_miterlimitAttr, AnimatedNumber },
674 { stroke_opacityAttr, AnimatedNumber },
675 { stroke_widthAttr, AnimatedLength },
676 { text_anchorAttr, AnimatedString },
677 { text_decorationAttr, AnimatedString },
678 { text_renderingAttr, AnimatedString },
679 { vector_effectAttr, AnimatedString },
680 { visibilityAttr, AnimatedString },
681 { word_spacingAttr, AnimatedLength },
683 for (size_t i = 0; i < WTF_ARRAY_LENGTH(attrToTypes); i++)
684 cssPropertyMap.set(attrToTypes[i].attr, attrToTypes[i].propType);
687 if (cssPropertyMap.contains(attributeName))
688 return cssPropertyMap.get(attributeName);
690 return AnimatedUnknown;
693 void SVGElement::addToPropertyMap(PassRefPtr<SVGAnimatedPropertyBase> passProperty)
695 RefPtr<SVGAnimatedPropertyBase> property(passProperty);
696 QualifiedName attributeName = property->attributeName();
697 m_attributeToPropertyMap.set(attributeName, property.release());
700 PassRefPtr<SVGAnimatedPropertyBase> SVGElement::propertyFromAttribute(const QualifiedName& attributeName)
702 AttributeToPropertyMap::iterator it = m_attributeToPropertyMap.find<SVGAttributeHashTranslator>(attributeName);
703 if (it == m_attributeToPropertyMap.end())
709 bool SVGElement::isAnimatableCSSProperty(const QualifiedName& attrName)
711 return animatedPropertyTypeForCSSAttribute(attrName) != AnimatedUnknown;
714 bool SVGElement::isPresentationAttribute(const QualifiedName& name) const
716 return cssPropertyIdForSVGAttributeName(name) > 0;
719 void SVGElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
721 CSSPropertyID propertyID = cssPropertyIdForSVGAttributeName(name);
723 addPropertyToPresentationAttributeStyle(style, propertyID, value);
726 bool SVGElement::haveLoadedRequiredResources()
728 for (SVGElement* child = Traversal<SVGElement>::firstChild(*this); child; child = Traversal<SVGElement>::nextSibling(*child)) {
729 if (!child->haveLoadedRequiredResources())
735 static inline void collectInstancesForSVGElement(SVGElement* element, WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& instances)
738 if (element->containingShadowRoot())
741 ASSERT(!element->instanceUpdatesBlocked());
743 instances = element->instancesForElement();
746 bool SVGElement::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
748 RefPtr<EventListener> listener = prpListener;
750 // Add event listener to regular DOM element
751 if (!Node::addEventListener(eventType, listener, useCapture))
754 // Add event listener to all shadow tree DOM element instances
755 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
756 collectInstancesForSVGElement(this, instances);
757 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
758 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
759 bool result = (*it)->Node::addEventListener(eventType, listener, useCapture);
760 ASSERT_UNUSED(result, result);
766 bool SVGElement::removeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> prpListener, bool useCapture)
768 RefPtr<EventListener> listener = prpListener;
770 // Remove event listener from regular DOM element
771 if (!Node::removeEventListener(eventType, listener, useCapture))
774 // Remove event listener from all shadow tree DOM element instances
775 WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> > instances;
776 collectInstancesForSVGElement(this, instances);
777 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = instances.end();
778 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = instances.begin(); it != end; ++it) {
779 SVGElement* shadowTreeElement = *it;
780 ASSERT(shadowTreeElement);
782 shadowTreeElement->Node::removeEventListener(eventType, listener, useCapture);
788 static bool hasLoadListener(Element* element)
790 if (element->hasEventListeners(EventTypeNames::load))
793 for (element = element->parentOrShadowHostElement(); element; element = element->parentOrShadowHostElement()) {
794 const EventListenerVector& entry = element->getEventListeners(EventTypeNames::load);
795 for (size_t i = 0; i < entry.size(); ++i) {
796 if (entry[i].useCapture)
804 bool SVGElement::sendSVGLoadEventIfPossible()
806 if (!haveLoadedRequiredResources())
808 if ((isStructurallyExternal() || isSVGSVGElement(*this)) && hasLoadListener(this))
809 dispatchEvent(Event::create(EventTypeNames::load));
813 void SVGElement::sendSVGLoadEventToSelfAndAncestorChainIfPossible()
815 // Let Document::implicitClose() dispatch the 'load' to the outermost SVG root.
816 if (isOutermostSVGSVGElement())
819 // Save the next parent to dispatch to in case dispatching the event mutates the tree.
820 RefPtrWillBeRawPtr<Element> parent = parentOrShadowHostElement();
821 if (!sendSVGLoadEventIfPossible())
824 // If document/window 'load' has been sent already, then only deliver to
825 // the element in question.
826 if (document().loadEventFinished())
829 if (!parent || !parent->isSVGElement())
832 toSVGElement(parent)->sendSVGLoadEventToSelfAndAncestorChainIfPossible();
835 void SVGElement::sendSVGLoadEventIfPossibleAsynchronously()
837 svgLoadEventTimer()->startOneShot(0, FROM_HERE);
840 void SVGElement::svgLoadEventTimerFired(Timer<SVGElement>*)
842 sendSVGLoadEventIfPossible();
845 Timer<SVGElement>* SVGElement::svgLoadEventTimer()
847 ASSERT_NOT_REACHED();
851 void SVGElement::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
853 Element::attributeChanged(name, newValue);
855 if (isIdAttributeName(name))
856 rebuildAllIncomingReferences();
858 // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
859 // so we don't want changes to the style attribute to result in extra work here.
860 if (name != HTMLNames::styleAttr)
861 svgAttributeChanged(name);
864 void SVGElement::svgAttributeChanged(const QualifiedName& attrName)
866 CSSPropertyID propId = SVGElement::cssPropertyIdForSVGAttributeName(attrName);
868 invalidateInstances();
872 if (attrName == HTMLNames::classAttr) {
873 classAttributeChanged(AtomicString(m_className->currentValue()->value()));
874 invalidateInstances();
878 if (isIdAttributeName(attrName)) {
879 RenderObject* object = renderer();
880 // Notify resources about id changes, this is important as we cache resources by id in SVGDocumentExtensions
881 if (object && object->isSVGResourceContainer())
882 toRenderSVGResourceContainer(object)->idChanged();
884 buildPendingResourcesIfNeeded();
885 invalidateInstances();
890 void SVGElement::synchronizeAnimatedSVGAttribute(const QualifiedName& name) const
892 if (!elementData() || !elementData()->m_animatedSVGAttributesAreDirty)
895 if (name == anyQName()) {
896 AttributeToPropertyMap::const_iterator::Values it = m_attributeToPropertyMap.values().begin();
897 AttributeToPropertyMap::const_iterator::Values end = m_attributeToPropertyMap.values().end();
898 for (; it != end; ++it) {
899 if ((*it)->needsSynchronizeAttribute())
900 (*it)->synchronizeAttribute();
903 elementData()->m_animatedSVGAttributesAreDirty = false;
905 RefPtr<SVGAnimatedPropertyBase> property = m_attributeToPropertyMap.get(name);
906 if (property && property->needsSynchronizeAttribute())
907 property->synchronizeAttribute();
911 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
913 if (!correspondingElement())
914 return document().ensureStyleResolver().styleForElement(this);
916 RenderStyle* style = 0;
917 if (Element* parent = parentOrShadowHostElement()) {
918 if (RenderObject* renderer = parent->renderer())
919 style = renderer->style();
922 return document().ensureStyleResolver().styleForElement(correspondingElement(), style, DisallowStyleSharing);
925 MutableStylePropertySet* SVGElement::animatedSMILStyleProperties() const
927 if (hasSVGRareData())
928 return svgRareData()->animatedSMILStyleProperties();
932 MutableStylePropertySet* SVGElement::ensureAnimatedSMILStyleProperties()
934 return ensureSVGRareData()->ensureAnimatedSMILStyleProperties();
937 void SVGElement::setUseOverrideComputedStyle(bool value)
939 if (hasSVGRareData())
940 svgRareData()->setUseOverrideComputedStyle(value);
943 RenderStyle* SVGElement::computedStyle(PseudoId pseudoElementSpecifier)
945 if (!hasSVGRareData() || !svgRareData()->useOverrideComputedStyle())
946 return Element::computedStyle(pseudoElementSpecifier);
948 RenderStyle* parentStyle = 0;
949 if (Element* parent = parentOrShadowHostElement()) {
950 if (RenderObject* renderer = parent->renderer())
951 parentStyle = renderer->style();
954 return svgRareData()->overrideComputedStyle(this, parentStyle);
957 bool SVGElement::hasFocusEventListeners() const
959 return hasEventListeners(EventTypeNames::focusin) || hasEventListeners(EventTypeNames::focusout)
960 || hasEventListeners(EventTypeNames::focus) || hasEventListeners(EventTypeNames::blur);
963 void SVGElement::markForLayoutAndParentResourceInvalidation(RenderObject* renderer)
966 RenderSVGResourceContainer::markForLayoutAndParentResourceInvalidation(renderer, true);
969 void SVGElement::invalidateInstances()
974 if (instanceUpdatesBlocked())
977 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >& set = instancesForElement();
981 // Mark all use elements referencing 'element' for rebuilding
982 const WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator end = set.end();
983 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<SVGElement> >::const_iterator it = set.begin(); it != end; ++it) {
984 (*it)->setCorrespondingElement(0);
986 if (SVGUseElement* element = (*it)->correspondingUseElement()) {
987 ASSERT(element->inDocument());
988 element->invalidateShadowTree();
992 svgRareData()->elementInstances().clear();
994 document().updateRenderTreeIfNeeded();
997 SVGElement::InstanceUpdateBlocker::InstanceUpdateBlocker(SVGElement* targetElement)
998 : m_targetElement(targetElement)
1000 if (m_targetElement)
1001 m_targetElement->setInstanceUpdatesBlocked(true);
1004 SVGElement::InstanceUpdateBlocker::~InstanceUpdateBlocker()
1006 if (m_targetElement)
1007 m_targetElement->setInstanceUpdatesBlocked(false);
1011 bool SVGElement::isAnimatableAttribute(const QualifiedName& name) const
1013 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, animatableAttributes, ());
1015 if (animatableAttributes.isEmpty()) {
1016 const QualifiedName* const animatableAttrs[] = {
1017 &XLinkNames::hrefAttr,
1018 &SVGNames::amplitudeAttr,
1019 &SVGNames::azimuthAttr,
1020 &SVGNames::baseFrequencyAttr,
1021 &SVGNames::biasAttr,
1022 &SVGNames::clipPathUnitsAttr,
1025 &SVGNames::diffuseConstantAttr,
1026 &SVGNames::divisorAttr,
1029 &SVGNames::edgeModeAttr,
1030 &SVGNames::elevationAttr,
1031 &SVGNames::exponentAttr,
1032 &SVGNames::filterResAttr,
1033 &SVGNames::filterUnitsAttr,
1036 &SVGNames::gradientTransformAttr,
1037 &SVGNames::gradientUnitsAttr,
1038 &SVGNames::heightAttr,
1041 &SVGNames::interceptAttr,
1046 &SVGNames::kernelMatrixAttr,
1047 &SVGNames::kernelUnitLengthAttr,
1048 &SVGNames::lengthAdjustAttr,
1049 &SVGNames::limitingConeAngleAttr,
1050 &SVGNames::markerHeightAttr,
1051 &SVGNames::markerUnitsAttr,
1052 &SVGNames::markerWidthAttr,
1053 &SVGNames::maskContentUnitsAttr,
1054 &SVGNames::maskUnitsAttr,
1055 &SVGNames::methodAttr,
1056 &SVGNames::modeAttr,
1057 &SVGNames::numOctavesAttr,
1058 &SVGNames::offsetAttr,
1059 &SVGNames::operatorAttr,
1060 &SVGNames::orderAttr,
1061 &SVGNames::orientAttr,
1062 &SVGNames::pathLengthAttr,
1063 &SVGNames::patternContentUnitsAttr,
1064 &SVGNames::patternTransformAttr,
1065 &SVGNames::patternUnitsAttr,
1066 &SVGNames::pointsAtXAttr,
1067 &SVGNames::pointsAtYAttr,
1068 &SVGNames::pointsAtZAttr,
1069 &SVGNames::preserveAlphaAttr,
1070 &SVGNames::preserveAspectRatioAttr,
1071 &SVGNames::primitiveUnitsAttr,
1072 &SVGNames::radiusAttr,
1074 &SVGNames::refXAttr,
1075 &SVGNames::refYAttr,
1076 &SVGNames::resultAttr,
1077 &SVGNames::rotateAttr,
1080 &SVGNames::scaleAttr,
1081 &SVGNames::seedAttr,
1082 &SVGNames::slopeAttr,
1083 &SVGNames::spacingAttr,
1084 &SVGNames::specularConstantAttr,
1085 &SVGNames::specularExponentAttr,
1086 &SVGNames::spreadMethodAttr,
1087 &SVGNames::startOffsetAttr,
1088 &SVGNames::stdDeviationAttr,
1089 &SVGNames::stitchTilesAttr,
1090 &SVGNames::surfaceScaleAttr,
1091 &SVGNames::tableValuesAttr,
1092 &SVGNames::targetAttr,
1093 &SVGNames::targetXAttr,
1094 &SVGNames::targetYAttr,
1095 &SVGNames::transformAttr,
1096 &SVGNames::typeAttr,
1097 &SVGNames::valuesAttr,
1098 &SVGNames::viewBoxAttr,
1099 &SVGNames::widthAttr,
1103 &SVGNames::xChannelSelectorAttr,
1107 &SVGNames::yChannelSelectorAttr,
1110 for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableAttrs); i++)
1111 animatableAttributes.add(*animatableAttrs[i]);
1114 if (name == classAttr)
1117 return animatableAttributes.contains(name);
1121 SVGElementSet* SVGElement::setOfIncomingReferences() const
1123 if (!hasSVGRareData())
1125 return &svgRareData()->incomingReferences();
1128 void SVGElement::addReferenceTo(SVGElement* targetElement)
1130 ASSERT(targetElement);
1132 ensureSVGRareData()->outgoingReferences().add(targetElement);
1133 targetElement->ensureSVGRareData()->incomingReferences().add(this);
1136 void SVGElement::rebuildAllIncomingReferences()
1138 if (!hasSVGRareData())
1141 const SVGElementSet& incomingReferences = svgRareData()->incomingReferences();
1143 // Iterate on a snapshot as |incomingReferences| may be altered inside loop.
1144 WillBeHeapVector<RawPtrWillBeMember<SVGElement> > incomingReferencesSnapshot;
1145 copyToVector(incomingReferences, incomingReferencesSnapshot);
1147 // Force rebuilding the |sourceElement| so it knows about this change.
1148 for (WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::iterator it = incomingReferencesSnapshot.begin(), itEnd = incomingReferencesSnapshot.end(); it != itEnd; ++it) {
1149 SVGElement* sourceElement = *it;
1151 // Before rebuilding |sourceElement| ensure it was not removed from under us.
1152 if (incomingReferences.contains(sourceElement))
1153 sourceElement->svgAttributeChanged(XLinkNames::hrefAttr);
1157 void SVGElement::removeAllIncomingReferences()
1159 if (!hasSVGRareData())
1162 SVGElementSet& incomingReferences = svgRareData()->incomingReferences();
1163 for (SVGElementSet::iterator it = incomingReferences.begin(), itEnd = incomingReferences.end(); it != itEnd; ++it) {
1164 SVGElement* sourceElement = *it;
1165 ASSERT(sourceElement->hasSVGRareData());
1166 sourceElement->ensureSVGRareData()->outgoingReferences().remove(this);
1168 incomingReferences.clear();
1171 void SVGElement::removeAllOutgoingReferences()
1173 if (!hasSVGRareData())
1176 SVGElementSet& outgoingReferences = svgRareData()->outgoingReferences();
1177 for (SVGElementSet::iterator it = outgoingReferences.begin(), itEnd = outgoingReferences.end(); it != itEnd; ++it) {
1178 SVGElement* targetElement = *it;
1179 ASSERT(targetElement->hasSVGRareData());
1180 targetElement->ensureSVGRareData()->incomingReferences().remove(this);
1182 outgoingReferences.clear();
1185 void SVGElement::trace(Visitor* visitor)
1188 visitor->trace(m_elementsWithRelativeLengths);
1189 visitor->trace(m_SVGRareData);
1191 Element::trace(visitor);
1194 const AtomicString& SVGElement::eventParameterName()
1196 DEFINE_STATIC_LOCAL(const AtomicString, evtString, ("evt", AtomicString::ConstructFromLiteral));
1200 } // namespace blink