1 /*
2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2007 Rob Buis <buis@kde.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #if ENABLE(SVG)
24 #include "SVGScriptElement.h"
25
26 #include "Attribute.h"
27 #include "Document.h"
28 #include "Event.h"
29 #include "EventNames.h"
30 #include "SVGNames.h"
31
32 namespace WebCore {
33
34 // Animated property definitions
DEFINE_ANIMATED_STRING(SVGScriptElement,XLinkNames::hrefAttr,Href,href)35 DEFINE_ANIMATED_STRING(SVGScriptElement, XLinkNames::hrefAttr, Href, href)
36 DEFINE_ANIMATED_BOOLEAN(SVGScriptElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
37
38 inline SVGScriptElement::SVGScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool alreadyStarted)
39 : SVGElement(tagName, document)
40 , ScriptElement(this, wasInsertedByParser, alreadyStarted)
41 {
42 }
43
create(const QualifiedName & tagName,Document * document,bool insertedByParser)44 PassRefPtr<SVGScriptElement> SVGScriptElement::create(const QualifiedName& tagName, Document* document, bool insertedByParser)
45 {
46 return adoptRef(new SVGScriptElement(tagName, document, insertedByParser, false));
47 }
48
parseMappedAttribute(Attribute * attr)49 void SVGScriptElement::parseMappedAttribute(Attribute* attr)
50 {
51 const QualifiedName& attrName = attr->name();
52
53 if (attrName == SVGNames::typeAttr)
54 setType(attr->value());
55 else {
56 if (SVGURIReference::parseMappedAttribute(attr))
57 return;
58 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
59 return;
60
61 SVGElement::parseMappedAttribute(attr);
62 }
63 }
64
svgAttributeChanged(const QualifiedName & attrName)65 void SVGScriptElement::svgAttributeChanged(const QualifiedName& attrName)
66 {
67 SVGElement::svgAttributeChanged(attrName);
68
69 if (SVGURIReference::isKnownAttribute(attrName))
70 handleSourceAttribute(href());
71 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) {
72 // Handle dynamic updates of the 'externalResourcesRequired' attribute. Only possible case: changing from 'true' to 'false'
73 // causes an immediate dispatch of the SVGLoad event. If the attribute value was 'false' before inserting the script element
74 // in the document, the SVGLoad event has already been dispatched.
75 if (!externalResourcesRequiredBaseValue() && !haveFiredLoadEvent() && !isParserInserted()) {
76 setHaveFiredLoadEvent(true);
77 ASSERT(haveLoadedRequiredResources());
78
79 sendSVGLoadEventIfPossible();
80 }
81 }
82 }
83
synchronizeProperty(const QualifiedName & attrName)84 void SVGScriptElement::synchronizeProperty(const QualifiedName& attrName)
85 {
86 SVGElement::synchronizeProperty(attrName);
87
88 if (attrName == anyQName()) {
89 synchronizeExternalResourcesRequired();
90 synchronizeHref();
91 return;
92 }
93
94 if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
95 synchronizeExternalResourcesRequired();
96 else if (SVGURIReference::isKnownAttribute(attrName))
97 synchronizeHref();
98 }
99
attributeToPropertyTypeMap()100 AttributeToPropertyTypeMap& SVGScriptElement::attributeToPropertyTypeMap()
101 {
102 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
103 return s_attributeToPropertyTypeMap;
104 }
105
fillAttributeToPropertyTypeMap()106 void SVGScriptElement::fillAttributeToPropertyTypeMap()
107 {
108 attributeToPropertyTypeMap().set(XLinkNames::hrefAttr, AnimatedString);
109 }
110
insertedIntoDocument()111 void SVGScriptElement::insertedIntoDocument()
112 {
113 SVGElement::insertedIntoDocument();
114 ScriptElement::insertedIntoDocument();
115
116 if (isParserInserted())
117 return;
118
119 // Eventually send SVGLoad event now for the dynamically inserted script element
120 if (!externalResourcesRequiredBaseValue()) {
121 setHaveFiredLoadEvent(true);
122 sendSVGLoadEventIfPossible();
123 }
124 }
125
removedFromDocument()126 void SVGScriptElement::removedFromDocument()
127 {
128 SVGElement::removedFromDocument();
129 ScriptElement::removedFromDocument();
130 }
131
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)132 void SVGScriptElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
133 {
134 ScriptElement::childrenChanged();
135 SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
136 }
137
isURLAttribute(Attribute * attr) const138 bool SVGScriptElement::isURLAttribute(Attribute* attr) const
139 {
140 return attr->name() == sourceAttributeValue();
141 }
142
finishParsingChildren()143 void SVGScriptElement::finishParsingChildren()
144 {
145 SVGElement::finishParsingChildren();
146
147 // A SVGLoad event has been fired by SVGElement::finishParsingChildren.
148 if (!externalResourcesRequiredBaseValue())
149 setHaveFiredLoadEvent(true);
150 }
151
type() const152 String SVGScriptElement::type() const
153 {
154 return m_type;
155 }
156
setType(const String & type)157 void SVGScriptElement::setType(const String& type)
158 {
159 m_type = type;
160 }
161
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const162 void SVGScriptElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
163 {
164 SVGElement::addSubresourceAttributeURLs(urls);
165
166 addSubresourceURL(urls, document()->completeURL(href()));
167 }
168
haveLoadedRequiredResources()169 bool SVGScriptElement::haveLoadedRequiredResources()
170 {
171 return !externalResourcesRequiredBaseValue() || haveFiredLoadEvent();
172 }
173
sourceAttributeValue() const174 String SVGScriptElement::sourceAttributeValue() const
175 {
176 return href();
177 }
178
charsetAttributeValue() const179 String SVGScriptElement::charsetAttributeValue() const
180 {
181 return String();
182 }
183
typeAttributeValue() const184 String SVGScriptElement::typeAttributeValue() const
185 {
186 return type();
187 }
188
languageAttributeValue() const189 String SVGScriptElement::languageAttributeValue() const
190 {
191 return String();
192 }
193
forAttributeValue() const194 String SVGScriptElement::forAttributeValue() const
195 {
196 return String();
197 }
198
eventAttributeValue() const199 String SVGScriptElement::eventAttributeValue() const
200 {
201 return String();
202 }
203
asyncAttributeValue() const204 bool SVGScriptElement::asyncAttributeValue() const
205 {
206 return false;
207 }
208
deferAttributeValue() const209 bool SVGScriptElement::deferAttributeValue() const
210 {
211 return false;
212 }
213
hasSourceAttribute() const214 bool SVGScriptElement::hasSourceAttribute() const
215 {
216 return hasAttribute(XLinkNames::hrefAttr);
217 }
218
dispatchLoadEvent()219 void SVGScriptElement::dispatchLoadEvent()
220 {
221 bool externalResourcesRequired = externalResourcesRequiredBaseValue();
222
223 if (isParserInserted())
224 ASSERT(externalResourcesRequired != haveFiredLoadEvent());
225 else if (haveFiredLoadEvent()) {
226 // If we've already fired an load event and externalResourcesRequired is set to 'true'
227 // externalResourcesRequired has been modified while loading the <script>. Don't dispatch twice.
228 if (externalResourcesRequired)
229 return;
230 }
231
232 // HTML and SVG differ completly in the 'onload' event handling of <script> elements.
233 // HTML fires the 'load' event after it sucessfully loaded a remote resource, otherwhise an error event.
234 // SVG fires the SVGLoad event immediately after parsing the <script> element, if externalResourcesRequired
235 // is set to 'false', otherwhise it dispatches the 'SVGLoad' event just after loading the remote resource.
236 if (externalResourcesRequired) {
237 ASSERT(!haveFiredLoadEvent());
238
239 // Dispatch SVGLoad event
240 setHaveFiredLoadEvent(true);
241 ASSERT(haveLoadedRequiredResources());
242
243 sendSVGLoadEventIfPossible();
244 }
245 }
246
dispatchErrorEvent()247 void SVGScriptElement::dispatchErrorEvent()
248 {
249 dispatchEvent(Event::create(eventNames().errorEvent, true, false));
250 }
251
cloneElementWithoutAttributesAndChildren() const252 PassRefPtr<Element> SVGScriptElement::cloneElementWithoutAttributesAndChildren() const
253 {
254 return adoptRef(new SVGScriptElement(tagQName(), document(), false, alreadyStarted()));
255 }
256
257 }
258
259 #endif // ENABLE(SVG)
260