1/* 2 Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 3 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#if ENABLE(SVG) 27#include "SVGElement.h" 28 29#include "CSSCursorImageValue.h" 30#include "DOMImplementation.h" 31#include "Document.h" 32#include "Event.h" 33#include "EventListener.h" 34#include "EventNames.h" 35#include "FrameView.h" 36#include "HTMLNames.h" 37#include "MappedAttribute.h" 38#include "RegisteredEventListener.h" 39#include "RenderObject.h" 40#include "SVGCursorElement.h" 41#include "SVGElementInstance.h" 42#include "SVGElementRareData.h" 43#include "SVGNames.h" 44#include "SVGResource.h" 45#include "SVGSVGElement.h" 46#include "SVGURIReference.h" 47#include "SVGUseElement.h" 48#include "ScriptEventListener.h" 49#include "XMLNames.h" 50 51namespace WebCore { 52 53using namespace HTMLNames; 54 55SVGElement::SVGElement(const QualifiedName& tagName, Document* document) 56 : StyledElement(tagName, document, CreateElementZeroRefCount) 57{ 58} 59 60PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document) 61{ 62 return new SVGElement(tagName, document); 63} 64 65SVGElement::~SVGElement() 66{ 67 if (!hasRareSVGData()) 68 ASSERT(!SVGElementRareData::rareDataMap().contains(this)); 69 else { 70 SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap(); 71 SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this); 72 ASSERT(it != rareDataMap.end()); 73 74 SVGElementRareData* rareData = it->second; 75 if (SVGCursorElement* cursorElement = rareData->cursorElement()) 76 cursorElement->removeClient(this); 77 if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue()) 78 cursorImageValue->removeReferencedElement(this); 79 80 delete rareData; 81 rareDataMap.remove(it); 82 } 83} 84 85SVGElementRareData* SVGElement::rareSVGData() const 86{ 87 ASSERT(hasRareSVGData()); 88 return SVGElementRareData::rareDataFromMap(this); 89} 90 91SVGElementRareData* SVGElement::ensureRareSVGData() 92{ 93 if (hasRareSVGData()) 94 return rareSVGData(); 95 96 ASSERT(!SVGElementRareData::rareDataMap().contains(this)); 97 SVGElementRareData* data = new SVGElementRareData; 98 SVGElementRareData::rareDataMap().set(this, data); 99 m_hasRareSVGData = true; 100 return data; 101} 102 103bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const 104{ 105 return DOMImplementation::hasFeature(feature, version); 106} 107 108String SVGElement::xmlbase() const 109{ 110 return getAttribute(XMLNames::baseAttr); 111} 112 113void SVGElement::setXmlbase(const String& value, ExceptionCode&) 114{ 115 setAttribute(XMLNames::baseAttr, value); 116} 117 118SVGSVGElement* SVGElement::ownerSVGElement() const 119{ 120 Node* n = isShadowNode() ? const_cast<SVGElement*>(this)->shadowParentNode() : parentNode(); 121 while (n) { 122 if (n->hasTagName(SVGNames::svgTag)) 123 return static_cast<SVGSVGElement*>(n); 124 125 n = n->isShadowNode() ? n->shadowParentNode() : n->parentNode(); 126 } 127 128 return 0; 129} 130 131SVGElement* SVGElement::viewportElement() const 132{ 133 // This function needs shadow tree support - as RenderSVGContainer uses this function 134 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise. 135 Node* n = isShadowNode() ? const_cast<SVGElement*>(this)->shadowParentNode() : parentNode(); 136 while (n) { 137 if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag)) 138 return static_cast<SVGElement*>(n); 139 140 n = n->isShadowNode() ? n->shadowParentNode() : n->parentNode(); 141 } 142 143 return 0; 144} 145 146SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions() const 147{ 148 // This function is provided for use by SVGAnimatedProperty to avoid 149 // global inclusion of Document.h in SVG code. 150 return document() ? document()->accessSVGExtensions() : 0; 151} 152 153void SVGElement::mapInstanceToElement(SVGElementInstance* instance) 154{ 155 ASSERT(instance); 156 157 HashSet<SVGElementInstance*>& instances = ensureRareSVGData()->elementInstances(); 158 ASSERT(!instances.contains(instance)); 159 160 instances.add(instance); 161} 162 163void SVGElement::removeInstanceMapping(SVGElementInstance* instance) 164{ 165 ASSERT(instance); 166 ASSERT(hasRareSVGData()); 167 168 HashSet<SVGElementInstance*>& instances = rareSVGData()->elementInstances(); 169 ASSERT(instances.contains(instance)); 170 171 instances.remove(instance); 172} 173 174const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const 175{ 176 if (!hasRareSVGData()) { 177 DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ()); 178 return emptyInstances; 179 } 180 return rareSVGData()->elementInstances(); 181} 182 183void SVGElement::setCursorElement(SVGCursorElement* cursorElement) 184{ 185 ensureRareSVGData()->setCursorElement(cursorElement); 186} 187 188void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue) 189{ 190 ensureRareSVGData()->setCursorImageValue(cursorImageValue); 191} 192 193void SVGElement::parseMappedAttribute(MappedAttribute* attr) 194{ 195 // standard events 196 if (attr->name() == onloadAttr) 197 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); 198 else if (attr->name() == onclickAttr) 199 setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, attr)); 200 else if (attr->name() == onmousedownAttr) 201 setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, attr)); 202 else if (attr->name() == onmousemoveAttr) 203 setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, attr)); 204 else if (attr->name() == onmouseoutAttr) 205 setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, attr)); 206 else if (attr->name() == onmouseoverAttr) 207 setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, attr)); 208 else if (attr->name() == onmouseupAttr) 209 setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, attr)); 210 else if (attr->name() == SVGNames::onfocusinAttr) 211 setAttributeEventListener(eventNames().DOMFocusInEvent, createAttributeEventListener(this, attr)); 212 else if (attr->name() == SVGNames::onfocusoutAttr) 213 setAttributeEventListener(eventNames().DOMFocusOutEvent, createAttributeEventListener(this, attr)); 214 else if (attr->name() == SVGNames::onactivateAttr) 215 setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, attr)); 216 else 217 StyledElement::parseMappedAttribute(attr); 218} 219 220bool SVGElement::haveLoadedRequiredResources() 221{ 222 Node* child = firstChild(); 223 while (child) { 224 if (child->isSVGElement() && !static_cast<SVGElement*>(child)->haveLoadedRequiredResources()) 225 return false; 226 child = child->nextSibling(); 227 } 228 return true; 229} 230 231static bool hasLoadListener(Node* node) 232{ 233 if (node->hasEventListeners(eventNames().loadEvent)) 234 return true; 235 236 for (node = node->parentNode(); node && node->isElementNode(); node = node->parentNode()) { 237 const EventListenerVector& entry = node->getEventListeners(eventNames().loadEvent); 238 for (size_t i = 0; i < entry.size(); ++i) { 239 if (entry[i].useCapture) 240 return true; 241 } 242 } 243 244 return false; 245} 246 247void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents) 248{ 249 RefPtr<SVGElement> currentTarget = this; 250 while (currentTarget && currentTarget->haveLoadedRequiredResources()) { 251 RefPtr<Node> parent; 252 if (sendParentLoadEvents) 253 parent = currentTarget->parentNode(); // save the next parent to dispatch too incase dispatching the event changes the tree 254 if (hasLoadListener(currentTarget.get())) { 255 RefPtr<Event> event = Event::create(eventNames().loadEvent, false, false); 256 event->setTarget(currentTarget); 257 currentTarget->dispatchGenericEvent(event.release()); 258 } 259 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : 0; 260 } 261} 262 263void SVGElement::finishParsingChildren() 264{ 265 StyledElement::finishParsingChildren(); 266 267 // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>) 268 // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish 269 sendSVGLoadEventIfPossible(); 270} 271 272bool SVGElement::childShouldCreateRenderer(Node* child) const 273{ 274 if (child->isSVGElement()) 275 return static_cast<SVGElement*>(child)->isValid(); 276 return false; 277} 278 279void SVGElement::insertedIntoDocument() 280{ 281 StyledElement::insertedIntoDocument(); 282 SVGDocumentExtensions* extensions = document()->accessSVGExtensions(); 283 284 String resourceId = SVGURIReference::getTarget(getAttribute(idAttributeName())); 285 if (extensions->isPendingResource(resourceId)) { 286 std::auto_ptr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(resourceId)); 287 if (clients->isEmpty()) 288 return; 289 290 HashSet<SVGStyledElement*>::const_iterator it = clients->begin(); 291 const HashSet<SVGStyledElement*>::const_iterator end = clients->end(); 292 293 for (; it != end; ++it) 294 (*it)->buildPendingResource(); 295 296 SVGResource::invalidateClients(*clients); 297 } 298} 299 300void SVGElement::attributeChanged(Attribute* attr, bool preserveDecls) 301{ 302 ASSERT(attr); 303 if (!attr) 304 return; 305 306 StyledElement::attributeChanged(attr, preserveDecls); 307 svgAttributeChanged(attr->name()); 308} 309 310void SVGElement::updateAnimatedSVGAttribute(const QualifiedName& name) const 311{ 312 ASSERT(!m_areSVGAttributesValid); 313 314 if (m_synchronizingSVGAttributes) 315 return; 316 317 m_synchronizingSVGAttributes = true; 318 319 const_cast<SVGElement*>(this)->synchronizeProperty(name); 320 if (name == anyQName()) 321 m_areSVGAttributesValid = true; 322 323 m_synchronizingSVGAttributes = false; 324} 325 326ContainerNode* SVGElement::eventParentNode() 327{ 328 if (Node* shadowParent = shadowParentNode()) { 329 ASSERT(shadowParent->isContainerNode()); 330 return static_cast<ContainerNode*>(shadowParent); 331 } 332 return StyledElement::eventParentNode(); 333} 334 335} 336 337#endif // ENABLE(SVG) 338