Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2007 Rob Buis <buis (at) 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)
    260