KHtml

SVGTransformable.cpp
1 /*
2  Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <[email protected]>
3  2004, 2005, 2006, 2007 Rob Buis <[email protected]>
4  2007 Eric Seidel <[email protected]>
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 "Document.h"
25 
26 #if ENABLE(SVG)
27 #include "SVGTransformable.h"
28 
29 #include "AffineTransform.h"
30 #include "FloatConversion.h"
31 //#include "RegularExpression.h"
32 #include "SVGNames.h"
33 #include "SVGParserUtilities.h"
34 #include "SVGStyledElement.h"
35 #include "SVGTransformList.h"
36 
37 namespace WebCore
38 {
39 
40 SVGTransformable::SVGTransformable() : SVGLocatable()
41 {
42 }
43 
44 SVGTransformable::~SVGTransformable()
45 {
46 }
47 
48 AffineTransform SVGTransformable::getCTM(const SVGElement *element) const
49 {
50  AffineTransform ctm = SVGLocatable::getCTM(element);
51  return animatedLocalTransform() * ctm;
52 }
53 
54 AffineTransform SVGTransformable::getScreenCTM(const SVGElement *element) const
55 {
56  AffineTransform ctm = SVGLocatable::getScreenCTM(element);
57  return animatedLocalTransform() * ctm;
58 }
59 
60 int parseTransformParamList(const UChar *&ptr, const UChar *end, float *values, int required, int optional)
61 {
62  int optionalParams = 0, requiredParams = 0;
63 
64  if (!skipOptionalSpaces(ptr, end) || *ptr != '(') {
65  return -1;
66  }
67 
68  ptr++;
69 
70  skipOptionalSpaces(ptr, end);
71 
72  while (requiredParams < required) {
73  if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false)) {
74  return -1;
75  }
76  requiredParams++;
77  if (requiredParams < required) {
78  skipOptionalSpacesOrDelimiter(ptr, end);
79  }
80  }
81  if (!skipOptionalSpaces(ptr, end)) {
82  return -1;
83  }
84 
85  bool delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
86 
87  if (ptr >= end) {
88  return -1;
89  }
90 
91  if (*ptr == ')') { // skip optionals
92  ptr++;
93  if (delimParsed) {
94  return -1;
95  }
96  } else {
97  while (optionalParams < optional) {
98  if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false)) {
99  return -1;
100  }
101  optionalParams++;
102  if (optionalParams < optional) {
103  skipOptionalSpacesOrDelimiter(ptr, end);
104  }
105  }
106 
107  if (!skipOptionalSpaces(ptr, end)) {
108  return -1;
109  }
110 
111  delimParsed = skipOptionalSpacesOrDelimiter(ptr, end);
112 
113  if (ptr >= end || *ptr != ')' || delimParsed) {
114  return -1;
115  }
116  ptr++;
117  }
118 
119  return requiredParams + optionalParams;
120 }
121 
122 // These should be kept in sync with enum SVGTransformType
123 static const int requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1};
124 static const int optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0};
125 
126 bool SVGTransformable::parseTransformValue(unsigned type, const UChar *&ptr, const UChar *end, SVGTransform &t)
127 {
128  if (type == SVGTransform::SVG_TRANSFORM_UNKNOWN) {
129  return false;
130  }
131 
132  int valueCount = 0;
133  float values[] = {0, 0, 0, 0, 0, 0};
134  if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0) {
135  return false;
136  }
137 
138  switch (type) {
139  case SVGTransform::SVG_TRANSFORM_SKEWX:
140  t.setSkewX(values[0]);
141  break;
142  case SVGTransform::SVG_TRANSFORM_SKEWY:
143  t.setSkewY(values[0]);
144  break;
145  case SVGTransform::SVG_TRANSFORM_SCALE:
146  if (valueCount == 1) { // Spec: if only one param given, assume uniform scaling
147  t.setScale(values[0], values[0]);
148  } else {
149  t.setScale(values[0], values[1]);
150  }
151  break;
152  case SVGTransform::SVG_TRANSFORM_TRANSLATE:
153  if (valueCount == 1) { // Spec: if only one param given, assume 2nd param to be 0
154  t.setTranslate(values[0], 0);
155  } else {
156  t.setTranslate(values[0], values[1]);
157  }
158  break;
159  case SVGTransform::SVG_TRANSFORM_ROTATE:
160  if (valueCount == 1) {
161  t.setRotate(values[0], 0, 0);
162  } else {
163  t.setRotate(values[0], values[1], values[2]);
164  }
165  break;
166  case SVGTransform::SVG_TRANSFORM_MATRIX:
167  t.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5]));
168  break;
169  }
170 
171  return true;
172 }
173 
174 static const UChar skewXDesc[] = {'s', 'k', 'e', 'w', 'X'};
175 static const UChar skewYDesc[] = {'s', 'k', 'e', 'w', 'Y'};
176 static const UChar scaleDesc[] = {'s', 'c', 'a', 'l', 'e'};
177 static const UChar translateDesc[] = {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'};
178 static const UChar rotateDesc[] = {'r', 'o', 't', 'a', 't', 'e'};
179 static const UChar matrixDesc[] = {'m', 'a', 't', 'r', 'i', 'x'};
180 
181 // KHTML
182 /*static inline bool skipString(const UChar*& currTransform, const UChar* end, const UChar* pattern, int len)
183 {
184  int i = len;
185  const UChar* curr = currTransform;
186  while (i && curr < end) {
187  if (*curr++ != *pattern++)
188  return false;
189  --i;
190  }
191  if (i)
192  return false;
193  currTransform += len;
194  return true;
195 }*/
196 
197 static inline bool parseAndSkipType(const UChar *&currTransform, const UChar *end, unsigned short &type)
198 {
199  if (currTransform >= end) {
200  return false;
201  }
202 
203  if (*currTransform == 's') {
204  if (skipString(currTransform, end, skewXDesc, sizeof(skewXDesc) / sizeof(UChar))) {
205  type = SVGTransform::SVG_TRANSFORM_SKEWX;
206  } else if (skipString(currTransform, end, skewYDesc, sizeof(skewYDesc) / sizeof(UChar))) {
207  type = SVGTransform::SVG_TRANSFORM_SKEWY;
208  } else if (skipString(currTransform, end, scaleDesc, sizeof(scaleDesc) / sizeof(UChar))) {
209  type = SVGTransform::SVG_TRANSFORM_SCALE;
210  } else {
211  return false;
212  }
213  } else if (skipString(currTransform, end, translateDesc, sizeof(translateDesc) / sizeof(UChar))) {
214  type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
215  } else if (skipString(currTransform, end, rotateDesc, sizeof(rotateDesc) / sizeof(UChar))) {
216  type = SVGTransform::SVG_TRANSFORM_ROTATE;
217  } else if (skipString(currTransform, end, matrixDesc, sizeof(matrixDesc) / sizeof(UChar))) {
218  type = SVGTransform::SVG_TRANSFORM_MATRIX;
219  } else {
220  return false;
221  }
222 
223  return true;
224 }
225 
226 bool SVGTransformable::parseTransformAttribute(SVGTransformList *list, const AtomicString &transform)
227 {
228  const UChar *start = transform.characters();
229  const UChar *end = start + transform.length();
230  return parseTransformAttribute(list, start, end);
231 }
232 
233 bool SVGTransformable::parseTransformAttribute(SVGTransformList *list, const UChar *&currTransform, const UChar *end)
234 {
235  bool delimParsed = false;
236  while (currTransform < end) {
237  delimParsed = false;
238  unsigned short type = SVGTransform::SVG_TRANSFORM_UNKNOWN;
239  skipOptionalSpaces(currTransform, end);
240 
241  if (!parseAndSkipType(currTransform, end, type)) {
242  return false;
243  }
244 
245  SVGTransform t;
246  if (!parseTransformValue(type, currTransform, end, t)) {
247  return false;
248  }
249 
250  ExceptionCode ec = 0;
251  list->appendItem(t, ec);
252  skipOptionalSpaces(currTransform, end);
253  if (currTransform < end && *currTransform == ',') {
254  delimParsed = true;
255  currTransform++;
256  }
257  skipOptionalSpaces(currTransform, end);
258  }
259 
260  return !delimParsed;
261 }
262 
263 bool SVGTransformable::isKnownAttribute(const QualifiedName &attrName)
264 {
265  return attrName.matches(SVGNames::transformAttr);
266 }
267 
268 }
269 
270 #endif // ENABLE(SVG)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.