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