Home | History | Annotate | Download | only in svg
      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