2
* Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved.
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public License
15
* along with this library; see the file COPYING.LIB. If not, write to
16
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301, USA.
23
#include "SVGPathBlender.h"
25
#include "AnimationUtilities.h"
26
#include "SVGPathSeg.h"
27
#include <wtf/TemporaryChange.h>
31
SVGPathBlender::SVGPathBlender()
37
, m_isInFirstHalfOfAnimation(false)
42
static inline FloatPoint blendFloatPoint(const FloatPoint& a, const FloatPoint& b, float progress)
44
return FloatPoint(blend(a.x(), b.x(), progress), blend(a.y(), b.y(), progress));
47
float SVGPathBlender::blendAnimatedDimensonalFloat(float from, float to, FloatBlendMode blendMode)
49
if (m_addTypesCount) {
50
ASSERT(m_fromMode == m_toMode);
51
return from + to * m_addTypesCount;
54
if (m_fromMode == m_toMode)
55
return blend(from, to, m_progress);
57
float fromValue = blendMode == BlendHorizontal ? m_fromCurrentPoint.x() : m_fromCurrentPoint.y();
58
float toValue = blendMode == BlendHorizontal ? m_toCurrentPoint.x() : m_toCurrentPoint.y();
60
// Transform toY to the coordinate mode of fromY
61
float animValue = blend(from, m_fromMode == AbsoluteCoordinates ? to + toValue : to - toValue, m_progress);
63
if (m_isInFirstHalfOfAnimation)
66
// Transform the animated point to the coordinate mode, needed for the current progress.
67
float currentValue = blend(fromValue, toValue, m_progress);
68
return m_toMode == AbsoluteCoordinates ? animValue + currentValue : animValue - currentValue;
71
FloatPoint SVGPathBlender::blendAnimatedFloatPoint(const FloatPoint& fromPoint, const FloatPoint& toPoint)
73
if (m_addTypesCount) {
74
ASSERT(m_fromMode == m_toMode);
75
FloatPoint repeatedToPoint = toPoint;
76
repeatedToPoint.scale(m_addTypesCount, m_addTypesCount);
77
return fromPoint + repeatedToPoint;
80
if (m_fromMode == m_toMode)
81
return blendFloatPoint(fromPoint, toPoint, m_progress);
83
// Transform toPoint to the coordinate mode of fromPoint
84
FloatPoint animatedPoint = toPoint;
85
if (m_fromMode == AbsoluteCoordinates)
86
animatedPoint += m_toCurrentPoint;
88
animatedPoint.move(-m_toCurrentPoint.x(), -m_toCurrentPoint.y());
90
animatedPoint = blendFloatPoint(fromPoint, animatedPoint, m_progress);
92
if (m_isInFirstHalfOfAnimation)
95
// Transform the animated point to the coordinate mode, needed for the current progress.
96
FloatPoint currentPoint = blendFloatPoint(m_fromCurrentPoint, m_toCurrentPoint, m_progress);
97
if (m_toMode == AbsoluteCoordinates)
98
return animatedPoint + currentPoint;
100
animatedPoint.move(-currentPoint.x(), -currentPoint.y());
101
return animatedPoint;
104
bool SVGPathBlender::blendMoveToSegment()
106
FloatPoint fromTargetPoint;
107
FloatPoint toTargetPoint;
108
if ((m_fromSource->hasMoreData() && !m_fromSource->parseMoveToSegment(fromTargetPoint))
109
|| !m_toSource->parseMoveToSegment(toTargetPoint))
112
m_consumer->moveTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint), false, m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
113
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
114
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
118
bool SVGPathBlender::blendLineToSegment()
120
FloatPoint fromTargetPoint;
121
FloatPoint toTargetPoint;
122
if ((m_fromSource->hasMoreData() && !m_fromSource->parseLineToSegment(fromTargetPoint))
123
|| !m_toSource->parseLineToSegment(toTargetPoint))
126
m_consumer->lineTo(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
127
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
128
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
132
bool SVGPathBlender::blendLineToHorizontalSegment()
136
if ((m_fromSource->hasMoreData() && !m_fromSource->parseLineToHorizontalSegment(fromX))
137
|| !m_toSource->parseLineToHorizontalSegment(toX))
140
m_consumer->lineToHorizontal(blendAnimatedDimensonalFloat(fromX, toX, BlendHorizontal), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
141
m_fromCurrentPoint.setX(m_fromMode == AbsoluteCoordinates ? fromX : m_fromCurrentPoint.x() + fromX);
142
m_toCurrentPoint.setX(m_toMode == AbsoluteCoordinates ? toX : m_toCurrentPoint.x() + toX);
146
bool SVGPathBlender::blendLineToVerticalSegment()
150
if ((m_fromSource->hasMoreData() && !m_fromSource->parseLineToVerticalSegment(fromY))
151
|| !m_toSource->parseLineToVerticalSegment(toY))
154
m_consumer->lineToVertical(blendAnimatedDimensonalFloat(fromY, toY, BlendVertical), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
155
m_fromCurrentPoint.setY(m_fromMode == AbsoluteCoordinates ? fromY : m_fromCurrentPoint.y() + fromY);
156
m_toCurrentPoint.setY(m_toMode == AbsoluteCoordinates ? toY : m_toCurrentPoint.y() + toY);
160
bool SVGPathBlender::blendCurveToCubicSegment()
162
FloatPoint fromTargetPoint;
163
FloatPoint fromPoint1;
164
FloatPoint fromPoint2;
165
FloatPoint toTargetPoint;
168
if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToCubicSegment(fromPoint1, fromPoint2, fromTargetPoint))
169
|| !m_toSource->parseCurveToCubicSegment(toPoint1, toPoint2, toTargetPoint))
172
m_consumer->curveToCubic(blendAnimatedFloatPoint(fromPoint1, toPoint1),
173
blendAnimatedFloatPoint(fromPoint2, toPoint2),
174
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
175
m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
176
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
177
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
181
bool SVGPathBlender::blendCurveToCubicSmoothSegment()
183
FloatPoint fromTargetPoint;
184
FloatPoint fromPoint2;
185
FloatPoint toTargetPoint;
187
if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToCubicSmoothSegment(fromPoint2, fromTargetPoint))
188
|| !m_toSource->parseCurveToCubicSmoothSegment(toPoint2, toTargetPoint))
191
m_consumer->curveToCubicSmooth(blendAnimatedFloatPoint(fromPoint2, toPoint2),
192
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
193
m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
194
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
195
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
199
bool SVGPathBlender::blendCurveToQuadraticSegment()
201
FloatPoint fromTargetPoint;
202
FloatPoint fromPoint1;
203
FloatPoint toTargetPoint;
205
if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToQuadraticSegment(fromPoint1, fromTargetPoint))
206
|| !m_toSource->parseCurveToQuadraticSegment(toPoint1, toTargetPoint))
209
m_consumer->curveToQuadratic(blendAnimatedFloatPoint(fromPoint1, toPoint1),
210
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
211
m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
212
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
213
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
217
bool SVGPathBlender::blendCurveToQuadraticSmoothSegment()
219
FloatPoint fromTargetPoint;
220
FloatPoint toTargetPoint;
221
if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToQuadraticSmoothSegment(fromTargetPoint))
222
|| !m_toSource->parseCurveToQuadraticSmoothSegment(toTargetPoint))
225
m_consumer->curveToQuadraticSmooth(blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint), m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
226
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
227
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
231
bool SVGPathBlender::blendArcToSegment()
236
bool fromLargeArc = false;
237
bool fromSweep = false;
238
FloatPoint fromTargetPoint;
242
bool toLargeArc = false;
243
bool toSweep = false;
244
FloatPoint toTargetPoint;
245
if ((m_fromSource->hasMoreData() && !m_fromSource->parseArcToSegment(fromRx, fromRy, fromAngle, fromLargeArc, fromSweep, fromTargetPoint))
246
|| !m_toSource->parseArcToSegment(toRx, toRy, toAngle, toLargeArc, toSweep, toTargetPoint))
249
if (m_addTypesCount) {
250
ASSERT(m_fromMode == m_toMode);
251
FloatPoint scaledToTargetPoint = toTargetPoint;
252
scaledToTargetPoint.scale(m_addTypesCount, m_addTypesCount);
253
m_consumer->arcTo(fromRx + toRx * m_addTypesCount,
254
fromRy + toRy * m_addTypesCount,
255
fromAngle + toAngle * m_addTypesCount,
256
fromLargeArc || toLargeArc,
257
fromSweep || toSweep,
258
fromTargetPoint + scaledToTargetPoint,
261
m_consumer->arcTo(blend(fromRx, toRx, m_progress),
262
blend(fromRy, toRy, m_progress),
263
blend(fromAngle, toAngle, m_progress),
264
m_isInFirstHalfOfAnimation ? fromLargeArc : toLargeArc,
265
m_isInFirstHalfOfAnimation ? fromSweep : toSweep,
266
blendAnimatedFloatPoint(fromTargetPoint, toTargetPoint),
267
m_isInFirstHalfOfAnimation ? m_fromMode : m_toMode);
269
m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
270
m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
274
static inline PathCoordinateMode coordinateModeOfCommand(const SVGPathSegType& type)
276
if (type < PathSegMoveToAbs)
277
return AbsoluteCoordinates;
279
// Odd number = relative command
281
return RelativeCoordinates;
283
return AbsoluteCoordinates;
286
static inline bool isSegmentEqual(const SVGPathSegType& fromType, const SVGPathSegType& toType, const PathCoordinateMode& fromMode, const PathCoordinateMode& toMode)
288
if (fromType == toType && (fromType == PathSegUnknown || fromType == PathSegClosePath))
291
unsigned short from = fromType;
292
unsigned short to = toType;
293
if (fromMode == toMode)
295
if (fromMode == AbsoluteCoordinates)
296
return from == to - 1;
297
return to == from - 1;
300
bool SVGPathBlender::addAnimatedPath(SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer, unsigned repeatCount)
302
TemporaryChange<unsigned> change(m_addTypesCount, repeatCount);
303
return blendAnimatedPath(0, fromSource, toSource, consumer);
306
bool SVGPathBlender::blendAnimatedPath(float progress, SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer)
311
m_fromSource = fromSource;
312
m_toSource = toSource;
313
m_consumer = consumer;
314
m_isInFirstHalfOfAnimation = progress < 0.5f;
315
m_progress = progress;
317
bool fromSourceHadData = m_fromSource->hasMoreData();
318
while (m_toSource->hasMoreData()) {
319
SVGPathSegType fromCommand;
320
SVGPathSegType toCommand;
321
if ((fromSourceHadData && !m_fromSource->parseSVGSegmentType(fromCommand)) || !m_toSource->parseSVGSegmentType(toCommand))
324
m_toMode = coordinateModeOfCommand(toCommand);
325
m_fromMode = fromSourceHadData ? coordinateModeOfCommand(fromCommand) : m_toMode;
326
if (m_fromMode != m_toMode && m_addTypesCount)
329
if (fromSourceHadData && !isSegmentEqual(fromCommand, toCommand, m_fromMode, m_toMode))
333
case PathSegMoveToRel:
334
case PathSegMoveToAbs:
335
if (!blendMoveToSegment())
338
case PathSegLineToRel:
339
case PathSegLineToAbs:
340
if (!blendLineToSegment())
343
case PathSegLineToHorizontalRel:
344
case PathSegLineToHorizontalAbs:
345
if (!blendLineToHorizontalSegment())
348
case PathSegLineToVerticalRel:
349
case PathSegLineToVerticalAbs:
350
if (!blendLineToVerticalSegment())
353
case PathSegClosePath:
354
m_consumer->closePath();
356
case PathSegCurveToCubicRel:
357
case PathSegCurveToCubicAbs:
358
if (!blendCurveToCubicSegment())
361
case PathSegCurveToCubicSmoothRel:
362
case PathSegCurveToCubicSmoothAbs:
363
if (!blendCurveToCubicSmoothSegment())
366
case PathSegCurveToQuadraticRel:
367
case PathSegCurveToQuadraticAbs:
368
if (!blendCurveToQuadraticSegment())
371
case PathSegCurveToQuadraticSmoothRel:
372
case PathSegCurveToQuadraticSmoothAbs:
373
if (!blendCurveToQuadraticSmoothSegment())
378
if (!blendArcToSegment())
385
if (!fromSourceHadData)
387
if (m_fromSource->hasMoreData() != m_toSource->hasMoreData())
389
if (!m_fromSource->hasMoreData() || !m_toSource->hasMoreData())
396
void SVGPathBlender::cleanup()
399
ASSERT(m_fromSource);
402
m_consumer->cleanup();
406
m_fromCurrentPoint = FloatPoint();
407
m_toCurrentPoint = FloatPoint();
412
#endif // ENABLE(SVG)