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

« back to all changes in this revision

Viewing changes to Source/WebCore/page/animation/CSSPropertyAnimation.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) 2007, 2008, 2009 Apple Inc. All rights reserved.
 
3
 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * 1.  Redistributions of source code must retain the above copyright
 
10
 *     notice, this list of conditions and the following disclaimer. 
 
11
 * 2.  Redistributions in binary form must reproduce the above copyright
 
12
 *     notice, this list of conditions and the following disclaimer in the
 
13
 *     documentation and/or other materials provided with the distribution. 
 
14
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 
15
 *     its contributors may be used to endorse or promote products derived
 
16
 *     from this software without specific prior written permission. 
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
21
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
28
 */
 
29
 
 
30
#include "config.h"
 
31
#include "CSSPropertyAnimation.h"
 
32
 
 
33
#include "AnimationBase.h"
 
34
#include "CSSCrossfadeValue.h"
 
35
#include "CSSImageGeneratorValue.h"
 
36
#include "CSSImageValue.h"
 
37
#include "CSSPrimitiveValue.h"
 
38
#include "CSSPropertyNames.h"
 
39
#include "ClipPathOperation.h"
 
40
#include "FloatConversion.h"
 
41
#include "IdentityTransformOperation.h"
 
42
#include "Matrix3DTransformOperation.h"
 
43
#include "MatrixTransformOperation.h"
 
44
#include "RenderBox.h"
 
45
#include "RenderStyle.h"
 
46
#include "StyleCachedImage.h"
 
47
#include "StyleGeneratedImage.h"
 
48
#include "StylePropertyShorthand.h"
 
49
#include "StyleResolver.h"
 
50
#include <algorithm>
 
51
#include <wtf/Noncopyable.h>
 
52
#include <wtf/RefCounted.h>
 
53
 
 
54
namespace WebCore {
 
55
 
 
56
static inline int blendFunc(const AnimationBase*, int from, int to, double progress)
 
57
{
 
58
    return blend(from, to, progress);
 
59
}
 
60
 
 
61
static inline unsigned blendFunc(const AnimationBase*, unsigned from, unsigned to, double progress)
 
62
{
 
63
    return blend(from, to, progress);
 
64
}
 
65
 
 
66
static inline double blendFunc(const AnimationBase*, double from, double to, double progress)
 
67
{
 
68
    return blend(from, to, progress);
 
69
}
 
70
 
 
71
static inline float blendFunc(const AnimationBase*, float from, float to, double progress)
 
72
{
 
73
    return narrowPrecisionToFloat(from + (to - from) * progress);
 
74
}
 
75
 
 
76
static inline Color blendFunc(const AnimationBase*, const Color& from, const Color& to, double progress)
 
77
{
 
78
    return blend(from, to, progress);
 
79
}
 
80
 
 
81
static inline Length blendFunc(const AnimationBase*, const Length& from, const Length& to, double progress)
 
82
{
 
83
    return to.blend(from, narrowPrecisionToFloat(progress));
 
84
}
 
85
 
 
86
static inline LengthSize blendFunc(const AnimationBase* anim, const LengthSize& from, const LengthSize& to, double progress)
 
87
{
 
88
    return LengthSize(blendFunc(anim, from.width(), to.width(), progress),
 
89
                      blendFunc(anim, from.height(), to.height(), progress));
 
90
}
 
91
 
 
92
static inline IntSize blendFunc(const AnimationBase* anim, const IntSize& from, const IntSize& to, double progress)
 
93
{
 
94
    return IntSize(blendFunc(anim, from.width(), to.width(), progress),
 
95
                   blendFunc(anim, from.height(), to.height(), progress));
 
96
}
 
97
 
 
98
static inline ShadowStyle blendFunc(const AnimationBase* anim, ShadowStyle from, ShadowStyle to, double progress)
 
99
{
 
100
    if (from == to)
 
101
        return to;
 
102
 
 
103
    double fromVal = from == Normal ? 1 : 0;
 
104
    double toVal = to == Normal ? 1 : 0;
 
105
    double result = blendFunc(anim, fromVal, toVal, progress);
 
106
    return result > 0 ? Normal : Inset;
 
107
}
 
108
 
 
109
static inline PassOwnPtr<ShadowData> blendFunc(const AnimationBase* anim, const ShadowData* from, const ShadowData* to, double progress)
 
110
{
 
111
    ASSERT(from && to);
 
112
    if (from->style() != to->style())
 
113
        return adoptPtr(new ShadowData(*to));
 
114
 
 
115
    return adoptPtr(new ShadowData(blend(from->location(), to->location(), progress),
 
116
                                   blend(from->blur(), to->blur(), progress),
 
117
                                   blend(from->spread(), to->spread(), progress),
 
118
                                   blendFunc(anim, from->style(), to->style(), progress),
 
119
                                   from->isWebkitBoxShadow(),
 
120
                                   blend(from->color(), to->color(), progress)));
 
121
}
 
122
 
 
123
static inline TransformOperations blendFunc(const AnimationBase* anim, const TransformOperations& from, const TransformOperations& to, double progress)
 
124
{
 
125
    if (anim->isTransformFunctionListValid())
 
126
        return to.blendByMatchingOperations(from, progress);
 
127
    return to.blendByUsingMatrixInterpolation(from, progress, anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize());
 
128
}
 
129
 
 
130
static inline PassRefPtr<ClipPathOperation> blendFunc(const AnimationBase*, ClipPathOperation* from, ClipPathOperation* to, double progress)
 
131
{
 
132
    // Other clip-path operations than BasicShapes can not be animated.
 
133
    if (from->getOperationType() != ClipPathOperation::SHAPE || to->getOperationType() != ClipPathOperation::SHAPE)
 
134
        return to;
 
135
 
 
136
    const BasicShape* fromShape = static_cast<ShapeClipPathOperation*>(from)->basicShape();
 
137
    const BasicShape* toShape = static_cast<ShapeClipPathOperation*>(to)->basicShape();
 
138
 
 
139
    if (!fromShape->canBlend(toShape))
 
140
        return to;
 
141
 
 
142
    return ShapeClipPathOperation::create(toShape->blend(fromShape, progress));
 
143
}
 
144
 
 
145
#if ENABLE(CSS_EXCLUSIONS)
 
146
static inline PassRefPtr<ExclusionShapeValue> blendFunc(const AnimationBase*, ExclusionShapeValue* from, ExclusionShapeValue* to, double progress)
 
147
{
 
148
    // FIXME Bug 102723: Shape-inside should be able to animate a value of 'outside-shape' when shape-outside is set to a BasicShape
 
149
    if (from->type() != ExclusionShapeValue::SHAPE || to->type() != ExclusionShapeValue::SHAPE)
 
150
        return to;
 
151
 
 
152
    const BasicShape* fromShape = from->shape();
 
153
    const BasicShape* toShape = to->shape();
 
154
 
 
155
    if (!fromShape->canBlend(toShape))
 
156
        return to;
 
157
 
 
158
    return ExclusionShapeValue::createShapeValue(toShape->blend(fromShape, progress));
 
159
}
 
160
#endif
 
161
 
 
162
#if ENABLE(CSS_FILTERS)
 
163
static inline PassRefPtr<FilterOperation> blendFunc(const AnimationBase* anim, FilterOperation* fromOp, FilterOperation* toOp, double progress, bool blendToPassthrough = false)
 
164
{
 
165
    ASSERT(toOp);
 
166
    if (toOp->blendingNeedsRendererSize()) {
 
167
        LayoutSize size = anim->renderer()->isBox() ? toRenderBox(anim->renderer())->borderBoxRect().size() : LayoutSize();
 
168
        return toOp->blend(fromOp, progress, size, blendToPassthrough);
 
169
    }
 
170
    return toOp->blend(fromOp, progress, blendToPassthrough);
 
171
}
 
172
 
 
173
static inline FilterOperations blendFunc(const AnimationBase* anim, const FilterOperations& from, const FilterOperations& to, double progress)
 
174
{
 
175
    FilterOperations result;
 
176
 
 
177
    // If we have a filter function list, use that to do a per-function animation.
 
178
    if (anim->filterFunctionListsMatch()) {
 
179
        size_t fromSize = from.operations().size();
 
180
        size_t toSize = to.operations().size();
 
181
        size_t size = max(fromSize, toSize);
 
182
        for (size_t i = 0; i < size; i++) {
 
183
            RefPtr<FilterOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : 0;
 
184
            RefPtr<FilterOperation> toOp = (i < toSize) ? to.operations()[i].get() : 0;
 
185
            RefPtr<FilterOperation> blendedOp = toOp ? blendFunc(anim, fromOp.get(), toOp.get(), progress) : (fromOp ? blendFunc(anim, 0, fromOp.get(), progress, true) : 0);
 
186
            if (blendedOp)
 
187
                result.operations().append(blendedOp);
 
188
            else {
 
189
                RefPtr<FilterOperation> identityOp = PassthroughFilterOperation::create();
 
190
                if (progress > 0.5)
 
191
                    result.operations().append(toOp ? toOp : identityOp);
 
192
                else
 
193
                    result.operations().append(fromOp ? fromOp : identityOp);
 
194
            }
 
195
        }
 
196
    } else {
 
197
        // If the filter function lists don't match, we could try to cross-fade, but don't yet have a way to represent that in CSS.
 
198
        // For now we'll just fail to animate.
 
199
        result = to;
 
200
    }
 
201
 
 
202
    return result;
 
203
}
 
204
#endif // ENABLE(CSS_FILTERS)
 
205
 
 
206
static inline EVisibility blendFunc(const AnimationBase* anim, EVisibility from, EVisibility to, double progress)
 
207
{
 
208
    // Any non-zero result means we consider the object to be visible. Only at 0 do we consider the object to be
 
209
    // invisible. The invisible value we use (HIDDEN vs. COLLAPSE) depends on the specified from/to values.
 
210
    double fromVal = from == VISIBLE ? 1. : 0.;
 
211
    double toVal = to == VISIBLE ? 1. : 0.;
 
212
    if (fromVal == toVal)
 
213
        return to;
 
214
    double result = blendFunc(anim, fromVal, toVal, progress);
 
215
    return result > 0. ? VISIBLE : (to != VISIBLE ? to : from);
 
216
}
 
217
 
 
218
static inline LengthBox blendFunc(const AnimationBase* anim, const LengthBox& from, const LengthBox& to, double progress)
 
219
{
 
220
    // Length types have to match to animate
 
221
    if (from.top().type() != to.top().type()
 
222
        || from.right().type() != to.right().type()
 
223
        || from.bottom().type() != to.bottom().type()
 
224
        || from.left().type() != to.left().type())
 
225
        return to;
 
226
 
 
227
    LengthBox result(blendFunc(anim, from.top(), to.top(), progress),
 
228
                     blendFunc(anim, from.right(), to.right(), progress),
 
229
                     blendFunc(anim, from.bottom(), to.bottom(), progress),
 
230
                     blendFunc(anim, from.left(), to.left(), progress));
 
231
    return result;
 
232
}
 
233
 
 
234
#if ENABLE(SVG)
 
235
static inline SVGLength blendFunc(const AnimationBase*, const SVGLength& from, const SVGLength& to, double progress)
 
236
{
 
237
    return to.blend(from, narrowPrecisionToFloat(progress));
 
238
}
 
239
#endif
 
240
 
 
241
static inline PassRefPtr<StyleImage> crossfadeBlend(const AnimationBase*, StyleCachedImage* fromStyleImage, StyleCachedImage* toStyleImage, double progress)
 
242
{
 
243
    // If progress is at one of the extremes, we want getComputedStyle to show the image,
 
244
    // not a completed cross-fade, so we hand back one of the existing images.
 
245
    if (!progress)
 
246
        return fromStyleImage;
 
247
    if (progress == 1)
 
248
        return toStyleImage;
 
249
 
 
250
    CachedImage* fromCachedImage = static_cast<CachedImage*>(fromStyleImage->data());
 
251
    CachedImage* toCachedImage = static_cast<CachedImage*>(toStyleImage->data());
 
252
 
 
253
    RefPtr<CSSImageValue> fromImageValue = CSSImageValue::create(fromCachedImage->url(), fromStyleImage);
 
254
    RefPtr<CSSImageValue> toImageValue = CSSImageValue::create(toCachedImage->url(), toStyleImage);
 
255
    RefPtr<CSSCrossfadeValue> crossfadeValue = CSSCrossfadeValue::create(fromImageValue, toImageValue);
 
256
 
 
257
    crossfadeValue->setPercentage(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER));
 
258
 
 
259
    return StyleGeneratedImage::create(crossfadeValue.get());
 
260
}
 
261
 
 
262
static inline PassRefPtr<StyleImage> blendFunc(const AnimationBase* anim, StyleImage* from, StyleImage* to, double progress)
 
263
{
 
264
    if (!from || !to)
 
265
        return to;
 
266
 
 
267
    if (from->isCachedImage() && to->isCachedImage())
 
268
        return crossfadeBlend(anim, static_cast<StyleCachedImage*>(from), static_cast<StyleCachedImage*>(to), progress);
 
269
 
 
270
    // FIXME: Support transitioning generated images as well. (gradients, etc.)
 
271
 
 
272
    return to;
 
273
}
 
274
 
 
275
static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePieceImage& from, const NinePieceImage& to, double progress)
 
276
{
 
277
    if (!from.hasImage() || !to.hasImage())
 
278
        return to;
 
279
 
 
280
    // FIXME (74112): Support transitioning between NinePieceImages that differ by more than image content.
 
281
 
 
282
    if (from.imageSlices() != to.imageSlices() || from.borderSlices() != to.borderSlices() || from.outset() != to.outset() || from.fill() != to.fill() || from.horizontalRule() != to.horizontalRule() || from.verticalRule() != to.verticalRule())
 
283
        return to;
 
284
 
 
285
    if (from.image()->imageSize(anim->renderer(), 1.0) != to.image()->imageSize(anim->renderer(), 1.0))
 
286
        return to;
 
287
 
 
288
    RefPtr<StyleImage> newContentImage = blendFunc(anim, from.image(), to.image(), progress);
 
289
 
 
290
    return NinePieceImage(newContentImage, from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
 
291
}
 
292
 
 
293
class AnimationPropertyWrapperBase {
 
294
    WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase);
 
295
    WTF_MAKE_FAST_ALLOCATED;
 
296
public:
 
297
    AnimationPropertyWrapperBase(CSSPropertyID prop)
 
298
        : m_prop(prop)
 
299
    {
 
300
    }
 
301
 
 
302
    virtual ~AnimationPropertyWrapperBase() { }
 
303
 
 
304
    virtual bool isShorthandWrapper() const { return false; }
 
305
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const = 0;
 
306
    virtual void blend(const AnimationBase*, RenderStyle*, const RenderStyle*, const RenderStyle*, double) const = 0;
 
307
 
 
308
    CSSPropertyID property() const { return m_prop; }
 
309
 
 
310
#if USE(ACCELERATED_COMPOSITING)
 
311
    virtual bool animationIsAccelerated() const { return false; }
 
312
#endif
 
313
 
 
314
private:
 
315
    CSSPropertyID m_prop;
 
316
};
 
317
 
 
318
static int gPropertyWrapperMap[numCSSProperties];
 
319
static const int cInvalidPropertyWrapperIndex = -1;
 
320
static Vector<AnimationPropertyWrapperBase*>* gPropertyWrappers = 0;
 
321
 
 
322
static void addPropertyWrapper(CSSPropertyID propertyID, AnimationPropertyWrapperBase* wrapper)
 
323
{
 
324
    int propIndex = propertyID - firstCSSProperty;
 
325
 
 
326
    ASSERT(gPropertyWrapperMap[propIndex] == cInvalidPropertyWrapperIndex);
 
327
 
 
328
    unsigned wrapperIndex = gPropertyWrappers->size();
 
329
    gPropertyWrappers->append(wrapper);
 
330
    gPropertyWrapperMap[propIndex] = wrapperIndex;
 
331
}
 
332
 
 
333
static AnimationPropertyWrapperBase* wrapperForProperty(CSSPropertyID propertyID)
 
334
{
 
335
    int propIndex = propertyID - firstCSSProperty;
 
336
    if (propIndex >= 0 && propIndex < numCSSProperties) {
 
337
        int wrapperIndex = gPropertyWrapperMap[propIndex];
 
338
        if (wrapperIndex >= 0)
 
339
            return (*gPropertyWrappers)[wrapperIndex];
 
340
    }
 
341
    return 0;
 
342
}
 
343
 
 
344
template <typename T>
 
345
class PropertyWrapperGetter : public AnimationPropertyWrapperBase {
 
346
public:
 
347
    PropertyWrapperGetter(CSSPropertyID prop, T (RenderStyle::*getter)() const)
 
348
        : AnimationPropertyWrapperBase(prop)
 
349
        , m_getter(getter)
 
350
    {
 
351
    }
 
352
 
 
353
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
354
    {
 
355
        // If the style pointers are the same, don't bother doing the test.
 
356
        // If either is null, return false. If both are null, return true.
 
357
        if ((!a && !b) || a == b)
 
358
            return true;
 
359
        if (!a || !b)
 
360
            return false;
 
361
        return (a->*m_getter)() == (b->*m_getter)();
 
362
    }
 
363
 
 
364
protected:
 
365
    T (RenderStyle::*m_getter)() const;
 
366
};
 
367
 
 
368
template <typename T>
 
369
class PropertyWrapper : public PropertyWrapperGetter<T> {
 
370
public:
 
371
    PropertyWrapper(CSSPropertyID prop, T (RenderStyle::*getter)() const, void (RenderStyle::*setter)(T))
 
372
        : PropertyWrapperGetter<T>(prop, getter)
 
373
        , m_setter(setter)
 
374
    {
 
375
    }
 
376
 
 
377
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
378
    {
 
379
        (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T>::m_getter)(), (b->*PropertyWrapperGetter<T>::m_getter)(), progress));
 
380
    }
 
381
 
 
382
protected:
 
383
    void (RenderStyle::*m_setter)(T);
 
384
};
 
385
 
 
386
template <typename T>
 
387
class RefCountedPropertyWrapper : public PropertyWrapperGetter<T*> {
 
388
public:
 
389
    RefCountedPropertyWrapper(CSSPropertyID prop, T* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<T>))
 
390
        : PropertyWrapperGetter<T*>(prop, getter)
 
391
        , m_setter(setter)
 
392
    {
 
393
    }
 
394
 
 
395
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
396
    {
 
397
        (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<T*>::m_getter)(), (b->*PropertyWrapperGetter<T*>::m_getter)(), progress));
 
398
    }
 
399
 
 
400
protected:
 
401
    void (RenderStyle::*m_setter)(PassRefPtr<T>);
 
402
};
 
403
 
 
404
 
 
405
class PropertyWrapperClipPath : public RefCountedPropertyWrapper<ClipPathOperation> {
 
406
public:
 
407
    PropertyWrapperClipPath(CSSPropertyID prop, ClipPathOperation* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ClipPathOperation>))
 
408
        : RefCountedPropertyWrapper<ClipPathOperation>(prop, getter, setter)
 
409
    {
 
410
    }
 
411
};
 
412
 
 
413
#if ENABLE(CSS_EXCLUSIONS)
 
414
class PropertyWrapperExclusionShape : public RefCountedPropertyWrapper<ExclusionShapeValue> {
 
415
public:
 
416
    PropertyWrapperExclusionShape(CSSPropertyID prop, ExclusionShapeValue* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<ExclusionShapeValue>))
 
417
        : RefCountedPropertyWrapper<ExclusionShapeValue>(prop, getter, setter)
 
418
    {
 
419
    }
 
420
};
 
421
#endif
 
422
 
 
423
class StyleImagePropertyWrapper : public RefCountedPropertyWrapper<StyleImage> {
 
424
public:
 
425
    StyleImagePropertyWrapper(CSSPropertyID prop, StyleImage* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassRefPtr<StyleImage>))
 
426
        : RefCountedPropertyWrapper<StyleImage>(prop, getter, setter)
 
427
    {
 
428
    }
 
429
 
 
430
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
431
    {
 
432
       // If the style pointers are the same, don't bother doing the test.
 
433
       // If either is null, return false. If both are null, return true.
 
434
       if (a == b)
 
435
           return true;
 
436
       if (!a || !b)
 
437
            return false;
 
438
 
 
439
        StyleImage* imageA = (a->*m_getter)();
 
440
        StyleImage* imageB = (b->*m_getter)();
 
441
        return StyleImage::imagesEquivalent(imageA, imageB);
 
442
    }
 
443
};
 
444
 
 
445
class PropertyWrapperColor : public PropertyWrapperGetter<Color> {
 
446
public:
 
447
    PropertyWrapperColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
 
448
        : PropertyWrapperGetter<Color>(prop, getter)
 
449
        , m_setter(setter)
 
450
    {
 
451
    }
 
452
 
 
453
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
454
    {
 
455
        (dst->*m_setter)(blendFunc(anim, (a->*PropertyWrapperGetter<Color>::m_getter)(), (b->*PropertyWrapperGetter<Color>::m_getter)(), progress));
 
456
    }
 
457
 
 
458
protected:
 
459
    void (RenderStyle::*m_setter)(const Color&);
 
460
};
 
461
 
 
462
#if USE(ACCELERATED_COMPOSITING)
 
463
class PropertyWrapperAcceleratedOpacity : public PropertyWrapper<float> {
 
464
public:
 
465
    PropertyWrapperAcceleratedOpacity()
 
466
        : PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity)
 
467
    {
 
468
    }
 
469
 
 
470
    virtual bool animationIsAccelerated() const { return true; }
 
471
 
 
472
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
473
    {
 
474
        float fromOpacity = a->opacity();
 
475
 
 
476
        // This makes sure we put the object being animated into a RenderLayer during the animation
 
477
        dst->setOpacity(blendFunc(anim, (fromOpacity == 1) ? 0.999999f : fromOpacity, b->opacity(), progress));
 
478
    }
 
479
};
 
480
 
 
481
class PropertyWrapperAcceleratedTransform : public PropertyWrapper<const TransformOperations&> {
 
482
public:
 
483
    PropertyWrapperAcceleratedTransform()
 
484
        : PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform)
 
485
    {
 
486
    }
 
487
 
 
488
    virtual bool animationIsAccelerated() const { return true; }
 
489
 
 
490
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
491
    {
 
492
        dst->setTransform(blendFunc(anim, a->transform(), b->transform(), progress));
 
493
    }
 
494
};
 
495
 
 
496
#if ENABLE(CSS_FILTERS)
 
497
class PropertyWrapperAcceleratedFilter : public PropertyWrapper<const FilterOperations&> {
 
498
public:
 
499
    PropertyWrapperAcceleratedFilter()
 
500
        : PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter)
 
501
    {
 
502
    }
 
503
 
 
504
    virtual bool animationIsAccelerated() const { return true; }
 
505
 
 
506
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
507
    {
 
508
        dst->setFilter(blendFunc(anim, a->filter(), b->filter(), progress));
 
509
    }
 
510
};
 
511
#endif
 
512
#endif // USE(ACCELERATED_COMPOSITING)
 
513
 
 
514
static inline size_t shadowListLength(const ShadowData* shadow)
 
515
{
 
516
    size_t count;
 
517
    for (count = 0; shadow; shadow = shadow->next())
 
518
        ++count;
 
519
    return count;
 
520
}
 
521
 
 
522
static inline const ShadowData* shadowForBlending(const ShadowData* srcShadow, const ShadowData* otherShadow)
 
523
{
 
524
    DEFINE_STATIC_LOCAL(ShadowData, defaultShadowData, (IntPoint(), 0, 0, Normal, false, Color::transparent));
 
525
    DEFINE_STATIC_LOCAL(ShadowData, defaultInsetShadowData, (IntPoint(), 0, 0, Inset, false, Color::transparent));
 
526
 
 
527
    DEFINE_STATIC_LOCAL(ShadowData, defaultWebKitBoxShadowData, (IntPoint(), 0, 0, Normal, true, Color::transparent));
 
528
    DEFINE_STATIC_LOCAL(ShadowData, defaultInsetWebKitBoxShadowData, (IntPoint(), 0, 0, Inset, true, Color::transparent));
 
529
 
 
530
    if (srcShadow)
 
531
        return srcShadow;
 
532
 
 
533
    if (otherShadow->style() == Inset)
 
534
        return otherShadow->isWebkitBoxShadow() ? &defaultInsetWebKitBoxShadowData : &defaultInsetShadowData;
 
535
 
 
536
    return otherShadow->isWebkitBoxShadow() ? &defaultWebKitBoxShadowData : &defaultShadowData;
 
537
}
 
538
 
 
539
class PropertyWrapperShadow : public AnimationPropertyWrapperBase {
 
540
public:
 
541
    PropertyWrapperShadow(CSSPropertyID prop, const ShadowData* (RenderStyle::*getter)() const, void (RenderStyle::*setter)(PassOwnPtr<ShadowData>, bool))
 
542
        : AnimationPropertyWrapperBase(prop)
 
543
        , m_getter(getter)
 
544
        , m_setter(setter)
 
545
    {
 
546
    }
 
547
 
 
548
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
549
    {
 
550
        const ShadowData* shadowA = (a->*m_getter)();
 
551
        const ShadowData* shadowB = (b->*m_getter)();
 
552
 
 
553
        while (true) {
 
554
            // end of both lists
 
555
            if (!shadowA && !shadowB)
 
556
                return true;
 
557
 
 
558
            // end of just one of the lists
 
559
            if (!shadowA || !shadowB)
 
560
                return false;
 
561
 
 
562
            if (*shadowA != *shadowB)
 
563
                return false;
 
564
 
 
565
            shadowA = shadowA->next();
 
566
            shadowB = shadowB->next();
 
567
        }
 
568
 
 
569
        return true;
 
570
    }
 
571
 
 
572
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
573
    {
 
574
        const ShadowData* shadowA = (a->*m_getter)();
 
575
        const ShadowData* shadowB = (b->*m_getter)();
 
576
 
 
577
        int fromLength = shadowListLength(shadowA);
 
578
        int toLength = shadowListLength(shadowB);
 
579
 
 
580
        if (fromLength == toLength || (fromLength <= 1 && toLength <= 1)) {
 
581
            (dst->*m_setter)(blendSimpleOrMatchedShadowLists(anim, progress, shadowA, shadowB), false);
 
582
            return;
 
583
        }
 
584
 
 
585
        (dst->*m_setter)(blendMismatchedShadowLists(anim, progress, shadowA, shadowB, fromLength, toLength), false);
 
586
    }
 
587
 
 
588
private:
 
589
    PassOwnPtr<ShadowData*> blendSimpleOrMatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB) const
 
590
    {
 
591
        OwnPtr<ShadowData> newShadowData;
 
592
        ShadowData* lastShadow = 0;
 
593
 
 
594
        while (shadowA || shadowB) {
 
595
            const ShadowData* srcShadow = shadowForBlending(shadowA, shadowB);
 
596
            const ShadowData* dstShadow = shadowForBlending(shadowB, shadowA);
 
597
 
 
598
            OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
 
599
            ShadowData* blendedShadowPtr = blendedShadow.get();
 
600
 
 
601
            if (!lastShadow)
 
602
                newShadowData = blendedShadow.release();
 
603
            else
 
604
                lastShadow->setNext(blendedShadow.release());
 
605
 
 
606
            lastShadow = blendedShadowPtr;
 
607
 
 
608
            shadowA = shadowA ? shadowA->next() : 0;
 
609
            shadowB = shadowB ? shadowB->next() : 0;
 
610
        }
 
611
 
 
612
        return newShadowData.release();
 
613
    }
 
614
 
 
615
    PassOwnPtr<ShadowData*> blendMismatchedShadowLists(const AnimationBase* anim, double progress, const ShadowData* shadowA, const ShadowData* shadowB, int fromLength, int toLength) const
 
616
    {
 
617
        // The shadows in ShadowData are stored in reverse order, so when animating mismatched lists,
 
618
        // reverse them and match from the end.
 
619
        Vector<const ShadowData*, 4> fromShadows(fromLength);
 
620
        for (int i = fromLength - 1; i >= 0; --i) {
 
621
            fromShadows[i] = shadowA;
 
622
            shadowA = shadowA->next();
 
623
        }
 
624
 
 
625
        Vector<const ShadowData*, 4> toShadows(toLength);
 
626
        for (int i = toLength - 1; i >= 0; --i) {
 
627
            toShadows[i] = shadowB;
 
628
            shadowB = shadowB->next();
 
629
        }
 
630
 
 
631
        OwnPtr<ShadowData> newShadowData;
 
632
 
 
633
        int maxLength = max(fromLength, toLength);
 
634
        for (int i = 0; i < maxLength; ++i) {
 
635
            const ShadowData* fromShadow = i < fromLength ? fromShadows[i] : 0;
 
636
            const ShadowData* toShadow = i < toLength ? toShadows[i] : 0;
 
637
 
 
638
            const ShadowData* srcShadow = shadowForBlending(fromShadow, toShadow);
 
639
            const ShadowData* dstShadow = shadowForBlending(toShadow, fromShadow);
 
640
 
 
641
            OwnPtr<ShadowData> blendedShadow = blendFunc(anim, srcShadow, dstShadow, progress);
 
642
            // Insert at the start of the list to preserve the order.
 
643
            blendedShadow->setNext(newShadowData.release());
 
644
            newShadowData = blendedShadow.release();
 
645
        }
 
646
 
 
647
        return newShadowData.release();
 
648
    }
 
649
 
 
650
    const ShadowData* (RenderStyle::*m_getter)() const;
 
651
    void (RenderStyle::*m_setter)(PassOwnPtr<ShadowData>, bool);
 
652
};
 
653
 
 
654
class PropertyWrapperMaybeInvalidColor : public AnimationPropertyWrapperBase {
 
655
public:
 
656
    PropertyWrapperMaybeInvalidColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
 
657
        : AnimationPropertyWrapperBase(prop)
 
658
        , m_getter(getter)
 
659
        , m_setter(setter)
 
660
    {
 
661
    }
 
662
 
 
663
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
664
    {
 
665
        Color fromColor = (a->*m_getter)();
 
666
        Color toColor = (b->*m_getter)();
 
667
 
 
668
        if (!fromColor.isValid() && !toColor.isValid())
 
669
            return true;
 
670
 
 
671
        if (!fromColor.isValid())
 
672
            fromColor = a->color();
 
673
        if (!toColor.isValid())
 
674
            toColor = b->color();
 
675
 
 
676
        return fromColor == toColor;
 
677
    }
 
678
 
 
679
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
680
    {
 
681
        Color fromColor = (a->*m_getter)();
 
682
        Color toColor = (b->*m_getter)();
 
683
 
 
684
        if (!fromColor.isValid() && !toColor.isValid())
 
685
            return;
 
686
 
 
687
        if (!fromColor.isValid())
 
688
            fromColor = a->color();
 
689
        if (!toColor.isValid())
 
690
            toColor = b->color();
 
691
        (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
 
692
    }
 
693
 
 
694
private:
 
695
    Color (RenderStyle::*m_getter)() const;
 
696
    void (RenderStyle::*m_setter)(const Color&);
 
697
};
 
698
 
 
699
 
 
700
enum MaybeInvalidColorTag { MaybeInvalidColor };
 
701
class PropertyWrapperVisitedAffectedColor : public AnimationPropertyWrapperBase {
 
702
public:
 
703
    PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
 
704
                                        Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
 
705
        : AnimationPropertyWrapperBase(prop)
 
706
        , m_wrapper(adoptPtr(new PropertyWrapperColor(prop, getter, setter)))
 
707
        , m_visitedWrapper(adoptPtr(new PropertyWrapperColor(prop, visitedGetter, visitedSetter)))
 
708
    {
 
709
    }
 
710
    PropertyWrapperVisitedAffectedColor(CSSPropertyID prop, MaybeInvalidColorTag, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&),
 
711
                                        Color (RenderStyle::*visitedGetter)() const, void (RenderStyle::*visitedSetter)(const Color&))
 
712
        : AnimationPropertyWrapperBase(prop)
 
713
        , m_wrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, getter, setter)))
 
714
        , m_visitedWrapper(adoptPtr(new PropertyWrapperMaybeInvalidColor(prop, visitedGetter, visitedSetter)))
 
715
    {
 
716
    }
 
717
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
718
    {
 
719
        return m_wrapper->equals(a, b) && m_visitedWrapper->equals(a, b);
 
720
    }
 
721
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
722
    {
 
723
        m_wrapper->blend(anim, dst, a, b, progress);
 
724
        m_visitedWrapper->blend(anim, dst, a, b, progress);
 
725
    }
 
726
 
 
727
private:
 
728
    OwnPtr<AnimationPropertyWrapperBase> m_wrapper;
 
729
    OwnPtr<AnimationPropertyWrapperBase> m_visitedWrapper;
 
730
};
 
731
 
 
732
// Wrapper base class for an animatable property in a FillLayer
 
733
class FillLayerAnimationPropertyWrapperBase {
 
734
public:
 
735
    FillLayerAnimationPropertyWrapperBase()
 
736
    {
 
737
    }
 
738
 
 
739
    virtual ~FillLayerAnimationPropertyWrapperBase() { }
 
740
 
 
741
    virtual bool equals(const FillLayer*, const FillLayer*) const = 0;
 
742
    virtual void blend(const AnimationBase*, FillLayer*, const FillLayer*, const FillLayer*, double) const = 0;
 
743
};
 
744
 
 
745
template <typename T>
 
746
class FillLayerPropertyWrapperGetter : public FillLayerAnimationPropertyWrapperBase {
 
747
    WTF_MAKE_NONCOPYABLE(FillLayerPropertyWrapperGetter);
 
748
public:
 
749
    FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const)
 
750
        : m_getter(getter)
 
751
    {
 
752
    }
 
753
 
 
754
    virtual bool equals(const FillLayer* a, const FillLayer* b) const
 
755
    {
 
756
       // If the style pointers are the same, don't bother doing the test.
 
757
       // If either is null, return false. If both are null, return true.
 
758
       if ((!a && !b) || a == b)
 
759
           return true;
 
760
       if (!a || !b)
 
761
            return false;
 
762
        return (a->*m_getter)() == (b->*m_getter)();
 
763
    }
 
764
 
 
765
protected:
 
766
    T (FillLayer::*m_getter)() const;
 
767
};
 
768
 
 
769
template <typename T>
 
770
class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> {
 
771
public:
 
772
    FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T))
 
773
        : FillLayerPropertyWrapperGetter<T>(getter)
 
774
        , m_setter(setter)
 
775
    {
 
776
    }
 
777
 
 
778
    virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
 
779
    {
 
780
        (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::m_getter)(), progress));
 
781
    }
 
782
 
 
783
protected:
 
784
    void (FillLayer::*m_setter)(T);
 
785
};
 
786
 
 
787
template <typename T>
 
788
class FillLayerRefCountedPropertyWrapper : public FillLayerPropertyWrapperGetter<T*> {
 
789
public:
 
790
    FillLayerRefCountedPropertyWrapper(T* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<T>))
 
791
        : FillLayerPropertyWrapperGetter<T*>(getter)
 
792
        , m_setter(setter)
 
793
    {
 
794
    }
 
795
 
 
796
    virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const
 
797
    {
 
798
        (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T*>::m_getter)(), progress));
 
799
    }
 
800
 
 
801
protected:
 
802
    void (FillLayer::*m_setter)(PassRefPtr<T>);
 
803
};
 
804
 
 
805
class FillLayerStyleImagePropertyWrapper : public FillLayerRefCountedPropertyWrapper<StyleImage> {
 
806
public:
 
807
    FillLayerStyleImagePropertyWrapper(StyleImage* (FillLayer::*getter)() const, void (FillLayer::*setter)(PassRefPtr<StyleImage>))
 
808
        : FillLayerRefCountedPropertyWrapper<StyleImage>(getter, setter)
 
809
    {
 
810
    }
 
811
 
 
812
    virtual bool equals(const FillLayer* a, const FillLayer* b) const
 
813
    {
 
814
       // If the style pointers are the same, don't bother doing the test.
 
815
       // If either is null, return false. If both are null, return true.
 
816
       if (a == b)
 
817
           return true;
 
818
       if (!a || !b)
 
819
            return false;
 
820
 
 
821
        StyleImage* imageA = (a->*m_getter)();
 
822
        StyleImage* imageB = (b->*m_getter)();
 
823
        return StyleImage::imagesEquivalent(imageA, imageB);
 
824
    }
 
825
};
 
826
 
 
827
 
 
828
class FillLayersPropertyWrapper : public AnimationPropertyWrapperBase {
 
829
public:
 
830
    typedef const FillLayer* (RenderStyle::*LayersGetter)() const;
 
831
    typedef FillLayer* (RenderStyle::*LayersAccessor)();
 
832
 
 
833
    FillLayersPropertyWrapper(CSSPropertyID prop, LayersGetter getter, LayersAccessor accessor)
 
834
        : AnimationPropertyWrapperBase(prop)
 
835
        , m_layersGetter(getter)
 
836
        , m_layersAccessor(accessor)
 
837
    {
 
838
        switch (prop) {
 
839
        case CSSPropertyBackgroundPositionX:
 
840
        case CSSPropertyWebkitMaskPositionX:
 
841
            m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::xPosition, &FillLayer::setXPosition);
 
842
            break;
 
843
        case CSSPropertyBackgroundPositionY:
 
844
        case CSSPropertyWebkitMaskPositionY:
 
845
            m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition);
 
846
            break;
 
847
        case CSSPropertyBackgroundSize:
 
848
        case CSSPropertyWebkitBackgroundSize:
 
849
        case CSSPropertyWebkitMaskSize:
 
850
            m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength);
 
851
            break;
 
852
        case CSSPropertyBackgroundImage:
 
853
            m_fillLayerPropertyWrapper = new FillLayerStyleImagePropertyWrapper(&FillLayer::image, &FillLayer::setImage);
 
854
            break;
 
855
        default:
 
856
            break;
 
857
        }
 
858
    }
 
859
 
 
860
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
861
    {
 
862
        const FillLayer* fromLayer = (a->*m_layersGetter)();
 
863
        const FillLayer* toLayer = (b->*m_layersGetter)();
 
864
 
 
865
        while (fromLayer && toLayer) {
 
866
            if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer))
 
867
                return false;
 
868
 
 
869
            fromLayer = fromLayer->next();
 
870
            toLayer = toLayer->next();
 
871
        }
 
872
 
 
873
        return true;
 
874
    }
 
875
 
 
876
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
877
    {
 
878
        const FillLayer* aLayer = (a->*m_layersGetter)();
 
879
        const FillLayer* bLayer = (b->*m_layersGetter)();
 
880
        FillLayer* dstLayer = (dst->*m_layersAccessor)();
 
881
 
 
882
        while (aLayer && bLayer && dstLayer) {
 
883
            m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress);
 
884
            aLayer = aLayer->next();
 
885
            bLayer = bLayer->next();
 
886
            dstLayer = dstLayer->next();
 
887
        }
 
888
    }
 
889
 
 
890
private:
 
891
    FillLayerAnimationPropertyWrapperBase* m_fillLayerPropertyWrapper;
 
892
 
 
893
    LayersGetter m_layersGetter;
 
894
    LayersAccessor m_layersAccessor;
 
895
};
 
896
 
 
897
class ShorthandPropertyWrapper : public AnimationPropertyWrapperBase {
 
898
public:
 
899
    ShorthandPropertyWrapper(CSSPropertyID property, const StylePropertyShorthand& shorthand)
 
900
        : AnimationPropertyWrapperBase(property)
 
901
    {
 
902
        for (unsigned i = 0; i < shorthand.length(); ++i) {
 
903
            AnimationPropertyWrapperBase* wrapper = wrapperForProperty(shorthand.properties()[i]);
 
904
            if (wrapper)
 
905
                m_propertyWrappers.append(wrapper);
 
906
        }
 
907
    }
 
908
 
 
909
    virtual bool isShorthandWrapper() const { return true; }
 
910
 
 
911
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
912
    {
 
913
        Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
 
914
        for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it) {
 
915
            if (!(*it)->equals(a, b))
 
916
                return false;
 
917
        }
 
918
        return true;
 
919
    }
 
920
 
 
921
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
922
    {
 
923
        Vector<AnimationPropertyWrapperBase*>::const_iterator end = m_propertyWrappers.end();
 
924
        for (Vector<AnimationPropertyWrapperBase*>::const_iterator it = m_propertyWrappers.begin(); it != end; ++it)
 
925
            (*it)->blend(anim, dst, a, b, progress);
 
926
    }
 
927
 
 
928
    const Vector<AnimationPropertyWrapperBase*> propertyWrappers() const { return m_propertyWrappers; }
 
929
 
 
930
private:
 
931
    Vector<AnimationPropertyWrapperBase*> m_propertyWrappers;
 
932
};
 
933
 
 
934
class PropertyWrapperFlex : public AnimationPropertyWrapperBase {
 
935
public:
 
936
    PropertyWrapperFlex() : AnimationPropertyWrapperBase(CSSPropertyWebkitFlex)
 
937
    {
 
938
    }
 
939
 
 
940
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
941
    {
 
942
        // If the style pointers are the same, don't bother doing the test.
 
943
        // If either is null, return false. If both are null, return true.
 
944
        if ((!a && !b) || a == b)
 
945
            return true;
 
946
        if (!a || !b)
 
947
            return false;
 
948
 
 
949
        return a->flexBasis() == b->flexBasis() && a->flexGrow() == b->flexGrow() && a->flexShrink() == b->flexShrink();
 
950
    }
 
951
 
 
952
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
953
    {
 
954
        dst->setFlexBasis(blendFunc(anim, a->flexBasis(), b->flexBasis(), progress));
 
955
        dst->setFlexGrow(blendFunc(anim, a->flexGrow(), b->flexGrow(), progress));
 
956
        dst->setFlexShrink(blendFunc(anim, a->flexShrink(), b->flexShrink(), progress));
 
957
    }
 
958
};
 
959
 
 
960
#if ENABLE(SVG)
 
961
class PropertyWrapperSVGPaint : public AnimationPropertyWrapperBase {
 
962
public:
 
963
    PropertyWrapperSVGPaint(CSSPropertyID prop, const SVGPaint::SVGPaintType& (RenderStyle::*paintTypeGetter)() const, Color (RenderStyle::*getter)() const, void (RenderStyle::*setter)(const Color&))
 
964
        : AnimationPropertyWrapperBase(prop)
 
965
        , m_paintTypeGetter(paintTypeGetter)
 
966
        , m_getter(getter)
 
967
        , m_setter(setter)
 
968
    {
 
969
    }
 
970
 
 
971
    virtual bool equals(const RenderStyle* a, const RenderStyle* b) const
 
972
    {
 
973
        if ((a->*m_paintTypeGetter)() != (b->*m_paintTypeGetter)())
 
974
            return false;
 
975
 
 
976
        // We only support animations between SVGPaints that are pure Color values.
 
977
        // For everything else we must return true for this method, otherwise
 
978
        // we will try to animate between values forever.
 
979
        if ((a->*m_paintTypeGetter)() == SVGPaint::SVG_PAINTTYPE_RGBCOLOR) {
 
980
            Color fromColor = (a->*m_getter)();
 
981
            Color toColor = (b->*m_getter)();
 
982
 
 
983
            if (!fromColor.isValid() && !toColor.isValid())
 
984
                return true;
 
985
 
 
986
            if (!fromColor.isValid())
 
987
                fromColor = Color();
 
988
            if (!toColor.isValid())
 
989
                toColor = Color();
 
990
 
 
991
            return fromColor == toColor;
 
992
        }
 
993
        return true;
 
994
    }
 
995
 
 
996
    virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const
 
997
    {
 
998
        if ((a->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR
 
999
            || (b->*m_paintTypeGetter)() != SVGPaint::SVG_PAINTTYPE_RGBCOLOR)
 
1000
            return;
 
1001
 
 
1002
        Color fromColor = (a->*m_getter)();
 
1003
        Color toColor = (b->*m_getter)();
 
1004
 
 
1005
        if (!fromColor.isValid() && !toColor.isValid())
 
1006
            return;
 
1007
 
 
1008
        if (!fromColor.isValid())
 
1009
            fromColor = Color();
 
1010
        if (!toColor.isValid())
 
1011
            toColor = Color();
 
1012
        (dst->*m_setter)(blendFunc(anim, fromColor, toColor, progress));
 
1013
    }
 
1014
 
 
1015
private:
 
1016
    const SVGPaint::SVGPaintType& (RenderStyle::*m_paintTypeGetter)() const;
 
1017
    Color (RenderStyle::*m_getter)() const;
 
1018
    void (RenderStyle::*m_setter)(const Color&);
 
1019
};
 
1020
#endif
 
1021
 
 
1022
static void addShorthandProperties()
 
1023
{
 
1024
    static const CSSPropertyID animatableShorthandProperties[] = {
 
1025
        CSSPropertyBackground, // for background-color, background-position, background-image
 
1026
        CSSPropertyBackgroundPosition,
 
1027
        CSSPropertyFont, // for font-size, font-weight
 
1028
        CSSPropertyWebkitMask, // for mask-position
 
1029
        CSSPropertyWebkitMaskPosition,
 
1030
        CSSPropertyBorderTop, CSSPropertyBorderRight, CSSPropertyBorderBottom, CSSPropertyBorderLeft,
 
1031
        CSSPropertyBorderColor,
 
1032
        CSSPropertyBorderRadius,
 
1033
        CSSPropertyBorderWidth,
 
1034
        CSSPropertyBorder,
 
1035
        CSSPropertyBorderImage,
 
1036
        CSSPropertyBorderSpacing,
 
1037
        CSSPropertyListStyle, // for list-style-image
 
1038
        CSSPropertyMargin,
 
1039
        CSSPropertyOutline,
 
1040
        CSSPropertyPadding,
 
1041
        CSSPropertyWebkitTextStroke,
 
1042
        CSSPropertyWebkitColumnRule,
 
1043
        CSSPropertyWebkitBorderRadius,
 
1044
        CSSPropertyWebkitTransformOrigin
 
1045
    };
 
1046
 
 
1047
    for (size_t i = 0; i < WTF_ARRAY_LENGTH(animatableShorthandProperties); ++i) {
 
1048
        CSSPropertyID propertyID = animatableShorthandProperties[i];
 
1049
        StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
 
1050
        if (shorthand.length() > 0)
 
1051
            addPropertyWrapper(propertyID, new ShorthandPropertyWrapper(propertyID, shorthand));
 
1052
    }
 
1053
}
 
1054
 
 
1055
void CSSPropertyAnimation::ensurePropertyMap()
 
1056
{
 
1057
    // FIXME: This data is never destroyed. Maybe we should ref count it and toss it when the last AnimationController is destroyed?
 
1058
    if (gPropertyWrappers)
 
1059
        return;
 
1060
 
 
1061
    gPropertyWrappers = new Vector<AnimationPropertyWrapperBase*>();
 
1062
 
 
1063
    // build the list of property wrappers to do the comparisons and blends
 
1064
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLeft, &RenderStyle::left, &RenderStyle::setLeft));
 
1065
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyRight, &RenderStyle::right, &RenderStyle::setRight));
 
1066
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTop, &RenderStyle::top, &RenderStyle::setTop));
 
1067
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBottom, &RenderStyle::bottom, &RenderStyle::setBottom));
 
1068
 
 
1069
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWidth, &RenderStyle::width, &RenderStyle::setWidth));
 
1070
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinWidth, &RenderStyle::minWidth, &RenderStyle::setMinWidth));
 
1071
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxWidth, &RenderStyle::maxWidth, &RenderStyle::setMaxWidth));
 
1072
 
 
1073
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyHeight, &RenderStyle::height, &RenderStyle::setHeight));
 
1074
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMinHeight, &RenderStyle::minHeight, &RenderStyle::setMinHeight));
 
1075
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMaxHeight, &RenderStyle::maxHeight, &RenderStyle::setMaxHeight));
 
1076
 
 
1077
    gPropertyWrappers->append(new PropertyWrapperFlex());
 
1078
 
 
1079
    gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderLeftWidth, &RenderStyle::borderLeftWidth, &RenderStyle::setBorderLeftWidth));
 
1080
    gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderRightWidth, &RenderStyle::borderRightWidth, &RenderStyle::setBorderRightWidth));
 
1081
    gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderTopWidth, &RenderStyle::borderTopWidth, &RenderStyle::setBorderTopWidth));
 
1082
    gPropertyWrappers->append(new PropertyWrapper<unsigned>(CSSPropertyBorderBottomWidth, &RenderStyle::borderBottomWidth, &RenderStyle::setBorderBottomWidth));
 
1083
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginLeft, &RenderStyle::marginLeft, &RenderStyle::setMarginLeft));
 
1084
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginRight, &RenderStyle::marginRight, &RenderStyle::setMarginRight));
 
1085
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginTop, &RenderStyle::marginTop, &RenderStyle::setMarginTop));
 
1086
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyMarginBottom, &RenderStyle::marginBottom, &RenderStyle::setMarginBottom));
 
1087
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingLeft, &RenderStyle::paddingLeft, &RenderStyle::setPaddingLeft));
 
1088
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingRight, &RenderStyle::paddingRight, &RenderStyle::setPaddingRight));
 
1089
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingTop, &RenderStyle::paddingTop, &RenderStyle::setPaddingTop));
 
1090
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyPaddingBottom, &RenderStyle::paddingBottom, &RenderStyle::setPaddingBottom));
 
1091
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor, &RenderStyle::visitedLinkColor, &RenderStyle::setVisitedLinkColor));
 
1092
 
 
1093
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor, &RenderStyle::visitedLinkBackgroundColor, &RenderStyle::setVisitedLinkBackgroundColor));
 
1094
 
 
1095
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundImage, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
 
1096
    gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyListStyleImage, &RenderStyle::listStyleImage, &RenderStyle::setListStyleImage));
 
1097
    gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskImage, &RenderStyle::maskImage, &RenderStyle::setMaskImage));
 
1098
 
 
1099
    gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyBorderImageSource, &RenderStyle::borderImageSource, &RenderStyle::setBorderImageSource));
 
1100
    gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageSlice, &RenderStyle::borderImageSlices, &RenderStyle::setBorderImageSlices));
 
1101
    gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageWidth, &RenderStyle::borderImageWidth, &RenderStyle::setBorderImageWidth));
 
1102
    gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyBorderImageOutset, &RenderStyle::borderImageOutset, &RenderStyle::setBorderImageOutset));
 
1103
 
 
1104
    gPropertyWrappers->append(new StyleImagePropertyWrapper(CSSPropertyWebkitMaskBoxImageSource, &RenderStyle::maskBoxImageSource, &RenderStyle::setMaskBoxImageSource));
 
1105
    gPropertyWrappers->append(new PropertyWrapper<const NinePieceImage&>(CSSPropertyWebkitMaskBoxImage, &RenderStyle::maskBoxImage, &RenderStyle::setMaskBoxImage));
 
1106
 
 
1107
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
 
1108
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
 
1109
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
 
1110
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers));
 
1111
 
 
1112
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
 
1113
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
 
1114
    gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers));
 
1115
 
 
1116
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFontSize,
 
1117
        // Must pass a specified size to setFontSize if Text Autosizing is enabled, but a computed size
 
1118
        // if text zoom is enabled (if neither is enabled it's irrelevant as they're probably the same).
 
1119
        // FIXME: Find some way to assert that text zoom isn't activated when Text Autosizing is compiled in.
 
1120
#if ENABLE(TEXT_AUTOSIZING)
 
1121
        &RenderStyle::specifiedFontSize,
 
1122
#else
 
1123
        &RenderStyle::computedFontSize,
 
1124
#endif
 
1125
        &RenderStyle::setFontSize));
 
1126
    gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth));
 
1127
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnGap, &RenderStyle::columnGap, &RenderStyle::setColumnGap));
 
1128
    gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnCount, &RenderStyle::columnCount, &RenderStyle::setColumnCount));
 
1129
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitColumnWidth, &RenderStyle::columnWidth, &RenderStyle::setColumnWidth));
 
1130
    gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderHorizontalSpacing, &RenderStyle::horizontalBorderSpacing, &RenderStyle::setHorizontalBorderSpacing));
 
1131
    gPropertyWrappers->append(new PropertyWrapper<short>(CSSPropertyWebkitBorderVerticalSpacing, &RenderStyle::verticalBorderSpacing, &RenderStyle::setVerticalBorderSpacing));
 
1132
    gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyZIndex, &RenderStyle::zIndex, &RenderStyle::setZIndex));
 
1133
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyLineHeight, &RenderStyle::specifiedLineHeight, &RenderStyle::setLineHeight));
 
1134
    gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyOutlineOffset, &RenderStyle::outlineOffset, &RenderStyle::setOutlineOffset));
 
1135
    gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyOutlineWidth, &RenderStyle::outlineWidth, &RenderStyle::setOutlineWidth));
 
1136
    gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyLetterSpacing, &RenderStyle::letterSpacing, &RenderStyle::setLetterSpacing));
 
1137
    gPropertyWrappers->append(new PropertyWrapper<int>(CSSPropertyWordSpacing, &RenderStyle::wordSpacing, &RenderStyle::setWordSpacing));
 
1138
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyTextIndent, &RenderStyle::textIndent, &RenderStyle::setTextIndent));
 
1139
 
 
1140
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitPerspective, &RenderStyle::perspective, &RenderStyle::setPerspective));
 
1141
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginX, &RenderStyle::perspectiveOriginX, &RenderStyle::setPerspectiveOriginX));
 
1142
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitPerspectiveOriginY, &RenderStyle::perspectiveOriginY, &RenderStyle::setPerspectiveOriginY));
 
1143
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginX, &RenderStyle::transformOriginX, &RenderStyle::setTransformOriginX));
 
1144
    gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitTransformOriginY, &RenderStyle::transformOriginY, &RenderStyle::setTransformOriginY));
 
1145
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyWebkitTransformOriginZ, &RenderStyle::transformOriginZ, &RenderStyle::setTransformOriginZ));
 
1146
    gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopLeftRadius, &RenderStyle::borderTopLeftRadius, &RenderStyle::setBorderTopLeftRadius));
 
1147
    gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderTopRightRadius, &RenderStyle::borderTopRightRadius, &RenderStyle::setBorderTopRightRadius));
 
1148
    gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomLeftRadius, &RenderStyle::borderBottomLeftRadius, &RenderStyle::setBorderBottomLeftRadius));
 
1149
    gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyBorderBottomRightRadius, &RenderStyle::borderBottomRightRadius, &RenderStyle::setBorderBottomRightRadius));
 
1150
    gPropertyWrappers->append(new PropertyWrapper<EVisibility>(CSSPropertyVisibility, &RenderStyle::visibility, &RenderStyle::setVisibility));
 
1151
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyZoom, &RenderStyle::zoom, &RenderStyle::setZoomWithoutReturnValue));
 
1152
 
 
1153
    gPropertyWrappers->append(new PropertyWrapper<LengthBox>(CSSPropertyClip, &RenderStyle::clip, &RenderStyle::setClip));
 
1154
 
 
1155
#if USE(ACCELERATED_COMPOSITING)
 
1156
    gPropertyWrappers->append(new PropertyWrapperAcceleratedOpacity());
 
1157
    gPropertyWrappers->append(new PropertyWrapperAcceleratedTransform());
 
1158
#if ENABLE(CSS_FILTERS)
 
1159
    gPropertyWrappers->append(new PropertyWrapperAcceleratedFilter());
 
1160
#endif
 
1161
#else
 
1162
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyOpacity, &RenderStyle::opacity, &RenderStyle::setOpacity));
 
1163
    gPropertyWrappers->append(new PropertyWrapper<const TransformOperations&>(CSSPropertyWebkitTransform, &RenderStyle::transform, &RenderStyle::setTransform));
 
1164
#if ENABLE(CSS_FILTERS)
 
1165
    gPropertyWrappers->append(new PropertyWrapper<const FilterOperations&>(CSSPropertyWebkitFilter, &RenderStyle::filter, &RenderStyle::setFilter));
 
1166
#endif
 
1167
#endif
 
1168
 
 
1169
    gPropertyWrappers->append(new PropertyWrapperClipPath(CSSPropertyWebkitClipPath, &RenderStyle::clipPath, &RenderStyle::setClipPath));
 
1170
 
 
1171
#if ENABLE(CSS_EXCLUSIONS)
 
1172
    gPropertyWrappers->append(new PropertyWrapperExclusionShape(CSSPropertyWebkitShapeInside, &RenderStyle::shapeInside, &RenderStyle::setShapeInside));
 
1173
#endif
 
1174
 
 
1175
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitColumnRuleColor, MaybeInvalidColor, &RenderStyle::columnRuleColor, &RenderStyle::setColumnRuleColor, &RenderStyle::visitedLinkColumnRuleColor, &RenderStyle::setVisitedLinkColumnRuleColor));
 
1176
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextStrokeColor, MaybeInvalidColor, &RenderStyle::textStrokeColor, &RenderStyle::setTextStrokeColor, &RenderStyle::visitedLinkTextStrokeColor, &RenderStyle::setVisitedLinkTextStrokeColor));
 
1177
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyWebkitTextFillColor, MaybeInvalidColor, &RenderStyle::textFillColor, &RenderStyle::setTextFillColor, &RenderStyle::visitedLinkTextFillColor, &RenderStyle::setVisitedLinkTextFillColor));
 
1178
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderLeftColor, MaybeInvalidColor, &RenderStyle::borderLeftColor, &RenderStyle::setBorderLeftColor, &RenderStyle::visitedLinkBorderLeftColor, &RenderStyle::setVisitedLinkBorderLeftColor));
 
1179
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderRightColor, MaybeInvalidColor, &RenderStyle::borderRightColor, &RenderStyle::setBorderRightColor, &RenderStyle::visitedLinkBorderRightColor, &RenderStyle::setVisitedLinkBorderRightColor));
 
1180
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderTopColor, MaybeInvalidColor, &RenderStyle::borderTopColor, &RenderStyle::setBorderTopColor, &RenderStyle::visitedLinkBorderTopColor, &RenderStyle::setVisitedLinkBorderTopColor));
 
1181
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyBorderBottomColor, MaybeInvalidColor, &RenderStyle::borderBottomColor, &RenderStyle::setBorderBottomColor, &RenderStyle::visitedLinkBorderBottomColor, &RenderStyle::setVisitedLinkBorderBottomColor));
 
1182
    gPropertyWrappers->append(new PropertyWrapperVisitedAffectedColor(CSSPropertyOutlineColor, MaybeInvalidColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor, &RenderStyle::visitedLinkOutlineColor, &RenderStyle::setVisitedLinkOutlineColor));
 
1183
 
 
1184
    gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
 
1185
    gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow));
 
1186
    gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow));
 
1187
 
 
1188
#if ENABLE(SVG)
 
1189
    gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyFill, &RenderStyle::fillPaintType, &RenderStyle::fillPaintColor, &RenderStyle::setFillPaintColor));
 
1190
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFillOpacity, &RenderStyle::fillOpacity, &RenderStyle::setFillOpacity));
 
1191
 
 
1192
    gPropertyWrappers->append(new PropertyWrapperSVGPaint(CSSPropertyStroke, &RenderStyle::strokePaintType, &RenderStyle::strokePaintColor, &RenderStyle::setStrokePaintColor));
 
1193
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeOpacity, &RenderStyle::strokeOpacity, &RenderStyle::setStrokeOpacity));
 
1194
    gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyStrokeWidth, &RenderStyle::strokeWidth, &RenderStyle::setStrokeWidth));
 
1195
    gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyStrokeDashoffset, &RenderStyle::strokeDashOffset, &RenderStyle::setStrokeDashOffset));
 
1196
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStrokeMiterlimit, &RenderStyle::strokeMiterLimit, &RenderStyle::setStrokeMiterLimit));
 
1197
 
 
1198
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyFloodOpacity, &RenderStyle::floodOpacity, &RenderStyle::setFloodOpacity));
 
1199
    gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyFloodColor, &RenderStyle::floodColor, &RenderStyle::setFloodColor));
 
1200
 
 
1201
    gPropertyWrappers->append(new PropertyWrapper<float>(CSSPropertyStopOpacity, &RenderStyle::stopOpacity, &RenderStyle::setStopOpacity));
 
1202
    gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyStopColor, &RenderStyle::stopColor, &RenderStyle::setStopColor));
 
1203
 
 
1204
    gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyLightingColor, &RenderStyle::lightingColor, &RenderStyle::setLightingColor));
 
1205
 
 
1206
    gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue));
 
1207
    gPropertyWrappers->append(new PropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning));
 
1208
#endif
 
1209
 
 
1210
    // TODO:
 
1211
    //
 
1212
    //  CSSPropertyVerticalAlign
 
1213
    //
 
1214
    // Compound properties that have components that should be animatable:
 
1215
    //
 
1216
    //  CSSPropertyWebkitColumns
 
1217
    //  CSSPropertyWebkitBoxReflect
 
1218
 
 
1219
    // Make sure unused slots have a value
 
1220
    for (unsigned int i = 0; i < static_cast<unsigned int>(numCSSProperties); ++i)
 
1221
        gPropertyWrapperMap[i] = cInvalidPropertyWrapperIndex;
 
1222
 
 
1223
    // First we put the non-shorthand property wrappers into the map, so the shorthand-building
 
1224
    // code can find them.
 
1225
    size_t n = gPropertyWrappers->size();
 
1226
    for (unsigned int i = 0; i < n; ++i) {
 
1227
        ASSERT((*gPropertyWrappers)[i]->property() - firstCSSProperty < numCSSProperties);
 
1228
        gPropertyWrapperMap[(*gPropertyWrappers)[i]->property() - firstCSSProperty] = i;
 
1229
    }
 
1230
 
 
1231
    // Now add the shorthand wrappers.
 
1232
    addShorthandProperties();
 
1233
}
 
1234
 
 
1235
static bool gatherEnclosingShorthandProperties(CSSPropertyID property, AnimationPropertyWrapperBase* wrapper, HashSet<CSSPropertyID>& propertySet)
 
1236
{
 
1237
    if (!wrapper->isShorthandWrapper())
 
1238
        return false;
 
1239
 
 
1240
    ShorthandPropertyWrapper* shorthandWrapper = static_cast<ShorthandPropertyWrapper*>(wrapper);
 
1241
 
 
1242
    bool contained = false;
 
1243
    for (size_t i = 0; i < shorthandWrapper->propertyWrappers().size(); ++i) {
 
1244
        AnimationPropertyWrapperBase* currWrapper = shorthandWrapper->propertyWrappers()[i];
 
1245
 
 
1246
        if (gatherEnclosingShorthandProperties(property, currWrapper, propertySet) || currWrapper->property() == property)
 
1247
            contained = true;
 
1248
    }
 
1249
 
 
1250
    if (contained)
 
1251
        propertySet.add(wrapper->property());
 
1252
 
 
1253
    return contained;
 
1254
}
 
1255
 
 
1256
// Returns true if we need to start animation timers
 
1257
bool CSSPropertyAnimation::blendProperties(const AnimationBase* anim, CSSPropertyID prop, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress)
 
1258
{
 
1259
    ASSERT(prop != CSSPropertyInvalid);
 
1260
 
 
1261
    ensurePropertyMap();
 
1262
 
 
1263
    AnimationPropertyWrapperBase* wrapper = wrapperForProperty(prop);
 
1264
    if (wrapper) {
 
1265
        wrapper->blend(anim, dst, a, b, progress);
 
1266
#if USE(ACCELERATED_COMPOSITING)
 
1267
        return !wrapper->animationIsAccelerated() || !anim->isAccelerated();
 
1268
#else
 
1269
        return true;
 
1270
#endif
 
1271
    }
 
1272
 
 
1273
    return false;
 
1274
}
 
1275
 
 
1276
#if USE(ACCELERATED_COMPOSITING)
 
1277
bool CSSPropertyAnimation::animationOfPropertyIsAccelerated(CSSPropertyID prop)
 
1278
{
 
1279
    ensurePropertyMap();
 
1280
    AnimationPropertyWrapperBase* wrapper = wrapperForProperty(prop);
 
1281
    return wrapper ? wrapper->animationIsAccelerated() : false;
 
1282
}
 
1283
#endif
 
1284
 
 
1285
// Note: this is inefficient. It's only called from pauseTransitionAtTime().
 
1286
HashSet<CSSPropertyID> CSSPropertyAnimation::animatableShorthandsAffectingProperty(CSSPropertyID property)
 
1287
{
 
1288
    ensurePropertyMap();
 
1289
 
 
1290
    HashSet<CSSPropertyID> foundProperties;
 
1291
    for (int i = 0; i < getNumProperties(); ++i)
 
1292
        gatherEnclosingShorthandProperties(property, (*gPropertyWrappers)[i], foundProperties);
 
1293
 
 
1294
    return foundProperties;
 
1295
}
 
1296
 
 
1297
bool CSSPropertyAnimation::propertiesEqual(CSSPropertyID prop, const RenderStyle* a, const RenderStyle* b)
 
1298
{
 
1299
    ensurePropertyMap();
 
1300
 
 
1301
    AnimationPropertyWrapperBase* wrapper = wrapperForProperty(prop);
 
1302
    if (wrapper)
 
1303
        return wrapper->equals(a, b);
 
1304
    return true;
 
1305
}
 
1306
 
 
1307
CSSPropertyID CSSPropertyAnimation::getPropertyAtIndex(int i, bool& isShorthand)
 
1308
{
 
1309
    ensurePropertyMap();
 
1310
 
 
1311
    if (i < 0 || i >= getNumProperties())
 
1312
        return CSSPropertyInvalid;
 
1313
 
 
1314
    AnimationPropertyWrapperBase* wrapper = (*gPropertyWrappers)[i];
 
1315
    isShorthand = wrapper->isShorthandWrapper();
 
1316
    return wrapper->property();
 
1317
}
 
1318
 
 
1319
int CSSPropertyAnimation::getNumProperties()
 
1320
{
 
1321
    ensurePropertyMap();
 
1322
 
 
1323
    return gPropertyWrappers->size();
 
1324
}
 
1325
 
 
1326
}