1 /*
2 Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 2007 Eric Seidel <eric@webkit.org>
5
6 This file is part of the WebKit project
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25
26 #if ENABLE(SVG)
27 #include "SVGTransformable.h"
28
29 #include "TransformationMatrix.h"
30 #include "FloatConversion.h"
31 #include "SVGNames.h"
32 #include "SVGParserUtilities.h"
33 #include "SVGStyledElement.h"
34 #include "SVGTransformList.h"
35
36 namespace WebCore {
37
SVGTransformable()38 SVGTransformable::SVGTransformable() : SVGLocatable()
39 {
40 }
41
~SVGTransformable()42 SVGTransformable::~SVGTransformable()
43 {
44 }
45
getCTM(const SVGElement * element) const46 TransformationMatrix SVGTransformable::getCTM(const SVGElement* element) const
47 {
48 TransformationMatrix ctm = SVGLocatable::getCTM(element);
49 return animatedLocalTransform() * ctm;
50 }
51
getScreenCTM(const SVGElement * element) const52 TransformationMatrix SVGTransformable::getScreenCTM(const SVGElement* element) const
53 {
54 TransformationMatrix ctm = SVGLocatable::getScreenCTM(element);
55 return animatedLocalTransform() * ctm;
56 }
57
parseTransformParamList(const UChar * & ptr,const UChar * end,float * values,int required,int optional)58 static int parseTransformParamList(const UChar*& ptr, const UChar* end, float* values, int required, int optional)
59 {
60 int optionalParams = 0, requiredParams = 0;
61
62 if (!skipOptionalSpaces(ptr, end) || *ptr != '(')
63 return -1;
64
65 ptr++;
66
67 skipOptionalSpaces(ptr, end);
68
69 while (requiredParams < required) {
70 if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false))
71 return -1;
72 requiredParams++;
73 if (requiredParams < required)
74 skipOptionalSpacesOrDelimiter(ptr, end);
75 }
76 if (!skipOptionalSpaces(ptr, end))
77 return -1;
78
79 bool delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
80
81 if (ptr >= end)
82 return -1;
83
84 if (*ptr == ')') { // skip optionals
85 ptr++;
86 if (delimParsed)
87 return -1;
88 } else {
89 while (optionalParams < optional) {
90 if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false))
91 return -1;
92 optionalParams++;
93 if (optionalParams < optional)
94 skipOptionalSpacesOrDelimiter(ptr, end);
95 }
96
97 if (!skipOptionalSpaces(ptr, end))
98 return -1;
99
100 delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
101
102 if (ptr >= end || *ptr != ')' || delimParsed)
103 return -1;
104 ptr++;
105 }
106
107 return requiredParams + optionalParams;
108 }
109
110 // These should be kept in sync with enum SVGTransformType
111 static const int requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1};
112 static const int optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0};
113
parseTransformValue(unsigned type,const UChar * & ptr,const UChar * end,SVGTransform & t)114 bool SVGTransformable::parseTransformValue(unsigned type, const UChar*& ptr, const UChar* end, SVGTransform& t)
115 {
116 if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN)
117 return false;
118
119 int valueCount = 0;
120 float values[] = {0, 0, 0, 0, 0, 0};
121 if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0)
122 return false;
123
124 switch (type) {
125 case SVGTransform::SVG_TRANSFORM_SKEWX:
126 t.setSkewX(values[0]);
127 break;
128 case SVGTransform::SVG_TRANSFORM_SKEWY:
129 t.setSkewY(values[0]);
130 break;
131 case SVGTransform::SVG_TRANSFORM_SCALE:
132 if (valueCount == 1) // Spec: if only one param given, assume uniform scaling
133 t.setScale(values[0], values[0]);
134 else
135 t.setScale(values[0], values[1]);
136 break;
137 case SVGTransform::SVG_TRANSFORM_TRANSLATE:
138 if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0
139 t.setTranslate(values[0], 0);
140 else
141 t.setTranslate(values[0], values[1]);
142 break;
143 case SVGTransform::SVG_TRANSFORM_ROTATE:
144 if (valueCount == 1)
145 t.setRotate(values[0], 0, 0);
146 else
147 t.setRotate(values[0], values[1], values[2]);
148 break;
149 case SVGTransform::SVG_TRANSFORM_MATRIX:
150 t.setMatrix(TransformationMatrix(values[0], values[1], values[2], values[3], values[4], values[5]));
151 break;
152 }
153
154 return true;
155 }
156
157 static const UChar skewXDesc[] = {'s', 'k', 'e', 'w', 'X'};
158 static const UChar skewYDesc[] = {'s', 'k', 'e', 'w', 'Y'};
159 static const UChar scaleDesc[] = {'s', 'c', 'a', 'l', 'e'};
160 static const UChar translateDesc[] = {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
161 static const UChar rotateDesc[] = {'r', 'o', 't', 'a', 't', 'e'};
162 static const UChar matrixDesc[] = {'m', 'a', 't', 'r', 'i', 'x'};
163
parseAndSkipType(const UChar * & currTransform,const UChar * end,unsigned short & type)164 static inline bool parseAndSkipType(const UChar*& currTransform, const UChar* end, unsigned short& type)
165 {
166 if (currTransform >= end)
167 return false;
168
169 if (*currTransform == 's') {
170 if (skipString(currTransform, end, skewXDesc, sizeof(skewXDesc) / sizeof(UChar)))
171 type = SVGTransform::SVG_TRANSFORM_SKEWX;
172 else if (skipString(currTransform, end, skewYDesc, sizeof(skewYDesc) / sizeof(UChar)))
173 type = SVGTransform::SVG_TRANSFORM_SKEWY;
174 else if (skipString(currTransform, end, scaleDesc, sizeof(scaleDesc) / sizeof(UChar)))
175 type = SVGTransform::SVG_TRANSFORM_SCALE;
176 else
177 return false;
178 } else if (skipString(currTransform, end, translateDesc, sizeof(translateDesc) / sizeof(UChar)))
179 type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
180 else if (skipString(currTransform, end, rotateDesc, sizeof(rotateDesc) / sizeof(UChar)))
181 type = SVGTransform::SVG_TRANSFORM_ROTATE;
182 else if (skipString(currTransform, end, matrixDesc, sizeof(matrixDesc) / sizeof(UChar)))
183 type = SVGTransform::SVG_TRANSFORM_MATRIX;
184 else
185 return false;
186
187 return true;
188 }
189
parseTransformAttribute(SVGTransformList * list,const AtomicString & transform)190 bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const AtomicString& transform)
191 {
192 const UChar* start = transform.characters();
193 const UChar* end = start + transform.length();
194 return parseTransformAttribute(list, start, end);
195 }
196
parseTransformAttribute(SVGTransformList * list,const UChar * & currTransform,const UChar * end)197 bool SVGTransformable::parseTransformAttribute(SVGTransformList* list, const UChar*& currTransform, const UChar* end)
198 {
199 bool delimParsed = false;
200 while (currTransform < end) {
201 delimParsed = false;
202 unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
203 skipOptionalSpaces(currTransform, end);
204
205 if (!parseAndSkipType(currTransform, end, type))
206 return false;
207
208 SVGTransform t;
209 if (!parseTransformValue(type, currTransform, end, t))
210 return false;
211
212 ExceptionCode ec = 0;
213 list->appendItem(t, ec);
214 skipOptionalSpaces(currTransform, end);
215 if (currTransform < end && *currTransform == ',') {
216 delimParsed = true;
217 currTransform++;
218 }
219 skipOptionalSpaces(currTransform, end);
220 }
221
222 return !delimParsed;
223 }
224
isKnownAttribute(const QualifiedName & attrName)225 bool SVGTransformable::isKnownAttribute(const QualifiedName& attrName)
226 {
227 return attrName == SVGNames::transformAttr;
228 }
229
230 }
231
232 #endif // ENABLE(SVG)
233