|
40 | 40 | };
|
41 | 41 |
|
42 | 42 | var pendingGroups = [];
|
43 |
| - function addPendingGroup(group) { |
| 43 | + scope.awaitStartTime = function(groupPlayer) { |
| 44 | + if (!isNaN(groupPlayer.startTime) || !groupPlayer._isGroup) |
| 45 | + return; |
44 | 46 | if (pendingGroups.length == 0) {
|
45 | 47 | requestAnimationFrame(updatePendingGroups);
|
46 | 48 | }
|
47 |
| - pendingGroups.push(group); |
48 |
| - } |
| 49 | + pendingGroups.push(groupPlayer); |
| 50 | + }; |
49 | 51 | function updatePendingGroups() {
|
50 | 52 | var updated = false;
|
51 | 53 | while (pendingGroups.length) {
|
52 |
| - pendingGroups.shift()(); |
| 54 | + pendingGroups.shift()._updateChildren(); |
53 | 55 | updated = true;
|
54 | 56 | }
|
55 | 57 | return updated;
|
|
66 | 68 | },
|
67 | 69 | });
|
68 | 70 |
|
| 71 | + // TODO: Call into this less frequently. |
| 72 | + scope.Player.prototype._updateChildren = function() { |
| 73 | + if (isNaN(this.startTime) || !this.source || !this._isGroup) |
| 74 | + return; |
| 75 | + var offset = 0; |
| 76 | + for (var i = 0; i < this.source.children.length; i++) { |
| 77 | + var child = this.source.children[i]; |
| 78 | + var childPlayer; |
| 79 | + |
| 80 | + if (i >= this._childPlayers.length) { |
| 81 | + childPlayer = window.document.timeline.play(child); |
| 82 | + child.player = this.source.player; |
| 83 | + this._childPlayers.push(childPlayer); |
| 84 | + } else { |
| 85 | + childPlayer = this._childPlayers[i]; |
| 86 | + } |
| 87 | + |
| 88 | + if (childPlayer.startTime != this.startTime + offset) { |
| 89 | + childPlayer.startTime = this.startTime + offset; |
| 90 | + childPlayer._updateChildren(); |
| 91 | + } |
| 92 | + |
| 93 | + if (this.playbackRate == -1 && this.currentTime < offset && childPlayer.currentTime !== -1) { |
| 94 | + childPlayer.currentTime = -1; |
| 95 | + } |
| 96 | + |
| 97 | + if (this.source instanceof window.AnimationSequence) |
| 98 | + offset += child.activeDuration; |
| 99 | + } |
| 100 | + }; |
| 101 | + |
69 | 102 | window.document.timeline.play = function(source) {
|
| 103 | + // TODO: Handle effect callback. |
70 | 104 | if (source instanceof window.Animation) {
|
| 105 | + // TODO: Handle null target. |
71 | 106 | var player = source.target.animate(source._effect, source.timing);
|
72 |
| - // TODO: make source setter call cancel. |
73 | 107 | player.source = source;
|
74 | 108 | source.player = player;
|
75 |
| - source._nativePlayer = player; |
76 |
| - var cancel = player.cancel; |
77 |
| - player.cancel = function() { |
78 |
| - player.source = null; |
79 |
| - cancel.call(this); |
80 |
| - }; |
81 | 109 | return player;
|
82 | 110 | }
|
83 | 111 | // FIXME: Move this code out of this module
|
|
89 | 117 | player._removePlayers();
|
90 | 118 | return;
|
91 | 119 | }
|
92 |
| - if (isNaN(player._startTime)) |
| 120 | + if (isNaN(player.startTime)) |
93 | 121 | return;
|
94 | 122 |
|
95 |
| - updateChildPlayers(player); |
| 123 | + player._updateChildren(); |
96 | 124 | };
|
97 | 125 |
|
98 |
| - function updateChildPlayers(updatingPlayer) { |
99 |
| - var offset = 0; |
100 |
| - |
101 |
| - // TODO: Call into this less frequently. |
102 |
| - |
103 |
| - for (var i = 0; i < updatingPlayer.source.children.length; i++) { |
104 |
| - var child = updatingPlayer.source.children[i]; |
105 |
| - |
106 |
| - if (i >= updatingPlayer._childPlayers.length) { |
107 |
| - var newPlayer = window.document.timeline.play(child); |
108 |
| - newPlayer.startTime = updatingPlayer.startTime + offset; |
109 |
| - child.player = updatingPlayer.source.player; |
110 |
| - updatingPlayer._childPlayers.push(newPlayer); |
111 |
| - if (!(child instanceof window.Animation)) |
112 |
| - updateChildPlayers(newPlayer); |
113 |
| - } |
114 |
| - |
115 |
| - var childPlayer = updatingPlayer._childPlayers[i]; |
116 |
| - if (updatingPlayer.playbackRate == -1 && updatingPlayer.currentTime < offset && childPlayer.currentTime !== -1) { |
117 |
| - childPlayer.currentTime = -1; |
118 |
| - } |
119 |
| - |
120 |
| - if (updatingPlayer.source instanceof window.AnimationSequence) |
121 |
| - offset += child.activeDuration; |
122 |
| - } |
123 |
| - }; |
124 |
| - |
125 |
| - addPendingGroup(function() { |
126 |
| - if (player.source) |
127 |
| - updateChildPlayers(player); |
128 |
| - }); |
129 | 126 |
|
130 | 127 | // TODO: Use a single static element rather than one per group.
|
131 | 128 | var player = document.createElement('div').animate(ticker, source.timing);
|
132 |
| - player._childPlayers = []; |
133 | 129 | player.source = source;
|
134 |
| - source._nativePlayer = player; |
| 130 | + player._isGroup = true; |
135 | 131 | source.player = player;
|
136 |
| - |
137 |
| - player._removePlayers = function() { |
138 |
| - while (this._childPlayers.length) |
139 |
| - this._childPlayers.pop().cancel(); |
140 |
| - }; |
141 |
| - |
| 132 | + scope.awaitStartTime(player); |
142 | 133 | return player;
|
143 | 134 | }
|
144 | 135 | };
|
145 |
| - |
146 |
| - function isGroupPlayer(player) { |
147 |
| - return !!player._childPlayers; |
148 |
| - } |
149 |
| - |
150 |
| - var playerProto = Object.getPrototypeOf(document.documentElement.animate([])); |
151 |
| - scope.hookMethod(playerProto, 'reverse', function() { |
152 |
| - if (isGroupPlayer(this)) { |
153 |
| - var offset = 0; |
154 |
| - this._childPlayers.forEach(function(child) { |
155 |
| - child.reverse(); |
156 |
| - child.startTime = this.startTime + offset * this.playbackRate; |
157 |
| - child.currentTime = this.currentTime + offset * this.playbackRate; |
158 |
| - if (this.source instanceof window.AnimationSequence) |
159 |
| - offset += child.source.activeDuration; |
160 |
| - }.bind(this)); |
161 |
| - } |
162 |
| - }); |
163 |
| - |
164 |
| - scope.hookMethod(playerProto, 'pause', function() { |
165 |
| - if (isGroupPlayer(this)) { |
166 |
| - this._childPlayers.forEach(function(child) { |
167 |
| - child.pause(); |
168 |
| - }); |
169 |
| - } |
170 |
| - }); |
171 |
| - |
172 |
| - scope.hookMethod(playerProto, 'play', function() { |
173 |
| - if (isGroupPlayer(this)) { |
174 |
| - this._childPlayers.forEach(function(child) { |
175 |
| - var time = child.currentTime; |
176 |
| - child.play(); |
177 |
| - child.currentTime = time; |
178 |
| - }); |
179 |
| - } |
180 |
| - }); |
181 |
| - |
182 |
| - scope.hookMethod(playerProto, 'cancel', function() { |
183 |
| - if (isGroupPlayer(this)) { |
184 |
| - this.source = null; |
185 |
| - this._removePlayers(); |
186 |
| - } |
187 |
| - }); |
188 |
| - |
189 |
| - scope.hookSetter(playerProto, 'currentTime', function(v) { |
190 |
| - if (isGroupPlayer(this)) { |
191 |
| - var offset = 0; |
192 |
| - this._childPlayers.forEach(function(child) { |
193 |
| - child.currentTime = v - offset; |
194 |
| - if (this.source instanceof window.AnimationSequence) |
195 |
| - offset += child.source.activeDuration; |
196 |
| - }.bind(this)); |
197 |
| - } |
198 |
| - }); |
199 |
| - |
200 |
| - scope.hookSetter(playerProto, 'startTime', function(v) { |
201 |
| - if (isGroupPlayer(this)) { |
202 |
| - var offset = 0; |
203 |
| - this._childPlayers.forEach(function(child) { |
204 |
| - child.startTime = v + offset; |
205 |
| - if (this.source instanceof window.AnimationSequence) |
206 |
| - offset += child.source.activeDuration; |
207 |
| - }.bind(this)); |
208 |
| - } |
209 |
| - }); |
210 | 136 | }(webAnimationsShared, webAnimationsMaxifill, webAnimationsTesting));
|
0 commit comments