Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: Source/core/svg/SVGTransformList.cpp

Issue 153883003: [SVG] SVGAnimatedTransform{,List} migration to new SVG property impl. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: haraken review Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698