aboutsummaryrefslogtreecommitdiff
path: root/catapult/third_party/polymer/components/web-animations-js/src/web-animations-next-animation.js
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/third_party/polymer/components/web-animations-js/src/web-animations-next-animation.js')
-rw-r--r--catapult/third_party/polymer/components/web-animations-js/src/web-animations-next-animation.js383
1 files changed, 383 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/web-animations-js/src/web-animations-next-animation.js b/catapult/third_party/polymer/components/web-animations-js/src/web-animations-next-animation.js
new file mode 100644
index 00000000..698532cd
--- /dev/null
+++ b/catapult/third_party/polymer/components/web-animations-js/src/web-animations-next-animation.js
@@ -0,0 +1,383 @@
+// 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) {
+ scope.animationsWithPromises = [];
+
+ scope.Animation = function(effect, timeline) {
+ this.id = '';
+ if (effect && effect._id) {
+ this.id = effect._id;
+ }
+ this.effect = effect;
+ if (effect) {
+ effect._animation = this;
+ }
+ if (!timeline) {
+ throw new Error('Animation with null timeline is not supported');
+ }
+ this._timeline = timeline;
+ this._sequenceNumber = shared.sequenceNumber++;
+ this._holdTime = 0;
+ this._paused = false;
+ this._isGroup = false;
+ this._animation = null;
+ this._childAnimations = [];
+ this._callback = null;
+ this._oldPlayState = 'idle';
+ this._rebuildUnderlyingAnimation();
+ // Animations are constructed in the idle state.
+ this._animation.cancel();
+ this._updatePromises();
+ };
+
+ scope.Animation.prototype = {
+ _updatePromises: function() {
+ var oldPlayState = this._oldPlayState;
+ var newPlayState = this.playState;
+ if (this._readyPromise && newPlayState !== oldPlayState) {
+ if (newPlayState == 'idle') {
+ this._rejectReadyPromise();
+ this._readyPromise = undefined;
+ } else if (oldPlayState == 'pending') {
+ this._resolveReadyPromise();
+ } else if (newPlayState == 'pending') {
+ this._readyPromise = undefined;
+ }
+ }
+ if (this._finishedPromise && newPlayState !== oldPlayState) {
+ if (newPlayState == 'idle') {
+ this._rejectFinishedPromise();
+ this._finishedPromise = undefined;
+ } else if (newPlayState == 'finished') {
+ this._resolveFinishedPromise();
+ } else if (oldPlayState == 'finished') {
+ this._finishedPromise = undefined;
+ }
+ }
+ this._oldPlayState = this.playState;
+ return (this._readyPromise || this._finishedPromise);
+ },
+ _rebuildUnderlyingAnimation: function() {
+ this._updatePromises();
+ var oldPlaybackRate;
+ var oldPaused;
+ var oldStartTime;
+ var oldCurrentTime;
+ var hadUnderlying = this._animation ? true : false;
+ if (hadUnderlying) {
+ oldPlaybackRate = this.playbackRate;
+ oldPaused = this._paused;
+ oldStartTime = this.startTime;
+ oldCurrentTime = this.currentTime;
+ this._animation.cancel();
+ this._animation._wrapper = null;
+ this._animation = null;
+ }
+
+ if (!this.effect || this.effect instanceof window.KeyframeEffect) {
+ this._animation = scope.newUnderlyingAnimationForKeyframeEffect(this.effect);
+ scope.bindAnimationForKeyframeEffect(this);
+ }
+ if (this.effect instanceof window.SequenceEffect || this.effect instanceof window.GroupEffect) {
+ this._animation = scope.newUnderlyingAnimationForGroup(this.effect);
+ scope.bindAnimationForGroup(this);
+ }
+ if (this.effect && this.effect._onsample) {
+ scope.bindAnimationForCustomEffect(this);
+ }
+ if (hadUnderlying) {
+ if (oldPlaybackRate != 1) {
+ this.playbackRate = oldPlaybackRate;
+ }
+ if (oldStartTime !== null) {
+ this.startTime = oldStartTime;
+ } else if (oldCurrentTime !== null) {
+ this.currentTime = oldCurrentTime;
+ } else if (this._holdTime !== null) {
+ this.currentTime = this._holdTime;
+ }
+ if (oldPaused) {
+ this.pause();
+ }
+ }
+ this._updatePromises();
+ },
+ _updateChildren: function() {
+ if (!this.effect || this.playState == 'idle')
+ return;
+
+ var offset = this.effect._timing.delay;
+ this._childAnimations.forEach(function(childAnimation) {
+ this._arrangeChildren(childAnimation, offset);
+ if (this.effect instanceof window.SequenceEffect)
+ offset += scope.groupChildDuration(childAnimation.effect);
+ }.bind(this));
+ },
+ _setExternalAnimation: function(animation) {
+ if (!this.effect || !this._isGroup)
+ return;
+ for (var i = 0; i < this.effect.children.length; i++) {
+ this.effect.children[i]._animation = animation;
+ this._childAnimations[i]._setExternalAnimation(animation);
+ }
+ },
+ _constructChildAnimations: function() {
+ if (!this.effect || !this._isGroup)
+ return;
+ var offset = this.effect._timing.delay;
+ this._removeChildAnimations();
+ this.effect.children.forEach(function(child) {
+ var childAnimation = scope.timeline._play(child);
+ this._childAnimations.push(childAnimation);
+ childAnimation.playbackRate = this.playbackRate;
+ if (this._paused)
+ childAnimation.pause();
+ child._animation = this.effect._animation;
+
+ this._arrangeChildren(childAnimation, offset);
+
+ if (this.effect instanceof window.SequenceEffect)
+ offset += scope.groupChildDuration(child);
+ }.bind(this));
+ },
+ _arrangeChildren: function(childAnimation, offset) {
+ if (this.startTime === null) {
+ childAnimation.currentTime = this.currentTime - offset / this.playbackRate;
+ } else if (childAnimation.startTime !== this.startTime + offset / this.playbackRate) {
+ childAnimation.startTime = this.startTime + offset / this.playbackRate;
+ }
+ },
+ get timeline() {
+ return this._timeline;
+ },
+ get playState() {
+ return this._animation ? this._animation.playState : 'idle';
+ },
+ get finished() {
+ if (!window.Promise) {
+ console.warn('Animation Promises require JavaScript Promise constructor');
+ return null;
+ }
+ if (!this._finishedPromise) {
+ if (scope.animationsWithPromises.indexOf(this) == -1) {
+ scope.animationsWithPromises.push(this);
+ }
+ this._finishedPromise = new Promise(
+ function(resolve, reject) {
+ this._resolveFinishedPromise = function() {
+ resolve(this);
+ };
+ this._rejectFinishedPromise = function() {
+ reject({type: DOMException.ABORT_ERR, name: 'AbortError'});
+ };
+ }.bind(this));
+ if (this.playState == 'finished') {
+ this._resolveFinishedPromise();
+ }
+ }
+ return this._finishedPromise;
+ },
+ get ready() {
+ if (!window.Promise) {
+ console.warn('Animation Promises require JavaScript Promise constructor');
+ return null;
+ }
+ if (!this._readyPromise) {
+ if (scope.animationsWithPromises.indexOf(this) == -1) {
+ scope.animationsWithPromises.push(this);
+ }
+ this._readyPromise = new Promise(
+ function(resolve, reject) {
+ this._resolveReadyPromise = function() {
+ resolve(this);
+ };
+ this._rejectReadyPromise = function() {
+ reject({type: DOMException.ABORT_ERR, name: 'AbortError'});
+ };
+ }.bind(this));
+ if (this.playState !== 'pending') {
+ this._resolveReadyPromise();
+ }
+ }
+ return this._readyPromise;
+ },
+ get onfinish() {
+ return this._animation.onfinish;
+ },
+ set onfinish(v) {
+ if (typeof v == 'function') {
+ this._animation.onfinish = (function(e) {
+ e.target = this;
+ v.call(this, e);
+ }).bind(this);
+ } else {
+ this._animation.onfinish = v;
+ }
+ },
+ get oncancel() {
+ return this._animation.oncancel;
+ },
+ set oncancel(v) {
+ if (typeof v == 'function') {
+ this._animation.oncancel = (function(e) {
+ e.target = this;
+ v.call(this, e);
+ }).bind(this);
+ } else {
+ this._animation.oncancel = v;
+ }
+ },
+ get currentTime() {
+ this._updatePromises();
+ var currentTime = this._animation.currentTime;
+ this._updatePromises();
+ return currentTime;
+ },
+ set currentTime(v) {
+ this._updatePromises();
+ this._animation.currentTime = isFinite(v) ? v : Math.sign(v) * Number.MAX_VALUE;
+ this._register();
+ this._forEachChild(function(child, offset) {
+ child.currentTime = v - offset;
+ });
+ this._updatePromises();
+ },
+ get startTime() {
+ return this._animation.startTime;
+ },
+ set startTime(v) {
+ this._updatePromises();
+ this._animation.startTime = isFinite(v) ? v : Math.sign(v) * Number.MAX_VALUE;
+ this._register();
+ this._forEachChild(function(child, offset) {
+ child.startTime = v + offset;
+ });
+ this._updatePromises();
+ },
+ get playbackRate() {
+ return this._animation.playbackRate;
+ },
+ set playbackRate(value) {
+ this._updatePromises();
+ var oldCurrentTime = this.currentTime;
+ this._animation.playbackRate = value;
+ this._forEachChild(function(childAnimation) {
+ childAnimation.playbackRate = value;
+ });
+ if (oldCurrentTime !== null) {
+ this.currentTime = oldCurrentTime;
+ }
+ this._updatePromises();
+ },
+ play: function() {
+ this._updatePromises();
+ this._paused = false;
+ this._animation.play();
+ if (this._timeline._animations.indexOf(this) == -1) {
+ this._timeline._animations.push(this);
+ }
+ this._register();
+ scope.awaitStartTime(this);
+ this._forEachChild(function(child) {
+ var time = child.currentTime;
+ child.play();
+ child.currentTime = time;
+ });
+ this._updatePromises();
+ },
+ pause: function() {
+ this._updatePromises();
+ if (this.currentTime) {
+ this._holdTime = this.currentTime;
+ }
+ this._animation.pause();
+ this._register();
+ this._forEachChild(function(child) {
+ child.pause();
+ });
+ this._paused = true;
+ this._updatePromises();
+ },
+ finish: function() {
+ this._updatePromises();
+ this._animation.finish();
+ this._register();
+ this._updatePromises();
+ },
+ cancel: function() {
+ this._updatePromises();
+ this._animation.cancel();
+ this._register();
+ this._removeChildAnimations();
+ this._updatePromises();
+ },
+ reverse: function() {
+ this._updatePromises();
+ var oldCurrentTime = this.currentTime;
+ this._animation.reverse();
+ this._forEachChild(function(childAnimation) {
+ childAnimation.reverse();
+ });
+ if (oldCurrentTime !== null) {
+ this.currentTime = oldCurrentTime;
+ }
+ this._updatePromises();
+ },
+ addEventListener: function(type, handler) {
+ var wrapped = handler;
+ if (typeof handler == 'function') {
+ wrapped = (function(e) {
+ e.target = this;
+ handler.call(this, e);
+ }).bind(this);
+ handler._wrapper = wrapped;
+ }
+ this._animation.addEventListener(type, wrapped);
+ },
+ removeEventListener: function(type, handler) {
+ this._animation.removeEventListener(type, (handler && handler._wrapper) || handler);
+ },
+ _removeChildAnimations: function() {
+ while (this._childAnimations.length)
+ this._childAnimations.pop().cancel();
+ },
+ _forEachChild: function(f) {
+ var offset = 0;
+ if (this.effect.children && this._childAnimations.length < this.effect.children.length)
+ this._constructChildAnimations();
+ this._childAnimations.forEach(function(child) {
+ f.call(this, child, offset);
+ if (this.effect instanceof window.SequenceEffect)
+ offset += child.effect.activeDuration;
+ }.bind(this));
+
+ if (this.playState == 'pending')
+ return;
+ var timing = this.effect._timing;
+ var t = this.currentTime;
+ if (t !== null)
+ t = shared.calculateIterationProgress(shared.calculateActiveDuration(timing), t, timing);
+ if (t == null || isNaN(t))
+ this._removeChildAnimations();
+ },
+ };
+
+ window.Animation = scope.Animation;
+
+ if (WEB_ANIMATIONS_TESTING) {
+ testing.webAnimationsNextAnimation = scope.Animation;
+ }
+
+})(webAnimationsShared, webAnimationsNext, webAnimationsTesting);