|
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) |