1 /* 2 Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 3 2004, 2005, 2006, 2008 Rob Buis <buis (at) kde.org> 4 Copyright (C) 2008 Apple Inc. All rights reserved. 5 Copyright (C) 2008 Alp Toker <alp (at) atoker.com> 6 Copyright (C) 2009 Cameron McCormack <cam (at) 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 51 namespace WebCore { 52 53 using namespace HTMLNames; 54 55 SVGElement::SVGElement(const QualifiedName& tagName, Document* document) 56 : StyledElement(tagName, document, CreateElementZeroRefCount) 57 { 58 } 59 60 PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document) 61 { 62 return new SVGElement(tagName, document); 63 } 64 65 SVGElement::~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 85 SVGElementRareData* SVGElement::rareSVGData() const 86 { 87 ASSERT(hasRareSVGData()); 88 return SVGElementRareData::rareDataFromMap(this); 89 } 90 91 SVGElementRareData* 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 103 bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const 104 { 105 return DOMImplementation::hasFeature(feature, version); 106 } 107 108 String SVGElement::xmlbase() const 109 { 110 return getAttribute(XMLNames::baseAttr); 111 } 112 113 void SVGElement::setXmlbase(const String& value, ExceptionCode&) 114 { 115 setAttribute(XMLNames::baseAttr, value); 116 } 117 118 SVGSVGElement* 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 131 SVGElement* 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 146 SVGDocumentExtensions* 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 153 void 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 163 void 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 174 const 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 183 void SVGElement::setCursorElement(SVGCursorElement* cursorElement) 184 { 185 ensureRareSVGData()->setCursorElement(cursorElement); 186 } 187 188 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue) 189 { 190 ensureRareSVGData()->setCursorImageValue(cursorImageValue); 191 } 192 193 void 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 220 bool 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 231 static 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 247 void 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 263 void 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 272 bool SVGElement::childShouldCreateRenderer(Node* child) const 273 { 274 if (child->isSVGElement()) 275 return static_cast<SVGElement*>(child)->isValid(); 276 return false; 277 } 278 279 void 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 300 void 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 310 void 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 326 ContainerNode* 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