~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/svg/SVGPathBlender.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved.
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
 
 
22
#if ENABLE(SVG)
 
23
#include "SVGPathBlender.h"
 
24
 
 
25
#include "AnimationUtilities.h"
 
26
#include "SVGPathSeg.h"
 
27
#include <wtf/TemporaryChange.h>
 
28
 
 
29
namespace WebCore {
 
30
 
 
31
SVGPathBlender::SVGPathBlender()
 
32
    : m_fromSource(0)
 
33
    , m_toSource(0)
 
34
    , m_consumer(0)
 
35
    , m_progress(0)
 
36
    , m_addTypesCount(0)
 
37
    , m_isInFirstHalfOfAnimation(false)
 
38
{
 
39
}
 
40
 
 
41
// Helper functions
 
42
static inline FloatPoint blendFloatPoint(const FloatPoint& a, const FloatPoint& b, float progress)
 
43
{
 
44
    return FloatPoint(blend(a.x(), b.x(), progress), blend(a.y(), b.y(), progress));
 
45
}
 
46
 
 
47
float SVGPathBlender::blendAnimatedDimensonalFloat(float from, float to, FloatBlendMode blendMode)
 
48
{
 
49
    if (m_addTypesCount) {
 
50
        ASSERT(m_fromMode == m_toMode);
 
51
        return from + to * m_addTypesCount;
 
52
    }
 
53
 
 
54
    if (m_fromMode == m_toMode)
 
55
        return blend(from, to, m_progress);
 
56
    
 
57
    float fromValue = blendMode == BlendHorizontal ? m_fromCurrentPoint.x() : m_fromCurrentPoint.y();
 
58
    float toValue = blendMode == BlendHorizontal ? m_toCurrentPoint.x() : m_toCurrentPoint.y();
 
59
 
 
60
    // Transform toY to the coordinate mode of fromY
 
61
    float animValue = blend(from, m_fromMode == AbsoluteCoordinates ? to + toValue : to - toValue, m_progress);
 
62
    
 
63
    if (m_isInFirstHalfOfAnimation)
 
64
        return animValue;
 
65
    
 
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;
 
69
}
 
70
 
 
71
FloatPoint SVGPathBlender::blendAnimatedFloatPoint(const FloatPoint& fromPoint, const FloatPoint& toPoint)
 
72
{
 
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;
 
78
    }
 
79
 
 
80
    if (m_fromMode == m_toMode)
 
81
        return blendFloatPoint(fromPoint, toPoint, m_progress);
 
82
 
 
83
    // Transform toPoint to the coordinate mode of fromPoint
 
84
    FloatPoint animatedPoint = toPoint;
 
85
    if (m_fromMode == AbsoluteCoordinates)
 
86
        animatedPoint += m_toCurrentPoint;
 
87
    else
 
88
        animatedPoint.move(-m_toCurrentPoint.x(), -m_toCurrentPoint.y());
 
89
 
 
90
    animatedPoint = blendFloatPoint(fromPoint, animatedPoint, m_progress);
 
91
 
 
92
    if (m_isInFirstHalfOfAnimation)
 
93
        return animatedPoint;
 
94
 
 
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;
 
99
 
 
100
    animatedPoint.move(-currentPoint.x(), -currentPoint.y());
 
101
    return animatedPoint;
 
102
}
 
103
 
 
104
bool SVGPathBlender::blendMoveToSegment()
 
105
{
 
106
    FloatPoint fromTargetPoint;
 
107
    FloatPoint toTargetPoint;
 
108
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseMoveToSegment(fromTargetPoint))
 
109
        || !m_toSource->parseMoveToSegment(toTargetPoint))
 
110
        return false;
 
111
 
 
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;
 
115
    return true;
 
116
}
 
117
 
 
118
bool SVGPathBlender::blendLineToSegment()
 
119
{
 
120
    FloatPoint fromTargetPoint;
 
121
    FloatPoint toTargetPoint;
 
122
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseLineToSegment(fromTargetPoint))
 
123
        || !m_toSource->parseLineToSegment(toTargetPoint))
 
124
        return false;
 
125
 
 
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;
 
129
    return true;
 
130
}
 
131
 
 
132
bool SVGPathBlender::blendLineToHorizontalSegment()
 
133
{
 
134
    float fromX = 0;
 
135
    float toX = 0;
 
136
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseLineToHorizontalSegment(fromX))
 
137
        || !m_toSource->parseLineToHorizontalSegment(toX))
 
138
        return false;
 
139
 
 
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);
 
143
    return true;
 
144
}
 
145
 
 
146
bool SVGPathBlender::blendLineToVerticalSegment()
 
147
{
 
148
    float fromY = 0;
 
149
    float toY = 0;
 
150
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseLineToVerticalSegment(fromY))
 
151
        || !m_toSource->parseLineToVerticalSegment(toY))
 
152
        return false;
 
153
 
 
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);
 
157
    return true;
 
158
}
 
159
 
 
160
bool SVGPathBlender::blendCurveToCubicSegment()
 
161
{
 
162
    FloatPoint fromTargetPoint;
 
163
    FloatPoint fromPoint1;
 
164
    FloatPoint fromPoint2;
 
165
    FloatPoint toTargetPoint;
 
166
    FloatPoint toPoint1;
 
167
    FloatPoint toPoint2;
 
168
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToCubicSegment(fromPoint1, fromPoint2, fromTargetPoint))
 
169
        || !m_toSource->parseCurveToCubicSegment(toPoint1, toPoint2, toTargetPoint))
 
170
        return false;
 
171
 
 
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;
 
178
    return true;
 
179
}
 
180
 
 
181
bool SVGPathBlender::blendCurveToCubicSmoothSegment()
 
182
{
 
183
    FloatPoint fromTargetPoint;
 
184
    FloatPoint fromPoint2;
 
185
    FloatPoint toTargetPoint;
 
186
    FloatPoint toPoint2;
 
187
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToCubicSmoothSegment(fromPoint2, fromTargetPoint))
 
188
        || !m_toSource->parseCurveToCubicSmoothSegment(toPoint2, toTargetPoint))
 
189
        return false;
 
190
 
 
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;
 
196
    return true;
 
197
}
 
198
 
 
199
bool SVGPathBlender::blendCurveToQuadraticSegment()
 
200
{
 
201
    FloatPoint fromTargetPoint;
 
202
    FloatPoint fromPoint1;
 
203
    FloatPoint toTargetPoint;
 
204
    FloatPoint toPoint1;
 
205
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToQuadraticSegment(fromPoint1, fromTargetPoint))
 
206
        || !m_toSource->parseCurveToQuadraticSegment(toPoint1, toTargetPoint))
 
207
        return false;
 
208
 
 
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;
 
214
    return true;
 
215
}
 
216
 
 
217
bool SVGPathBlender::blendCurveToQuadraticSmoothSegment()
 
218
{
 
219
    FloatPoint fromTargetPoint;
 
220
    FloatPoint toTargetPoint;
 
221
    if ((m_fromSource->hasMoreData() && !m_fromSource->parseCurveToQuadraticSmoothSegment(fromTargetPoint))
 
222
        || !m_toSource->parseCurveToQuadraticSmoothSegment(toTargetPoint))
 
223
        return false;
 
224
 
 
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;
 
228
    return true;
 
229
}
 
230
 
 
231
bool SVGPathBlender::blendArcToSegment()
 
232
{
 
233
    float fromRx = 0;
 
234
    float fromRy = 0;
 
235
    float fromAngle = 0;
 
236
    bool fromLargeArc = false;
 
237
    bool fromSweep = false;
 
238
    FloatPoint fromTargetPoint;
 
239
    float toRx = 0;
 
240
    float toRy = 0;
 
241
    float toAngle = 0;
 
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))
 
247
        return false;
 
248
 
 
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,
 
259
                          m_fromMode);
 
260
    } else {
 
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);
 
268
    }
 
269
    m_fromCurrentPoint = m_fromMode == AbsoluteCoordinates ? fromTargetPoint : m_fromCurrentPoint + fromTargetPoint;
 
270
    m_toCurrentPoint = m_toMode == AbsoluteCoordinates ? toTargetPoint : m_toCurrentPoint + toTargetPoint;
 
271
    return true;
 
272
}
 
273
 
 
274
static inline PathCoordinateMode coordinateModeOfCommand(const SVGPathSegType& type)
 
275
{
 
276
    if (type < PathSegMoveToAbs)
 
277
        return AbsoluteCoordinates;
 
278
 
 
279
    // Odd number = relative command
 
280
    if (type % 2)
 
281
        return RelativeCoordinates;
 
282
 
 
283
    return AbsoluteCoordinates;
 
284
}
 
285
 
 
286
static inline bool isSegmentEqual(const SVGPathSegType& fromType, const SVGPathSegType& toType, const PathCoordinateMode& fromMode, const PathCoordinateMode& toMode)
 
287
{
 
288
    if (fromType == toType && (fromType == PathSegUnknown || fromType == PathSegClosePath))
 
289
        return true;
 
290
 
 
291
    unsigned short from = fromType;
 
292
    unsigned short to = toType;
 
293
    if (fromMode == toMode)
 
294
        return from == to;
 
295
    if (fromMode == AbsoluteCoordinates)
 
296
        return from == to - 1;
 
297
    return to == from - 1;
 
298
}
 
299
 
 
300
bool SVGPathBlender::addAnimatedPath(SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer, unsigned repeatCount)
 
301
{
 
302
    TemporaryChange<unsigned> change(m_addTypesCount, repeatCount);
 
303
    return blendAnimatedPath(0, fromSource, toSource, consumer);
 
304
}
 
305
 
 
306
bool SVGPathBlender::blendAnimatedPath(float progress, SVGPathSource* fromSource, SVGPathSource* toSource, SVGPathConsumer* consumer)
 
307
{
 
308
    ASSERT(fromSource);
 
309
    ASSERT(toSource);
 
310
    ASSERT(consumer);
 
311
    m_fromSource = fromSource;
 
312
    m_toSource = toSource;
 
313
    m_consumer = consumer;
 
314
    m_isInFirstHalfOfAnimation = progress < 0.5f;
 
315
    m_progress = progress;
 
316
 
 
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))
 
322
            return false;
 
323
 
 
324
        m_toMode = coordinateModeOfCommand(toCommand);
 
325
        m_fromMode = fromSourceHadData ? coordinateModeOfCommand(fromCommand) : m_toMode;
 
326
        if (m_fromMode != m_toMode && m_addTypesCount)
 
327
            return false;
 
328
 
 
329
        if (fromSourceHadData && !isSegmentEqual(fromCommand, toCommand, m_fromMode, m_toMode))
 
330
            return false;
 
331
 
 
332
        switch (toCommand) {
 
333
        case PathSegMoveToRel:
 
334
        case PathSegMoveToAbs:
 
335
            if (!blendMoveToSegment())
 
336
                return false;
 
337
            break;
 
338
        case PathSegLineToRel:
 
339
        case PathSegLineToAbs:
 
340
            if (!blendLineToSegment())
 
341
                return false;
 
342
            break;
 
343
        case PathSegLineToHorizontalRel:
 
344
        case PathSegLineToHorizontalAbs:
 
345
            if (!blendLineToHorizontalSegment())
 
346
                return false;
 
347
            break;
 
348
        case PathSegLineToVerticalRel:
 
349
        case PathSegLineToVerticalAbs:
 
350
            if (!blendLineToVerticalSegment())
 
351
                return false;
 
352
            break;
 
353
        case PathSegClosePath:
 
354
            m_consumer->closePath();
 
355
            break;
 
356
        case PathSegCurveToCubicRel:
 
357
        case PathSegCurveToCubicAbs:
 
358
            if (!blendCurveToCubicSegment())
 
359
                return false;
 
360
            break;
 
361
        case PathSegCurveToCubicSmoothRel:
 
362
        case PathSegCurveToCubicSmoothAbs:
 
363
            if (!blendCurveToCubicSmoothSegment())
 
364
                return false;
 
365
            break;
 
366
        case PathSegCurveToQuadraticRel:
 
367
        case PathSegCurveToQuadraticAbs:
 
368
            if (!blendCurveToQuadraticSegment())
 
369
                return false;
 
370
            break;
 
371
        case PathSegCurveToQuadraticSmoothRel:
 
372
        case PathSegCurveToQuadraticSmoothAbs:
 
373
            if (!blendCurveToQuadraticSmoothSegment())
 
374
                return false;
 
375
            break;
 
376
        case PathSegArcRel:
 
377
        case PathSegArcAbs:
 
378
            if (!blendArcToSegment())
 
379
                return false;
 
380
            break;
 
381
        case PathSegUnknown:
 
382
            return false;
 
383
        }
 
384
 
 
385
        if (!fromSourceHadData)
 
386
            continue;
 
387
        if (m_fromSource->hasMoreData() != m_toSource->hasMoreData())
 
388
            return false;
 
389
        if (!m_fromSource->hasMoreData() || !m_toSource->hasMoreData())
 
390
            return true;
 
391
    }
 
392
 
 
393
    return true;
 
394
}
 
395
 
 
396
void SVGPathBlender::cleanup()
 
397
{
 
398
    ASSERT(m_toSource);
 
399
    ASSERT(m_fromSource);
 
400
    ASSERT(m_consumer);
 
401
 
 
402
    m_consumer->cleanup();
 
403
    m_toSource = 0;
 
404
    m_fromSource = 0;
 
405
    m_consumer = 0;
 
406
    m_fromCurrentPoint = FloatPoint();
 
407
    m_toCurrentPoint = FloatPoint();
 
408
}
 
409
 
 
410
}
 
411
 
 
412
#endif // ENABLE(SVG)