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