1 | /* |
2 | * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
3 | * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
4 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
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 | #include "SVGTransformable.h" |
24 | |
25 | #include "AffineTransform.h" |
26 | #include "FloatConversion.h" |
27 | #include "SVGElement.h" |
28 | #include "SVGNames.h" |
29 | #include "SVGParserUtilities.h" |
30 | #include <wtf/text/StringView.h> |
31 | |
32 | namespace WebCore { |
33 | |
34 | static int parseTransformParamList(const UChar*& ptr, const UChar* end, float* values, int required, int optional) |
35 | { |
36 | int optionalParams = 0, requiredParams = 0; |
37 | |
38 | if (!skipOptionalSVGSpaces(ptr, end) || *ptr != '(') |
39 | return -1; |
40 | |
41 | ptr++; |
42 | |
43 | skipOptionalSVGSpaces(ptr, end); |
44 | |
45 | while (requiredParams < required) { |
46 | if (ptr >= end || !parseNumber(ptr, end, values[requiredParams], false)) |
47 | return -1; |
48 | requiredParams++; |
49 | if (requiredParams < required) |
50 | skipOptionalSVGSpacesOrDelimiter(ptr, end); |
51 | } |
52 | if (!skipOptionalSVGSpaces(ptr, end)) |
53 | return -1; |
54 | |
55 | bool delimParsed = skipOptionalSVGSpacesOrDelimiter(ptr, end); |
56 | |
57 | if (ptr >= end) |
58 | return -1; |
59 | |
60 | if (*ptr == ')') { // skip optionals |
61 | ptr++; |
62 | if (delimParsed) |
63 | return -1; |
64 | } else { |
65 | while (optionalParams < optional) { |
66 | if (ptr >= end || !parseNumber(ptr, end, values[requiredParams + optionalParams], false)) |
67 | return -1; |
68 | optionalParams++; |
69 | if (optionalParams < optional) |
70 | skipOptionalSVGSpacesOrDelimiter(ptr, end); |
71 | } |
72 | |
73 | if (!skipOptionalSVGSpaces(ptr, end)) |
74 | return -1; |
75 | |
76 | delimParsed = skipOptionalSVGSpacesOrDelimiter(ptr, end); |
77 | |
78 | if (ptr >= end || *ptr != ')' || delimParsed) |
79 | return -1; |
80 | ptr++; |
81 | } |
82 | |
83 | return requiredParams + optionalParams; |
84 | } |
85 | |
86 | // These should be kept in sync with enum SVGTransformType |
87 | static const int requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1}; |
88 | static const int optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0}; |
89 | |
90 | // This destructor is needed in order to link correctly with Intel ICC. |
91 | SVGTransformable::~SVGTransformable() = default; |
92 | |
93 | bool SVGTransformable::parseTransformValue(SVGTransformValue::SVGTransformType type, const UChar*& ptr, const UChar* end, SVGTransformValue& transform) |
94 | { |
95 | if (type == SVGTransformValue::SVG_TRANSFORM_UNKNOWN) |
96 | return false; |
97 | |
98 | int valueCount = 0; |
99 | float values[] = {0, 0, 0, 0, 0, 0}; |
100 | if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesForType[type], optionalValuesForType[type])) < 0) |
101 | return false; |
102 | |
103 | switch (type) { |
104 | case SVGTransformValue::SVG_TRANSFORM_UNKNOWN: |
105 | ASSERT_NOT_REACHED(); |
106 | break; |
107 | case SVGTransformValue::SVG_TRANSFORM_SKEWX: |
108 | transform.setSkewX(values[0]); |
109 | break; |
110 | case SVGTransformValue::SVG_TRANSFORM_SKEWY: |
111 | transform.setSkewY(values[0]); |
112 | break; |
113 | case SVGTransformValue::SVG_TRANSFORM_SCALE: |
114 | if (valueCount == 1) // Spec: if only one param given, assume uniform scaling |
115 | transform.setScale(values[0], values[0]); |
116 | else |
117 | transform.setScale(values[0], values[1]); |
118 | break; |
119 | case SVGTransformValue::SVG_TRANSFORM_TRANSLATE: |
120 | if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0 |
121 | transform.setTranslate(values[0], 0); |
122 | else |
123 | transform.setTranslate(values[0], values[1]); |
124 | break; |
125 | case SVGTransformValue::SVG_TRANSFORM_ROTATE: |
126 | if (valueCount == 1) |
127 | transform.setRotate(values[0], 0, 0); |
128 | else |
129 | transform.setRotate(values[0], values[1], values[2]); |
130 | break; |
131 | case SVGTransformValue::SVG_TRANSFORM_MATRIX: |
132 | transform.setMatrix(AffineTransform(values[0], values[1], values[2], values[3], values[4], values[5])); |
133 | break; |
134 | } |
135 | |
136 | return true; |
137 | } |
138 | |
139 | static const UChar skewXDesc[] = {'s', 'k', 'e', 'w', 'X'}; |
140 | static const UChar skewYDesc[] = {'s', 'k', 'e', 'w', 'Y'}; |
141 | static const UChar scaleDesc[] = {'s', 'c', 'a', 'l', 'e'}; |
142 | static const UChar translateDesc[] = {'t', 'r', 'a', 'n', 's', 'l', 'a', 't', 'e'}; |
143 | static const UChar rotateDesc[] = {'r', 'o', 't', 'a', 't', 'e'}; |
144 | static const UChar matrixDesc[] = {'m', 'a', 't', 'r', 'i', 'x'}; |
145 | |
146 | bool SVGTransformable::parseAndSkipType(const UChar*& currTransform, const UChar* end, SVGTransformValue::SVGTransformType& type) |
147 | { |
148 | if (currTransform >= end) |
149 | return false; |
150 | |
151 | if (*currTransform == 's') { |
152 | if (skipString(currTransform, end, skewXDesc, WTF_ARRAY_LENGTH(skewXDesc))) |
153 | type = SVGTransformValue::SVG_TRANSFORM_SKEWX; |
154 | else if (skipString(currTransform, end, skewYDesc, WTF_ARRAY_LENGTH(skewYDesc))) |
155 | type = SVGTransformValue::SVG_TRANSFORM_SKEWY; |
156 | else if (skipString(currTransform, end, scaleDesc, WTF_ARRAY_LENGTH(scaleDesc))) |
157 | type = SVGTransformValue::SVG_TRANSFORM_SCALE; |
158 | else |
159 | return false; |
160 | } else if (skipString(currTransform, end, translateDesc, WTF_ARRAY_LENGTH(translateDesc))) |
161 | type = SVGTransformValue::SVG_TRANSFORM_TRANSLATE; |
162 | else if (skipString(currTransform, end, rotateDesc, WTF_ARRAY_LENGTH(rotateDesc))) |
163 | type = SVGTransformValue::SVG_TRANSFORM_ROTATE; |
164 | else if (skipString(currTransform, end, matrixDesc, WTF_ARRAY_LENGTH(matrixDesc))) |
165 | type = SVGTransformValue::SVG_TRANSFORM_MATRIX; |
166 | else |
167 | return false; |
168 | |
169 | return true; |
170 | } |
171 | |
172 | SVGTransformValue::SVGTransformType SVGTransformable::parseTransformType(const String& typeString) |
173 | { |
174 | SVGTransformValue::SVGTransformType type = SVGTransformValue::SVG_TRANSFORM_UNKNOWN; |
175 | auto upconvertedCharacters = StringView(typeString).upconvertedCharacters(); |
176 | const UChar* characters = upconvertedCharacters; |
177 | parseAndSkipType(characters, characters + typeString.length(), type); |
178 | return type; |
179 | } |
180 | |
181 | } |
182 | |