Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2006 Alexander Kellett <lypanov (at) kde.org>
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Library General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Library General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Library General Public License
     17  * along with this library; see the file COPYING.LIB.  If not, write to
     18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     19  * Boston, MA 02110-1301, USA.
     20  */
     21 
     22 #include "config.h"
     23 
     24 #include "core/svg/SVGImageElement.h"
     25 
     26 #include "core/CSSPropertyNames.h"
     27 #include "core/XLinkNames.h"
     28 #include "core/rendering/RenderImageResource.h"
     29 #include "core/rendering/svg/RenderSVGImage.h"
     30 #include "core/rendering/svg/RenderSVGResource.h"
     31 
     32 namespace blink {
     33 
     34 inline SVGImageElement::SVGImageElement(Document& document)
     35     : SVGGraphicsElement(SVGNames::imageTag, document)
     36     , SVGURIReference(this)
     37     , m_x(SVGAnimatedLength::create(this, SVGNames::xAttr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
     38     , m_y(SVGAnimatedLength::create(this, SVGNames::yAttr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
     39     , m_width(SVGAnimatedLength::create(this, SVGNames::widthAttr, SVGLength::create(LengthModeWidth), ForbidNegativeLengths))
     40     , m_height(SVGAnimatedLength::create(this, SVGNames::heightAttr, SVGLength::create(LengthModeHeight), ForbidNegativeLengths))
     41     , m_preserveAspectRatio(SVGAnimatedPreserveAspectRatio::create(this, SVGNames::preserveAspectRatioAttr, SVGPreserveAspectRatio::create()))
     42     , m_imageLoader(SVGImageLoader::create(this))
     43     , m_needsLoaderURIUpdate(true)
     44 {
     45     addToPropertyMap(m_x);
     46     addToPropertyMap(m_y);
     47     addToPropertyMap(m_width);
     48     addToPropertyMap(m_height);
     49     addToPropertyMap(m_preserveAspectRatio);
     50 }
     51 
     52 DEFINE_NODE_FACTORY(SVGImageElement)
     53 
     54 void SVGImageElement::trace(Visitor* visitor)
     55 {
     56     visitor->trace(m_imageLoader);
     57     SVGGraphicsElement::trace(visitor);
     58 }
     59 
     60 bool SVGImageElement::currentFrameHasSingleSecurityOrigin() const
     61 {
     62     if (RenderSVGImage* renderSVGImage = toRenderSVGImage(renderer())) {
     63         if (renderSVGImage->imageResource()->hasImage()) {
     64             if (Image* image = renderSVGImage->imageResource()->cachedImage()->image())
     65                 return image->currentFrameHasSingleSecurityOrigin();
     66         }
     67     }
     68 
     69     return true;
     70 }
     71 
     72 bool SVGImageElement::isSupportedAttribute(const QualifiedName& attrName)
     73 {
     74     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     75     if (supportedAttributes.isEmpty()) {
     76         SVGURIReference::addSupportedAttributes(supportedAttributes);
     77         supportedAttributes.add(SVGNames::xAttr);
     78         supportedAttributes.add(SVGNames::yAttr);
     79         supportedAttributes.add(SVGNames::widthAttr);
     80         supportedAttributes.add(SVGNames::heightAttr);
     81         supportedAttributes.add(SVGNames::preserveAspectRatioAttr);
     82     }
     83     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
     84 }
     85 
     86 bool SVGImageElement::isPresentationAttribute(const QualifiedName& name) const
     87 {
     88     if (name == SVGNames::widthAttr || name == SVGNames::heightAttr)
     89         return true;
     90     return SVGGraphicsElement::isPresentationAttribute(name);
     91 }
     92 
     93 void SVGImageElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
     94 {
     95     if (!isSupportedAttribute(name))
     96         SVGGraphicsElement::collectStyleForPresentationAttribute(name, value, style);
     97     else if (name == SVGNames::widthAttr)
     98         addPropertyToPresentationAttributeStyle(style, CSSPropertyWidth, value);
     99     else if (name == SVGNames::heightAttr)
    100         addPropertyToPresentationAttributeStyle(style, CSSPropertyHeight, value);
    101 }
    102 
    103 void SVGImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
    104 {
    105     parseAttributeNew(name, value);
    106 }
    107 
    108 void SVGImageElement::svgAttributeChanged(const QualifiedName& attrName)
    109 {
    110     if (!isSupportedAttribute(attrName)) {
    111         SVGGraphicsElement::svgAttributeChanged(attrName);
    112         return;
    113     }
    114 
    115     SVGElement::InvalidationGuard invalidationGuard(this);
    116 
    117     bool isLengthAttribute = attrName == SVGNames::xAttr
    118                           || attrName == SVGNames::yAttr
    119                           || attrName == SVGNames::widthAttr
    120                           || attrName == SVGNames::heightAttr;
    121 
    122     if (isLengthAttribute)
    123         updateRelativeLengthsInformation();
    124 
    125     if (SVGURIReference::isKnownAttribute(attrName)) {
    126         if (inDocument())
    127             imageLoader().updateFromElement(ImageLoader::UpdateIgnorePreviousError);
    128         else
    129             m_needsLoaderURIUpdate = true;
    130         return;
    131     }
    132 
    133     RenderObject* renderer = this->renderer();
    134     if (!renderer)
    135         return;
    136 
    137     if (isLengthAttribute) {
    138         if (toRenderSVGImage(renderer)->updateImageViewport())
    139             RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    140         return;
    141     }
    142 
    143     if (attrName == SVGNames::preserveAspectRatioAttr) {
    144         RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
    145         return;
    146     }
    147 
    148     ASSERT_NOT_REACHED();
    149 }
    150 
    151 bool SVGImageElement::selfHasRelativeLengths() const
    152 {
    153     return m_x->currentValue()->isRelative()
    154         || m_y->currentValue()->isRelative()
    155         || m_width->currentValue()->isRelative()
    156         || m_height->currentValue()->isRelative();
    157 }
    158 
    159 RenderObject* SVGImageElement::createRenderer(RenderStyle*)
    160 {
    161     return new RenderSVGImage(this);
    162 }
    163 
    164 bool SVGImageElement::haveLoadedRequiredResources()
    165 {
    166     return !m_needsLoaderURIUpdate && !imageLoader().hasPendingActivity();
    167 }
    168 
    169 void SVGImageElement::attach(const AttachContext& context)
    170 {
    171     SVGGraphicsElement::attach(context);
    172 
    173     if (RenderSVGImage* imageObj = toRenderSVGImage(renderer())) {
    174         if (imageObj->imageResource()->hasImage())
    175             return;
    176 
    177         imageObj->imageResource()->setImageResource(imageLoader().image());
    178     }
    179 }
    180 
    181 Node::InsertionNotificationRequest SVGImageElement::insertedInto(ContainerNode* rootParent)
    182 {
    183     SVGGraphicsElement::insertedInto(rootParent);
    184     if (!rootParent->inDocument())
    185         return InsertionDone;
    186 
    187     // We can only resolve base URIs properly after tree insertion - hence, URI mutations while
    188     // detached are deferred until this point.
    189     if (m_needsLoaderURIUpdate) {
    190         imageLoader().updateFromElement(ImageLoader::UpdateIgnorePreviousError);
    191         m_needsLoaderURIUpdate = false;
    192     } else {
    193         // A previous loader update may have failed to actually fetch the image if the document
    194         // was inactive. In that case, force a re-update (but don't clear previous errors).
    195         if (!imageLoader().image())
    196             imageLoader().updateFromElement();
    197     }
    198 
    199     return InsertionDone;
    200 }
    201 
    202 const AtomicString SVGImageElement::imageSourceURL() const
    203 {
    204     return AtomicString(hrefString());
    205 }
    206 
    207 void SVGImageElement::didMoveToNewDocument(Document& oldDocument)
    208 {
    209     imageLoader().elementDidMoveToNewDocument();
    210     SVGGraphicsElement::didMoveToNewDocument(oldDocument);
    211 }
    212 
    213 } // namespace blink
    214