Node::document() should return a reference.
[WebKit-https.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 "SVGFitToViewBox.h"
38 #include "SVGGraphicsElement.h"
39 #include "SVGNames.h"
40 #include "SVGRenderSupport.h"
41 #include "SVGSVGElement.h"
42 #include "SVGTransformable.h"
43 #include "XLinkNames.h"
44
45 namespace WebCore {
46
47 // Animated property definitions
48 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::xAttr, X, x)
49 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::yAttr, Y, y)
50 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::widthAttr, Width, width)
51 DEFINE_ANIMATED_LENGTH(SVGPatternElement, SVGNames::heightAttr, Height, height)
52 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternUnitsAttr, PatternUnits, patternUnits, SVGUnitTypes::SVGUnitType)
53 DEFINE_ANIMATED_ENUMERATION(SVGPatternElement, SVGNames::patternContentUnitsAttr, PatternContentUnits, patternContentUnits, SVGUnitTypes::SVGUnitType)
54 DEFINE_ANIMATED_TRANSFORM_LIST(SVGPatternElement, SVGNames::patternTransformAttr, PatternTransform, patternTransform) 
55 DEFINE_ANIMATED_STRING(SVGPatternElement, XLinkNames::hrefAttr, Href, href)
56 DEFINE_ANIMATED_BOOLEAN(SVGPatternElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
57 DEFINE_ANIMATED_RECT(SVGPatternElement, SVGNames::viewBoxAttr, ViewBox, viewBox)
58 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGPatternElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio) 
59
60 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGPatternElement)
61     REGISTER_LOCAL_ANIMATED_PROPERTY(x)
62     REGISTER_LOCAL_ANIMATED_PROPERTY(y)
63     REGISTER_LOCAL_ANIMATED_PROPERTY(width)
64     REGISTER_LOCAL_ANIMATED_PROPERTY(height)
65     REGISTER_LOCAL_ANIMATED_PROPERTY(patternUnits)
66     REGISTER_LOCAL_ANIMATED_PROPERTY(patternContentUnits)
67     REGISTER_LOCAL_ANIMATED_PROPERTY(patternTransform)
68     REGISTER_LOCAL_ANIMATED_PROPERTY(href)
69     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
70     REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox)
71     REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio) 
72     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
73     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
74 END_REGISTER_ANIMATED_PROPERTIES
75
76 inline SVGPatternElement::SVGPatternElement(const QualifiedName& tagName, Document* document)
77     : SVGElement(tagName, document)
78     , m_x(LengthModeWidth)
79     , m_y(LengthModeHeight)
80     , m_width(LengthModeWidth)
81     , m_height(LengthModeHeight)
82     , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
83     , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
84 {
85     ASSERT(hasTagName(SVGNames::patternTag));
86     registerAnimatedPropertiesForSVGPatternElement();
87 }
88
89 PassRefPtr<SVGPatternElement> SVGPatternElement::create(const QualifiedName& tagName, Document* document)
90 {
91     return adoptRef(new SVGPatternElement(tagName, document));
92 }
93
94 bool SVGPatternElement::isSupportedAttribute(const QualifiedName& attrName)
95 {
96     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
97     if (supportedAttributes.isEmpty()) {
98         SVGURIReference::addSupportedAttributes(supportedAttributes);
99         SVGTests::addSupportedAttributes(supportedAttributes);
100         SVGLangSpace::addSupportedAttributes(supportedAttributes);
101         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
102         SVGFitToViewBox::addSupportedAttributes(supportedAttributes);
103         supportedAttributes.add(SVGNames::patternUnitsAttr);
104         supportedAttributes.add(SVGNames::patternContentUnitsAttr);
105         supportedAttributes.add(SVGNames::patternTransformAttr);
106         supportedAttributes.add(SVGNames::xAttr);
107         supportedAttributes.add(SVGNames::yAttr);
108         supportedAttributes.add(SVGNames::widthAttr);
109         supportedAttributes.add(SVGNames::heightAttr);
110     }
111     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
112 }
113
114 void SVGPatternElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
115 {
116     SVGParsingError parseError = NoError;
117
118     if (!isSupportedAttribute(name))
119         SVGElement::parseAttribute(name, value);
120     else if (name == SVGNames::patternUnitsAttr) {
121         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
122         if (propertyValue > 0)
123             setPatternUnitsBaseValue(propertyValue);
124         return;
125     } else if (name == SVGNames::patternContentUnitsAttr) {
126         SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value);
127         if (propertyValue > 0)
128             setPatternContentUnitsBaseValue(propertyValue);
129         return;
130     } else if (name == SVGNames::patternTransformAttr) {
131         SVGTransformList newList;
132         newList.parse(value);
133         detachAnimatedPatternTransformListWrappers(newList.size());
134         setPatternTransformBaseValue(newList);
135         return;
136     } else if (name == SVGNames::xAttr)
137         setXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
138     else if (name == SVGNames::yAttr)
139         setYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
140     else if (name == SVGNames::widthAttr)
141         setWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError, ForbidNegativeLengths));
142     else if (name == SVGNames::heightAttr)
143         setHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError, ForbidNegativeLengths));
144     else if (SVGURIReference::parseAttribute(name, value)
145              || SVGTests::parseAttribute(name, value)
146              || SVGLangSpace::parseAttribute(name, value)
147              || SVGExternalResourcesRequired::parseAttribute(name, value)
148              || SVGFitToViewBox::parseAttribute(this, name, value)) {
149     } else
150         ASSERT_NOT_REACHED();
151
152     reportAttributeParsingError(parseError, name, value);
153 }
154
155 void SVGPatternElement::svgAttributeChanged(const QualifiedName& attrName)
156 {
157     if (!isSupportedAttribute(attrName)) {
158         SVGElement::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     SVGElement::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) && current->viewBoxIsValid())
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->childElementCount())
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 AffineTransform SVGPatternElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope) const
247 {
248     AffineTransform matrix;
249     patternTransform().concatenate(matrix);
250     return matrix;
251 }
252
253 bool SVGPatternElement::selfHasRelativeLengths() const
254 {
255     return x().isRelative()
256         || y().isRelative()
257         || width().isRelative()
258         || height().isRelative();
259 }
260
261 }
262
263 #endif // ENABLE(SVG)