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>
6 This file is part of the WebKit project
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.
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.
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.
28 #include "SVGTransformable.h"
30 #include "AffineTransform.h"
31 #include "FloatConversion.h"
32 //#include "RegularExpression.h"
34 #include "SVGParserUtilities.h"
35 #include "SVGStyledElement.h"
36 #include "SVGTransformList.h"
40 SVGTransformable::SVGTransformable() : SVGLocatable()
44 SVGTransformable::~SVGTransformable()
48 AffineTransform
SVGTransformable::getCTM(const SVGElement
* element
) const
50 AffineTransform ctm
= SVGLocatable::getCTM(element
);
51 return animatedLocalTransform() * ctm
;
54 AffineTransform
SVGTransformable::getScreenCTM(const SVGElement
* element
) const
56 AffineTransform ctm
= SVGLocatable::getScreenCTM(element
);
57 return animatedLocalTransform() * ctm
;
60 int parseTransformParamList(const UChar
*& ptr
, const UChar
* end
, float* values
, int required
, int optional
)
62 int optionalParams
= 0, requiredParams
= 0;
64 if (!skipOptionalSpaces(ptr
, end
) || *ptr
!= '(')
69 skipOptionalSpaces(ptr
, end
);
71 while (requiredParams
< required
) {
72 if (ptr
>= end
|| !parseNumber(ptr
, end
, values
[requiredParams
], false))
75 if (requiredParams
< required
)
76 skipOptionalSpacesOrDelimiter(ptr
, end
);
78 if (!skipOptionalSpaces(ptr
, end
))
81 bool delimParsed
= skipOptionalSpacesOrDelimiter(ptr
, end
);
86 if (*ptr
== ')') { // skip optionals
91 while (optionalParams
< optional
) {
92 if (ptr
>= end
|| !parseNumber(ptr
, end
, values
[requiredParams
+ optionalParams
], false))
95 if (optionalParams
< optional
)
96 skipOptionalSpacesOrDelimiter(ptr
, end
);
99 if (!skipOptionalSpaces(ptr
, end
))
102 delimParsed
= skipOptionalSpacesOrDelimiter(ptr
, end
);
104 if (ptr
>= end
|| *ptr
!= ')' || delimParsed
)
109 return requiredParams
+ optionalParams
;
112 // These should be kept in sync with enum SVGTransformType
113 static const int requiredValuesForType
[] = {0, 6, 1, 1, 1, 1, 1};
114 static const int optionalValuesForType
[] = {0, 0, 1, 1, 2, 0, 0};
116 bool SVGTransformable::parseTransformValue(unsigned type
, const UChar
*& ptr
, const UChar
* end
, SVGTransform
& t
)
118 if (type
== SVGTransform::SVG_TRANSFORM_UNKNOWN
)
122 float values
[] = {0, 0, 0, 0, 0, 0};
123 if ((valueCount
= parseTransformParamList(ptr
, end
, values
, requiredValuesForType
[type
], optionalValuesForType
[type
])) < 0)
127 case SVGTransform::SVG_TRANSFORM_SKEWX
:
128 t
.setSkewX(values
[0]);
130 case SVGTransform::SVG_TRANSFORM_SKEWY
:
131 t
.setSkewY(values
[0]);
133 case SVGTransform::SVG_TRANSFORM_SCALE
:
134 if (valueCount
== 1) // Spec: if only one param given, assume uniform scaling
135 t
.setScale(values
[0], values
[0]);
137 t
.setScale(values
[0], values
[1]);
139 case SVGTransform::SVG_TRANSFORM_TRANSLATE
:
140 if (valueCount
== 1) // Spec: if only one param given, assume 2nd param to be 0
141 t
.setTranslate(values
[0], 0);
143 t
.setTranslate(values
[0], values
[1]);
145 case SVGTransform::SVG_TRANSFORM_ROTATE
:
147 t
.setRotate(values
[0], 0, 0);
149 t
.setRotate(values
[0], values
[1], values
[2]);
151 case SVGTransform::SVG_TRANSFORM_MATRIX
:
152 t
.setMatrix(AffineTransform(values
[0], values
[1], values
[2], values
[3], values
[4], values
[5]));
159 static const UChar skewXDesc
[] = {'s','k','e','w', 'X'};
160 static const UChar skewYDesc
[] = {'s','k','e','w', 'Y'};
161 static const UChar scaleDesc
[] = {'s','c','a','l', 'e'};
162 static const UChar translateDesc
[] = {'t','r','a','n', 's', 'l', 'a', 't', 'e'};
163 static const UChar rotateDesc
[] = {'r','o','t','a', 't', 'e'};
164 static const UChar matrixDesc
[] = {'m','a','t','r', 'i', 'x'};
167 /*static inline bool skipString(const UChar*& currTransform, const UChar* end, const UChar* pattern, int len)
170 const UChar* curr = currTransform;
171 while (i && curr < end) {
172 if (*curr++ != *pattern++)
178 currTransform += len;
182 static inline bool parseAndSkipType(const UChar
*& currTransform
, const UChar
* end
, unsigned short& type
)
184 if (currTransform
>= end
)
187 if (*currTransform
== 's') {
188 if (skipString(currTransform
, end
, skewXDesc
, sizeof(skewXDesc
) / sizeof(UChar
)))
189 type
= SVGTransform::SVG_TRANSFORM_SKEWX
;
190 else if (skipString(currTransform
, end
, skewYDesc
, sizeof(skewYDesc
) / sizeof(UChar
)))
191 type
= SVGTransform::SVG_TRANSFORM_SKEWY
;
192 else if (skipString(currTransform
, end
, scaleDesc
, sizeof(scaleDesc
) / sizeof(UChar
)))
193 type
= SVGTransform::SVG_TRANSFORM_SCALE
;
196 } else if (skipString(currTransform
, end
, translateDesc
, sizeof(translateDesc
) / sizeof(UChar
)))
197 type
= SVGTransform::SVG_TRANSFORM_TRANSLATE
;
198 else if (skipString(currTransform
, end
, rotateDesc
, sizeof(rotateDesc
) / sizeof(UChar
)))
199 type
= SVGTransform::SVG_TRANSFORM_ROTATE
;
200 else if (skipString(currTransform
, end
, matrixDesc
, sizeof(matrixDesc
) / sizeof(UChar
)))
201 type
= SVGTransform::SVG_TRANSFORM_MATRIX
;
208 bool SVGTransformable::parseTransformAttribute(SVGTransformList
* list
, const AtomicString
& transform
)
210 const UChar
* start
= transform
.characters();
211 const UChar
* end
= start
+ transform
.length();
212 return parseTransformAttribute(list
, start
, end
);
215 bool SVGTransformable::parseTransformAttribute(SVGTransformList
* list
, const UChar
*& currTransform
, const UChar
* end
)
217 bool delimParsed
= false;
218 while (currTransform
< end
) {
220 unsigned short type
= SVGTransform::SVG_TRANSFORM_UNKNOWN
;
221 skipOptionalSpaces(currTransform
, end
);
223 if (!parseAndSkipType(currTransform
, end
, type
))
227 if (!parseTransformValue(type
, currTransform
, end
, t
))
230 ExceptionCode ec
= 0;
231 list
->appendItem(t
, ec
);
232 skipOptionalSpaces(currTransform
, end
);
233 if (currTransform
< end
&& *currTransform
== ',') {
237 skipOptionalSpaces(currTransform
, end
);
243 bool SVGTransformable::isKnownAttribute(const QualifiedName
& attrName
)
245 return attrName
.matches(SVGNames::transformAttr
);
250 #endif // ENABLE(SVG)