2 * Copyright (c) 2013, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "core/animation/ElementAnimation.h"
34 #include "bindings/v8/Dictionary.h"
35 #include "core/animation/AnimatableLength.h"
36 #include "core/animation/Animation.h"
37 #include "core/animation/AnimationClock.h"
38 #include "core/animation/DocumentTimeline.h"
39 #include "core/animation/KeyframeEffectModel.h"
40 #include "core/animation/Timing.h"
41 #include "core/dom/Document.h"
42 #include "core/dom/Element.h"
44 #include <gtest/gtest.h>
50 v8::Handle<v8::Value> stringToV8Value(String string)
52 return v8::Handle<v8::Value>::Cast(v8String(v8::Isolate::GetCurrent(), string));
55 v8::Handle<v8::Value> doubleToV8Value(double number)
57 return v8::Handle<v8::Value>::Cast(v8::Number::New(v8::Isolate::GetCurrent(), number));
60 void setV8ObjectPropertyAsString(v8::Handle<v8::Object> object, String name, String value)
62 object->Set(stringToV8Value(name), stringToV8Value(value));
65 void setV8ObjectPropertyAsNumber(v8::Handle<v8::Object> object, String name, double value)
67 object->Set(stringToV8Value(name), doubleToV8Value(value));
72 class AnimationElementAnimationTest : public ::testing::Test {
76 document = Document::create();
77 document->animationClock().resetTimeForTesting();
78 element = document->createElement("foo", ASSERT_NO_EXCEPTION);
79 document->timeline()->setZeroTime(0);
80 ASSERT_EQ(0, document->timeline()->currentTime());
83 RefPtr<Document> document;
84 RefPtr<Element> element;
86 Animation* startAnimation(Element* element, Vector<Dictionary> keyframesDictionaryVector, Dictionary timingInput)
88 return ElementAnimation::startAnimation(element, keyframesDictionaryVector, timingInput);
91 Animation* startAnimation(Element* element, Vector<Dictionary> keyframesDictionaryVector, double timingInput)
93 return ElementAnimation::startAnimation(element, keyframesDictionaryVector, timingInput);
96 Animation* startAnimation(Element* element, Vector<Dictionary> keyframesDictionaryVector)
98 return ElementAnimation::startAnimation(element, keyframesDictionaryVector);
101 void populateTiming(Timing& timing, Dictionary timingInputDictionary)
103 ElementAnimation::populateTiming(timing, timingInputDictionary);
106 void applyTimingInputNumber(Timing& timing, v8::Isolate* isolate, String timingProperty, double timingPropertyValue)
108 v8::Handle<v8::Object> timingInput = v8::Object::New(isolate);
109 setV8ObjectPropertyAsNumber(timingInput, timingProperty, timingPropertyValue);
110 Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), isolate);
111 populateTiming(timing, timingInputDictionary);
114 void applyTimingInputString(Timing& timing, v8::Isolate* isolate, String timingProperty, String timingPropertyValue)
116 v8::Handle<v8::Object> timingInput = v8::Object::New(isolate);
117 setV8ObjectPropertyAsString(timingInput, timingProperty, timingPropertyValue);
118 Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), isolate);
119 populateTiming(timing, timingInputDictionary);
123 TEST_F(AnimationElementAnimationTest, CanStartAnAnimation)
125 v8::Isolate* isolate = v8::Isolate::GetCurrent();
126 v8::HandleScope scope(isolate);
127 v8::Local<v8::Context> context = v8::Context::New(isolate);
128 v8::Context::Scope contextScope(context);
130 Vector<Dictionary> jsKeyframes;
131 v8::Handle<v8::Object> keyframe1 = v8::Object::New(isolate);
132 v8::Handle<v8::Object> keyframe2 = v8::Object::New(isolate);
134 setV8ObjectPropertyAsString(keyframe1, "width", "100px");
135 setV8ObjectPropertyAsString(keyframe1, "offset", "0");
136 setV8ObjectPropertyAsString(keyframe2, "width", "0px");
137 setV8ObjectPropertyAsString(keyframe2, "offset", "1");
139 jsKeyframes.append(Dictionary(keyframe1, isolate));
140 jsKeyframes.append(Dictionary(keyframe2, isolate));
143 ASSERT_TRUE(jsKeyframes[0].get("width", value1));
144 ASSERT_EQ("100px", value1);
147 ASSERT_TRUE(jsKeyframes[1].get("width", value2));
148 ASSERT_EQ("0px", value2);
150 Animation* animation = startAnimation(element.get(), jsKeyframes, 0);
152 Player* player = document->timeline()->players().at(0).get();
153 EXPECT_EQ(animation, player->source());
155 Element* target = animation->target();
156 EXPECT_EQ(*element.get(), *target);
158 const KeyframeEffectModel::KeyframeVector keyframes =
159 toKeyframeEffectModel(animation->effect())->getFrames();
161 EXPECT_EQ(0, keyframes[0]->offset());
162 EXPECT_EQ(1, keyframes[1]->offset());
164 const AnimatableValue* keyframe1Width = keyframes[0]->propertyValue(CSSPropertyWidth);
165 const AnimatableValue* keyframe2Width = keyframes[1]->propertyValue(CSSPropertyWidth);
166 ASSERT(keyframe1Width);
167 ASSERT(keyframe2Width);
169 EXPECT_TRUE(keyframe1Width->isLength());
170 EXPECT_TRUE(keyframe2Width->isLength());
172 EXPECT_EQ("100px", toAnimatableLength(keyframe1Width)->toCSSValue()->cssText());
173 EXPECT_EQ("0px", toAnimatableLength(keyframe2Width)->toCSSValue()->cssText());
176 TEST_F(AnimationElementAnimationTest, ParseCamelCasePropertyNames)
178 EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("line-height")));
179 EXPECT_EQ(CSSPropertyLineHeight, ElementAnimation::camelCaseCSSPropertyNameToID(String("lineHeight")));
180 EXPECT_EQ(CSSPropertyBorderTopWidth, ElementAnimation::camelCaseCSSPropertyNameToID(String("borderTopWidth")));
181 EXPECT_EQ(CSSPropertyWidth, ElementAnimation::camelCaseCSSPropertyNameToID(String("width")));
182 EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("Width")));
183 EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("-webkit-transform")));
184 EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("webkitTransform")));
185 EXPECT_EQ(CSSPropertyInvalid, ElementAnimation::camelCaseCSSPropertyNameToID(String("cssFloat")));
188 TEST_F(AnimationElementAnimationTest, CanSetDuration)
190 v8::Isolate* isolate = v8::Isolate::GetCurrent();
191 v8::HandleScope scope(isolate);
192 v8::Local<v8::Context> context = v8::Context::New(isolate);
193 v8::Context::Scope contextScope(context);
195 Vector<Dictionary, 0> jsKeyframes;
198 Animation* animation = startAnimation(element.get(), jsKeyframes, duration);
200 Player* player = document->timeline()->players().at(0).get();
202 EXPECT_EQ(animation, player->source());
203 EXPECT_TRUE(player->source()->specified().hasIterationDuration);
204 EXPECT_EQ(duration, player->source()->specified().iterationDuration);
207 TEST_F(AnimationElementAnimationTest, CanOmitSpecifiedDuration)
209 v8::Isolate* isolate = v8::Isolate::GetCurrent();
210 v8::HandleScope scope(isolate);
211 v8::Local<v8::Context> context = v8::Context::New(isolate);
212 v8::Context::Scope contextScope(context);
214 Vector<Dictionary, 0> jsKeyframes;
216 Animation* animation = startAnimation(element.get(), jsKeyframes);
218 Player* player = document->timeline()->players().at(0).get();
219 EXPECT_EQ(animation, player->source());
221 EXPECT_FALSE(player->source()->specified().hasIterationDuration);
222 EXPECT_EQ(0, player->source()->specified().iterationDuration);
225 TEST_F(AnimationElementAnimationTest, ClipNegativeDurationToZero)
227 v8::Isolate* isolate = v8::Isolate::GetCurrent();
228 v8::HandleScope scope(isolate);
229 v8::Local<v8::Context> context = v8::Context::New(isolate);
230 v8::Context::Scope contextScope(context);
232 Vector<Dictionary, 0> jsKeyframes;
234 Animation* animation = startAnimation(element.get(), jsKeyframes, -2);
236 Player* player = document->timeline()->players().at(0).get();
237 EXPECT_EQ(animation, player->source());
239 EXPECT_TRUE(player->source()->specified().hasIterationDuration);
240 EXPECT_EQ(0, player->source()->specified().iterationDuration);
243 TEST_F(AnimationElementAnimationTest, TimingInputStartDelay)
245 v8::Isolate* isolate = v8::Isolate::GetCurrent();
246 v8::HandleScope scope(isolate);
247 v8::Local<v8::Context> context = v8::Context::New(isolate);
248 v8::Context::Scope contextScope(context);
251 EXPECT_EQ(0, timing.startDelay);
253 applyTimingInputNumber(timing, isolate, "delay", 1.1);
254 EXPECT_EQ(1.1, timing.startDelay);
255 timing.startDelay = 0;
257 applyTimingInputNumber(timing, isolate, "delay", -1);
258 EXPECT_EQ(-1, timing.startDelay);
259 timing.startDelay = 0;
261 applyTimingInputString(timing, isolate, "delay", "1");
262 EXPECT_EQ(1, timing.startDelay);
263 timing.startDelay = 0;
265 applyTimingInputString(timing, isolate, "delay", "1s");
266 EXPECT_EQ(0, timing.startDelay);
267 timing.startDelay = 0;
269 applyTimingInputString(timing, isolate, "delay", "Infinity");
270 EXPECT_EQ(0, timing.startDelay);
271 timing.startDelay = 0;
273 applyTimingInputString(timing, isolate, "delay", "-Infinity");
274 EXPECT_EQ(0, timing.startDelay);
275 timing.startDelay = 0;
277 applyTimingInputString(timing, isolate, "delay", "NaN");
278 EXPECT_EQ(0, timing.startDelay);
279 timing.startDelay = 0;
281 applyTimingInputString(timing, isolate, "delay", "rubbish");
282 EXPECT_EQ(0, timing.startDelay);
283 timing.startDelay = 0;
286 TEST_F(AnimationElementAnimationTest, TimingInputFillMode)
288 v8::Isolate* isolate = v8::Isolate::GetCurrent();
289 v8::HandleScope scope(isolate);
290 v8::Local<v8::Context> context = v8::Context::New(isolate);
291 v8::Context::Scope contextScope(context);
294 Timing::FillMode defaultFillMode = Timing::FillModeForwards;
295 EXPECT_EQ(defaultFillMode, timing.fillMode);
297 applyTimingInputString(timing, isolate, "fill", "forwards");
298 EXPECT_EQ(Timing::FillModeForwards, timing.fillMode);
299 timing.fillMode = defaultFillMode;
301 applyTimingInputString(timing, isolate, "fill", "none");
302 EXPECT_EQ(Timing::FillModeNone, timing.fillMode);
303 timing.fillMode = defaultFillMode;
305 applyTimingInputString(timing, isolate, "fill", "backwards");
306 EXPECT_EQ(Timing::FillModeBackwards, timing.fillMode);
307 timing.fillMode = defaultFillMode;
309 applyTimingInputString(timing, isolate, "fill", "both");
310 EXPECT_EQ(Timing::FillModeBoth, timing.fillMode);
311 timing.fillMode = defaultFillMode;
313 applyTimingInputString(timing, isolate, "fill", "everything!");
314 EXPECT_EQ(defaultFillMode, timing.fillMode);
315 timing.fillMode = defaultFillMode;
317 applyTimingInputString(timing, isolate, "fill", "backwardsandforwards");
318 EXPECT_EQ(defaultFillMode, timing.fillMode);
319 timing.fillMode = defaultFillMode;
321 applyTimingInputNumber(timing, isolate, "fill", 2);
322 EXPECT_EQ(defaultFillMode, timing.fillMode);
323 timing.fillMode = defaultFillMode;
326 TEST_F(AnimationElementAnimationTest, TimingInputIterationStart)
328 v8::Isolate* isolate = v8::Isolate::GetCurrent();
329 v8::HandleScope scope(isolate);
330 v8::Local<v8::Context> context = v8::Context::New(isolate);
331 v8::Context::Scope contextScope(context);
334 EXPECT_EQ(0, timing.iterationStart);
336 applyTimingInputNumber(timing, isolate, "iterationStart", 1.1);
337 EXPECT_EQ(1.1, timing.iterationStart);
338 timing.iterationStart = 0;
340 applyTimingInputNumber(timing, isolate, "iterationStart", -1);
341 EXPECT_EQ(0, timing.iterationStart);
342 timing.iterationStart = 0;
344 applyTimingInputString(timing, isolate, "iterationStart", "Infinity");
345 EXPECT_EQ(0, timing.iterationStart);
346 timing.iterationStart = 0;
348 applyTimingInputString(timing, isolate, "iterationStart", "-Infinity");
349 EXPECT_EQ(0, timing.iterationStart);
350 timing.iterationStart = 0;
352 applyTimingInputString(timing, isolate, "iterationStart", "NaN");
353 EXPECT_EQ(0, timing.iterationStart);
354 timing.iterationStart = 0;
356 applyTimingInputString(timing, isolate, "iterationStart", "rubbish");
357 EXPECT_EQ(0, timing.iterationStart);
358 timing.iterationStart = 0;
361 TEST_F(AnimationElementAnimationTest, TimingInputIterationCount)
363 v8::Isolate* isolate = v8::Isolate::GetCurrent();
364 v8::HandleScope scope(isolate);
365 v8::Local<v8::Context> context = v8::Context::New(isolate);
366 v8::Context::Scope contextScope(context);
369 EXPECT_EQ(1, timing.iterationCount);
371 applyTimingInputNumber(timing, isolate, "iterations", 2.1);
372 EXPECT_EQ(2.1, timing.iterationCount);
373 timing.iterationCount = 1;
375 applyTimingInputNumber(timing, isolate, "iterations", -1);
376 EXPECT_EQ(0, timing.iterationCount);
377 timing.iterationCount = 1;
379 applyTimingInputString(timing, isolate, "iterations", "Infinity");
380 EXPECT_TRUE(std::isinf(timing.iterationCount) && (timing.iterationCount > 0));
381 timing.iterationCount = 1;
383 applyTimingInputString(timing, isolate, "iterations", "-Infinity");
384 EXPECT_EQ(0, timing.iterationCount);
385 timing.iterationCount = 1;
387 applyTimingInputString(timing, isolate, "iterations", "NaN");
388 EXPECT_EQ(1, timing.iterationCount);
389 timing.iterationCount = 1;
391 applyTimingInputString(timing, isolate, "iterations", "rubbish");
392 EXPECT_EQ(1, timing.iterationCount);
393 timing.iterationCount = 1;
396 TEST_F(AnimationElementAnimationTest, TimingInputIterationDuration)
398 v8::Isolate* isolate = v8::Isolate::GetCurrent();
399 v8::HandleScope scope(isolate);
400 v8::Local<v8::Context> context = v8::Context::New(isolate);
401 v8::Context::Scope contextScope(context);
404 EXPECT_EQ(0, timing.iterationDuration);
405 EXPECT_FALSE(timing.hasIterationDuration);
407 applyTimingInputNumber(timing, isolate, "duration", 1.1);
408 EXPECT_EQ(1.1, timing.iterationDuration);
409 EXPECT_TRUE(timing.hasIterationDuration);
410 timing.hasIterationDuration = false;
411 timing.iterationDuration = 0;
413 applyTimingInputNumber(timing, isolate, "duration", -1);
414 EXPECT_EQ(0, timing.iterationDuration);
415 EXPECT_FALSE(timing.hasIterationDuration);
416 timing.hasIterationDuration = false;
417 timing.iterationDuration = 0;
419 applyTimingInputString(timing, isolate, "duration", "1");
420 EXPECT_EQ(1, timing.iterationDuration);
421 EXPECT_TRUE(timing.hasIterationDuration);
422 timing.hasIterationDuration = false;
423 timing.iterationDuration = 0;
425 applyTimingInputString(timing, isolate, "duration", "Infinity");
426 EXPECT_TRUE(std::isinf(timing.iterationDuration) && (timing.iterationDuration > 0));
427 EXPECT_TRUE(timing.hasIterationDuration);
428 timing.hasIterationDuration = false;
429 timing.iterationDuration = 0;
431 applyTimingInputString(timing, isolate, "duration", "-Infinity");
432 EXPECT_EQ(0, timing.iterationDuration);
433 EXPECT_FALSE(timing.hasIterationDuration);
434 timing.hasIterationDuration = false;
435 timing.iterationDuration = 0;
437 applyTimingInputString(timing, isolate, "duration", "NaN");
438 EXPECT_EQ(0, timing.iterationDuration);
439 EXPECT_FALSE(timing.hasIterationDuration);
440 timing.hasIterationDuration = false;
441 timing.iterationDuration = 0;
443 applyTimingInputString(timing, isolate, "duration", "auto");
444 EXPECT_EQ(0, timing.iterationDuration);
445 EXPECT_FALSE(timing.hasIterationDuration);
446 timing.hasIterationDuration = false;
447 timing.iterationDuration = 0;
449 applyTimingInputString(timing, isolate, "duration", "rubbish");
450 EXPECT_EQ(0, timing.iterationDuration);
451 EXPECT_FALSE(timing.hasIterationDuration);
452 timing.hasIterationDuration = false;
453 timing.iterationDuration = 0;
456 TEST_F(AnimationElementAnimationTest, TimingInputPlaybackRate)
458 v8::Isolate* isolate = v8::Isolate::GetCurrent();
459 v8::HandleScope scope(isolate);
460 v8::Local<v8::Context> context = v8::Context::New(isolate);
461 v8::Context::Scope contextScope(context);
464 EXPECT_EQ(1, timing.playbackRate);
466 applyTimingInputNumber(timing, isolate, "playbackRate", 2.1);
467 EXPECT_EQ(2.1, timing.playbackRate);
468 timing.playbackRate = 1;
470 applyTimingInputNumber(timing, isolate, "playbackRate", -1);
471 EXPECT_EQ(-1, timing.playbackRate);
472 timing.playbackRate = 1;
474 applyTimingInputString(timing, isolate, "playbackRate", "Infinity");
475 EXPECT_EQ(1, timing.playbackRate);
476 timing.playbackRate = 1;
478 applyTimingInputString(timing, isolate, "playbackRate", "-Infinity");
479 EXPECT_EQ(1, timing.playbackRate);
480 timing.playbackRate = 1;
482 applyTimingInputString(timing, isolate, "playbackRate", "NaN");
483 EXPECT_EQ(1, timing.playbackRate);
484 timing.playbackRate = 1;
486 applyTimingInputString(timing, isolate, "playbackRate", "rubbish");
487 EXPECT_EQ(1, timing.playbackRate);
488 timing.playbackRate = 1;
491 TEST_F(AnimationElementAnimationTest, TimingInputDirection)
493 v8::Isolate* isolate = v8::Isolate::GetCurrent();
494 v8::HandleScope scope(isolate);
495 v8::Local<v8::Context> context = v8::Context::New(isolate);
496 v8::Context::Scope contextScope(context);
499 Timing::PlaybackDirection defaultPlaybackDirection = Timing::PlaybackDirectionNormal;
500 EXPECT_EQ(defaultPlaybackDirection, timing.direction);
502 applyTimingInputString(timing, isolate, "direction", "normal");
503 EXPECT_EQ(Timing::PlaybackDirectionNormal, timing.direction);
504 timing.direction = defaultPlaybackDirection;
506 applyTimingInputString(timing, isolate, "direction", "reverse");
507 EXPECT_EQ(Timing::PlaybackDirectionReverse, timing.direction);
508 timing.direction = defaultPlaybackDirection;
510 applyTimingInputString(timing, isolate, "direction", "alternate");
511 EXPECT_EQ(Timing::PlaybackDirectionAlternate, timing.direction);
512 timing.direction = defaultPlaybackDirection;
514 applyTimingInputString(timing, isolate, "direction", "alternate-reverse");
515 EXPECT_EQ(Timing::PlaybackDirectionAlternateReverse, timing.direction);
516 timing.direction = defaultPlaybackDirection;
518 applyTimingInputString(timing, isolate, "direction", "rubbish");
519 EXPECT_EQ(defaultPlaybackDirection, timing.direction);
520 timing.direction = defaultPlaybackDirection;
522 applyTimingInputNumber(timing, isolate, "direction", 2);
523 EXPECT_EQ(defaultPlaybackDirection, timing.direction);
524 timing.direction = defaultPlaybackDirection;
527 TEST_F(AnimationElementAnimationTest, TimingInputEmpty)
529 v8::Isolate* isolate = v8::Isolate::GetCurrent();
530 v8::HandleScope scope(isolate);
531 v8::Local<v8::Context> context = v8::Context::New(isolate);
532 v8::Context::Scope contextScope(context);
534 Timing updatedTiming;
535 Timing controlTiming;
537 v8::Handle<v8::Object> timingInput = v8::Object::New(isolate);
538 Dictionary timingInputDictionary = Dictionary(v8::Handle<v8::Value>::Cast(timingInput), isolate);
539 populateTiming(updatedTiming, timingInputDictionary);
541 EXPECT_EQ(controlTiming.startDelay, updatedTiming.startDelay);
542 EXPECT_EQ(controlTiming.fillMode, updatedTiming.fillMode);
543 EXPECT_EQ(controlTiming.iterationStart, updatedTiming.iterationStart);
544 EXPECT_EQ(controlTiming.iterationCount, updatedTiming.iterationCount);
545 EXPECT_EQ(controlTiming.iterationDuration, updatedTiming.iterationDuration);
546 EXPECT_EQ(controlTiming.hasIterationDuration, updatedTiming.hasIterationDuration);
547 EXPECT_EQ(controlTiming.playbackRate, updatedTiming.playbackRate);
548 EXPECT_EQ(controlTiming.direction, updatedTiming.direction);
551 } // namespace WebCore