OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org> |
pdr.
2014/02/18 00:53:57
We lost a 2008 for Niko
kouhei (in TOK)
2014/02/18 02:09:15
Done.
| |
3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> |
4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org> | |
5 * Copyright (C) 2008 Apple Inc. All rights reserved. | |
6 * Copyright (C) Research In Motion Limited 2012. All rights reserved. | |
4 * | 7 * |
5 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
7 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
9 * | 12 * |
10 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 * Library General Public License for more details. | 16 * Library General Public License for more details. |
14 * | 17 * |
15 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
16 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
19 */ | 22 */ |
20 | 23 |
21 #include "config.h" | 24 #include "config.h" |
25 | |
22 #include "core/svg/SVGTransformList.h" | 26 #include "core/svg/SVGTransformList.h" |
23 | 27 |
28 #include "SVGNames.h" | |
29 #include "core/svg/SVGAnimateTransformElement.h" | |
30 #include "core/svg/SVGAnimatedNumber.h" | |
24 #include "core/svg/SVGParserUtilities.h" | 31 #include "core/svg/SVGParserUtilities.h" |
25 #include "core/svg/SVGSVGElement.h" | 32 #include "core/svg/SVGTransformDistance.h" |
26 #include "platform/transforms/AffineTransform.h" | |
27 #include "wtf/text/StringBuilder.h" | 33 #include "wtf/text/StringBuilder.h" |
34 #include "wtf/text/WTFString.h" | |
28 | 35 |
29 namespace WebCore { | 36 namespace WebCore { |
30 | 37 |
31 SVGTransform SVGTransformList::createSVGTransformFromMatrix(const SVGMatrix& mat rix) const | 38 inline PassRefPtr<SVGTransformList> toSVGTransformList(PassRefPtr<NewSVGProperty Base> passBase) |
32 { | 39 { |
33 return SVGSVGElement::createSVGTransformFromMatrix(matrix); | 40 RefPtr<NewSVGPropertyBase> base = passBase; |
34 } | 41 ASSERT(base->type() == SVGTransformList::classType()); |
35 | 42 return static_pointer_cast<SVGTransformList>(base.release()); |
36 SVGTransform SVGTransformList::consolidate() | 43 } |
44 | |
45 SVGTransformList::SVGTransformList() | |
46 { | |
47 } | |
48 | |
49 SVGTransformList::~SVGTransformList() | |
50 { | |
51 } | |
52 | |
53 PassRefPtr<SVGTransform> SVGTransformList::consolidate() | |
37 { | 54 { |
38 AffineTransform matrix; | 55 AffineTransform matrix; |
39 if (!concatenate(matrix)) | 56 if (!concatenate(matrix)) |
40 return SVGTransform(); | 57 return SVGTransform::create(); |
41 | 58 |
42 SVGTransform transform(matrix); | 59 RefPtr<SVGTransform> transform = SVGTransform::create(matrix); |
43 clear(); | 60 clear(); |
44 append(transform); | 61 return appendItem(transform); |
45 return transform; | |
46 } | 62 } |
47 | 63 |
48 bool SVGTransformList::concatenate(AffineTransform& result) const | 64 bool SVGTransformList::concatenate(AffineTransform& result) const |
49 { | 65 { |
50 unsigned size = this->size(); | 66 if (isEmpty()) |
51 if (!size) | |
52 return false; | 67 return false; |
53 | 68 |
54 for (unsigned i = 0; i < size; ++i) | 69 ConstIterator it = begin(); |
55 result *= at(i).matrix(); | 70 ConstIterator itEnd = end(); |
71 for (; it != itEnd; ++it) | |
72 result *= it->matrix(); | |
56 | 73 |
57 return true; | 74 return true; |
58 } | 75 } |
59 | 76 |
77 PassRefPtr<SVGTransformList> SVGTransformList::clone() | |
78 { | |
79 RefPtr<SVGTransformList> svgTransformList = SVGTransformList::create(); | |
80 svgTransformList->deepCopy(this); | |
81 return svgTransformList.release(); | |
82 } | |
83 | |
84 namespace { | |
85 | |
86 template<typename CharType> | |
87 int parseTransformParamList(const CharType*& ptr, const CharType* end, float* va lues, int required, int optional) | |
88 { | |
89 int parsedParams = 0; | |
90 int maxPossibleParams = required + optional; | |
91 | |
92 bool trailingDelimiter = false; | |
93 | |
94 skipOptionalSVGSpaces(ptr, end); | |
95 while (parsedParams < maxPossibleParams) { | |
96 if (!parseNumber(ptr, end, values[parsedParams], false)) | |
97 break; | |
98 | |
99 ++parsedParams; | |
100 | |
101 if (skipOptionalSVGSpaces(ptr, end) && *ptr == ',') { | |
102 ++ptr; | |
103 skipOptionalSVGSpaces(ptr, end); | |
104 | |
105 trailingDelimiter = true; | |
106 } else { | |
107 trailingDelimiter = false; | |
108 } | |
109 } | |
110 | |
111 if (trailingDelimiter || !(parsedParams == required || parsedParams == maxPo ssibleParams)) | |
112 return -1; | |
113 | |
114 return parsedParams; | |
115 } | |
116 | |
117 // These should be kept in sync with enum SVGTransformType | |
118 static const int requiredValuesForType[] = {0, 6, 1, 1, 1, 1, 1}; | |
119 static const int optionalValuesForType[] = {0, 0, 1, 1, 2, 0, 0}; | |
120 | |
121 template<typename CharType> | |
122 PassRefPtr<SVGTransform> parseTransformOfType(unsigned type, const CharType*& pt r, const CharType* end) | |
123 { | |
124 if (type == SVG_TRANSFORM_UNKNOWN) | |
125 return 0; | |
126 | |
127 int valueCount = 0; | |
128 float values[] = {0, 0, 0, 0, 0, 0}; | |
129 String aaa(ptr, end-ptr); | |
fs
2014/02/17 14:14:31
Nit: Not used/needed.
kouhei (in TOK)
2014/02/18 02:09:15
Done.
| |
130 if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesFo rType[type], optionalValuesForType[type])) < 0) { | |
131 return 0; | |
132 } | |
133 | |
134 RefPtr<SVGTransform> transform = SVGTransform::create(); | |
135 | |
136 switch (type) { | |
137 case SVG_TRANSFORM_SKEWX: | |
138 transform->setSkewX(values[0]); | |
139 break; | |
140 case SVG_TRANSFORM_SKEWY: | |
141 transform->setSkewY(values[0]); | |
142 break; | |
143 case SVG_TRANSFORM_SCALE: | |
144 if (valueCount == 1) // Spec: if only one param given, assume uniform sc aling | |
145 transform->setScale(values[0], values[0]); | |
146 else | |
147 transform->setScale(values[0], values[1]); | |
148 break; | |
149 case SVG_TRANSFORM_TRANSLATE: | |
150 if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0 | |
151 transform->setTranslate(values[0], 0); | |
152 else | |
153 transform->setTranslate(values[0], values[1]); | |
154 break; | |
155 case SVG_TRANSFORM_ROTATE: | |
156 if (valueCount == 1) | |
157 transform->setRotate(values[0], 0, 0); | |
158 else | |
159 transform->setRotate(values[0], values[1], values[2]); | |
160 break; | |
161 case SVG_TRANSFORM_MATRIX: | |
162 transform->setMatrix(AffineTransform(values[0], values[1], values[2], va lues[3], values[4], values[5])); | |
163 break; | |
164 } | |
165 | |
166 return transform.release(); | |
167 } | |
168 | |
169 } | |
170 | |
171 template<typename CharType> | |
172 bool SVGTransformList::parseInternal(const CharType*& ptr, const CharType* end) | |
173 { | |
174 String(ptr, end-ptr).show(); | |
fs
2014/02/17 14:14:31
Nit: Drop.
kouhei (in TOK)
2014/02/18 02:09:15
Done.
| |
175 | |
176 clear(); | |
177 | |
178 bool delimParsed = false; | |
179 while (ptr < end) { | |
180 delimParsed = false; | |
181 SVGTransformType transformType = SVG_TRANSFORM_UNKNOWN; | |
182 skipOptionalSVGSpaces(ptr, end); | |
183 | |
184 if (!parseAndSkipTransformType(ptr, end, transformType)) | |
185 return false; | |
186 | |
187 if (!skipOptionalSVGSpaces(ptr, end) || *ptr != '(') | |
188 return false; | |
189 ptr++; | |
190 | |
191 RefPtr<SVGTransform> transform = parseTransformOfType(transformType, ptr , end); | |
192 if (!transform) | |
193 return false; | |
194 | |
195 if (!skipOptionalSVGSpaces(ptr, end) || *ptr != ')') | |
196 return false; | |
197 ptr++; | |
198 | |
199 append(transform.release()); | |
200 | |
201 skipOptionalSVGSpaces(ptr, end); | |
202 if (ptr < end && *ptr == ',') { | |
203 delimParsed = true; | |
204 ++ptr; | |
205 } | |
206 skipOptionalSVGSpaces(ptr, end); | |
fs
2014/02/17 14:14:31
Could also be moved into the if-block, since it's
kouhei (in TOK)
2014/02/18 02:09:15
Done.
| |
207 } | |
208 | |
209 return !delimParsed; | |
210 } | |
211 | |
212 bool SVGTransformList::parse(const UChar*& ptr, const UChar* end) | |
213 { | |
214 return parseInternal(ptr, end); | |
215 } | |
216 | |
217 bool SVGTransformList::parse(const LChar*& ptr, const LChar* end) | |
218 { | |
219 return parseInternal(ptr, end); | |
220 } | |
221 | |
60 String SVGTransformList::valueAsString() const | 222 String SVGTransformList::valueAsString() const |
61 { | 223 { |
62 StringBuilder builder; | 224 StringBuilder builder; |
63 unsigned size = this->size(); | 225 |
64 for (unsigned i = 0; i < size; ++i) { | 226 ConstIterator it = begin(); |
65 if (i > 0) | 227 ConstIterator itEnd = end(); |
228 if (it != itEnd) { | |
fs
2014/02/17 14:14:31
Alternatively:
while (it != itEnd) {
builder.ap
kouhei (in TOK)
2014/02/18 02:09:15
Done.
| |
229 builder.append(it->valueAsString()); | |
230 ++it; | |
231 | |
232 for (; it != itEnd; ++it) { | |
66 builder.append(' '); | 233 builder.append(' '); |
67 | 234 builder.append(it->valueAsString()); |
68 builder.append(at(i).valueAsString()); | 235 } |
69 } | 236 } |
70 | 237 |
71 return builder.toString(); | 238 return builder.toString(); |
72 } | 239 } |
73 | 240 |
74 void SVGTransformList::parse(const String& transform) | 241 void SVGTransformList::setValueAsString(const String& value, ExceptionState& exc eptionState) |
75 { | 242 { |
76 if (transform.isEmpty()) { | 243 if (value.isEmpty()) { |
77 // FIXME: The parseTransformAttribute function secretly calls clear() | |
78 // based on a |mode| parameter. We should study whether we should | |
79 // remove the |mode| parameter and force callers to call clear() | |
80 // themselves. | |
81 clear(); | 244 clear(); |
82 } else if (transform.is8Bit()) { | 245 return; |
83 const LChar* ptr = transform.characters8(); | 246 } |
84 const LChar* end = ptr + transform.length(); | 247 |
85 if (!parseTransformAttribute(*this, ptr, end)) | 248 bool valid = false; |
86 clear(); | 249 if (value.is8Bit()) { |
250 const LChar* ptr = value.characters8(); | |
251 const LChar* end = ptr + value.length(); | |
252 valid = parse(ptr, end); | |
87 } else { | 253 } else { |
88 const UChar* ptr = transform.characters16(); | 254 const UChar* ptr = value.characters16(); |
89 const UChar* end = ptr + transform.length(); | 255 const UChar* end = ptr + value.length(); |
90 if (!parseTransformAttribute(*this, ptr, end)) | 256 valid = parse(ptr, end); |
91 clear(); | 257 } |
92 } | 258 |
93 } | 259 if (!valid) { |
94 | 260 clear(); |
95 } // namespace WebCore | 261 exceptionState.throwDOMException(SyntaxError, "Problem parsing transform list=\""+value+"\""); |
262 } | |
263 } | |
264 | |
265 PassRefPtr<NewSVGPropertyBase> SVGTransformList::cloneForAnimation(const String& value) const | |
266 { | |
267 ASSERT_NOT_REACHED(); | |
268 } | |
269 | |
270 PassRefPtr<SVGTransformList> SVGTransformList::create(SVGTransformType transform Type, const String& value) | |
271 { | |
272 RefPtr<SVGTransform> transform; | |
273 if (value.isEmpty()) { | |
274 } else if (value.is8Bit()) { | |
275 const LChar* ptr = value.characters8(); | |
276 const LChar* end = ptr + value.length(); | |
277 transform = parseTransformOfType(transformType, ptr, end); | |
278 } else { | |
279 const UChar* ptr = value.characters16(); | |
280 const UChar* end = ptr + value.length(); | |
281 transform = parseTransformOfType(transformType, ptr, end); | |
282 } | |
283 | |
284 RefPtr<SVGTransformList> svgTransformList = SVGTransformList::create(); | |
285 if (transform) | |
286 svgTransformList->append(transform); | |
287 return svgTransformList.release(); | |
288 } | |
289 | |
290 void SVGTransformList::add(PassRefPtr<NewSVGPropertyBase> other, SVGElement* con textElement) | |
291 { | |
292 if (isEmpty()) | |
293 return; | |
294 | |
295 RefPtr<SVGTransformList> otherList = toSVGTransformList(other); | |
296 if (numberOfItems() != otherList->numberOfItems()) | |
297 return; | |
298 | |
299 ASSERT(numberOfItems() == 1); | |
300 RefPtr<SVGTransform> fromTransform = at(0); | |
301 RefPtr<SVGTransform> toTransform = otherList->at(0); | |
302 | |
303 ASSERT(fromTransform->transformType() == toTransform->transformType()); | |
304 clear(); | |
305 append(SVGTransformDistance::addSVGTransforms(fromTransform, toTransform)); | |
306 } | |
307 | |
308 void SVGTransformList::calculateAnimatedValue(SVGAnimationElement* animationElem ent, float percentage, unsigned repeatCount, PassRefPtr<NewSVGPropertyBase> from Value, PassRefPtr<NewSVGPropertyBase> toValue, PassRefPtr<NewSVGPropertyBase> to AtEndOfDurationValue, SVGElement* contextElement) | |
309 { | |
310 ASSERT(animationElement); | |
311 bool isToAnimation = animationElement->animationMode() == ToAnimation; | |
312 | |
313 // Spec: To animations provide specific functionality to get a smooth change from the underlying value to the | |
314 // ‘to’ attribute value, which conflicts mathematically with the requirement for additive transform animations | |
315 // to be post-multiplied. As a consequence, in SVG 1.1 the behavior of to an imations for ‘animateTransform’ is undefined | |
316 // FIXME: This is not taken into account yet. | |
317 RefPtr<SVGTransformList> fromList = isToAnimation ? this : toSVGTransformLis t(fromValue); | |
318 RefPtr<SVGTransformList> toList = toSVGTransformList(toValue); | |
319 RefPtr<SVGTransformList> toAtEndOfDurationList = toSVGTransformList(toAtEndO fDurationValue); | |
320 | |
321 size_t fromListSize = fromList->numberOfItems(); | |
322 size_t toListSize = toList->numberOfItems(); | |
323 | |
324 if (!toListSize) | |
325 return; | |
326 | |
327 // Never resize the animatedTransformList to the toList size, instead either clear the list or append to it. | |
328 if (!isEmpty() && !animationElement->isAdditive()) | |
329 clear(); | |
330 | |
331 RefPtr<SVGTransform> toTransform = toList->at(0); | |
332 RefPtr<SVGTransform> effectiveFrom = fromListSize ? fromList->at(0) : SVGTra nsform::create(toTransform->transformType(), SVGTransform::ConstructZeroTransfor m); | |
333 RefPtr<SVGTransform> currentTransform = SVGTransformDistance(effectiveFrom, toTransform).scaledDistance(percentage).addToSVGTransform(effectiveFrom); | |
334 if (animationElement->isAccumulated() && repeatCount) { | |
335 RefPtr<SVGTransform> effectiveToAtEnd = !toAtEndOfDurationList->isEmpty( ) ? toAtEndOfDurationList->at(0) : SVGTransform::create(toTransform->transformTy pe(), SVGTransform::ConstructZeroTransform); | |
336 append(SVGTransformDistance::addSVGTransforms(currentTransform, effectiv eToAtEnd, repeatCount)); | |
337 } else { | |
338 append(currentTransform); | |
339 } | |
340 } | |
341 | |
342 float SVGTransformList::calculateDistance(PassRefPtr<NewSVGPropertyBase> toValue , SVGElement*) | |
343 { | |
344 // FIXME: This is not correct in all cases. The spec demands that each compo nent (translate x and y for example) | |
345 // is paced separately. To implement this we need to treat each component as individual animation everywhere. | |
346 | |
347 RefPtr<SVGTransformList> toList = toSVGTransformList(toValue); | |
348 if (isEmpty() || numberOfItems() != toList->numberOfItems()) | |
349 return -1; | |
350 | |
351 ASSERT(numberOfItems() == 1); | |
352 if (at(0)->transformType() == toList->at(0)->transformType()) | |
353 return -1; | |
354 | |
355 // Spec: http://www.w3.org/TR/SVG/animate.html#complexDistances | |
356 // Paced animations assume a notion of distance between the various animatio n values defined by the ‘to’, ‘from’, ‘by’ and ‘values’ attributes. | |
357 // Distance is defined only for scalar types (such as <length>), colors and the subset of transformation types that are supported by ‘animateTransform’. | |
358 return SVGTransformDistance(at(0), toList->at(0)).distance(); | |
359 } | |
360 | |
361 } | |
OLD | NEW |