1// Copyright 2014 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15 16(function(shared, scope, testing) { 17 var originalRequestAnimationFrame = window.requestAnimationFrame; 18 window.requestAnimationFrame = function(f) { 19 return originalRequestAnimationFrame(function(x) { 20 scope.timeline._updateAnimationsPromises(); 21 f(x); 22 scope.timeline._updateAnimationsPromises(); 23 }); 24 }; 25 26 scope.AnimationTimeline = function() { 27 this._animations = []; 28 this.currentTime = undefined; 29 }; 30 31 scope.AnimationTimeline.prototype = { 32 getAnimations: function() { 33 this._discardAnimations(); 34 return this._animations.slice(); 35 }, 36 _updateAnimationsPromises: function() { 37 scope.animationsWithPromises = scope.animationsWithPromises.filter(function(animation) { 38 return animation._updatePromises(); 39 }); 40 }, 41 _discardAnimations: function() { 42 this._updateAnimationsPromises(); 43 this._animations = this._animations.filter(function(animation) { 44 return animation.playState != 'finished' && animation.playState != 'idle'; 45 }); 46 }, 47 _play: function(effect) { 48 var animation = new scope.Animation(effect, this); 49 this._animations.push(animation); 50 scope.restartWebAnimationsNextTick(); 51 // Use animation._animation.play() here, NOT animation.play(). 52 // 53 // Timeline.play calls new scope.Animation(effect) which (indirectly) calls Timeline.play on 54 // effect's children, and Animation.play is also recursive. We only need to call play on each 55 // animation in the tree once. 56 animation._updatePromises(); 57 animation._animation.play(); 58 animation._updatePromises(); 59 return animation; 60 }, 61 play: function(effect) { 62 if (effect) { 63 effect.remove(); 64 } 65 return this._play(effect); 66 } 67 }; 68 69 var ticking = false; 70 71 scope.restartWebAnimationsNextTick = function() { 72 if (!ticking) { 73 ticking = true; 74 requestAnimationFrame(webAnimationsNextTick); 75 } 76 }; 77 78 function webAnimationsNextTick(t) { 79 var timeline = scope.timeline; 80 timeline.currentTime = t; 81 timeline._discardAnimations(); 82 if (timeline._animations.length == 0) 83 ticking = false; 84 else 85 requestAnimationFrame(webAnimationsNextTick); 86 } 87 88 var timeline = new scope.AnimationTimeline(); 89 scope.timeline = timeline; 90 91 try { 92 Object.defineProperty(window.document, 'timeline', { 93 configurable: true, 94 get: function() { return timeline; } 95 }); 96 } catch (e) { } 97 try { 98 window.document.timeline = timeline; 99 } catch (e) { } 100 101})(webAnimationsShared, webAnimationsNext, webAnimationsTesting); 102