initial import
[vuplus_webkit] / Source / WebCore / svg / SVGElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 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 "CSSStyleSelector.h"
32 #include "DOMImplementation.h"
33 #include "Document.h"
34 #include "Event.h"
35 #include "EventListener.h"
36 #include "EventNames.h"
37 #include "FrameView.h"
38 #include "HTMLNames.h"
39 #include "RegisteredEventListener.h"
40 #include "RenderObject.h"
41 #include "SVGCursorElement.h"
42 #include "SVGDocumentExtensions.h"
43 #include "SVGElementInstance.h"
44 #include "SVGElementRareData.h"
45 #include "SVGNames.h"
46 #include "SVGSVGElement.h"
47 #include "SVGStyledLocatableElement.h"
48 #include "SVGTextElement.h"
49 #include "SVGURIReference.h"
50 #include "SVGUseElement.h"
51 #include "ScriptEventListener.h"
52 #include "XMLNames.h"
53
54 namespace WebCore {
55
56 using namespace HTMLNames;
57
58 SVGElement::SVGElement(const QualifiedName& tagName, Document* document)
59     : StyledElement(tagName, document, CreateSVGElement)
60 {
61     setHasCustomStyleForRenderer();
62 }
63
64 PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document)
65 {
66     return adoptRef(new SVGElement(tagName, document));
67 }
68
69 SVGElement::~SVGElement()
70 {
71     if (!hasRareSVGData())
72         ASSERT(!SVGElementRareData::rareDataMap().contains(this));
73     else {
74         SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
75         SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
76         ASSERT(it != rareDataMap.end());
77
78         SVGElementRareData* rareData = it->second;
79         if (SVGCursorElement* cursorElement = rareData->cursorElement())
80             cursorElement->removeClient(this);
81         if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
82             cursorImageValue->removeReferencedElement(this);
83
84         delete rareData;
85         rareDataMap.remove(it);
86     }
87     document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(this);
88 }
89
90 SVGElementRareData* SVGElement::rareSVGData() const
91 {
92     ASSERT(hasRareSVGData());
93     return SVGElementRareData::rareDataFromMap(this);
94 }
95
96 SVGElementRareData* SVGElement::ensureRareSVGData()
97 {
98     if (hasRareSVGData())
99         return rareSVGData();
100
101     ASSERT(!SVGElementRareData::rareDataMap().contains(this));
102     SVGElementRareData* data = new SVGElementRareData;
103     SVGElementRareData::rareDataMap().set(this, data);
104     setHasRareSVGData();
105     return data;
106 }
107
108 void SVGElement::reportAttributeParsingError(SVGParsingError error, Attribute* attribute)
109 {
110     if (error == NoError)
111         return;
112
113     String errorString = "<" + tagName() + "> attribute " + attribute->name().toString() + "=\"" + attribute->value() + "\"";
114     SVGDocumentExtensions* extensions = document()->accessSVGExtensions();
115
116     if (error == NegativeValueForbiddenError) {
117         extensions->reportError("Invalid negative value for " + errorString);
118         return;
119     }
120
121     if (error == ParsingAttributeFailedError) {
122         extensions->reportError("Invalid value for " + errorString);
123         return;
124     }
125
126     ASSERT_NOT_REACHED();
127 }
128
129
130 bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const
131 {
132     return DOMImplementation::hasFeature(feature, version);
133 }
134
135 String SVGElement::xmlbase() const
136 {
137     return fastGetAttribute(XMLNames::baseAttr);
138 }
139
140 void SVGElement::setXmlbase(const String& value, ExceptionCode&)
141 {
142     setAttribute(XMLNames::baseAttr, value);
143 }
144
145 void SVGElement::removedFromDocument()
146 {
147     document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(this);
148     StyledElement::removedFromDocument();
149 }
150
151 SVGSVGElement* SVGElement::ownerSVGElement() const
152 {
153     ContainerNode* n = parentOrHostNode();
154     while (n) {
155         if (n->hasTagName(SVGNames::svgTag))
156             return static_cast<SVGSVGElement*>(n);
157
158         n = n->parentOrHostNode();
159     }
160
161     return 0;
162 }
163
164 SVGElement* SVGElement::viewportElement() const
165 {
166     // This function needs shadow tree support - as RenderSVGContainer uses this function
167     // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
168     ContainerNode* n = parentOrHostNode();
169     while (n) {
170         if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
171             return static_cast<SVGElement*>(n);
172
173         n = n->parentOrHostNode();
174     }
175
176     return 0;
177 }
178
179 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions()
180 {
181     // This function is provided for use by SVGAnimatedProperty to avoid
182     // global inclusion of Document.h in SVG code.
183     return document() ? document()->accessSVGExtensions() : 0;
184 }
185  
186 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
187 {
188     ASSERT(instance);
189
190     HashSet<SVGElementInstance*>& instances = ensureRareSVGData()->elementInstances();
191     ASSERT(!instances.contains(instance));
192
193     instances.add(instance);
194 }
195  
196 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
197 {
198     ASSERT(instance);
199     ASSERT(hasRareSVGData());
200
201     HashSet<SVGElementInstance*>& instances = rareSVGData()->elementInstances();
202     ASSERT(instances.contains(instance));
203
204     instances.remove(instance);
205 }
206
207 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
208 {
209     if (!hasRareSVGData()) {
210         DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
211         return emptyInstances;
212     }
213     return rareSVGData()->elementInstances();
214 }
215
216 bool SVGElement::boundingBox(FloatRect& rect, SVGLocatable::StyleUpdateStrategy styleUpdateStrategy)
217 {
218     if (isStyledLocatable()) {
219         rect = static_cast<SVGStyledLocatableElement*>(this)->getBBox(styleUpdateStrategy);
220         return true;
221     }
222     if (hasTagName(SVGNames::textTag)) {
223         rect = static_cast<SVGTextElement*>(this)->getBBox(styleUpdateStrategy);
224         return true;
225     }
226     return false;
227 }
228
229 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
230 {
231     SVGElementRareData* rareData = ensureRareSVGData();
232     if (SVGCursorElement* oldCursorElement = rareData->cursorElement()) {
233         if (cursorElement == oldCursorElement)
234             return;
235         oldCursorElement->removeReferencedElement(this);
236     }
237     rareData->setCursorElement(cursorElement);
238 }
239
240 void SVGElement::cursorElementRemoved() 
241 {
242     ASSERT(hasRareSVGData());
243     rareSVGData()->setCursorElement(0);
244 }
245
246 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
247 {
248     SVGElementRareData* rareData = ensureRareSVGData();
249     if (CSSCursorImageValue* oldCursorImageValue = rareData->cursorImageValue()) {
250         if (cursorImageValue == oldCursorImageValue)
251             return;
252         oldCursorImageValue->removeReferencedElement(this);
253     }
254     rareData->setCursorImageValue(cursorImageValue);
255 }
256
257 void SVGElement::cursorImageValueRemoved()
258 {
259     ASSERT(hasRareSVGData());
260     rareSVGData()->setCursorImageValue(0);
261 }
262
263 SVGElement* SVGElement::correspondingElement()
264 {
265     ASSERT(!hasRareSVGData() || !rareSVGData()->correspondingElement() || shadowTreeRootNode());
266     return hasRareSVGData() ? rareSVGData()->correspondingElement() : 0;
267 }
268
269 void SVGElement::setCorrespondingElement(SVGElement* correspondingElement)
270 {
271     ensureRareSVGData()->setCorrespondingElement(correspondingElement);
272 }
273
274 void SVGElement::parseMappedAttribute(Attribute* attr)
275 {
276     // standard events
277     if (attr->name() == onloadAttr)
278         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
279     else if (attr->name() == onclickAttr)
280         setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, attr));
281     else if (attr->name() == onmousedownAttr)
282         setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, attr));
283     else if (attr->name() == onmousemoveAttr)
284         setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, attr));
285     else if (attr->name() == onmouseoutAttr)
286         setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, attr));
287     else if (attr->name() == onmouseoverAttr)
288         setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, attr));
289     else if (attr->name() == onmouseupAttr)
290         setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, attr));
291     else if (attr->name() == SVGNames::onfocusinAttr)
292         setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, attr));
293     else if (attr->name() == SVGNames::onfocusoutAttr)
294         setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, attr));
295     else if (attr->name() == SVGNames::onactivateAttr)
296         setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, attr));
297     else
298         StyledElement::parseMappedAttribute(attr);
299 }
300
301 void SVGElement::animatedPropertyTypeForAttribute(const QualifiedName& attributeName, Vector<AnimatedPropertyType>& propertyTypes)
302 {
303     localAttributeToPropertyMap().animatedPropertyTypeForAttribute(attributeName, propertyTypes);
304 }
305
306 bool SVGElement::haveLoadedRequiredResources()
307 {
308     Node* child = firstChild();
309     while (child) {
310         if (child->isSVGElement() && !static_cast<SVGElement*>(child)->haveLoadedRequiredResources())
311             return false;
312         child = child->nextSibling();
313     }
314     return true;
315 }
316
317 static bool hasLoadListener(Node* node)
318 {
319     if (node->hasEventListeners(eventNames().loadEvent))
320         return true;
321
322     for (node = node->parentNode(); node && node->isElementNode(); node = node->parentNode()) {
323         const EventListenerVector& entry = node->getEventListeners(eventNames().loadEvent);
324         for (size_t i = 0; i < entry.size(); ++i) {
325             if (entry[i].useCapture)
326                 return true;
327         }
328     }
329
330     return false;
331 }
332
333 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
334 {
335     RefPtr<SVGElement> currentTarget = this;
336     while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
337         RefPtr<Node> parent;
338         if (sendParentLoadEvents)
339             parent = currentTarget->parentNode(); // save the next parent to dispatch too incase dispatching the event changes the tree
340         if (hasLoadListener(currentTarget.get()))
341             currentTarget->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
342         currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : RefPtr<SVGElement>();
343     }
344 }
345
346 void SVGElement::finishParsingChildren()
347 {
348     StyledElement::finishParsingChildren();
349
350     // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
351     // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
352     sendSVGLoadEventIfPossible();
353 }
354
355 bool SVGElement::childShouldCreateRenderer(Node* child) const
356 {
357     if (child->isSVGElement())
358         return static_cast<SVGElement*>(child)->isValid();
359     return false;
360 }
361
362 void SVGElement::attributeChanged(Attribute* attr, bool preserveDecls)
363 {
364     ASSERT(attr);
365     if (!attr)
366         return;
367
368     StyledElement::attributeChanged(attr, preserveDecls);
369
370     // When an animated SVG property changes through SVG DOM, svgAttributeChanged() is called, not attributeChanged().
371     // Next time someone tries to access the XML attributes, the synchronization code starts. During that synchronization
372     // SVGAnimatedPropertySynchronizer may call NamedNodeMap::removeAttribute(), which in turn calls attributeChanged().
373     // At this point we're not allowed to call svgAttributeChanged() again - it may lead to extra work being done, or crashes
374     // see bug https://bugs.webkit.org/show_bug.cgi?id=40994.
375     if (isSynchronizingSVGAttributes())
376         return;
377
378     if (isIdAttributeName(attr->name()))
379         document()->accessSVGExtensions()->removeAllAnimationElementsFromTarget(this);
380
381     // Changes to the style attribute are processed lazily (see Element::getAttribute() and related methods),
382     // so we don't want changes to the style attribute to result in extra work here.
383     if (attr->name() != HTMLNames::styleAttr)
384         svgAttributeChanged(attr->name());
385 }
386
387 void SVGElement::updateAnimatedSVGAttribute(const QualifiedName& name) const
388 {
389     if (isSynchronizingSVGAttributes() || areSVGAttributesValid())
390         return;
391
392     setIsSynchronizingSVGAttributes();
393
394     SVGElement* nonConstThis = const_cast<SVGElement*>(this);
395     if (name == anyQName()) {
396         nonConstThis->localAttributeToPropertyMap().synchronizeProperties(nonConstThis);
397         setAreSVGAttributesValid();
398     } else
399         nonConstThis->localAttributeToPropertyMap().synchronizeProperty(nonConstThis, name);
400
401     clearIsSynchronizingSVGAttributes();
402 }
403
404 SVGAttributeToPropertyMap& SVGElement::localAttributeToPropertyMap()
405 {
406     ASSERT_NOT_REACHED();
407
408     DEFINE_STATIC_LOCAL(SVGAttributeToPropertyMap, dummyMap, ());
409     return dummyMap;
410 }
411
412 void SVGElement::synchronizeRequiredFeatures(void* contextElement)
413 {
414     ASSERT(contextElement);
415     static_cast<SVGElement*>(contextElement)->synchronizeRequiredFeatures();
416 }
417
418 void SVGElement::synchronizeRequiredExtensions(void* contextElement)
419 {
420     ASSERT(contextElement);
421     static_cast<SVGElement*>(contextElement)->synchronizeRequiredExtensions();
422 }
423
424 void SVGElement::synchronizeSystemLanguage(void* contextElement)
425 {
426     ASSERT(contextElement);
427     static_cast<SVGElement*>(contextElement)->synchronizeSystemLanguage();
428 }
429
430 PassRefPtr<RenderStyle> SVGElement::customStyleForRenderer()
431 {
432     if (correspondingElement())
433         return document()->styleSelector()->styleForElement(correspondingElement(), parentNode() ? parentNode()->renderer()->style() : 0, false/*allowSharing*/);
434
435     return document()->styleSelector()->styleForElement(static_cast<Element*>(this), 0, true);
436 }
437
438 }
439
440 #endif // ENABLE(SVG)