1 /* 2 * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005 Rob Buis <buis (at) kde.org> 4 * Copyright (C) 2010 Dirk Schulze <krit (at) webkit.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/SVGFEImageElement.h" 25 26 #include "SVGNames.h" 27 #include "XLinkNames.h" 28 #include "core/dom/Document.h" 29 #include "core/loader/cache/FetchRequest.h" 30 #include "core/loader/cache/ImageResource.h" 31 #include "core/loader/cache/ResourceFetcher.h" 32 #include "core/platform/graphics/Image.h" 33 #include "core/rendering/svg/RenderSVGResource.h" 34 #include "core/svg/SVGElementInstance.h" 35 #include "core/svg/SVGPreserveAspectRatio.h" 36 37 namespace WebCore { 38 39 // Animated property definitions 40 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGFEImageElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) 41 DEFINE_ANIMATED_STRING(SVGFEImageElement, XLinkNames::hrefAttr, Href, href) 42 DEFINE_ANIMATED_BOOLEAN(SVGFEImageElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 43 44 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGFEImageElement) 45 REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio) 46 REGISTER_LOCAL_ANIMATED_PROPERTY(href) 47 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) 48 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGFilterPrimitiveStandardAttributes) 49 END_REGISTER_ANIMATED_PROPERTIES 50 51 inline SVGFEImageElement::SVGFEImageElement(const QualifiedName& tagName, Document* document) 52 : SVGFilterPrimitiveStandardAttributes(tagName, document) 53 { 54 ASSERT(hasTagName(SVGNames::feImageTag)); 55 ScriptWrappable::init(this); 56 registerAnimatedPropertiesForSVGFEImageElement(); 57 } 58 59 PassRefPtr<SVGFEImageElement> SVGFEImageElement::create(const QualifiedName& tagName, Document* document) 60 { 61 return adoptRef(new SVGFEImageElement(tagName, document)); 62 } 63 64 SVGFEImageElement::~SVGFEImageElement() 65 { 66 clearResourceReferences(); 67 } 68 69 void SVGFEImageElement::clearResourceReferences() 70 { 71 if (m_cachedImage) { 72 m_cachedImage->removeClient(this); 73 m_cachedImage = 0; 74 } 75 76 ASSERT(document()); 77 document()->accessSVGExtensions()->removeAllTargetReferencesForElement(this); 78 } 79 80 void SVGFEImageElement::requestImageResource() 81 { 82 FetchRequest request(ResourceRequest(ownerDocument()->completeURL(hrefCurrentValue())), localName()); 83 m_cachedImage = document()->fetcher()->requestImage(request); 84 85 if (m_cachedImage) 86 m_cachedImage->addClient(this); 87 } 88 89 void SVGFEImageElement::buildPendingResource() 90 { 91 clearResourceReferences(); 92 if (!inDocument()) 93 return; 94 95 String id; 96 Element* target = SVGURIReference::targetElementFromIRIString(hrefCurrentValue(), document(), &id); 97 if (!target) { 98 if (id.isEmpty()) 99 requestImageResource(); 100 else { 101 document()->accessSVGExtensions()->addPendingResource(id, this); 102 ASSERT(hasPendingResources()); 103 } 104 } else if (target->isSVGElement()) { 105 // Register us with the target in the dependencies map. Any change of hrefElement 106 // that leads to relayout/repainting now informs us, so we can react to it. 107 document()->accessSVGExtensions()->addElementReferencingTarget(this, toSVGElement(target)); 108 } 109 110 invalidate(); 111 } 112 113 bool SVGFEImageElement::isSupportedAttribute(const QualifiedName& attrName) 114 { 115 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ()); 116 if (supportedAttributes.isEmpty()) { 117 SVGURIReference::addSupportedAttributes(supportedAttributes); 118 SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes); 119 supportedAttributes.add(SVGNames::preserveAspectRatioAttr); 120 } 121 return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName); 122 } 123 124 void SVGFEImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 125 { 126 if (!isSupportedAttribute(name)) { 127 SVGFilterPrimitiveStandardAttributes::parseAttribute(name, value); 128 return; 129 } 130 131 if (name == SVGNames::preserveAspectRatioAttr) { 132 SVGPreserveAspectRatio preserveAspectRatio; 133 preserveAspectRatio.parse(value); 134 setPreserveAspectRatioBaseValue(preserveAspectRatio); 135 return; 136 } 137 138 if (SVGURIReference::parseAttribute(name, value)) 139 return; 140 if (SVGExternalResourcesRequired::parseAttribute(name, value)) 141 return; 142 143 ASSERT_NOT_REACHED(); 144 } 145 146 void SVGFEImageElement::svgAttributeChanged(const QualifiedName& attrName) 147 { 148 if (!isSupportedAttribute(attrName)) { 149 SVGFilterPrimitiveStandardAttributes::svgAttributeChanged(attrName); 150 return; 151 } 152 153 SVGElementInstance::InvalidationGuard invalidationGuard(this); 154 155 if (attrName == SVGNames::preserveAspectRatioAttr) { 156 invalidate(); 157 return; 158 } 159 160 if (SVGURIReference::isKnownAttribute(attrName)) { 161 buildPendingResource(); 162 return; 163 } 164 165 if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) 166 return; 167 168 ASSERT_NOT_REACHED(); 169 } 170 171 Node::InsertionNotificationRequest SVGFEImageElement::insertedInto(ContainerNode* rootParent) 172 { 173 SVGFilterPrimitiveStandardAttributes::insertedInto(rootParent); 174 buildPendingResource(); 175 return InsertionDone; 176 } 177 178 void SVGFEImageElement::removedFrom(ContainerNode* rootParent) 179 { 180 SVGFilterPrimitiveStandardAttributes::removedFrom(rootParent); 181 if (rootParent->inDocument()) 182 clearResourceReferences(); 183 } 184 185 void SVGFEImageElement::notifyFinished(Resource*) 186 { 187 if (!inDocument()) 188 return; 189 190 Element* parent = parentElement(); 191 ASSERT(parent); 192 193 if (!parent->hasTagName(SVGNames::filterTag) || !parent->renderer()) 194 return; 195 196 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer()); 197 } 198 199 PassRefPtr<FilterEffect> SVGFEImageElement::build(SVGFilterBuilder*, Filter* filter) 200 { 201 if (m_cachedImage) 202 return FEImage::createWithImage(filter, m_cachedImage->imageForRenderer(renderer()), preserveAspectRatioCurrentValue()); 203 return FEImage::createWithIRIReference(filter, document(), hrefCurrentValue(), preserveAspectRatioCurrentValue()); 204 } 205 206 void SVGFEImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 207 { 208 SVGFilterPrimitiveStandardAttributes::addSubresourceAttributeURLs(urls); 209 210 addSubresourceURL(urls, document()->completeURL(hrefCurrentValue())); 211 } 212 213 } 214