1 /*
2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Rob Buis <buis@kde.org>
4 * Copyright (C) 2006 Alexander Kellett <lypanov@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 #if ENABLE(SVG)
25 #include "SVGImageElement.h"
26
27 #include "Attribute.h"
28 #include "CSSPropertyNames.h"
29 #include "RenderImageResource.h"
30 #include "RenderSVGImage.h"
31 #include "RenderSVGResource.h"
32 #include "SVGNames.h"
33 #include "SVGSVGElement.h"
34 #include "XLinkNames.h"
35
36 namespace WebCore {
37
38 // Animated property definitions
DEFINE_ANIMATED_LENGTH(SVGImageElement,SVGNames::xAttr,X,x)39 DEFINE_ANIMATED_LENGTH(SVGImageElement, SVGNames::xAttr, X, x)
40 DEFINE_ANIMATED_LENGTH(SVGImageElement, SVGNames::yAttr, Y, y)
41 DEFINE_ANIMATED_LENGTH(SVGImageElement, SVGNames::widthAttr, Width, width)
42 DEFINE_ANIMATED_LENGTH(SVGImageElement, SVGNames::heightAttr, Height, height)
43 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGImageElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio)
44 DEFINE_ANIMATED_STRING(SVGImageElement, XLinkNames::hrefAttr, Href, href)
45 DEFINE_ANIMATED_BOOLEAN(SVGImageElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
46
47 inline SVGImageElement::SVGImageElement(const QualifiedName& tagName, Document* document)
48 : SVGStyledTransformableElement(tagName, document)
49 , m_x(LengthModeWidth)
50 , m_y(LengthModeHeight)
51 , m_width(LengthModeWidth)
52 , m_height(LengthModeHeight)
53 , m_imageLoader(this)
54 {
55 }
56
create(const QualifiedName & tagName,Document * document)57 PassRefPtr<SVGImageElement> SVGImageElement::create(const QualifiedName& tagName, Document* document)
58 {
59 return adoptRef(new SVGImageElement(tagName, document));
60 }
61
parseMappedAttribute(Attribute * attr)62 void SVGImageElement::parseMappedAttribute(Attribute* attr)
63 {
64 if (attr->name() == SVGNames::xAttr)
65 setXBaseValue(SVGLength(LengthModeWidth, attr->value()));
66 else if (attr->name() == SVGNames::yAttr)
67 setYBaseValue(SVGLength(LengthModeHeight, attr->value()));
68 else if (attr->name() == SVGNames::preserveAspectRatioAttr)
69 SVGPreserveAspectRatio::parsePreserveAspectRatio(this, attr->value());
70 else if (attr->name() == SVGNames::widthAttr) {
71 setWidthBaseValue(SVGLength(LengthModeWidth, attr->value()));
72 addCSSProperty(attr, CSSPropertyWidth, attr->value());
73 if (widthBaseValue().value(this) < 0.0)
74 document()->accessSVGExtensions()->reportError("A negative value for image attribute <width> is not allowed");
75 } else if (attr->name() == SVGNames::heightAttr) {
76 setHeightBaseValue(SVGLength(LengthModeHeight, attr->value()));
77 addCSSProperty(attr, CSSPropertyHeight, attr->value());
78 if (heightBaseValue().value(this) < 0.0)
79 document()->accessSVGExtensions()->reportError("A negative value for image attribute <height> is not allowed");
80 } else {
81 if (SVGTests::parseMappedAttribute(attr))
82 return;
83 if (SVGLangSpace::parseMappedAttribute(attr))
84 return;
85 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
86 return;
87 if (SVGURIReference::parseMappedAttribute(attr))
88 return;
89 SVGStyledTransformableElement::parseMappedAttribute(attr);
90 }
91 }
92
svgAttributeChanged(const QualifiedName & attrName)93 void SVGImageElement::svgAttributeChanged(const QualifiedName& attrName)
94 {
95 SVGStyledTransformableElement::svgAttributeChanged(attrName);
96
97 if (SVGURIReference::isKnownAttribute(attrName))
98 m_imageLoader.updateFromElementIgnoringPreviousError();
99
100 bool isLengthAttribute = attrName == SVGNames::xAttr
101 || attrName == SVGNames::yAttr
102 || attrName == SVGNames::widthAttr
103 || attrName == SVGNames::heightAttr;
104
105 if (isLengthAttribute)
106 updateRelativeLengthsInformation();
107
108 if (SVGTests::handleAttributeChange(this, attrName))
109 return;
110
111 RenderObject* renderer = this->renderer();
112 if (!renderer)
113 return;
114
115 if (isLengthAttribute) {
116 renderer->updateFromElement();
117 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
118 return;
119 }
120
121 if (attrName == SVGNames::preserveAspectRatioAttr
122 || SVGLangSpace::isKnownAttribute(attrName)
123 || SVGExternalResourcesRequired::isKnownAttribute(attrName))
124 RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
125 }
126
synchronizeProperty(const QualifiedName & attrName)127 void SVGImageElement::synchronizeProperty(const QualifiedName& attrName)
128 {
129 SVGStyledTransformableElement::synchronizeProperty(attrName);
130
131 if (attrName == anyQName()) {
132 synchronizeX();
133 synchronizeY();
134 synchronizeWidth();
135 synchronizeHeight();
136 synchronizePreserveAspectRatio();
137 synchronizeExternalResourcesRequired();
138 synchronizeHref();
139 SVGTests::synchronizeProperties(this, attrName);
140 return;
141 }
142
143 if (attrName == SVGNames::xAttr)
144 synchronizeX();
145 else if (attrName == SVGNames::yAttr)
146 synchronizeY();
147 else if (attrName == SVGNames::widthAttr)
148 synchronizeWidth();
149 else if (attrName == SVGNames::heightAttr)
150 synchronizeHeight();
151 else if (attrName == SVGNames::preserveAspectRatioAttr)
152 synchronizePreserveAspectRatio();
153 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
154 synchronizeExternalResourcesRequired();
155 else if (SVGURIReference::isKnownAttribute(attrName))
156 synchronizeHref();
157 else if (SVGTests::isKnownAttribute(attrName))
158 SVGTests::synchronizeProperties(this, attrName);
159 }
160
attributeToPropertyTypeMap()161 AttributeToPropertyTypeMap& SVGImageElement::attributeToPropertyTypeMap()
162 {
163 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
164 return s_attributeToPropertyTypeMap;
165 }
166
fillAttributeToPropertyTypeMap()167 void SVGImageElement::fillAttributeToPropertyTypeMap()
168 {
169 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
170
171 SVGStyledTransformableElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
172 attributeToPropertyTypeMap.set(SVGNames::xAttr, AnimatedLength);
173 attributeToPropertyTypeMap.set(SVGNames::yAttr, AnimatedLength);
174 attributeToPropertyTypeMap.set(SVGNames::widthAttr, AnimatedLength);
175 attributeToPropertyTypeMap.set(SVGNames::heightAttr, AnimatedLength);
176 attributeToPropertyTypeMap.set(SVGNames::preserveAspectRatioAttr, AnimatedPreserveAspectRatio);
177 attributeToPropertyTypeMap.set(XLinkNames::hrefAttr, AnimatedString);
178 }
179
selfHasRelativeLengths() const180 bool SVGImageElement::selfHasRelativeLengths() const
181 {
182 return x().isRelative()
183 || y().isRelative()
184 || width().isRelative()
185 || height().isRelative();
186 }
187
createRenderer(RenderArena * arena,RenderStyle *)188 RenderObject* SVGImageElement::createRenderer(RenderArena* arena, RenderStyle*)
189 {
190 return new (arena) RenderSVGImage(this);
191 }
192
haveLoadedRequiredResources()193 bool SVGImageElement::haveLoadedRequiredResources()
194 {
195 return !externalResourcesRequiredBaseValue() || m_imageLoader.haveFiredLoadEvent();
196 }
197
attach()198 void SVGImageElement::attach()
199 {
200 SVGStyledTransformableElement::attach();
201
202 if (RenderSVGImage* imageObj = toRenderSVGImage(renderer())) {
203 if (imageObj->imageResource()->hasImage())
204 return;
205
206 imageObj->imageResource()->setCachedImage(m_imageLoader.image());
207 }
208 }
209
insertedIntoDocument()210 void SVGImageElement::insertedIntoDocument()
211 {
212 SVGStyledTransformableElement::insertedIntoDocument();
213
214 // Update image loader, as soon as we're living in the tree.
215 // We can only resolve base URIs properly, after that!
216 m_imageLoader.updateFromElement();
217 }
218
imageSourceAttributeName() const219 const QualifiedName& SVGImageElement::imageSourceAttributeName() const
220 {
221 return XLinkNames::hrefAttr;
222 }
223
addSubresourceAttributeURLs(ListHashSet<KURL> & urls) const224 void SVGImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
225 {
226 SVGStyledTransformableElement::addSubresourceAttributeURLs(urls);
227
228 addSubresourceURL(urls, document()->completeURL(href()));
229 }
230
willMoveToNewOwnerDocument()231 void SVGImageElement::willMoveToNewOwnerDocument()
232 {
233 m_imageLoader.elementWillMoveToNewOwnerDocument();
234 SVGStyledTransformableElement::willMoveToNewOwnerDocument();
235 }
236
237 }
238
239 #endif // ENABLE(SVG)
240