2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
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.
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.
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.
25 #include "SVGPatternElement.h"
27 #include "AffineTransform.h"
28 #include "Attribute.h"
30 #include "FloatConversion.h"
31 #include "GraphicsContext.h"
32 #include "ImageBuffer.h"
33 #include "PatternAttributes.h"
34 #include "RenderSVGContainer.h"
35 #include "RenderSVGResourcePattern.h"
36 #include "SVGElementInstance.h"
38 #include "SVGRenderSupport.h"
39 #include "SVGSVGElement.h"
40 #include "SVGStyledTransformableElement.h"
41 #include "SVGTransformable.h"
45 // Animated property definitions
46 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::xAttr, X, x)
47 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::yAttr, Y, y)
48 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::widthAttr, Width, width)
49 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::heightAttr, Height, height)
50 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternUnitsAttr, PatternUnits, patternUnits, SVGUnitTypes::SVGUnitType)
51 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternContentUnitsAttr, PatternContentUnits, patternContentUnits, SVGUnitTypes::SVGUnitType)
52 DEFINE_ANIMATED_TRANSFORM_LIST(SVGPatternElement, SVGNames::patternTransformAttr, PatternTransform, patternTransform)
53 DEFINE_ANIMATED_STRING(SVGPatternElement, XLinkNames::hrefAttr, Href, href)
54 DEFINE_ANIMATED_BOOLEAN(SVGPatternElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
55 DEFINE_ANIMATED_RECT(SVGPatternElement, SVGNames::viewBoxAttr, ViewBox, viewBox)
56 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGPatternElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio)
58 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGPatternElement)
59 REGISTER_LOCAL_ANIMATED_PROPERTY(x)
60 REGISTER_LOCAL_ANIMATED_PROPERTY(y)
61 REGISTER_LOCAL_ANIMATED_PROPERTY(width)
62 REGISTER_LOCAL_ANIMATED_PROPERTY(height)
63 REGISTER_LOCAL_ANIMATED_PROPERTY(patternUnits)
64 REGISTER_LOCAL_ANIMATED_PROPERTY(patternContentUnits)
65 REGISTER_LOCAL_ANIMATED_PROPERTY(patternTransform)
66 REGISTER_LOCAL_ANIMATED_PROPERTY(href)
67 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
68 REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox)
69 REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio)
70 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGStyledElement)
71 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
72 END_REGISTER_ANIMATED_PROPERTIES
74 inline SVGPatternElement::SVGPatternElement(const QualifiedName& tagName, Document* document)
75 : SVGStyledElement(tagName, document)
76 , m_x(LengthModeWidth)
77 , m_y(LengthModeHeight)
78 , m_width(LengthModeWidth)
79 , m_height(LengthModeHeight)
80 , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
81 , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
83 ASSERT(hasTagName(SVGNames::patternTag));
84 registerAnimatedPropertiesForSVGPatternElement();
87 PassRefPtr<SVGPatternElement> SVGPatternElement::create(const QualifiedName& tagName, Document* document)
89 return adoptRef(new SVGPatternElement(tagName, document));
92 bool SVGPatternElement::isSupportedAttribute(const QualifiedName& attrName)
94 DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
95 if (supportedAttributes.isEmpty()) {
96 SVGURIReference::addSupportedAttributes(supportedAttributes);
97 SVGTests::addSupportedAttributes(supportedAttributes);
98 SVGLangSpace::addSupportedAttributes(supportedAttributes);
99 SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
100 SVGFitToViewBox::addSupportedAttributes(supportedAttributes);
101 supportedAttributes.add(SVGNames::patternUnitsAttr);
102 supportedAttributes.add(SVGNames::patternContentUnitsAttr);
103 supportedAttributes.add(SVGNames::patternTransformAttr);
104 supportedAttributes.add(SVGNames::xAttr);
105 supportedAttributes.add(SVGNames::yAttr);
106 supportedAttributes.add(SVGNames::widthAttr);
107 supportedAttributes.add(SVGNames::heightAttr);
109 return supportedAttributes.contains<QualifiedName, SVGAttributeHashTranslator>(attrName);
112 void SVGPatternElement::parseMappedAttribute(Attribute* attr)
114 SVGParsingError parseError = NoError;
116 if (!isSupportedAttribute(attr->name()))
117 SVGStyledElement::parseMappedAttribute(attr);
118 else if (attr->name() == SVGNames::patternUnitsAttr) {
119 SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(attr->value());
120 if (propertyValue > 0)
121 setPatternUnitsBaseValue(propertyValue);
123 } else if (attr->name() == SVGNames::patternContentUnitsAttr) {
124 SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(attr->value());
125 if (propertyValue > 0)
126 setPatternContentUnitsBaseValue(propertyValue);
128 } else if (attr->name() == SVGNames::patternTransformAttr) {
129 SVGTransformList newList;
130 if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
133 detachAnimatedPatternTransformListWrappers(newList.size());
134 setPatternTransformBaseValue(newList);
136 } else if (attr->name() == SVGNames::xAttr)
137 setXBaseValue(SVGLength::construct(LengthModeWidth, attr->value(), parseError));
138 else if (attr->name() == SVGNames::yAttr)
139 setYBaseValue(SVGLength::construct(LengthModeHeight, attr->value(), parseError));
140 else if (attr->name() == SVGNames::widthAttr)
141 setWidthBaseValue(SVGLength::construct(LengthModeWidth, attr->value(), parseError, ForbidNegativeLengths));
142 else if (attr->name() == SVGNames::heightAttr)
143 setHeightBaseValue(SVGLength::construct(LengthModeHeight, attr->value(), parseError, ForbidNegativeLengths));
144 else if (SVGURIReference::parseMappedAttribute(attr)
145 || SVGTests::parseMappedAttribute(attr)
146 || SVGLangSpace::parseMappedAttribute(attr)
147 || SVGExternalResourcesRequired::parseMappedAttribute(attr)
148 || SVGFitToViewBox::parseMappedAttribute(document(), attr)) {
150 ASSERT_NOT_REACHED();
152 reportAttributeParsingError(parseError, attr);
155 void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
157 if (!isSupportedAttribute(attrName)) {
158 SVGStyledElement::svgAttributeChanged(attrName);
162 SVGElementInstance::InvalidationGuard invalidationGuard(this);
164 if (attrName == SVGNames::xAttr
165 || attrName == SVGNames::yAttr
166 || attrName == SVGNames::widthAttr
167 || attrName == SVGNames::heightAttr)
168 updateRelativeLengthsInformation();
170 if (RenderObject* object = renderer())
171 object->setNeedsLayout(true);
174 void SVGPatternElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
176 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
181 if (RenderObject* object = renderer())
182 object->setNeedsLayout(true);
185 RenderObject* SVGPatternElement::createRenderer(RenderArena* arena, RenderStyle*)
187 return new (arena) RenderSVGResourcePattern(this);
190 void SVGPatternElement::collectPatternAttributes(PatternAttributes& attributes) const
192 HashSet<const SVGPatternElement*> processedPatterns;
194 const SVGPatternElement* current = this;
196 if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
197 attributes.setX(current->x());
199 if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
200 attributes.setY(current->y());
202 if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
203 attributes.setWidth(current->width());
205 if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
206 attributes.setHeight(current->height());
208 if (!attributes.hasViewBox() && current->hasAttribute(SVGNames::viewBoxAttr))
209 attributes.setViewBox(current->viewBox());
211 if (!attributes.hasPreserveAspectRatio() && current->hasAttribute(SVGNames::preserveAspectRatioAttr))
212 attributes.setPreserveAspectRatio(current->preserveAspectRatio());
214 if (!attributes.hasPatternUnits() && current->hasAttribute(SVGNames::patternUnitsAttr))
215 attributes.setPatternUnits(current->patternUnits());
217 if (!attributes.hasPatternContentUnits() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
218 attributes.setPatternContentUnits(current->patternContentUnits());
220 if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr)) {
221 AffineTransform transform;
222 current->patternTransform().concatenate(transform);
223 attributes.setPatternTransform(transform);
226 if (!attributes.hasPatternContentElement() && current->hasChildNodes())
227 attributes.setPatternContentElement(current);
229 processedPatterns.add(current);
231 // Respect xlink:href, take attributes from referenced element
232 Node* refNode = SVGURIReference::targetElementFromIRIString(current->href(), document());
233 if (refNode && refNode->hasTagName(SVGNames::patternTag)) {
234 current = static_cast<const SVGPatternElement*>(const_cast<const Node*>(refNode));
237 if (processedPatterns.contains(current)) {
246 bool SVGPatternElement::selfHasRelativeLengths() const
248 return x().isRelative()
250 || width().isRelative()
251 || height().isRelative();
256 #endif // ENABLE(SVG)