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

Side by Side Diff: third_party/WebKit/Source/core/animation/PathSVGInterpolation.cpp

Issue 1413463008: Web Animations: Migrate SVG path interpolation to interpolation types (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month 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
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/animation/PathSVGInterpolation.h"
7
8 #include "core/svg/SVGPathByteStreamBuilder.h"
9 #include "core/svg/SVGPathByteStreamSource.h"
10 #include "core/svg/SVGPathElement.h"
11 #include "core/svg/SVGPathParser.h"
12
13 namespace blink {
14
15 namespace {
16
17 struct SubPathCoordinates {
18 double initialX = 0;
19 double initialY = 0;
20 double currentX = 0;
21 double currentY = 0;
22 };
23
24 PassOwnPtr<InterpolableNumber> controlToInterpolableValue(double value, bool isA bsolute, double currentValue)
25 {
26 if (isAbsolute)
27 return InterpolableNumber::create(value);
28 return InterpolableNumber::create(currentValue + value);
29 }
30
31 double controlFromInterpolableValue(const InterpolableValue* number, bool isAbso lute, double currentValue)
32 {
33 double value = toInterpolableNumber(number)->value();
34
35 if (isAbsolute)
36 return value;
37 return value - currentValue;
38 }
39
40 PassOwnPtr<InterpolableNumber> specifiedToInterpolableValue(double value, bool i sAbsolute, double& currentValue)
41 {
42 if (isAbsolute)
43 currentValue = value;
44 else
45 currentValue += value;
46 return InterpolableNumber::create(currentValue);
47 }
48
49 double specifiedFromInterpolableValue(const InterpolableValue* number, bool isAb solute, double& currentValue)
50 {
51 double previousValue = currentValue;
52 currentValue = toInterpolableNumber(number)->value();
53
54 if (isAbsolute)
55 return currentValue;
56 return currentValue - previousValue;
57 }
58
59 PassOwnPtr<InterpolableValue> pathSegClosePathToInterpolableValue(const PathSegm entData&, SubPathCoordinates& coordinates)
60 {
61 coordinates.currentX = coordinates.initialX;
62 coordinates.currentY = coordinates.initialY;
63
64 // arbitrary
65 return InterpolableBool::create(false);
66 }
67
68 PathSegmentData pathSegClosePathFromInterpolableValue(const InterpolableValue&, SVGPathSegType segType, SubPathCoordinates& coordinates)
69 {
70 coordinates.currentX = coordinates.initialX;
71 coordinates.currentY = coordinates.initialY;
72
73 PathSegmentData segment;
74 segment.command = segType;
75 return segment;
76 }
77
78 PassOwnPtr<InterpolableValue> pathSegSingleCoordinateToInterpolableValue(const P athSegmentData& segment, SubPathCoordinates& coordinates)
79 {
80 bool isAbsolute = isAbsolutePathSegType(segment.command);
81 OwnPtr<InterpolableList> result = InterpolableList::create(2);
82 result->set(0, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin ates.currentX));
83 result->set(1, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin ates.currentY));
84
85 if (toAbsolutePathSegType(segment.command) == PathSegMoveToAbs) {
86 // Any upcoming 'closepath' commands bring us back to the location we ha ve just moved to.
87 coordinates.initialX = coordinates.currentX;
88 coordinates.initialY = coordinates.currentY;
89 }
90
91 return result.release();
92 }
93
94 PathSegmentData pathSegSingleCoordinateFromInterpolableValue(const InterpolableV alue& value, SVGPathSegType segType, SubPathCoordinates& coordinates)
95 {
96 const InterpolableList& list = toInterpolableList(value);
97 bool isAbsolute = isAbsolutePathSegType(segType);
98 PathSegmentData segment;
99 segment.command = segType;
100 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(0), isAbsol ute, coordinates.currentX));
101 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(1), isAbsol ute, coordinates.currentY));
102
103 if (toAbsolutePathSegType(segType) == PathSegMoveToAbs) {
104 // Any upcoming 'closepath' commands bring us back to the location we ha ve just moved to.
105 coordinates.initialX = coordinates.currentX;
106 coordinates.initialY = coordinates.currentY;
107 }
108
109 return segment;
110 }
111
112 PassOwnPtr<InterpolableValue> pathSegCurvetoCubicToInterpolableValue(const PathS egmentData& segment, SubPathCoordinates& coordinates)
113 {
114 bool isAbsolute = isAbsolutePathSegType(segment.command);
115 OwnPtr<InterpolableList> result = InterpolableList::create(6);
116 result->set(0, controlToInterpolableValue(segment.x1(), isAbsolute, coordina tes.currentX));
117 result->set(1, controlToInterpolableValue(segment.y1(), isAbsolute, coordina tes.currentY));
118 result->set(2, controlToInterpolableValue(segment.x2(), isAbsolute, coordina tes.currentX));
119 result->set(3, controlToInterpolableValue(segment.y2(), isAbsolute, coordina tes.currentY));
120 result->set(4, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin ates.currentX));
121 result->set(5, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin ates.currentY));
122 return result.release();
123 }
124
125 PathSegmentData pathSegCurvetoCubicFromInterpolableValue(const InterpolableValue & value, SVGPathSegType segType, SubPathCoordinates& coordinates)
126 {
127 const InterpolableList& list = toInterpolableList(value);
128 bool isAbsolute = isAbsolutePathSegType(segType);
129 PathSegmentData segment;
130 segment.command = segType;
131 segment.point1.setX(controlFromInterpolableValue(list.get(0), isAbsolute, co ordinates.currentX));
132 segment.point1.setY(controlFromInterpolableValue(list.get(1), isAbsolute, co ordinates.currentY));
133 segment.point2.setX(controlFromInterpolableValue(list.get(2), isAbsolute, co ordinates.currentX));
134 segment.point2.setY(controlFromInterpolableValue(list.get(3), isAbsolute, co ordinates.currentY));
135 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(4), isAbsol ute, coordinates.currentX));
136 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(5), isAbsol ute, coordinates.currentY));
137 return segment;
138 }
139
140 PassOwnPtr<InterpolableValue> pathSegCurvetoQuadraticToInterpolableValue(const P athSegmentData& segment, SubPathCoordinates& coordinates)
141 {
142 bool isAbsolute = isAbsolutePathSegType(segment.command);
143 OwnPtr<InterpolableList> result = InterpolableList::create(4);
144 result->set(0, controlToInterpolableValue(segment.x1(), isAbsolute, coordina tes.currentX));
145 result->set(1, controlToInterpolableValue(segment.y1(), isAbsolute, coordina tes.currentY));
146 result->set(2, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin ates.currentX));
147 result->set(3, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin ates.currentY));
148 return result.release();
149 }
150
151 PathSegmentData pathSegCurvetoQuadraticFromInterpolableValue(const InterpolableV alue& value, SVGPathSegType segType, SubPathCoordinates& coordinates)
152 {
153 const InterpolableList& list = toInterpolableList(value);
154 bool isAbsolute = isAbsolutePathSegType(segType);
155 PathSegmentData segment;
156 segment.command = segType;
157 segment.point1.setX(controlFromInterpolableValue(list.get(0), isAbsolute, co ordinates.currentX));
158 segment.point1.setY(controlFromInterpolableValue(list.get(1), isAbsolute, co ordinates.currentY));
159 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(2), isAbsol ute, coordinates.currentX));
160 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(3), isAbsol ute, coordinates.currentY));
161 return segment;
162 }
163
164 PassOwnPtr<InterpolableValue> pathSegArcToInterpolableValue(const PathSegmentDat a& segment, SubPathCoordinates& coordinates)
165 {
166 bool isAbsolute = isAbsolutePathSegType(segment.command);
167 OwnPtr<InterpolableList> result = InterpolableList::create(7);
168 result->set(0, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin ates.currentX));
169 result->set(1, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin ates.currentY));
170 result->set(2, InterpolableNumber::create(segment.r1()));
171 result->set(3, InterpolableNumber::create(segment.r2()));
172 result->set(4, InterpolableNumber::create(segment.arcAngle()));
173 result->set(5, InterpolableBool::create(segment.largeArcFlag()));
174 result->set(6, InterpolableBool::create(segment.sweepFlag()));
175 return result.release();
176 }
177
178 PathSegmentData pathSegArcFromInterpolableValue(const InterpolableValue& value, SVGPathSegType segType, SubPathCoordinates& coordinates)
179 {
180 const InterpolableList& list = toInterpolableList(value);
181 bool isAbsolute = isAbsolutePathSegType(segType);
182 PathSegmentData segment;
183 segment.command = segType;
184 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(0), isAbsol ute, coordinates.currentX));
185 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(1), isAbsol ute, coordinates.currentY));
186 segment.arcRadii().setX(toInterpolableNumber(list.get(2))->value());
187 segment.arcRadii().setY(toInterpolableNumber(list.get(3))->value());
188 segment.setArcAngle(toInterpolableNumber(list.get(4))->value());
189 segment.arcLarge = toInterpolableBool(list.get(5))->value();
190 segment.arcSweep = toInterpolableBool(list.get(6))->value();
191 return segment;
192 }
193
194 PassOwnPtr<InterpolableValue> pathSegLinetoHorizontalToInterpolableValue(const P athSegmentData& segment, SubPathCoordinates& coordinates)
195 {
196 bool isAbsolute = isAbsolutePathSegType(segment.command);
197 return specifiedToInterpolableValue(segment.x(), isAbsolute, coordinates.cur rentX);
198 }
199
200 PathSegmentData pathSegLinetoHorizontalFromInterpolableValue(const InterpolableV alue& value, SVGPathSegType segType, SubPathCoordinates& coordinates)
201 {
202 bool isAbsolute = isAbsolutePathSegType(segType);
203 PathSegmentData segment;
204 segment.command = segType;
205 segment.targetPoint.setX(specifiedFromInterpolableValue(&value, isAbsolute, coordinates.currentX));
206 return segment;
207 }
208
209 PassOwnPtr<InterpolableValue> pathSegLinetoVerticalToInterpolableValue(const Pat hSegmentData& segment, SubPathCoordinates& coordinates)
210 {
211 bool isAbsolute = isAbsolutePathSegType(segment.command);
212 return specifiedToInterpolableValue(segment.y(), isAbsolute, coordinates.cur rentY);
213 }
214
215 PathSegmentData pathSegLinetoVerticalFromInterpolableValue(const InterpolableVal ue& value, SVGPathSegType segType, SubPathCoordinates& coordinates)
216 {
217 bool isAbsolute = isAbsolutePathSegType(segType);
218 PathSegmentData segment;
219 segment.command = segType;
220 segment.targetPoint.setY(specifiedFromInterpolableValue(&value, isAbsolute, coordinates.currentY));
221 return segment;
222 }
223
224 PassOwnPtr<InterpolableValue> pathSegCurvetoCubicSmoothToInterpolableValue(const PathSegmentData& segment, SubPathCoordinates& coordinates)
225 {
226 bool isAbsolute = isAbsolutePathSegType(segment.command);
227 OwnPtr<InterpolableList> result = InterpolableList::create(4);
228 result->set(0, controlToInterpolableValue(segment.x2(), isAbsolute, coordina tes.currentX));
229 result->set(1, controlToInterpolableValue(segment.y2(), isAbsolute, coordina tes.currentY));
230 result->set(2, specifiedToInterpolableValue(segment.x(), isAbsolute, coordin ates.currentX));
231 result->set(3, specifiedToInterpolableValue(segment.y(), isAbsolute, coordin ates.currentY));
232 return result.release();
233 }
234
235 PathSegmentData pathSegCurvetoCubicSmoothFromInterpolableValue(const Interpolabl eValue& value, SVGPathSegType segType, SubPathCoordinates& coordinates)
236 {
237 const InterpolableList& list = toInterpolableList(value);
238 bool isAbsolute = isAbsolutePathSegType(segType);
239 PathSegmentData segment;
240 segment.command = segType;
241 segment.point2.setX(controlFromInterpolableValue(list.get(0), isAbsolute, co ordinates.currentX));
242 segment.point2.setY(controlFromInterpolableValue(list.get(1), isAbsolute, co ordinates.currentY));
243 segment.targetPoint.setX(specifiedFromInterpolableValue(list.get(2), isAbsol ute, coordinates.currentX));
244 segment.targetPoint.setY(specifiedFromInterpolableValue(list.get(3), isAbsol ute, coordinates.currentY));
245 return segment;
246 }
247
248 PassOwnPtr<InterpolableValue> pathSegToInterpolableValue(const PathSegmentData& segment, SubPathCoordinates& coordinates, SVGPathSegType* ptrSegType)
249 {
250 if (ptrSegType)
251 *ptrSegType = segment.command;
252
253 switch (segment.command) {
254 case PathSegClosePath:
255 return pathSegClosePathToInterpolableValue(segment, coordinates);
256
257 case PathSegMoveToAbs:
258 case PathSegMoveToRel:
259 case PathSegLineToAbs:
260 case PathSegLineToRel:
261 case PathSegCurveToQuadraticSmoothAbs:
262 case PathSegCurveToQuadraticSmoothRel:
263 return pathSegSingleCoordinateToInterpolableValue(segment, coordinates);
264
265 case PathSegCurveToCubicAbs:
266 case PathSegCurveToCubicRel:
267 return pathSegCurvetoCubicToInterpolableValue(segment, coordinates);
268
269 case PathSegCurveToQuadraticAbs:
270 case PathSegCurveToQuadraticRel:
271 return pathSegCurvetoQuadraticToInterpolableValue(segment, coordinates);
272
273 case PathSegArcAbs:
274 case PathSegArcRel:
275 return pathSegArcToInterpolableValue(segment, coordinates);
276
277 case PathSegLineToHorizontalAbs:
278 case PathSegLineToHorizontalRel:
279 return pathSegLinetoHorizontalToInterpolableValue(segment, coordinates);
280
281 case PathSegLineToVerticalAbs:
282 case PathSegLineToVerticalRel:
283 return pathSegLinetoVerticalToInterpolableValue(segment, coordinates);
284
285 case PathSegCurveToCubicSmoothAbs:
286 case PathSegCurveToCubicSmoothRel:
287 return pathSegCurvetoCubicSmoothToInterpolableValue(segment, coordinates );
288
289 case PathSegUnknown:
290 ASSERT_NOT_REACHED();
291 }
292 ASSERT_NOT_REACHED();
293 return nullptr;
294 }
295
296 PathSegmentData pathSegFromInterpolableValue(const InterpolableValue& value, SVG PathSegType segType, SubPathCoordinates& coordinates)
297 {
298 switch (segType) {
299 case PathSegClosePath:
300 return pathSegClosePathFromInterpolableValue(value, segType, coordinates );
301
302 case PathSegMoveToAbs:
303 case PathSegMoveToRel:
304 case PathSegLineToAbs:
305 case PathSegLineToRel:
306 case PathSegCurveToQuadraticSmoothAbs:
307 case PathSegCurveToQuadraticSmoothRel:
308 return pathSegSingleCoordinateFromInterpolableValue(value, segType, coor dinates);
309
310 case PathSegCurveToCubicAbs:
311 case PathSegCurveToCubicRel:
312 return pathSegCurvetoCubicFromInterpolableValue(value, segType, coordina tes);
313
314 case PathSegCurveToQuadraticAbs:
315 case PathSegCurveToQuadraticRel:
316 return pathSegCurvetoQuadraticFromInterpolableValue(value, segType, coor dinates);
317
318 case PathSegArcAbs:
319 case PathSegArcRel:
320 return pathSegArcFromInterpolableValue(value, segType, coordinates);
321
322 case PathSegLineToHorizontalAbs:
323 case PathSegLineToHorizontalRel:
324 return pathSegLinetoHorizontalFromInterpolableValue(value, segType, coor dinates);
325
326 case PathSegLineToVerticalAbs:
327 case PathSegLineToVerticalRel:
328 return pathSegLinetoVerticalFromInterpolableValue(value, segType, coordi nates);
329
330 case PathSegCurveToCubicSmoothAbs:
331 case PathSegCurveToCubicSmoothRel:
332 return pathSegCurvetoCubicSmoothFromInterpolableValue(value, segType, co ordinates);
333
334 case PathSegUnknown:
335 ASSERT_NOT_REACHED();
336 }
337 ASSERT_NOT_REACHED();
338 return PathSegmentData();
339 }
340
341 class InterpolatedPathSource : public SVGPathSource {
342 public:
343 InterpolatedPathSource(const InterpolableList& listValue, const Vector<SVGPa thSegType>& pathSegTypes)
344 : m_currentIndex(0)
345 , m_list(listValue)
346 , m_segmentTypes(pathSegTypes)
347 {
348 ASSERT(m_list.length() == m_segmentTypes.size());
349 }
350
351 private:
352 bool hasMoreData() const override;
353 SVGPathSegType peekSegmentType() override;
354 PathSegmentData parseSegment() override;
355
356 SubPathCoordinates m_normalizationState;
357 size_t m_currentIndex;
358 const InterpolableList& m_list;
359 const Vector<SVGPathSegType>& m_segmentTypes;
360 };
361
362 bool InterpolatedPathSource::hasMoreData() const
363 {
364 return m_currentIndex < m_list.length();
365 }
366
367 SVGPathSegType InterpolatedPathSource::peekSegmentType()
368 {
369 ASSERT(hasMoreData());
370 return m_segmentTypes.at(m_currentIndex);
371 }
372
373 PathSegmentData InterpolatedPathSource::parseSegment()
374 {
375 PathSegmentData segment = pathSegFromInterpolableValue(*m_list.get(m_current Index), m_segmentTypes.at(m_currentIndex), m_normalizationState);
376 ++m_currentIndex;
377 return segment;
378 }
379
380 size_t countPathCommands(const SVGPathByteStream& path)
381 {
382 size_t count = 0;
383 SVGPathByteStreamSource pathSource(path);
384 while (pathSource.hasMoreData()) {
385 pathSource.parseSegment();
386 ++count;
387 }
388 return count;
389 }
390
391 } // namespace
392
393 PassRefPtr<PathSVGInterpolation> PathSVGInterpolation::maybeCreate(SVGPropertyBa se* start, SVGPropertyBase* end, PassRefPtrWillBeRawPtr<SVGAnimatedPropertyBase> attribute)
394 {
395 ASSERT(start->type() == SVGPath::classType());
396 ASSERT(end->type() == SVGPath::classType());
397
398 const SVGPathByteStream& startPath = static_cast<SVGPath*>(start)->byteStrea m();
399 const SVGPathByteStream& endPath = static_cast<SVGPath*>(end)->byteStream();
400
401 if (startPath.size() != endPath.size())
402 return nullptr;
403
404 size_t length = countPathCommands(startPath);
405
406 SVGPathByteStreamSource startPathSource(startPath);
407 SVGPathByteStreamSource endPathSource(endPath);
408
409 Vector<SVGPathSegType> pathSegTypes(length);
410 OwnPtr<InterpolableList> startValue = InterpolableList::create(length);
411 OwnPtr<InterpolableList> endValue = InterpolableList::create(length);
412 SubPathCoordinates startCoordinates;
413 SubPathCoordinates endCoordinates;
414 size_t i = 0;
415 while (startPathSource.hasMoreData()) {
416 if (toAbsolutePathSegType(startPathSource.peekSegmentType()) != toAbsolu tePathSegType(endPathSource.peekSegmentType()))
417 return nullptr;
418
419 // Like Firefox SMIL, we use the final path seg type.
420 const PathSegmentData startSeg = startPathSource.parseSegment();
421 startValue->set(i, pathSegToInterpolableValue(startSeg, startCoordinates , nullptr));
422
423 const PathSegmentData endSeg = endPathSource.parseSegment();
424 endValue->set(i, pathSegToInterpolableValue(endSeg, endCoordinates, &pat hSegTypes.at(i)));
425
426 ++i;
427 }
428 ASSERT(!endPathSource.hasMoreData());
429 ASSERT(i == length);
430
431 return adoptRef(new PathSVGInterpolation(startValue.release(), endValue.rele ase(), attribute, pathSegTypes));
432 }
433
434 PassRefPtrWillBeRawPtr<SVGPropertyBase> PathSVGInterpolation::fromInterpolableVa lue(const InterpolableValue& value, const Vector<SVGPathSegType>& pathSegTypes)
435 {
436 RefPtrWillBeRawPtr<SVGPath> result = SVGPath::create();
437 InterpolatedPathSource source(toInterpolableList(value), pathSegTypes);
438 SVGPathByteStreamBuilder builder(result->mutableByteStream());
439 SVGPathParser parser(&source, &builder);
440 parser.parsePathDataFromSource(UnalteredParsing, false);
441 return result.release();
442 }
443
444 PassRefPtrWillBeRawPtr<SVGPropertyBase> PathSVGInterpolation::interpolatedValue( SVGElement&) const
445 {
446 return fromInterpolableValue(*m_cachedValue, m_pathSegTypes);
447 }
448
449 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698