Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / animation / AnimationTest.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/animation/Animation.h"
7
8 #include "bindings/core/v8/Dictionary.h"
9 #include "bindings/core/v8/UnionTypesCore.h"
10 #include "core/animation/AnimationClock.h"
11 #include "core/animation/AnimationNodeTiming.h"
12 #include "core/animation/AnimationTestHelper.h"
13 #include "core/animation/AnimationTimeline.h"
14 #include "core/animation/KeyframeEffectModel.h"
15 #include "core/animation/Timing.h"
16 #include "core/dom/Document.h"
17 #include "core/testing/DummyPageHolder.h"
18 #include <gtest/gtest.h>
19 #include <v8.h>
20
21 namespace blink {
22
23 class AnimationAnimationTest : public ::testing::Test {
24 protected:
25     AnimationAnimationTest()
26         : pageHolder(DummyPageHolder::create())
27         , document(pageHolder->document())
28         , element(document.createElement("foo", ASSERT_NO_EXCEPTION))
29     {
30         document.animationClock().resetTimeForTesting(document.timeline().zeroTime());
31         EXPECT_EQ(0, document.timeline().currentTime());
32     }
33
34     OwnPtr<DummyPageHolder> pageHolder;
35     Document& document;
36     RefPtrWillBePersistent<Element> element;
37     TrackExceptionState exceptionState;
38 };
39
40 class AnimationAnimationV8Test : public AnimationAnimationTest {
41 protected:
42     AnimationAnimationV8Test()
43         : m_isolate(v8::Isolate::GetCurrent())
44         , m_scope(m_isolate)
45     {
46     }
47
48     template<typename T>
49     static PassRefPtrWillBeRawPtr<Animation> createAnimation(Element* element, Vector<Dictionary> keyframeDictionaryVector, T timingInput, ExceptionState& exceptionState)
50     {
51         return Animation::create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState), timingInput);
52     }
53     static PassRefPtrWillBeRawPtr<Animation> createAnimation(Element* element, Vector<Dictionary> keyframeDictionaryVector, ExceptionState& exceptionState)
54     {
55         return Animation::create(element, EffectInput::convert(element, keyframeDictionaryVector, exceptionState));
56     }
57
58     v8::Isolate* m_isolate;
59
60 private:
61     V8TestingScope m_scope;
62 };
63
64 TEST_F(AnimationAnimationV8Test, CanCreateAnAnimation)
65 {
66     Vector<Dictionary> jsKeyframes;
67     v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
68     v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
69
70     setV8ObjectPropertyAsString(keyframe1, "width", "100px");
71     setV8ObjectPropertyAsString(keyframe1, "offset", "0");
72     setV8ObjectPropertyAsString(keyframe1, "easing", "ease-in-out");
73     setV8ObjectPropertyAsString(keyframe2, "width", "0px");
74     setV8ObjectPropertyAsString(keyframe2, "offset", "1");
75     setV8ObjectPropertyAsString(keyframe2, "easing", "cubic-bezier(1, 1, 0.3, 0.3)");
76
77     jsKeyframes.append(Dictionary(keyframe1, m_isolate));
78     jsKeyframes.append(Dictionary(keyframe2, m_isolate));
79
80     String value1;
81     ASSERT_TRUE(DictionaryHelper::get(jsKeyframes[0], "width", value1));
82     ASSERT_EQ("100px", value1);
83
84     String value2;
85     ASSERT_TRUE(DictionaryHelper::get(jsKeyframes[1], "width", value2));
86     ASSERT_EQ("0px", value2);
87
88     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, 0, exceptionState);
89
90     Element* target = animation->target();
91     EXPECT_EQ(*element.get(), *target);
92
93     const KeyframeVector keyframes = toKeyframeEffectModelBase(animation->effect())->getFrames();
94
95     EXPECT_EQ(0, keyframes[0]->offset());
96     EXPECT_EQ(1, keyframes[1]->offset());
97
98     const CSSValue* keyframe1Width = toStringKeyframe(keyframes[0].get())->propertyValue(CSSPropertyWidth);
99     const CSSValue* keyframe2Width = toStringKeyframe(keyframes[1].get())->propertyValue(CSSPropertyWidth);
100     ASSERT(keyframe1Width);
101     ASSERT(keyframe2Width);
102
103     EXPECT_EQ("100px", keyframe1Width->cssText());
104     EXPECT_EQ("0px", keyframe2Width->cssText());
105
106     EXPECT_EQ(*(CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseInOut)), keyframes[0]->easing());
107     EXPECT_EQ(*(CubicBezierTimingFunction::create(1, 1, 0.3, 0.3).get()), keyframes[1]->easing());
108 }
109
110 TEST_F(AnimationAnimationV8Test, CanSetDuration)
111 {
112     Vector<Dictionary, 0> jsKeyframes;
113     double duration = 2000;
114
115     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, duration, exceptionState);
116
117     EXPECT_EQ(duration / 1000, animation->specifiedTiming().iterationDuration);
118 }
119
120 TEST_F(AnimationAnimationV8Test, CanOmitSpecifiedDuration)
121 {
122     Vector<Dictionary, 0> jsKeyframes;
123     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, exceptionState);
124     EXPECT_TRUE(std::isnan(animation->specifiedTiming().iterationDuration));
125 }
126
127 TEST_F(AnimationAnimationV8Test, NegativeDurationIsAuto)
128 {
129     Vector<Dictionary, 0> jsKeyframes;
130     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, -2, exceptionState);
131     EXPECT_TRUE(std::isnan(animation->specifiedTiming().iterationDuration));
132 }
133
134 TEST_F(AnimationAnimationV8Test, MismatchedKeyframePropertyRaisesException)
135 {
136     Vector<Dictionary> jsKeyframes;
137     v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
138     v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
139
140     setV8ObjectPropertyAsString(keyframe1, "width", "100px");
141     setV8ObjectPropertyAsString(keyframe1, "offset", "0");
142
143     // Height property appears only in keyframe2
144     setV8ObjectPropertyAsString(keyframe2, "height", "100px");
145     setV8ObjectPropertyAsString(keyframe2, "width", "0px");
146     setV8ObjectPropertyAsString(keyframe2, "offset", "1");
147
148     jsKeyframes.append(Dictionary(keyframe1, m_isolate));
149     jsKeyframes.append(Dictionary(keyframe2, m_isolate));
150
151     createAnimation(element.get(), jsKeyframes, 0, exceptionState);
152
153     EXPECT_TRUE(exceptionState.hadException());
154     EXPECT_EQ(NotSupportedError, exceptionState.code());
155 }
156
157 TEST_F(AnimationAnimationV8Test, MissingOffsetZeroRaisesException)
158 {
159     Vector<Dictionary> jsKeyframes;
160     v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
161     v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
162
163     setV8ObjectPropertyAsString(keyframe1, "width", "100px");
164     setV8ObjectPropertyAsString(keyframe1, "offset", "0.1");
165     setV8ObjectPropertyAsString(keyframe2, "width", "0px");
166     setV8ObjectPropertyAsString(keyframe2, "offset", "1");
167
168     jsKeyframes.append(Dictionary(keyframe1, m_isolate));
169     jsKeyframes.append(Dictionary(keyframe2, m_isolate));
170
171     createAnimation(element.get(), jsKeyframes, 0, exceptionState);
172
173     EXPECT_TRUE(exceptionState.hadException());
174     EXPECT_EQ(NotSupportedError, exceptionState.code());
175 }
176
177 TEST_F(AnimationAnimationV8Test, MissingOffsetOneRaisesException)
178 {
179     Vector<Dictionary> jsKeyframes;
180     v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
181     v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
182
183     setV8ObjectPropertyAsString(keyframe1, "width", "100px");
184     setV8ObjectPropertyAsString(keyframe1, "offset", "0");
185     setV8ObjectPropertyAsString(keyframe2, "width", "0px");
186     setV8ObjectPropertyAsString(keyframe2, "offset", "0.1");
187
188     jsKeyframes.append(Dictionary(keyframe1, m_isolate));
189     jsKeyframes.append(Dictionary(keyframe2, m_isolate));
190
191     createAnimation(element.get(), jsKeyframes, 0, exceptionState);
192
193     EXPECT_TRUE(exceptionState.hadException());
194     EXPECT_EQ(NotSupportedError, exceptionState.code());
195 }
196
197 TEST_F(AnimationAnimationV8Test, MissingOffsetZeroAndOneRaisesException)
198 {
199     Vector<Dictionary> jsKeyframes;
200     v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
201     v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
202
203     setV8ObjectPropertyAsString(keyframe1, "width", "100px");
204     setV8ObjectPropertyAsString(keyframe1, "offset", "0.1");
205     setV8ObjectPropertyAsString(keyframe2, "width", "0px");
206     setV8ObjectPropertyAsString(keyframe2, "offset", "0.2");
207
208     jsKeyframes.append(Dictionary(keyframe1, m_isolate));
209     jsKeyframes.append(Dictionary(keyframe2, m_isolate));
210
211     createAnimation(element.get(), jsKeyframes, 0, exceptionState);
212
213     EXPECT_TRUE(exceptionState.hadException());
214     EXPECT_EQ(NotSupportedError, exceptionState.code());
215 }
216
217 TEST_F(AnimationAnimationV8Test, SpecifiedGetters)
218 {
219     Vector<Dictionary, 0> jsKeyframes;
220
221     v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
222     setV8ObjectPropertyAsNumber(timingInput, "delay", 2);
223     setV8ObjectPropertyAsNumber(timingInput, "endDelay", 0.5);
224     setV8ObjectPropertyAsString(timingInput, "fill", "backwards");
225     setV8ObjectPropertyAsNumber(timingInput, "iterationStart", 2);
226     setV8ObjectPropertyAsNumber(timingInput, "iterations", 10);
227     setV8ObjectPropertyAsNumber(timingInput, "playbackRate", 2);
228     setV8ObjectPropertyAsString(timingInput, "direction", "reverse");
229     setV8ObjectPropertyAsString(timingInput, "easing", "step-start");
230     Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
231
232     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, timingInputDictionary, exceptionState);
233
234     RefPtrWillBeRawPtr<AnimationNodeTiming> specified = animation->timing();
235     EXPECT_EQ(2, specified->delay());
236     EXPECT_EQ(0.5, specified->endDelay());
237     EXPECT_EQ("backwards", specified->fill());
238     EXPECT_EQ(2, specified->iterationStart());
239     EXPECT_EQ(10, specified->iterations());
240     EXPECT_EQ(2, specified->playbackRate());
241     EXPECT_EQ("reverse", specified->direction());
242     EXPECT_EQ("step-start", specified->easing());
243 }
244
245 TEST_F(AnimationAnimationV8Test, SpecifiedDurationGetter)
246 {
247     Vector<Dictionary, 0> jsKeyframes;
248
249     v8::Handle<v8::Object> timingInputWithDuration = v8::Object::New(m_isolate);
250     setV8ObjectPropertyAsNumber(timingInputWithDuration, "duration", 2.5);
251     Dictionary timingInputDictionaryWithDuration = Dictionary(v8::Handle<v8::Value>::Cast(timingInputWithDuration), m_isolate);
252
253     RefPtrWillBeRawPtr<Animation> animationWithDuration = createAnimation(element.get(), jsKeyframes, timingInputDictionaryWithDuration, exceptionState);
254
255     RefPtrWillBeRawPtr<AnimationNodeTiming> specifiedWithDuration = animationWithDuration->timing();
256     DoubleOrString duration;
257     specifiedWithDuration->getDuration("duration", duration);
258     EXPECT_TRUE(duration.isDouble());
259     EXPECT_EQ(2.5, duration.getAsDouble());
260     EXPECT_FALSE(duration.isString());
261
262
263     v8::Handle<v8::Object> timingInputNoDuration = v8::Object::New(m_isolate);
264     Dictionary timingInputDictionaryNoDuration = Dictionary(v8::Handle<v8::Value>::Cast(timingInputNoDuration), m_isolate);
265
266     RefPtrWillBeRawPtr<Animation> animationNoDuration = createAnimation(element.get(), jsKeyframes, timingInputDictionaryNoDuration, exceptionState);
267
268     RefPtrWillBeRawPtr<AnimationNodeTiming> specifiedNoDuration = animationNoDuration->timing();
269     DoubleOrString duration2;
270     specifiedNoDuration->getDuration("duration", duration2);
271     EXPECT_FALSE(duration2.isDouble());
272     EXPECT_TRUE(duration2.isString());
273     EXPECT_EQ("auto", duration2.getAsString());
274 }
275
276 TEST_F(AnimationAnimationV8Test, SpecifiedSetters)
277 {
278     Vector<Dictionary, 0> jsKeyframes;
279     v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
280     Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
281     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, timingInputDictionary, exceptionState);
282
283     RefPtrWillBeRawPtr<AnimationNodeTiming> specified = animation->timing();
284
285     EXPECT_EQ(0, specified->delay());
286     specified->setDelay(2);
287     EXPECT_EQ(2, specified->delay());
288
289     EXPECT_EQ(0, specified->endDelay());
290     specified->setEndDelay(0.5);
291     EXPECT_EQ(0.5, specified->endDelay());
292
293     EXPECT_EQ("auto", specified->fill());
294     specified->setFill("backwards");
295     EXPECT_EQ("backwards", specified->fill());
296
297     EXPECT_EQ(0, specified->iterationStart());
298     specified->setIterationStart(2);
299     EXPECT_EQ(2, specified->iterationStart());
300
301     EXPECT_EQ(1, specified->iterations());
302     specified->setIterations(10);
303     EXPECT_EQ(10, specified->iterations());
304
305     EXPECT_EQ(1, specified->playbackRate());
306     specified->setPlaybackRate(2);
307     EXPECT_EQ(2, specified->playbackRate());
308
309     EXPECT_EQ("normal", specified->direction());
310     specified->setDirection("reverse");
311     EXPECT_EQ("reverse", specified->direction());
312
313     EXPECT_EQ("linear", specified->easing());
314     specified->setEasing("step-start");
315     EXPECT_EQ("step-start", specified->easing());
316 }
317
318 TEST_F(AnimationAnimationV8Test, SetSpecifiedDuration)
319 {
320     Vector<Dictionary, 0> jsKeyframes;
321     v8::Handle<v8::Object> timingInput = v8::Object::New(m_isolate);
322     Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), m_isolate);
323     RefPtrWillBeRawPtr<Animation> animation = createAnimation(element.get(), jsKeyframes, timingInputDictionary, exceptionState);
324
325     RefPtrWillBeRawPtr<AnimationNodeTiming> specified = animation->timing();
326
327     DoubleOrString duration;
328     specified->getDuration("duration", duration);
329     EXPECT_FALSE(duration.isDouble());
330     EXPECT_TRUE(duration.isString());
331     EXPECT_EQ("auto", duration.getAsString());
332
333     specified->setDuration("duration", 2.5);
334     DoubleOrString duration2;
335     specified->getDuration("duration", duration2);
336     EXPECT_TRUE(duration2.isDouble());
337     EXPECT_EQ(2.5, duration2.getAsDouble());
338     EXPECT_FALSE(duration2.isString());
339 }
340
341 TEST_F(AnimationAnimationTest, TimeToEffectChange)
342 {
343     Timing timing;
344     timing.iterationDuration = 100;
345     timing.startDelay = 100;
346     timing.endDelay = 100;
347     timing.fillMode = Timing::FillModeNone;
348     RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
349     RefPtrWillBeRawPtr<AnimationPlayer> player = document.timeline().play(animation.get());
350     double inf = std::numeric_limits<double>::infinity();
351
352     EXPECT_EQ(100, animation->timeToForwardsEffectChange());
353     EXPECT_EQ(inf, animation->timeToReverseEffectChange());
354
355     player->setCurrentTimeInternal(100);
356     EXPECT_EQ(0, animation->timeToForwardsEffectChange());
357     EXPECT_EQ(0, animation->timeToReverseEffectChange());
358
359     player->setCurrentTimeInternal(199);
360     EXPECT_EQ(0, animation->timeToForwardsEffectChange());
361     EXPECT_EQ(0, animation->timeToReverseEffectChange());
362
363     player->setCurrentTimeInternal(200);
364     // End-exclusive.
365     EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
366     EXPECT_EQ(0, animation->timeToReverseEffectChange());
367
368     player->setCurrentTimeInternal(300);
369     EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
370     EXPECT_EQ(100, animation->timeToReverseEffectChange());
371 }
372
373 TEST_F(AnimationAnimationTest, TimeToEffectChangeWithPlaybackRate)
374 {
375     Timing timing;
376     timing.iterationDuration = 100;
377     timing.startDelay = 100;
378     timing.endDelay = 100;
379     timing.playbackRate = 2;
380     timing.fillMode = Timing::FillModeNone;
381     RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
382     RefPtrWillBeRawPtr<AnimationPlayer> player = document.timeline().play(animation.get());
383     double inf = std::numeric_limits<double>::infinity();
384
385     EXPECT_EQ(100, animation->timeToForwardsEffectChange());
386     EXPECT_EQ(inf, animation->timeToReverseEffectChange());
387
388     player->setCurrentTimeInternal(100);
389     EXPECT_EQ(0, animation->timeToForwardsEffectChange());
390     EXPECT_EQ(0, animation->timeToReverseEffectChange());
391
392     player->setCurrentTimeInternal(149);
393     EXPECT_EQ(0, animation->timeToForwardsEffectChange());
394     EXPECT_EQ(0, animation->timeToReverseEffectChange());
395
396     player->setCurrentTimeInternal(150);
397     // End-exclusive.
398     EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
399     EXPECT_EQ(0, animation->timeToReverseEffectChange());
400
401     player->setCurrentTimeInternal(200);
402     EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
403     EXPECT_EQ(50, animation->timeToReverseEffectChange());
404 }
405
406 TEST_F(AnimationAnimationTest, TimeToEffectChangeWithNegativePlaybackRate)
407 {
408     Timing timing;
409     timing.iterationDuration = 100;
410     timing.startDelay = 100;
411     timing.endDelay = 100;
412     timing.playbackRate = -2;
413     timing.fillMode = Timing::FillModeNone;
414     RefPtrWillBeRawPtr<Animation> animation = Animation::create(0, nullptr, timing);
415     RefPtrWillBeRawPtr<AnimationPlayer> player = document.timeline().play(animation.get());
416     double inf = std::numeric_limits<double>::infinity();
417
418     EXPECT_EQ(100, animation->timeToForwardsEffectChange());
419     EXPECT_EQ(inf, animation->timeToReverseEffectChange());
420
421     player->setCurrentTimeInternal(100);
422     EXPECT_EQ(0, animation->timeToForwardsEffectChange());
423     EXPECT_EQ(0, animation->timeToReverseEffectChange());
424
425     player->setCurrentTimeInternal(149);
426     EXPECT_EQ(0, animation->timeToForwardsEffectChange());
427     EXPECT_EQ(0, animation->timeToReverseEffectChange());
428
429     player->setCurrentTimeInternal(150);
430     EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
431     EXPECT_EQ(0, animation->timeToReverseEffectChange());
432
433     player->setCurrentTimeInternal(200);
434     EXPECT_EQ(inf, animation->timeToForwardsEffectChange());
435     EXPECT_EQ(50, animation->timeToReverseEffectChange());
436 }
437
438 TEST_F(AnimationAnimationTest, ElementDestructorClearsAnimationTarget)
439 {
440     // This test expects incorrect behaviour should be removed once Element
441     // and Animation are moved to Oilpan. See crbug.com/362404 for context.
442     Timing timing;
443     timing.iterationDuration = 5;
444     RefPtrWillBeRawPtr<Animation> animation = Animation::create(element.get(), nullptr, timing);
445     EXPECT_EQ(element.get(), animation->target());
446     document.timeline().play(animation.get());
447     pageHolder.clear();
448     element.clear();
449 #if !ENABLE(OILPAN)
450     EXPECT_EQ(0, animation->target());
451 #endif
452 }
453
454 } // namespace blink