• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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