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

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: remove m_zoomAndPan 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
« no previous file with comments | « Source/core/svg/SVGTransformList.h ('k') | Source/core/svg/SVGTransformList.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> 2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
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 if ((valueCount = parseTransformParamList(ptr, end, values, requiredValuesFo rType[type], optionalValuesForType[type])) < 0) {
130 return 0;
131 }
132
133 RefPtr<SVGTransform> transform = SVGTransform::create();
134
135 switch (type) {
136 case SVG_TRANSFORM_SKEWX:
137 transform->setSkewX(values[0]);
138 break;
139 case SVG_TRANSFORM_SKEWY:
140 transform->setSkewY(values[0]);
141 break;
142 case SVG_TRANSFORM_SCALE:
143 if (valueCount == 1) // Spec: if only one param given, assume uniform sc aling
144 transform->setScale(values[0], values[0]);
145 else
146 transform->setScale(values[0], values[1]);
147 break;
148 case SVG_TRANSFORM_TRANSLATE:
149 if (valueCount == 1) // Spec: if only one param given, assume 2nd param to be 0
150 transform->setTranslate(values[0], 0);
151 else
152 transform->setTranslate(values[0], values[1]);
153 break;
154 case SVG_TRANSFORM_ROTATE:
155 if (valueCount == 1)
156 transform->setRotate(values[0], 0, 0);
157 else
158 transform->setRotate(values[0], values[1], values[2]);
159 break;
160 case SVG_TRANSFORM_MATRIX:
161 transform->setMatrix(AffineTransform(values[0], values[1], values[2], va lues[3], values[4], values[5]));
162 break;
163 }
164
165 return transform.release();
166 }
167
168 }
169
170 template<typename CharType>
171 bool SVGTransformList::parseInternal(const CharType*& ptr, const CharType* end)
172 {
173 clear();
174
175 bool delimParsed = false;
176 while (ptr < end) {
177 delimParsed = false;
178 SVGTransformType transformType = SVG_TRANSFORM_UNKNOWN;
179 skipOptionalSVGSpaces(ptr, end);
180
181 if (!parseAndSkipTransformType(ptr, end, transformType))
182 return false;
183
184 if (!skipOptionalSVGSpaces(ptr, end) || *ptr != '(')
185 return false;
186 ptr++;
187
188 RefPtr<SVGTransform> transform = parseTransformOfType(transformType, ptr , end);
189 if (!transform)
190 return false;
191
192 if (!skipOptionalSVGSpaces(ptr, end) || *ptr != ')')
193 return false;
194 ptr++;
195
196 append(transform.release());
197
198 skipOptionalSVGSpaces(ptr, end);
199 if (ptr < end && *ptr == ',') {
200 delimParsed = true;
201 ++ptr;
202 skipOptionalSVGSpaces(ptr, end);
203 }
204 }
205
206 return !delimParsed;
207 }
208
209 bool SVGTransformList::parse(const UChar*& ptr, const UChar* end)
210 {
211 return parseInternal(ptr, end);
212 }
213
214 bool SVGTransformList::parse(const LChar*& ptr, const LChar* end)
215 {
216 return parseInternal(ptr, end);
217 }
218
60 String SVGTransformList::valueAsString() const 219 String SVGTransformList::valueAsString() const
61 { 220 {
62 StringBuilder builder; 221 StringBuilder builder;
63 unsigned size = this->size(); 222
64 for (unsigned i = 0; i < size; ++i) { 223 ConstIterator it = begin();
65 if (i > 0) 224 ConstIterator itEnd = end();
225 while (it != itEnd) {
226 builder.append(it->valueAsString());
227 ++it;
228 if (it != itEnd)
66 builder.append(' '); 229 builder.append(' ');
67
68 builder.append(at(i).valueAsString());
69 } 230 }
70 231
71 return builder.toString(); 232 return builder.toString();
72 } 233 }
73 234
74 void SVGTransformList::parse(const String& transform) 235 void SVGTransformList::setValueAsString(const String& value, ExceptionState& exc eptionState)
75 { 236 {
76 if (transform.isEmpty()) { 237 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(); 238 clear();
82 } else if (transform.is8Bit()) { 239 return;
83 const LChar* ptr = transform.characters8(); 240 }
84 const LChar* end = ptr + transform.length(); 241
85 if (!parseTransformAttribute(*this, ptr, end)) 242 bool valid = false;
86 clear(); 243 if (value.is8Bit()) {
244 const LChar* ptr = value.characters8();
245 const LChar* end = ptr + value.length();
246 valid = parse(ptr, end);
87 } else { 247 } else {
88 const UChar* ptr = transform.characters16(); 248 const UChar* ptr = value.characters16();
89 const UChar* end = ptr + transform.length(); 249 const UChar* end = ptr + value.length();
90 if (!parseTransformAttribute(*this, ptr, end)) 250 valid = parse(ptr, end);
91 clear(); 251 }
92 } 252
93 } 253 if (!valid) {
94 254 clear();
95 } // namespace WebCore 255 exceptionState.throwDOMException(SyntaxError, "Problem parsing transform list=\""+value+"\"");
256 }
257 }
258
259 PassRefPtr<NewSVGPropertyBase> SVGTransformList::cloneForAnimation(const String& value) const
260 {
261 ASSERT_NOT_REACHED();
262 return 0;
263 }
264
265 PassRefPtr<SVGTransformList> SVGTransformList::create(SVGTransformType transform Type, const String& value)
266 {
267 RefPtr<SVGTransform> transform;
268 if (value.isEmpty()) {
269 } else if (value.is8Bit()) {
270 const LChar* ptr = value.characters8();
271 const LChar* end = ptr + value.length();
272 transform = parseTransformOfType(transformType, ptr, end);
273 } else {
274 const UChar* ptr = value.characters16();
275 const UChar* end = ptr + value.length();
276 transform = parseTransformOfType(transformType, ptr, end);
277 }
278
279 RefPtr<SVGTransformList> svgTransformList = SVGTransformList::create();
280 if (transform)
281 svgTransformList->append(transform);
282 return svgTransformList.release();
283 }
284
285 void SVGTransformList::add(PassRefPtr<NewSVGPropertyBase> other, SVGElement* con textElement)
286 {
287 if (isEmpty())
288 return;
289
290 RefPtr<SVGTransformList> otherList = toSVGTransformList(other);
291 if (numberOfItems() != otherList->numberOfItems())
292 return;
293
294 ASSERT(numberOfItems() == 1);
295 RefPtr<SVGTransform> fromTransform = at(0);
296 RefPtr<SVGTransform> toTransform = otherList->at(0);
297
298 ASSERT(fromTransform->transformType() == toTransform->transformType());
299 clear();
300 append(SVGTransformDistance::addSVGTransforms(fromTransform, toTransform));
301 }
302
303 void SVGTransformList::calculateAnimatedValue(SVGAnimationElement* animationElem ent, float percentage, unsigned repeatCount, PassRefPtr<NewSVGPropertyBase> from Value, PassRefPtr<NewSVGPropertyBase> toValue, PassRefPtr<NewSVGPropertyBase> to AtEndOfDurationValue, SVGElement* contextElement)
304 {
305 ASSERT(animationElement);
306 bool isToAnimation = animationElement->animationMode() == ToAnimation;
307
308 // Spec: To animations provide specific functionality to get a smooth change from the underlying value to the
309 // ‘to’ attribute value, which conflicts mathematically with the requirement for additive transform animations
310 // to be post-multiplied. As a consequence, in SVG 1.1 the behavior of to an imations for ‘animateTransform’ is undefined
311 // FIXME: This is not taken into account yet.
312 RefPtr<SVGTransformList> fromList = isToAnimation ? this : toSVGTransformLis t(fromValue);
313 RefPtr<SVGTransformList> toList = toSVGTransformList(toValue);
314 RefPtr<SVGTransformList> toAtEndOfDurationList = toSVGTransformList(toAtEndO fDurationValue);
315
316 size_t fromListSize = fromList->numberOfItems();
317 size_t toListSize = toList->numberOfItems();
318
319 if (!toListSize)
320 return;
321
322 // Never resize the animatedTransformList to the toList size, instead either clear the list or append to it.
323 if (!isEmpty() && !animationElement->isAdditive())
324 clear();
325
326 RefPtr<SVGTransform> toTransform = toList->at(0);
327 RefPtr<SVGTransform> effectiveFrom = fromListSize ? fromList->at(0) : SVGTra nsform::create(toTransform->transformType(), SVGTransform::ConstructZeroTransfor m);
328 RefPtr<SVGTransform> currentTransform = SVGTransformDistance(effectiveFrom, toTransform).scaledDistance(percentage).addToSVGTransform(effectiveFrom);
329 if (animationElement->isAccumulated() && repeatCount) {
330 RefPtr<SVGTransform> effectiveToAtEnd = !toAtEndOfDurationList->isEmpty( ) ? toAtEndOfDurationList->at(0) : SVGTransform::create(toTransform->transformTy pe(), SVGTransform::ConstructZeroTransform);
331 append(SVGTransformDistance::addSVGTransforms(currentTransform, effectiv eToAtEnd, repeatCount));
332 } else {
333 append(currentTransform);
334 }
335 }
336
337 float SVGTransformList::calculateDistance(PassRefPtr<NewSVGPropertyBase> toValue , SVGElement*)
338 {
339 // FIXME: This is not correct in all cases. The spec demands that each compo nent (translate x and y for example)
340 // is paced separately. To implement this we need to treat each component as individual animation everywhere.
341
342 RefPtr<SVGTransformList> toList = toSVGTransformList(toValue);
343 if (isEmpty() || numberOfItems() != toList->numberOfItems())
344 return -1;
345
346 ASSERT(numberOfItems() == 1);
347 if (at(0)->transformType() == toList->at(0)->transformType())
348 return -1;
349
350 // Spec: http://www.w3.org/TR/SVG/animate.html#complexDistances
351 // Paced animations assume a notion of distance between the various animatio n values defined by the ‘to’, ‘from’, ‘by’ and ‘values’ attributes.
352 // Distance is defined only for scalar types (such as <length>), colors and the subset of transformation types that are supported by ‘animateTransform’.
353 return SVGTransformDistance(at(0), toList->at(0)).distance();
354 }
355
356 }
OLDNEW
« no previous file with comments | « Source/core/svg/SVGTransformList.h ('k') | Source/core/svg/SVGTransformList.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698