tizen beta release
[framework/web/webkit-efl.git] / Source / WebCore / svg / SVGPatternElement.cpp
1 /*
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.
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 "SVGPatternElement.h"
26
27 #include "AffineTransform.h"
28 #include "Attribute.h"
29 #include "Document.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"
37 #include "SVGNames.h"
38 #include "SVGRenderSupport.h"
39 #include "SVGSVGElement.h"
40 #include "SVGStyledTransformableElement.h"
41 #include "SVGTransformable.h"
42
43 namespace WebCore {
44
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) 
57
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
73
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)
82 {
83     ASSERT(hasTagName(SVGNames::patternTag));
84     registerAnimatedPropertiesForSVGPatternElement();
85 }
86
87 PassRefPtr<SVGPatternElement> SVGPatternElement::create(const QualifiedName& tagName, Document* document)
88 {
89     return adoptRef(new SVGPatternElement(tagName, document));
90 }
91
92 bool SVGPatternElement::isSupportedAttribute(const QualifiedName& attrName)
93 {
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);
108     }
109     return supportedAttributes.contains<QualifiedName, SVGAttributeHashTranslator>(attrName);
110 }
111
112 void SVGPatternElement::parseMappedAttribute(Attribute* attr)
113 {
114     SVGParsingError parseError = NoError;
115
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);
122         return;
123     } else if (attr->name() == SVGNames::patternContentUnitsAttr) {
124         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(attr->value());
125         if (propertyValue > 0)
126             setPatternContentUnitsBaseValue(propertyValue);
127         return;
128     } else if (attr->name() == SVGNames::patternTransformAttr) {
129         SVGTransformList newList;
130         if (!SVGTransformable::parseTransformAttribute(newList, attr->value()))
131             newList.clear();
132
133         detachAnimatedPatternTransformListWrappers(newList.size());
134         setPatternTransformBaseValue(newList);
135         return;
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)) {
149     } else
150         ASSERT_NOT_REACHED();
151
152     reportAttributeParsingError(parseError, attr);
153 }
154
155 void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
156 {
157     if (!isSupportedAttribute(attrName)) {
158         SVGStyledElement::svgAttributeChanged(attrName);
159         return;
160     }
161
162     SVGElementInstance::InvalidationGuard invalidationGuard(this);
163     
164     if (attrName == SVGNames::xAttr
165         || attrName == SVGNames::yAttr
166         || attrName == SVGNames::widthAttr
167         || attrName == SVGNames::heightAttr)
168         updateRelativeLengthsInformation();
169
170     if (RenderObject* object = renderer())
171         object->setNeedsLayout(true);
172 }
173
174 void SVGPatternElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
175 {
176     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
177
178     if (changedByParser)
179         return;
180
181     if (RenderObject* object = renderer())
182         object->setNeedsLayout(true);
183 }
184
185 RenderObject* SVGPatternElement::createRenderer(RenderArena* arena, RenderStyle*)
186 {
187     return new (arena) RenderSVGResourcePattern(this);
188 }
189
190 void SVGPatternElement::collectPatternAttributes(PatternAttributes& attributes) const
191 {
192     HashSet<const SVGPatternElement*> processedPatterns;
193
194     const SVGPatternElement* current = this;
195     while (current) {
196         if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
197             attributes.setX(current->x());
198
199         if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
200             attributes.setY(current->y());
201
202         if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
203             attributes.setWidth(current->width());
204
205         if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
206             attributes.setHeight(current->height());
207
208         if (!attributes.hasViewBox() && current->hasAttribute(SVGNames::viewBoxAttr))
209             attributes.setViewBox(current->viewBox());
210
211         if (!attributes.hasPreserveAspectRatio() && current->hasAttribute(SVGNames::preserveAspectRatioAttr))
212             attributes.setPreserveAspectRatio(current->preserveAspectRatio());
213
214         if (!attributes.hasPatternUnits() && current->hasAttribute(SVGNames::patternUnitsAttr))
215             attributes.setPatternUnits(current->patternUnits());
216
217         if (!attributes.hasPatternContentUnits() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
218             attributes.setPatternContentUnits(current->patternContentUnits());
219
220         if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr)) {
221             AffineTransform transform;
222             current->patternTransform().concatenate(transform);
223             attributes.setPatternTransform(transform);
224         }
225
226         if (!attributes.hasPatternContentElement() && current->hasChildNodes())
227             attributes.setPatternContentElement(current);
228
229         processedPatterns.add(current);
230
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));
235
236             // Cycle detection
237             if (processedPatterns.contains(current)) {
238                 current = 0;
239                 break;
240             }
241         } else
242             current = 0;
243     }
244 }
245
246 bool SVGPatternElement::selfHasRelativeLengths() const
247 {
248     return x().isRelative()
249         || y().isRelative()
250         || width().isRelative()
251         || height().isRelative();
252 }
253
254 }
255
256 #endif // ENABLE(SVG)