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(function(shared, scope, testing) { 16 scope.Player = function(source) { 17 this.source = source; 18 if (source) { 19 // FIXME: detach existing player. 20 source.player = this; 21 } 22 this._isGroup = false; 23 this._player = null; 24 this._childPlayers = []; 25 this._callback = null; 26 this._rebuildUnderlyingPlayer(); 27 // Players are constructed in the idle state. 28 this._player.cancel(); 29 }; 30 31 // TODO: add a source getter/setter 32 scope.Player.prototype = { 33 _rebuildUnderlyingPlayer: function() { 34 if (this._player) { 35 this._player.cancel(); 36 this._player = null; 37 } 38 39 if (!this.source || this.source instanceof window.Animation) { 40 this._player = scope.newUnderlyingPlayerForAnimation(this.source); 41 scope.bindPlayerForAnimation(this); 42 } 43 if (this.source instanceof window.AnimationSequence || this.source instanceof window.AnimationGroup) { 44 this._player = scope.newUnderlyingPlayerForGroup(this.source); 45 scope.bindPlayerForGroup(this); 46 } 47 48 // FIXME: move existing currentTime/startTime/playState to new player 49 }, 50 get paused() { 51 return this._player.paused; 52 }, 53 get playState() { 54 return this._player.playState; 55 }, 56 get onfinish() { 57 return this._onfinish; 58 }, 59 set onfinish(v) { 60 if (typeof v == 'function') { 61 this._onfinish = v; 62 this._player.onfinish = (function(e) { 63 e.target = this; 64 v.call(this, e); 65 }).bind(this); 66 } else { 67 this._player.onfinish = v; 68 this.onfinish = this._player.onfinish; 69 } 70 }, 71 get currentTime() { 72 return this._player.currentTime; 73 }, 74 set currentTime(v) { 75 this._player.currentTime = v; 76 this._register(); 77 this._forEachChild(function(child, offset) { 78 child.currentTime = v - offset; 79 }); 80 }, 81 get startTime() { 82 return this._player.startTime; 83 }, 84 set startTime(v) { 85 this._player.startTime = v; 86 this._register(); 87 this._forEachChild(function(child, offset) { 88 child.startTime = v + offset; 89 }); 90 }, 91 get playbackRate() { 92 return this._player.playbackRate; 93 }, 94 set playbackRate(value) { 95 this._player.playbackRate = value; 96 this._forEachChild(function(childPlayer) { 97 childPlayer.playbackRate = value; 98 }); 99 }, 100 get finished() { 101 return this._player.finished; 102 }, 103 play: function() { 104 this._player.play(); 105 this._register(); 106 scope.awaitStartTime(this); 107 this._forEachChild(function(child) { 108 var time = child.currentTime; 109 child.play(); 110 child.currentTime = time; 111 }); 112 }, 113 pause: function() { 114 this._player.pause(); 115 this._register(); 116 this._forEachChild(function(child) { 117 child.pause(); 118 }); 119 }, 120 finish: function() { 121 this._player.finish(); 122 this._register(); 123 // TODO: child players?? 124 }, 125 cancel: function() { 126 this._player.cancel(); 127 this._register(); 128 this._removePlayers(); 129 }, 130 reverse: function() { 131 this._player.reverse(); 132 scope.awaitStartTime(this); 133 this._register(); 134 this._forEachChild(function(child, offset) { 135 child.reverse(); 136 child.startTime = this.startTime + offset * this.playbackRate; 137 child.currentTime = this.currentTime + offset * this.playbackRate; 138 }); 139 }, 140 addEventListener: function(type, handler) { 141 var wrapped = handler; 142 if (typeof handler == 'function') { 143 wrapped = (function(e) { 144 e.target = this; 145 handler.call(this, e); 146 }).bind(this); 147 handler._wrapper = wrapped; 148 } 149 this._player.addEventListener(type, wrapped); 150 }, 151 removeEventListener: function(type, handler) { 152 this._player.removeEventListener(type, (handler && handler._wrapper) || handler); 153 }, 154 _removePlayers: function() { 155 while (this._childPlayers.length) 156 this._childPlayers.pop().cancel(); 157 }, 158 _forEachChild: function(f) { 159 var offset = 0; 160 this._childPlayers.forEach(function(child) { 161 f.call(this, child, offset); 162 if (this.source instanceof window.AnimationSequence) 163 offset += child.source.activeDuration; 164 }.bind(this)); 165 }, 166 }; 167 168})(webAnimationsShared, webAnimationsNext, webAnimationsTesting); 169