2011-02-19 James Simonsen <simonjam@chromium.org>
[WebKit-https.git] / Source / WebCore / svg / SVGScriptElement.cpp
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
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
44 PassRefPtr<SVGScriptElement> SVGScriptElement::create(const QualifiedName& tagName, Document* document, bool insertedByParser)
45 {
46     return adoptRef(new SVGScriptElement(tagName, document, insertedByParser, false));
47 }
48
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
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
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
100 AttributeToPropertyTypeMap& SVGScriptElement::attributeToPropertyTypeMap()
101 {
102     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
103     return s_attributeToPropertyTypeMap;
104 }
105
106 void SVGScriptElement::fillAttributeToPropertyTypeMap()
107 {
108     attributeToPropertyTypeMap().set(XLinkNames::hrefAttr, AnimatedString);
109 }
110
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
126 void SVGScriptElement::removedFromDocument()
127 {
128     SVGElement::removedFromDocument();
129     ScriptElement::removedFromDocument();
130 }
131
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
138 bool SVGScriptElement::isURLAttribute(Attribute* attr) const
139 {
140     return attr->name() == sourceAttributeValue();
141 }
142
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
152 String SVGScriptElement::type() const
153 {
154     return m_type;
155 }
156
157 void SVGScriptElement::setType(const String& type)
158 {
159     m_type = type;
160 }
161
162 void SVGScriptElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
163 {
164     SVGElement::addSubresourceAttributeURLs(urls);
165
166     addSubresourceURL(urls, document()->completeURL(href()));
167 }
168
169 bool SVGScriptElement::haveLoadedRequiredResources()
170 {
171     return !externalResourcesRequiredBaseValue() || haveFiredLoadEvent();
172 }
173
174 String SVGScriptElement::sourceAttributeValue() const
175 {
176     return href();
177 }
178
179 String SVGScriptElement::charsetAttributeValue() const
180 {
181     return String();
182 }
183
184 String SVGScriptElement::typeAttributeValue() const
185 {
186     return type();
187 }
188
189 String SVGScriptElement::languageAttributeValue() const
190 {
191     return String();
192 }
193
194 String SVGScriptElement::forAttributeValue() const
195 {
196     return String();
197 }
198
199 String SVGScriptElement::eventAttributeValue() const
200 {
201     return String();
202 }
203
204 bool SVGScriptElement::asyncAttributeValue() const
205 {
206     return false;
207 }
208
209 bool SVGScriptElement::deferAttributeValue() const
210 {
211     return false;
212 }
213
214 bool SVGScriptElement::hasSourceAttribute() const
215 {
216     return hasAttribute(XLinkNames::hrefAttr);
217 }
218
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
247 void SVGScriptElement::dispatchErrorEvent()
248 {
249     dispatchEvent(Event::create(eventNames().errorEvent, true, false));
250 }
251
252 PassRefPtr<Element> SVGScriptElement::cloneElementWithoutAttributesAndChildren() const
253 {
254     return adoptRef(new SVGScriptElement(tagQName(), document(), false, alreadyStarted()));
255 }
256
257 }
258
259 #endif // ENABLE(SVG)