• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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