1 // Copyright 2014 Google Inc. All rights reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
16 (function(shared, scope, testing) {
17 var originalRequestAnimationFrame = window.requestAnimationFrame;
18 var rafCallbacks = [];
20 window.requestAnimationFrame = function(f) {
22 if (rafCallbacks.length == 0 && !WEB_ANIMATIONS_TESTING) {
23 originalRequestAnimationFrame(processRafCallbacks);
25 rafCallbacks.push([id, f]);
29 window.cancelAnimationFrame = function(id) {
30 rafCallbacks.forEach(function(entry) {
32 entry[1] = function() {};
37 function processRafCallbacks(t) {
38 var processing = rafCallbacks;
41 processing.forEach(function(entry) { entry[1](t); });
44 applyPendingEffects();
47 function comparePlayers(leftPlayer, rightPlayer) {
48 return leftPlayer._sequenceNumber - rightPlayer._sequenceNumber;
51 function InternalTimeline() {
53 // Android 4.3 browser has window.performance, but not window.performance.now
54 this.currentTime = window.performance && performance.now ? performance.now() : 0;
57 InternalTimeline.prototype = {
58 _play: function(source) {
59 source._timing = shared.normalizeTimingInput(source.timing);
60 var player = new scope.Player(source);
62 player._timeline = this;
63 this._players.push(player);
65 scope.invalidateEffects();
71 var hasRestartedThisFrame = false;
73 scope.restart = function() {
76 requestAnimationFrame(function() {});
77 hasRestartedThisFrame = true;
79 return hasRestartedThisFrame;
82 var needsRetick = false;
83 scope.invalidateEffects = function() {
87 var pendingEffects = [];
88 function applyPendingEffects() {
89 pendingEffects.forEach(function(f) { f(); });
92 var originalGetComputedStyle = window.getComputedStyle;
93 Object.defineProperty(window, 'getComputedStyle', {
97 if (needsRetick) tick(timeline.currentTime);
98 applyPendingEffects();
99 return originalGetComputedStyle.apply(this, arguments);
104 hasRestartedThisFrame = false;
105 var timeline = scope.timeline;
106 timeline.currentTime = t;
107 timeline._players.sort(comparePlayers);
109 var updatingPlayers = timeline._players;
110 timeline._players = [];
112 var newPendingClears = [];
113 var newPendingEffects = [];
114 updatingPlayers = updatingPlayers.filter(function(player) {
115 player._inTimeline = player._tick(t);
117 if (!player._inEffect)
118 newPendingClears.push(player._source);
120 newPendingEffects.push(player._source);
122 if (!player.finished && !player.paused && !player._idle)
125 return player._inTimeline;
128 pendingEffects.length = 0;
129 pendingEffects.push.apply(pendingEffects, newPendingClears);
130 pendingEffects.push.apply(pendingEffects, newPendingEffects);
132 timeline._players.push.apply(timeline._players, updatingPlayers);
136 requestAnimationFrame(function() {});
139 if (WEB_ANIMATIONS_TESTING) {
140 testing.tick = processRafCallbacks;
141 testing.isTicking = function() { return ticking; };
142 testing.setTicking = function(newVal) { ticking = newVal; };
145 var timeline = new InternalTimeline();
146 scope.timeline = timeline;
148 })(webAnimationsShared, webAnimations1, webAnimationsTesting);