diff options
Diffstat (limited to 'catapult/third_party/polymer/components/web-animations-js/src/tick.js')
-rw-r--r-- | catapult/third_party/polymer/components/web-animations-js/src/tick.js | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/web-animations-js/src/tick.js b/catapult/third_party/polymer/components/web-animations-js/src/tick.js new file mode 100644 index 00000000..08b0a140 --- /dev/null +++ b/catapult/third_party/polymer/components/web-animations-js/src/tick.js @@ -0,0 +1,181 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +(function(shared, scope, testing) { + var originalRequestAnimationFrame = window.requestAnimationFrame; + var rafCallbacks = []; + var rafId = 0; + window.requestAnimationFrame = function(f) { + var id = rafId++; + if (rafCallbacks.length == 0 && !WEB_ANIMATIONS_TESTING) { + originalRequestAnimationFrame(processRafCallbacks); + } + rafCallbacks.push([id, f]); + return id; + }; + + window.cancelAnimationFrame = function(id) { + rafCallbacks.forEach(function(entry) { + if (entry[0] == id) { + entry[1] = function() {}; + } + }); + }; + + function processRafCallbacks(t) { + var processing = rafCallbacks; + rafCallbacks = []; + if (t < timeline.currentTime) + t = timeline.currentTime; + timeline._animations.sort(compareAnimations); + timeline._animations = tick(t, true, timeline._animations)[0]; + processing.forEach(function(entry) { entry[1](t); }); + applyPendingEffects(); + _now = undefined; + } + + function compareAnimations(leftAnimation, rightAnimation) { + return leftAnimation._sequenceNumber - rightAnimation._sequenceNumber; + } + + function InternalTimeline() { + this._animations = []; + // Android 4.3 browser has window.performance, but not window.performance.now + this.currentTime = window.performance && performance.now ? performance.now() : 0; + }; + + InternalTimeline.prototype = { + _play: function(effect) { + effect._timing = shared.normalizeTimingInput(effect.timing); + var animation = new scope.Animation(effect); + animation._idle = false; + animation._timeline = this; + this._animations.push(animation); + scope.restart(); + scope.applyDirtiedAnimation(animation); + return animation; + } + }; + + var _now = undefined; + + if (WEB_ANIMATIONS_TESTING) { + var now = function() { return timeline.currentTime; }; + } else { + var now = function() { + if (_now == undefined) + _now = window.performance && performance.now ? performance.now() : Date.now(); + return _now; + }; + } + + var ticking = false; + var hasRestartedThisFrame = false; + + scope.restart = function() { + if (!ticking) { + ticking = true; + requestAnimationFrame(function() {}); + hasRestartedThisFrame = true; + } + return hasRestartedThisFrame; + }; + + // RAF is supposed to be the last script to occur before frame rendering but not + // all browsers behave like this. This function is for synchonously updating an + // animation's effects whenever its state is mutated by script to work around + // incorrect script execution ordering by the browser. + scope.applyDirtiedAnimation = function(animation) { + if (inTick) { + return; + } + animation._markTarget(); + var animations = animation._targetAnimations(); + animations.sort(compareAnimations); + var inactiveAnimations = tick(scope.timeline.currentTime, false, animations.slice())[1]; + inactiveAnimations.forEach(function(animation) { + var index = timeline._animations.indexOf(animation); + if (index !== -1) { + timeline._animations.splice(index, 1); + } + }); + applyPendingEffects(); + }; + + var pendingEffects = []; + function applyPendingEffects() { + pendingEffects.forEach(function(f) { f(); }); + pendingEffects.length = 0; + } + + var t60hz = 1000 / 60; + + var inTick = false; + function tick(t, isAnimationFrame, updatingAnimations) { + inTick = true; + hasRestartedThisFrame = false; + var timeline = scope.timeline; + + timeline.currentTime = t; + ticking = false; + + var newPendingClears = []; + var newPendingEffects = []; + var activeAnimations = []; + var inactiveAnimations = []; + updatingAnimations.forEach(function(animation) { + animation._tick(t, isAnimationFrame); + + if (!animation._inEffect) { + newPendingClears.push(animation._effect); + animation._unmarkTarget(); + } else { + newPendingEffects.push(animation._effect); + animation._markTarget(); + } + + if (animation._needsTick) + ticking = true; + + var alive = animation._inEffect || animation._needsTick; + animation._inTimeline = alive; + if (alive) { + activeAnimations.push(animation); + } else { + inactiveAnimations.push(animation); + } + }); + + // FIXME: Should remove dupliactes from pendingEffects. + pendingEffects.push.apply(pendingEffects, newPendingClears); + pendingEffects.push.apply(pendingEffects, newPendingEffects); + + if (ticking) + requestAnimationFrame(function() {}); + + inTick = false; + return [activeAnimations, inactiveAnimations]; + }; + + if (WEB_ANIMATIONS_TESTING) { + testing.tick = function(t) { timeline.currentTime = t; processRafCallbacks(t); }; + testing.isTicking = function() { return ticking; }; + testing.setTicking = function(newVal) { ticking = newVal; }; + } + + var timeline = new InternalTimeline(); + scope.timeline = timeline; + +})(webAnimationsShared, webAnimations1, webAnimationsTesting); |