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#include "core/svg/SVGScriptElement.h"
24
25#include "bindings/core/v8/ScriptEventListener.h"
26#include "core/HTMLNames.h"
27#include "core/XLinkNames.h"
28#include "core/dom/Attribute.h"
29#include "core/dom/ScriptLoader.h"
30#include "core/dom/ScriptRunner.h"
31#include "core/events/Event.h"
32
33namespace blink {
34
35inline SVGScriptElement::SVGScriptElement(Document& document, bool wasInsertedByParser, bool alreadyStarted)
36    : SVGElement(SVGNames::scriptTag, document)
37    , SVGURIReference(this)
38    , m_svgLoadEventTimer(this, &SVGElement::svgLoadEventTimerFired)
39    , m_loader(ScriptLoader::create(this, wasInsertedByParser, alreadyStarted))
40{
41}
42
43SVGScriptElement::~SVGScriptElement()
44{
45}
46
47PassRefPtrWillBeRawPtr<SVGScriptElement> SVGScriptElement::create(Document& document, bool insertedByParser)
48{
49    return adoptRefWillBeNoop(new SVGScriptElement(document, insertedByParser, false));
50}
51
52bool SVGScriptElement::isSupportedAttribute(const QualifiedName& attrName)
53{
54    DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
55    if (supportedAttributes.isEmpty()) {
56        SVGURIReference::addSupportedAttributes(supportedAttributes);
57        supportedAttributes.add(SVGNames::typeAttr);
58        supportedAttributes.add(HTMLNames::onerrorAttr);
59    }
60    return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
61}
62
63void SVGScriptElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
64{
65    if (!isSupportedAttribute(name)) {
66        SVGElement::parseAttribute(name, value);
67        return;
68    }
69
70    SVGParsingError parseError = NoError;
71    if (name == SVGNames::typeAttr)
72        return;
73
74    if (name == HTMLNames::onerrorAttr) {
75        setAttributeEventListener(EventTypeNames::error, createAttributeEventListener(this, name, value, eventParameterName()));
76    } else if (SVGURIReference::parseAttribute(name, value, parseError)) {
77    } else {
78        ASSERT_NOT_REACHED();
79    }
80
81    reportAttributeParsingError(parseError, name, value);
82}
83
84void SVGScriptElement::svgAttributeChanged(const QualifiedName& attrName)
85{
86    if (!isSupportedAttribute(attrName)) {
87        SVGElement::svgAttributeChanged(attrName);
88        return;
89    }
90
91    SVGElement::InvalidationGuard invalidationGuard(this);
92
93    if (attrName == SVGNames::typeAttr || attrName == HTMLNames::onerrorAttr)
94        return;
95
96    if (SVGURIReference::isKnownAttribute(attrName)) {
97        m_loader->handleSourceAttribute(hrefString());
98        return;
99    }
100
101    ASSERT_NOT_REACHED();
102}
103
104Node::InsertionNotificationRequest SVGScriptElement::insertedInto(ContainerNode* rootParent)
105{
106    SVGElement::insertedInto(rootParent);
107    return InsertionShouldCallDidNotifySubtreeInsertions;
108}
109
110void SVGScriptElement::didNotifySubtreeInsertionsToDocument()
111{
112    m_loader->didNotifySubtreeInsertionsToDocument();
113
114    if (!m_loader->isParserInserted()) {
115        m_loader->setHaveFiredLoadEvent(true);
116        sendSVGLoadEventIfPossibleAsynchronously();
117    }
118}
119
120void SVGScriptElement::childrenChanged(const ChildrenChange& change)
121{
122    SVGElement::childrenChanged(change);
123    m_loader->childrenChanged();
124}
125
126void SVGScriptElement::didMoveToNewDocument(Document& oldDocument)
127{
128    if (RefPtrWillBeRawPtr<Document> contextDocument = document().contextDocument().get())
129        oldDocument.scriptRunner()->movePendingAsyncScript(contextDocument->scriptRunner(), m_loader.get());
130    SVGElement::didMoveToNewDocument(oldDocument);
131}
132
133bool SVGScriptElement::isURLAttribute(const Attribute& attribute) const
134{
135    return attribute.name() == AtomicString(sourceAttributeValue());
136}
137
138void SVGScriptElement::finishParsingChildren()
139{
140    SVGElement::finishParsingChildren();
141    m_loader->setHaveFiredLoadEvent(true);
142}
143
144bool SVGScriptElement::haveLoadedRequiredResources()
145{
146    return m_loader->haveFiredLoadEvent();
147}
148
149String SVGScriptElement::sourceAttributeValue() const
150{
151    return hrefString();
152}
153
154String SVGScriptElement::charsetAttributeValue() const
155{
156    return String();
157}
158
159String SVGScriptElement::typeAttributeValue() const
160{
161    return getAttribute(SVGNames::typeAttr).string();
162}
163
164String SVGScriptElement::languageAttributeValue() const
165{
166    return String();
167}
168
169String SVGScriptElement::forAttributeValue() const
170{
171    return String();
172}
173
174String SVGScriptElement::eventAttributeValue() const
175{
176    return String();
177}
178
179bool SVGScriptElement::asyncAttributeValue() const
180{
181    return false;
182}
183
184bool SVGScriptElement::deferAttributeValue() const
185{
186    return false;
187}
188
189bool SVGScriptElement::hasSourceAttribute() const
190{
191    return href()->isSpecified();
192}
193
194PassRefPtrWillBeRawPtr<Element> SVGScriptElement::cloneElementWithoutAttributesAndChildren()
195{
196    return adoptRefWillBeNoop(new SVGScriptElement(document(), false, m_loader->alreadyStarted()));
197}
198
199void SVGScriptElement::dispatchLoadEvent()
200{
201    dispatchEvent(Event::create(EventTypeNames::load));
202}
203
204#if ENABLE(ASSERT)
205bool SVGScriptElement::isAnimatableAttribute(const QualifiedName& name) const
206{
207    if (name == SVGNames::typeAttr)
208        return false;
209
210    return SVGElement::isAnimatableAttribute(name);
211}
212#endif
213
214}
215