OLD | NEW |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | |
6 /** | 5 /** |
7 * @constructor | 6 * @unrestricted |
8 * @extends {WebInspector.SDKModel} | |
9 * @param {!WebInspector.Target} target | |
10 */ | 7 */ |
11 WebInspector.AnimationModel = function(target) | 8 WebInspector.AnimationModel = class extends WebInspector.SDKModel { |
12 { | 9 /** |
13 WebInspector.SDKModel.call(this, WebInspector.AnimationModel, target); | 10 * @param {!WebInspector.Target} target |
| 11 */ |
| 12 constructor(target) { |
| 13 super(WebInspector.AnimationModel, target); |
14 this._agent = target.animationAgent(); | 14 this._agent = target.animationAgent(); |
15 target.registerAnimationDispatcher(new WebInspector.AnimationDispatcher(this
)); | 15 target.registerAnimationDispatcher(new WebInspector.AnimationDispatcher(this
)); |
16 /** @type {!Map.<string, !WebInspector.AnimationModel.Animation>} */ | 16 /** @type {!Map.<string, !WebInspector.AnimationModel.Animation>} */ |
17 this._animationsById = new Map(); | 17 this._animationsById = new Map(); |
18 /** @type {!Map.<string, !WebInspector.AnimationModel.AnimationGroup>} */ | 18 /** @type {!Map.<string, !WebInspector.AnimationModel.AnimationGroup>} */ |
19 this._animationGroups = new Map(); | 19 this._animationGroups = new Map(); |
20 /** @type {!Array.<string>} */ | 20 /** @type {!Array.<string>} */ |
21 this._pendingAnimations = []; | 21 this._pendingAnimations = []; |
22 this._playbackRate = 1; | 22 this._playbackRate = 1; |
23 var resourceTreeModel = /** @type {!WebInspector.ResourceTreeModel} */ (WebI
nspector.ResourceTreeModel.fromTarget(target)); | 23 var resourceTreeModel = |
| 24 /** @type {!WebInspector.ResourceTreeModel} */ (WebInspector.ResourceTre
eModel.fromTarget(target)); |
24 resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.Events.Mai
nFrameNavigated, this._reset, this); | 25 resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.Events.Mai
nFrameNavigated, this._reset, this); |
25 this._screenshotCapture = new WebInspector.AnimationModel.ScreenshotCapture(
target, this, resourceTreeModel); | 26 this._screenshotCapture = new WebInspector.AnimationModel.ScreenshotCapture(
target, this, resourceTreeModel); |
| 27 } |
| 28 |
| 29 /** |
| 30 * @param {!WebInspector.Target} target |
| 31 * @return {?WebInspector.AnimationModel} |
| 32 */ |
| 33 static fromTarget(target) { |
| 34 if (!target.hasDOMCapability()) |
| 35 return null; |
| 36 if (!target[WebInspector.AnimationModel._symbol]) |
| 37 target[WebInspector.AnimationModel._symbol] = new WebInspector.AnimationMo
del(target); |
| 38 |
| 39 return target[WebInspector.AnimationModel._symbol]; |
| 40 } |
| 41 |
| 42 _reset() { |
| 43 this._animationsById.clear(); |
| 44 this._animationGroups.clear(); |
| 45 this._pendingAnimations = []; |
| 46 this.dispatchEventToListeners(WebInspector.AnimationModel.Events.ModelReset)
; |
| 47 } |
| 48 |
| 49 /** |
| 50 * @param {string} id |
| 51 */ |
| 52 animationCreated(id) { |
| 53 this._pendingAnimations.push(id); |
| 54 } |
| 55 |
| 56 /** |
| 57 * @param {string} id |
| 58 */ |
| 59 _animationCanceled(id) { |
| 60 this._pendingAnimations.remove(id); |
| 61 this._flushPendingAnimationsIfNeeded(); |
| 62 } |
| 63 |
| 64 /** |
| 65 * @param {!AnimationAgent.Animation} payload |
| 66 */ |
| 67 animationStarted(payload) { |
| 68 var animation = WebInspector.AnimationModel.Animation.parsePayload(this.targ
et(), payload); |
| 69 |
| 70 // Ignore Web Animations custom effects & groups. |
| 71 if (animation.type() === 'WebAnimation' && animation.source().keyframesRule(
).keyframes().length === 0) { |
| 72 this._pendingAnimations.remove(animation.id()); |
| 73 } else { |
| 74 this._animationsById.set(animation.id(), animation); |
| 75 if (this._pendingAnimations.indexOf(animation.id()) === -1) |
| 76 this._pendingAnimations.push(animation.id()); |
| 77 } |
| 78 |
| 79 this._flushPendingAnimationsIfNeeded(); |
| 80 } |
| 81 |
| 82 _flushPendingAnimationsIfNeeded() { |
| 83 for (var id of this._pendingAnimations) { |
| 84 if (!this._animationsById.get(id)) |
| 85 return; |
| 86 } |
| 87 |
| 88 while (this._pendingAnimations.length) |
| 89 this._matchExistingGroups(this._createGroupFromPendingAnimations()); |
| 90 } |
| 91 |
| 92 /** |
| 93 * @param {!WebInspector.AnimationModel.AnimationGroup} incomingGroup |
| 94 * @return {boolean} |
| 95 */ |
| 96 _matchExistingGroups(incomingGroup) { |
| 97 var matchedGroup = null; |
| 98 for (var group of this._animationGroups.values()) { |
| 99 if (group._matches(incomingGroup)) { |
| 100 matchedGroup = group; |
| 101 group._update(incomingGroup); |
| 102 break; |
| 103 } |
| 104 } |
| 105 |
| 106 if (!matchedGroup) { |
| 107 this._animationGroups.set(incomingGroup.id(), incomingGroup); |
| 108 this._screenshotCapture.captureScreenshots(incomingGroup.finiteDuration(),
incomingGroup._screenshots); |
| 109 } |
| 110 this.dispatchEventToListeners( |
| 111 WebInspector.AnimationModel.Events.AnimationGroupStarted, matchedGroup |
| incomingGroup); |
| 112 return !!matchedGroup; |
| 113 } |
| 114 |
| 115 /** |
| 116 * @return {!WebInspector.AnimationModel.AnimationGroup} |
| 117 */ |
| 118 _createGroupFromPendingAnimations() { |
| 119 console.assert(this._pendingAnimations.length); |
| 120 var groupedAnimations = [this._animationsById.get(this._pendingAnimations.sh
ift())]; |
| 121 var remainingAnimations = []; |
| 122 for (var id of this._pendingAnimations) { |
| 123 var anim = this._animationsById.get(id); |
| 124 if (anim.startTime() === groupedAnimations[0].startTime()) |
| 125 groupedAnimations.push(anim); |
| 126 else |
| 127 remainingAnimations.push(id); |
| 128 } |
| 129 this._pendingAnimations = remainingAnimations; |
| 130 return new WebInspector.AnimationModel.AnimationGroup(this, groupedAnimation
s[0].id(), groupedAnimations); |
| 131 } |
| 132 |
| 133 /** |
| 134 * @return {!Promise.<number>} |
| 135 */ |
| 136 playbackRatePromise() { |
| 137 /** |
| 138 * @param {?Protocol.Error} error |
| 139 * @param {number} playbackRate |
| 140 * @return {number} |
| 141 * @this {!WebInspector.AnimationModel} |
| 142 */ |
| 143 function callback(error, playbackRate) { |
| 144 if (error) |
| 145 return 1; |
| 146 this._playbackRate = playbackRate; |
| 147 return playbackRate; |
| 148 } |
| 149 |
| 150 return this._agent.getPlaybackRate(callback.bind(this)).catchException(1); |
| 151 } |
| 152 |
| 153 /** |
| 154 * @param {number} playbackRate |
| 155 */ |
| 156 setPlaybackRate(playbackRate) { |
| 157 this._playbackRate = playbackRate; |
| 158 this._agent.setPlaybackRate(playbackRate); |
| 159 } |
| 160 |
| 161 /** |
| 162 * @param {!Array.<string>} animations |
| 163 */ |
| 164 _releaseAnimations(animations) { |
| 165 this.target().animationAgent().releaseAnimations(animations); |
| 166 } |
| 167 |
| 168 /** |
| 169 * @override |
| 170 * @return {!Promise} |
| 171 */ |
| 172 suspendModel() { |
| 173 this._reset(); |
| 174 return this._agent.disable(); |
| 175 } |
| 176 |
| 177 /** |
| 178 * @override |
| 179 * @return {!Promise} |
| 180 */ |
| 181 resumeModel() { |
| 182 if (!this._enabled) |
| 183 return Promise.resolve(); |
| 184 return this._agent.enable(); |
| 185 } |
| 186 |
| 187 ensureEnabled() { |
| 188 if (this._enabled) |
| 189 return; |
| 190 this._agent.enable(); |
| 191 this._enabled = true; |
| 192 } |
26 }; | 193 }; |
27 | 194 |
28 /** @enum {symbol} */ | 195 /** @enum {symbol} */ |
29 WebInspector.AnimationModel.Events = { | 196 WebInspector.AnimationModel.Events = { |
30 AnimationGroupStarted: Symbol("AnimationGroupStarted"), | 197 AnimationGroupStarted: Symbol('AnimationGroupStarted'), |
31 ModelReset: Symbol("ModelReset") | 198 ModelReset: Symbol('ModelReset') |
32 }; | 199 }; |
33 | 200 |
34 WebInspector.AnimationModel.prototype = { | 201 WebInspector.AnimationModel._symbol = Symbol('AnimationModel'); |
35 _reset: function() | 202 |
36 { | |
37 this._animationsById.clear(); | |
38 this._animationGroups.clear(); | |
39 this._pendingAnimations = []; | |
40 this.dispatchEventToListeners(WebInspector.AnimationModel.Events.ModelRe
set); | |
41 }, | |
42 | |
43 /** | |
44 * @param {string} id | |
45 */ | |
46 animationCreated: function(id) | |
47 { | |
48 this._pendingAnimations.push(id); | |
49 }, | |
50 | |
51 /** | |
52 * @param {string} id | |
53 */ | |
54 _animationCanceled: function(id) | |
55 { | |
56 this._pendingAnimations.remove(id); | |
57 this._flushPendingAnimationsIfNeeded(); | |
58 }, | |
59 | |
60 /** | |
61 * @param {!AnimationAgent.Animation} payload | |
62 */ | |
63 animationStarted: function(payload) | |
64 { | |
65 var animation = WebInspector.AnimationModel.Animation.parsePayload(this.
target(), payload); | |
66 | |
67 // Ignore Web Animations custom effects & groups. | |
68 if (animation.type() === "WebAnimation" && animation.source().keyframesR
ule().keyframes().length === 0) { | |
69 this._pendingAnimations.remove(animation.id()); | |
70 } else { | |
71 this._animationsById.set(animation.id(), animation); | |
72 if (this._pendingAnimations.indexOf(animation.id()) === -1) | |
73 this._pendingAnimations.push(animation.id()); | |
74 } | |
75 | |
76 this._flushPendingAnimationsIfNeeded(); | |
77 }, | |
78 | |
79 _flushPendingAnimationsIfNeeded: function() | |
80 { | |
81 for (var id of this._pendingAnimations) { | |
82 if (!this._animationsById.get(id)) | |
83 return; | |
84 } | |
85 | |
86 while (this._pendingAnimations.length) | |
87 this._matchExistingGroups(this._createGroupFromPendingAnimations()); | |
88 }, | |
89 | |
90 /** | |
91 * @param {!WebInspector.AnimationModel.AnimationGroup} incomingGroup | |
92 * @return {boolean} | |
93 */ | |
94 _matchExistingGroups: function(incomingGroup) | |
95 { | |
96 var matchedGroup = null; | |
97 for (var group of this._animationGroups.values()) { | |
98 if (group._matches(incomingGroup)) { | |
99 matchedGroup = group; | |
100 group._update(incomingGroup); | |
101 break; | |
102 } | |
103 } | |
104 | |
105 if (!matchedGroup) { | |
106 this._animationGroups.set(incomingGroup.id(), incomingGroup); | |
107 this._screenshotCapture.captureScreenshots(incomingGroup.finiteDurat
ion(), incomingGroup._screenshots); | |
108 } | |
109 this.dispatchEventToListeners(WebInspector.AnimationModel.Events.Animati
onGroupStarted, matchedGroup || incomingGroup); | |
110 return !!matchedGroup; | |
111 }, | |
112 | |
113 /** | |
114 * @return {!WebInspector.AnimationModel.AnimationGroup} | |
115 */ | |
116 _createGroupFromPendingAnimations: function() | |
117 { | |
118 console.assert(this._pendingAnimations.length); | |
119 var groupedAnimations = [this._animationsById.get(this._pendingAnimation
s.shift())]; | |
120 var remainingAnimations = []; | |
121 for (var id of this._pendingAnimations) { | |
122 var anim = this._animationsById.get(id); | |
123 if (anim.startTime() === groupedAnimations[0].startTime()) | |
124 groupedAnimations.push(anim); | |
125 else | |
126 remainingAnimations.push(id); | |
127 } | |
128 this._pendingAnimations = remainingAnimations; | |
129 return new WebInspector.AnimationModel.AnimationGroup(this, groupedAnima
tions[0].id(), groupedAnimations); | |
130 }, | |
131 | |
132 /** | |
133 * @return {!Promise.<number>} | |
134 */ | |
135 playbackRatePromise: function() | |
136 { | |
137 /** | |
138 * @param {?Protocol.Error} error | |
139 * @param {number} playbackRate | |
140 * @return {number} | |
141 * @this {!WebInspector.AnimationModel} | |
142 */ | |
143 function callback(error, playbackRate) | |
144 { | |
145 if (error) | |
146 return 1; | |
147 this._playbackRate = playbackRate; | |
148 return playbackRate; | |
149 } | |
150 | |
151 return this._agent.getPlaybackRate(callback.bind(this)).catchException(1
); | |
152 }, | |
153 | |
154 /** | |
155 * @param {number} playbackRate | |
156 */ | |
157 setPlaybackRate: function(playbackRate) | |
158 { | |
159 this._playbackRate = playbackRate; | |
160 this._agent.setPlaybackRate(playbackRate); | |
161 }, | |
162 | |
163 /** | |
164 * @param {!Array.<string>} animations | |
165 */ | |
166 _releaseAnimations: function(animations) | |
167 { | |
168 this.target().animationAgent().releaseAnimations(animations); | |
169 }, | |
170 | |
171 /** | |
172 * @override | |
173 * @return {!Promise} | |
174 */ | |
175 suspendModel: function() | |
176 { | |
177 this._reset(); | |
178 return this._agent.disable(); | |
179 }, | |
180 | |
181 /** | |
182 * @override | |
183 * @return {!Promise} | |
184 */ | |
185 resumeModel: function() | |
186 { | |
187 if (!this._enabled) | |
188 return Promise.resolve(); | |
189 return this._agent.enable(); | |
190 }, | |
191 | |
192 ensureEnabled: function() | |
193 { | |
194 if (this._enabled) | |
195 return; | |
196 this._agent.enable(); | |
197 this._enabled = true; | |
198 }, | |
199 | |
200 __proto__: WebInspector.SDKModel.prototype | |
201 }; | |
202 | |
203 WebInspector.AnimationModel._symbol = Symbol("AnimationModel"); | |
204 | 203 |
205 /** | 204 /** |
206 * @param {!WebInspector.Target} target | 205 * @unrestricted |
207 * @return {?WebInspector.AnimationModel} | |
208 */ | 206 */ |
209 WebInspector.AnimationModel.fromTarget = function(target) | 207 WebInspector.AnimationModel.Animation = class extends WebInspector.SDKObject { |
210 { | 208 /** |
211 if (!target.hasDOMCapability()) | 209 * @param {!WebInspector.Target} target |
212 return null; | 210 * @param {!AnimationAgent.Animation} payload |
213 if (!target[WebInspector.AnimationModel._symbol]) | 211 */ |
214 target[WebInspector.AnimationModel._symbol] = new WebInspector.Animation
Model(target); | 212 constructor(target, payload) { |
215 | 213 super(target); |
216 return target[WebInspector.AnimationModel._symbol]; | |
217 }; | |
218 | |
219 /** | |
220 * @constructor | |
221 * @extends {WebInspector.SDKObject} | |
222 * @param {!WebInspector.Target} target | |
223 * @param {!AnimationAgent.Animation} payload | |
224 */ | |
225 WebInspector.AnimationModel.Animation = function(target, payload) | |
226 { | |
227 WebInspector.SDKObject.call(this, target); | |
228 this._payload = payload; | 214 this._payload = payload; |
229 this._source = new WebInspector.AnimationModel.AnimationEffect(this.target()
, this._payload.source); | 215 this._source = new WebInspector.AnimationModel.AnimationEffect(this.target()
, this._payload.source); |
230 }; | 216 } |
231 | 217 |
232 /** | 218 /** |
233 * @param {!WebInspector.Target} target | 219 * @param {!WebInspector.Target} target |
234 * @param {!AnimationAgent.Animation} payload | 220 * @param {!AnimationAgent.Animation} payload |
235 * @return {!WebInspector.AnimationModel.Animation} | 221 * @return {!WebInspector.AnimationModel.Animation} |
236 */ | 222 */ |
237 WebInspector.AnimationModel.Animation.parsePayload = function(target, payload) | 223 static parsePayload(target, payload) { |
238 { | |
239 return new WebInspector.AnimationModel.Animation(target, payload); | 224 return new WebInspector.AnimationModel.Animation(target, payload); |
240 }; | 225 } |
| 226 |
| 227 /** |
| 228 * @return {!AnimationAgent.Animation} |
| 229 */ |
| 230 payload() { |
| 231 return this._payload; |
| 232 } |
| 233 |
| 234 /** |
| 235 * @return {string} |
| 236 */ |
| 237 id() { |
| 238 return this._payload.id; |
| 239 } |
| 240 |
| 241 /** |
| 242 * @return {string} |
| 243 */ |
| 244 name() { |
| 245 return this._payload.name; |
| 246 } |
| 247 |
| 248 /** |
| 249 * @return {boolean} |
| 250 */ |
| 251 paused() { |
| 252 return this._payload.pausedState; |
| 253 } |
| 254 |
| 255 /** |
| 256 * @return {string} |
| 257 */ |
| 258 playState() { |
| 259 return this._playState || this._payload.playState; |
| 260 } |
| 261 |
| 262 /** |
| 263 * @param {string} playState |
| 264 */ |
| 265 setPlayState(playState) { |
| 266 this._playState = playState; |
| 267 } |
| 268 |
| 269 /** |
| 270 * @return {number} |
| 271 */ |
| 272 playbackRate() { |
| 273 return this._payload.playbackRate; |
| 274 } |
| 275 |
| 276 /** |
| 277 * @return {number} |
| 278 */ |
| 279 startTime() { |
| 280 return this._payload.startTime; |
| 281 } |
| 282 |
| 283 /** |
| 284 * @return {number} |
| 285 */ |
| 286 endTime() { |
| 287 if (!this.source().iterations) |
| 288 return Infinity; |
| 289 return this.startTime() + this.source().delay() + this.source().duration() *
this.source().iterations() + |
| 290 this.source().endDelay(); |
| 291 } |
| 292 |
| 293 /** |
| 294 * @return {number} |
| 295 */ |
| 296 _finiteDuration() { |
| 297 var iterations = Math.min(this.source().iterations(), 3); |
| 298 return this.source().delay() + this.source().duration() * iterations; |
| 299 } |
| 300 |
| 301 /** |
| 302 * @return {number} |
| 303 */ |
| 304 currentTime() { |
| 305 return this._payload.currentTime; |
| 306 } |
| 307 |
| 308 /** |
| 309 * @return {!WebInspector.AnimationModel.AnimationEffect} |
| 310 */ |
| 311 source() { |
| 312 return this._source; |
| 313 } |
| 314 |
| 315 /** |
| 316 * @return {!WebInspector.AnimationModel.Animation.Type} |
| 317 */ |
| 318 type() { |
| 319 return /** @type {!WebInspector.AnimationModel.Animation.Type} */ (this._pay
load.type); |
| 320 } |
| 321 |
| 322 /** |
| 323 * @param {!WebInspector.AnimationModel.Animation} animation |
| 324 * @return {boolean} |
| 325 */ |
| 326 overlaps(animation) { |
| 327 // Infinite animations |
| 328 if (!this.source().iterations() || !animation.source().iterations()) |
| 329 return true; |
| 330 |
| 331 var firstAnimation = this.startTime() < animation.startTime() ? this : anima
tion; |
| 332 var secondAnimation = firstAnimation === this ? animation : this; |
| 333 return firstAnimation.endTime() >= secondAnimation.startTime(); |
| 334 } |
| 335 |
| 336 /** |
| 337 * @param {number} duration |
| 338 * @param {number} delay |
| 339 */ |
| 340 setTiming(duration, delay) { |
| 341 this._source.node().then(this._updateNodeStyle.bind(this, duration, delay)); |
| 342 this._source._duration = duration; |
| 343 this._source._delay = delay; |
| 344 this.target().animationAgent().setTiming(this.id(), duration, delay); |
| 345 } |
| 346 |
| 347 /** |
| 348 * @param {number} duration |
| 349 * @param {number} delay |
| 350 * @param {!WebInspector.DOMNode} node |
| 351 */ |
| 352 _updateNodeStyle(duration, delay, node) { |
| 353 var animationPrefix; |
| 354 if (this.type() === WebInspector.AnimationModel.Animation.Type.CSSTransition
) |
| 355 animationPrefix = 'transition-'; |
| 356 else if (this.type() === WebInspector.AnimationModel.Animation.Type.CSSAnima
tion) |
| 357 animationPrefix = 'animation-'; |
| 358 else |
| 359 return; |
| 360 |
| 361 var cssModel = WebInspector.CSSModel.fromTarget(node.target()); |
| 362 if (!cssModel) |
| 363 return; |
| 364 cssModel.setEffectivePropertyValueForNode(node.id, animationPrefix + 'durati
on', duration + 'ms'); |
| 365 cssModel.setEffectivePropertyValueForNode(node.id, animationPrefix + 'delay'
, delay + 'ms'); |
| 366 } |
| 367 |
| 368 /** |
| 369 * @return {!Promise.<?WebInspector.RemoteObject>} |
| 370 */ |
| 371 remoteObjectPromise() { |
| 372 /** |
| 373 * @param {?Protocol.Error} error |
| 374 * @param {!RuntimeAgent.RemoteObject} payload |
| 375 * @return {?WebInspector.RemoteObject} |
| 376 * @this {!WebInspector.AnimationModel.Animation} |
| 377 */ |
| 378 function callback(error, payload) { |
| 379 return !error ? this.target().runtimeModel.createRemoteObject(payload) : n
ull; |
| 380 } |
| 381 |
| 382 return this.target().animationAgent().resolveAnimation(this.id(), callback.b
ind(this)); |
| 383 } |
| 384 |
| 385 /** |
| 386 * @return {string} |
| 387 */ |
| 388 _cssId() { |
| 389 return this._payload.cssId || ''; |
| 390 } |
| 391 }; |
| 392 |
241 | 393 |
242 /** @enum {string} */ | 394 /** @enum {string} */ |
243 WebInspector.AnimationModel.Animation.Type = { | 395 WebInspector.AnimationModel.Animation.Type = { |
244 CSSTransition: "CSSTransition", | 396 CSSTransition: 'CSSTransition', |
245 CSSAnimation: "CSSAnimation", | 397 CSSAnimation: 'CSSAnimation', |
246 WebAnimation: "WebAnimation" | 398 WebAnimation: 'WebAnimation' |
247 }; | |
248 | |
249 WebInspector.AnimationModel.Animation.prototype = { | |
250 /** | |
251 * @return {!AnimationAgent.Animation} | |
252 */ | |
253 payload: function() | |
254 { | |
255 return this._payload; | |
256 }, | |
257 | |
258 /** | |
259 * @return {string} | |
260 */ | |
261 id: function() | |
262 { | |
263 return this._payload.id; | |
264 }, | |
265 | |
266 /** | |
267 * @return {string} | |
268 */ | |
269 name: function() | |
270 { | |
271 return this._payload.name; | |
272 }, | |
273 | |
274 /** | |
275 * @return {boolean} | |
276 */ | |
277 paused: function() | |
278 { | |
279 return this._payload.pausedState; | |
280 }, | |
281 | |
282 /** | |
283 * @return {string} | |
284 */ | |
285 playState: function() | |
286 { | |
287 return this._playState || this._payload.playState; | |
288 }, | |
289 | |
290 /** | |
291 * @param {string} playState | |
292 */ | |
293 setPlayState: function(playState) | |
294 { | |
295 this._playState = playState; | |
296 }, | |
297 | |
298 /** | |
299 * @return {number} | |
300 */ | |
301 playbackRate: function() | |
302 { | |
303 return this._payload.playbackRate; | |
304 }, | |
305 | |
306 /** | |
307 * @return {number} | |
308 */ | |
309 startTime: function() | |
310 { | |
311 return this._payload.startTime; | |
312 }, | |
313 | |
314 /** | |
315 * @return {number} | |
316 */ | |
317 endTime: function() | |
318 { | |
319 if (!this.source().iterations) | |
320 return Infinity; | |
321 return this.startTime() + this.source().delay() + this.source().duration
() * this.source().iterations() + this.source().endDelay(); | |
322 }, | |
323 | |
324 /** | |
325 * @return {number} | |
326 */ | |
327 _finiteDuration: function() | |
328 { | |
329 var iterations = Math.min(this.source().iterations(), 3); | |
330 return this.source().delay() + this.source().duration() * iterations; | |
331 }, | |
332 | |
333 /** | |
334 * @return {number} | |
335 */ | |
336 currentTime: function() | |
337 { | |
338 return this._payload.currentTime; | |
339 }, | |
340 | |
341 /** | |
342 * @return {!WebInspector.AnimationModel.AnimationEffect} | |
343 */ | |
344 source: function() | |
345 { | |
346 return this._source; | |
347 }, | |
348 | |
349 /** | |
350 * @return {!WebInspector.AnimationModel.Animation.Type} | |
351 */ | |
352 type: function() | |
353 { | |
354 return /** @type {!WebInspector.AnimationModel.Animation.Type} */(this._
payload.type); | |
355 }, | |
356 | |
357 /** | |
358 * @param {!WebInspector.AnimationModel.Animation} animation | |
359 * @return {boolean} | |
360 */ | |
361 overlaps: function(animation) | |
362 { | |
363 // Infinite animations | |
364 if (!this.source().iterations() || !animation.source().iterations()) | |
365 return true; | |
366 | |
367 var firstAnimation = this.startTime() < animation.startTime() ? this : a
nimation; | |
368 var secondAnimation = firstAnimation === this ? animation : this; | |
369 return firstAnimation.endTime() >= secondAnimation.startTime(); | |
370 }, | |
371 | |
372 /** | |
373 * @param {number} duration | |
374 * @param {number} delay | |
375 */ | |
376 setTiming: function(duration, delay) | |
377 { | |
378 this._source.node().then(this._updateNodeStyle.bind(this, duration, dela
y)); | |
379 this._source._duration = duration; | |
380 this._source._delay = delay; | |
381 this.target().animationAgent().setTiming(this.id(), duration, delay); | |
382 }, | |
383 | |
384 /** | |
385 * @param {number} duration | |
386 * @param {number} delay | |
387 * @param {!WebInspector.DOMNode} node | |
388 */ | |
389 _updateNodeStyle: function(duration, delay, node) | |
390 { | |
391 var animationPrefix; | |
392 if (this.type() === WebInspector.AnimationModel.Animation.Type.CSSTransi
tion) | |
393 animationPrefix = "transition-"; | |
394 else if (this.type() === WebInspector.AnimationModel.Animation.Type.CSSA
nimation) | |
395 animationPrefix = "animation-"; | |
396 else | |
397 return; | |
398 | |
399 var cssModel = WebInspector.CSSModel.fromTarget(node.target()); | |
400 if (!cssModel) | |
401 return; | |
402 cssModel.setEffectivePropertyValueForNode(node.id, animationPrefix + "du
ration", duration + "ms"); | |
403 cssModel.setEffectivePropertyValueForNode(node.id, animationPrefix + "de
lay", delay + "ms"); | |
404 }, | |
405 | |
406 /** | |
407 * @return {!Promise.<?WebInspector.RemoteObject>} | |
408 */ | |
409 remoteObjectPromise: function() | |
410 { | |
411 /** | |
412 * @param {?Protocol.Error} error | |
413 * @param {!RuntimeAgent.RemoteObject} payload | |
414 * @return {?WebInspector.RemoteObject} | |
415 * @this {!WebInspector.AnimationModel.Animation} | |
416 */ | |
417 function callback(error, payload) | |
418 { | |
419 return !error ? this.target().runtimeModel.createRemoteObject(payloa
d) : null; | |
420 } | |
421 | |
422 return this.target().animationAgent().resolveAnimation(this.id(), callba
ck.bind(this)); | |
423 }, | |
424 | |
425 /** | |
426 * @return {string} | |
427 */ | |
428 _cssId: function() | |
429 { | |
430 return this._payload.cssId || ""; | |
431 }, | |
432 | |
433 __proto__: WebInspector.SDKObject.prototype | |
434 }; | 399 }; |
435 | 400 |
436 /** | 401 /** |
437 * @constructor | 402 * @unrestricted |
438 * @extends {WebInspector.SDKObject} | |
439 * @param {!WebInspector.Target} target | |
440 * @param {!AnimationAgent.AnimationEffect} payload | |
441 */ | 403 */ |
442 WebInspector.AnimationModel.AnimationEffect = function(target, payload) | 404 WebInspector.AnimationModel.AnimationEffect = class extends WebInspector.SDKObje
ct { |
443 { | 405 /** |
444 WebInspector.SDKObject.call(this, target); | 406 * @param {!WebInspector.Target} target |
| 407 * @param {!AnimationAgent.AnimationEffect} payload |
| 408 */ |
| 409 constructor(target, payload) { |
| 410 super(target); |
445 this._payload = payload; | 411 this._payload = payload; |
446 if (payload.keyframesRule) | 412 if (payload.keyframesRule) |
447 this._keyframesRule = new WebInspector.AnimationModel.KeyframesRule(targ
et, payload.keyframesRule); | 413 this._keyframesRule = new WebInspector.AnimationModel.KeyframesRule(target
, payload.keyframesRule); |
448 this._delay = this._payload.delay; | 414 this._delay = this._payload.delay; |
449 this._duration = this._payload.duration; | 415 this._duration = this._payload.duration; |
450 }; | 416 } |
451 | 417 |
452 WebInspector.AnimationModel.AnimationEffect.prototype = { | 418 /** |
453 /** | 419 * @return {number} |
454 * @return {number} | 420 */ |
455 */ | 421 delay() { |
456 delay: function() | 422 return this._delay; |
457 { | 423 } |
458 return this._delay; | 424 |
459 }, | 425 /** |
460 | 426 * @return {number} |
461 /** | 427 */ |
462 * @return {number} | 428 endDelay() { |
463 */ | 429 return this._payload.endDelay; |
464 endDelay: function() | 430 } |
465 { | 431 |
466 return this._payload.endDelay; | 432 /** |
467 }, | 433 * @return {number} |
468 | 434 */ |
469 /** | 435 iterationStart() { |
470 * @return {number} | 436 return this._payload.iterationStart; |
471 */ | 437 } |
472 iterationStart: function() | 438 |
473 { | 439 /** |
474 return this._payload.iterationStart; | 440 * @return {number} |
475 }, | 441 */ |
476 | 442 iterations() { |
477 /** | 443 // Animations with zero duration, zero delays and infinite iterations can't
be shown. |
478 * @return {number} | 444 if (!this.delay() && !this.endDelay() && !this.duration()) |
479 */ | 445 return 0; |
480 iterations: function() | 446 return this._payload.iterations || Infinity; |
481 { | 447 } |
482 // Animations with zero duration, zero delays and infinite iterations ca
n't be shown. | 448 |
483 if (!this.delay() && !this.endDelay() && !this.duration()) | 449 /** |
484 return 0; | 450 * @return {number} |
485 return this._payload.iterations || Infinity; | 451 */ |
486 }, | 452 duration() { |
487 | 453 return this._duration; |
488 /** | 454 } |
489 * @return {number} | 455 |
490 */ | 456 /** |
491 duration: function() | 457 * @return {string} |
492 { | 458 */ |
493 return this._duration; | 459 direction() { |
494 }, | 460 return this._payload.direction; |
495 | 461 } |
496 /** | 462 |
497 * @return {string} | 463 /** |
498 */ | 464 * @return {string} |
499 direction: function() | 465 */ |
500 { | 466 fill() { |
501 return this._payload.direction; | 467 return this._payload.fill; |
502 }, | 468 } |
503 | 469 |
504 /** | 470 /** |
505 * @return {string} | 471 * @return {!Promise.<!WebInspector.DOMNode>} |
506 */ | 472 */ |
507 fill: function() | 473 node() { |
508 { | 474 if (!this._deferredNode) |
509 return this._payload.fill; | 475 this._deferredNode = new WebInspector.DeferredDOMNode(this.target(), this.
backendNodeId()); |
510 }, | 476 return this._deferredNode.resolvePromise(); |
511 | 477 } |
512 /** | 478 |
513 * @return {!Promise.<!WebInspector.DOMNode>} | 479 /** |
514 */ | 480 * @return {!WebInspector.DeferredDOMNode} |
515 node: function() | 481 */ |
516 { | 482 deferredNode() { |
517 if (!this._deferredNode) | 483 return new WebInspector.DeferredDOMNode(this.target(), this.backendNodeId())
; |
518 this._deferredNode = new WebInspector.DeferredDOMNode(this.target(),
this.backendNodeId()); | 484 } |
519 return this._deferredNode.resolvePromise(); | 485 |
520 }, | 486 /** |
521 | 487 * @return {number} |
522 /** | 488 */ |
523 * @return {!WebInspector.DeferredDOMNode} | 489 backendNodeId() { |
524 */ | 490 return this._payload.backendNodeId; |
525 deferredNode: function() | 491 } |
526 { | 492 |
527 return new WebInspector.DeferredDOMNode(this.target(), this.backendNodeI
d()); | 493 /** |
528 }, | 494 * @return {?WebInspector.AnimationModel.KeyframesRule} |
529 | 495 */ |
530 /** | 496 keyframesRule() { |
531 * @return {number} | 497 return this._keyframesRule; |
532 */ | 498 } |
533 backendNodeId: function() | 499 |
534 { | 500 /** |
535 return this._payload.backendNodeId; | 501 * @return {string} |
536 }, | 502 */ |
537 | 503 easing() { |
538 /** | 504 return this._payload.easing; |
539 * @return {?WebInspector.AnimationModel.KeyframesRule} | 505 } |
540 */ | |
541 keyframesRule: function() | |
542 { | |
543 return this._keyframesRule; | |
544 }, | |
545 | |
546 /** | |
547 * @return {string} | |
548 */ | |
549 easing: function() | |
550 { | |
551 return this._payload.easing; | |
552 }, | |
553 | |
554 __proto__: WebInspector.SDKObject.prototype | |
555 }; | 506 }; |
556 | 507 |
557 /** | 508 /** |
558 * @constructor | 509 * @unrestricted |
559 * @extends {WebInspector.SDKObject} | |
560 * @param {!WebInspector.Target} target | |
561 * @param {!AnimationAgent.KeyframesRule} payload | |
562 */ | 510 */ |
563 WebInspector.AnimationModel.KeyframesRule = function(target, payload) | 511 WebInspector.AnimationModel.KeyframesRule = class extends WebInspector.SDKObject
{ |
564 { | 512 /** |
565 WebInspector.SDKObject.call(this, target); | 513 * @param {!WebInspector.Target} target |
| 514 * @param {!AnimationAgent.KeyframesRule} payload |
| 515 */ |
| 516 constructor(target, payload) { |
| 517 super(target); |
566 this._payload = payload; | 518 this._payload = payload; |
567 this._keyframes = this._payload.keyframes.map(function(keyframeStyle) { | 519 this._keyframes = this._payload.keyframes.map(function(keyframeStyle) { |
568 return new WebInspector.AnimationModel.KeyframeStyle(target, keyframeSty
le); | 520 return new WebInspector.AnimationModel.KeyframeStyle(target, keyframeStyle
); |
569 }); | 521 }); |
570 }; | 522 } |
571 | 523 |
572 WebInspector.AnimationModel.KeyframesRule.prototype = { | 524 /** |
573 /** | 525 * @param {!Array.<!AnimationAgent.KeyframeStyle>} payload |
574 * @param {!Array.<!AnimationAgent.KeyframeStyle>} payload | 526 */ |
575 */ | 527 _setKeyframesPayload(payload) { |
576 _setKeyframesPayload: function(payload) | 528 this._keyframes = payload.map(function(keyframeStyle) { |
577 { | 529 return new WebInspector.AnimationModel.KeyframeStyle(this._target, keyfram
eStyle); |
578 this._keyframes = payload.map(function(keyframeStyle) { | 530 }); |
579 return new WebInspector.AnimationModel.KeyframeStyle(this._target, k
eyframeStyle); | 531 } |
580 }); | 532 |
581 }, | 533 /** |
582 | 534 * @return {string|undefined} |
583 /** | 535 */ |
584 * @return {string|undefined} | 536 name() { |
585 */ | 537 return this._payload.name; |
586 name: function() | 538 } |
587 { | 539 |
588 return this._payload.name; | 540 /** |
589 }, | 541 * @return {!Array.<!WebInspector.AnimationModel.KeyframeStyle>} |
590 | 542 */ |
591 /** | 543 keyframes() { |
592 * @return {!Array.<!WebInspector.AnimationModel.KeyframeStyle>} | 544 return this._keyframes; |
593 */ | 545 } |
594 keyframes: function() | |
595 { | |
596 return this._keyframes; | |
597 }, | |
598 | |
599 __proto__: WebInspector.SDKObject.prototype | |
600 }; | 546 }; |
601 | 547 |
602 /** | 548 /** |
603 * @constructor | 549 * @unrestricted |
604 * @extends {WebInspector.SDKObject} | |
605 * @param {!WebInspector.Target} target | |
606 * @param {!AnimationAgent.KeyframeStyle} payload | |
607 */ | 550 */ |
608 WebInspector.AnimationModel.KeyframeStyle = function(target, payload) | 551 WebInspector.AnimationModel.KeyframeStyle = class extends WebInspector.SDKObject
{ |
609 { | 552 /** |
610 WebInspector.SDKObject.call(this, target); | 553 * @param {!WebInspector.Target} target |
| 554 * @param {!AnimationAgent.KeyframeStyle} payload |
| 555 */ |
| 556 constructor(target, payload) { |
| 557 super(target); |
611 this._payload = payload; | 558 this._payload = payload; |
612 this._offset = this._payload.offset; | 559 this._offset = this._payload.offset; |
613 }; | 560 } |
614 | 561 |
615 WebInspector.AnimationModel.KeyframeStyle.prototype = { | 562 /** |
616 /** | 563 * @return {string} |
617 * @return {string} | 564 */ |
618 */ | 565 offset() { |
619 offset: function() | 566 return this._offset; |
620 { | 567 } |
621 return this._offset; | 568 |
622 }, | 569 /** |
623 | 570 * @param {number} offset |
624 /** | 571 */ |
625 * @param {number} offset | 572 setOffset(offset) { |
626 */ | 573 this._offset = offset * 100 + '%'; |
627 setOffset: function(offset) | 574 } |
628 { | 575 |
629 this._offset = offset * 100 + "%"; | 576 /** |
630 }, | 577 * @return {number} |
631 | 578 */ |
632 /** | 579 offsetAsNumber() { |
633 * @return {number} | 580 return parseFloat(this._offset) / 100; |
634 */ | 581 } |
635 offsetAsNumber: function() | 582 |
636 { | 583 /** |
637 return parseFloat(this._offset) / 100; | 584 * @return {string} |
638 }, | 585 */ |
639 | 586 easing() { |
640 /** | 587 return this._payload.easing; |
641 * @return {string} | 588 } |
642 */ | |
643 easing: function() | |
644 { | |
645 return this._payload.easing; | |
646 }, | |
647 | |
648 __proto__: WebInspector.SDKObject.prototype | |
649 }; | 589 }; |
650 | 590 |
651 /** | 591 /** |
652 * @constructor | 592 * @unrestricted |
653 * @extends {WebInspector.SDKObject} | |
654 * @param {!WebInspector.AnimationModel} model | |
655 * @param {string} id | |
656 * @param {!Array.<!WebInspector.AnimationModel.Animation>} animations | |
657 */ | 593 */ |
658 WebInspector.AnimationModel.AnimationGroup = function(model, id, animations) | 594 WebInspector.AnimationModel.AnimationGroup = class extends WebInspector.SDKObjec
t { |
659 { | 595 /** |
660 WebInspector.SDKObject.call(this, model.target()); | 596 * @param {!WebInspector.AnimationModel} model |
| 597 * @param {string} id |
| 598 * @param {!Array.<!WebInspector.AnimationModel.Animation>} animations |
| 599 */ |
| 600 constructor(model, id, animations) { |
| 601 super(model.target()); |
661 this._model = model; | 602 this._model = model; |
662 this._id = id; | 603 this._id = id; |
663 this._animations = animations; | 604 this._animations = animations; |
664 this._paused = false; | 605 this._paused = false; |
665 this._screenshots = []; | 606 this._screenshots = []; |
666 this._screenshotImages = []; | 607 this._screenshotImages = []; |
667 }; | 608 } |
668 | 609 |
669 WebInspector.AnimationModel.AnimationGroup.prototype = { | 610 /** |
| 611 * @return {string} |
| 612 */ |
| 613 id() { |
| 614 return this._id; |
| 615 } |
| 616 |
| 617 /** |
| 618 * @return {!Array.<!WebInspector.AnimationModel.Animation>} |
| 619 */ |
| 620 animations() { |
| 621 return this._animations; |
| 622 } |
| 623 |
| 624 release() { |
| 625 this._model._animationGroups.remove(this.id()); |
| 626 this._model._releaseAnimations(this._animationIds()); |
| 627 } |
| 628 |
| 629 /** |
| 630 * @return {!Array.<string>} |
| 631 */ |
| 632 _animationIds() { |
670 /** | 633 /** |
| 634 * @param {!WebInspector.AnimationModel.Animation} animation |
671 * @return {string} | 635 * @return {string} |
672 */ | 636 */ |
673 id: function() | 637 function extractId(animation) { |
674 { | 638 return animation.id(); |
675 return this._id; | 639 } |
676 }, | 640 |
677 | 641 return this._animations.map(extractId); |
| 642 } |
| 643 |
| 644 /** |
| 645 * @return {number} |
| 646 */ |
| 647 startTime() { |
| 648 return this._animations[0].startTime(); |
| 649 } |
| 650 |
| 651 /** |
| 652 * @return {number} |
| 653 */ |
| 654 finiteDuration() { |
| 655 var maxDuration = 0; |
| 656 for (var i = 0; i < this._animations.length; ++i) |
| 657 maxDuration = Math.max(maxDuration, this._animations[i]._finiteDuration())
; |
| 658 return maxDuration; |
| 659 } |
| 660 |
| 661 /** |
| 662 * @param {number} currentTime |
| 663 */ |
| 664 seekTo(currentTime) { |
| 665 this.target().animationAgent().seekAnimations(this._animationIds(), currentT
ime); |
| 666 } |
| 667 |
| 668 /** |
| 669 * @return {boolean} |
| 670 */ |
| 671 paused() { |
| 672 return this._paused; |
| 673 } |
| 674 |
| 675 /** |
| 676 * @param {boolean} paused |
| 677 */ |
| 678 togglePause(paused) { |
| 679 if (paused === this._paused) |
| 680 return; |
| 681 this._paused = paused; |
| 682 this.target().animationAgent().setPaused(this._animationIds(), paused); |
| 683 } |
| 684 |
| 685 /** |
| 686 * @return {!Promise.<number>} |
| 687 */ |
| 688 currentTimePromise() { |
678 /** | 689 /** |
679 * @return {!Array.<!WebInspector.AnimationModel.Animation>} | 690 * @param {?Protocol.Error} error |
680 */ | 691 * @param {number} currentTime |
681 animations: function() | |
682 { | |
683 return this._animations; | |
684 }, | |
685 | |
686 release: function() | |
687 { | |
688 this._model._animationGroups.remove(this.id()); | |
689 this._model._releaseAnimations(this._animationIds()); | |
690 }, | |
691 | |
692 /** | |
693 * @return {!Array.<string>} | |
694 */ | |
695 _animationIds: function() | |
696 { | |
697 /** | |
698 * @param {!WebInspector.AnimationModel.Animation} animation | |
699 * @return {string} | |
700 */ | |
701 function extractId(animation) | |
702 { | |
703 return animation.id(); | |
704 } | |
705 | |
706 return this._animations.map(extractId); | |
707 }, | |
708 | |
709 /** | |
710 * @return {number} | 692 * @return {number} |
711 */ | 693 */ |
712 startTime: function() | 694 function callback(error, currentTime) { |
713 { | 695 return !error ? currentTime : 0; |
714 return this._animations[0].startTime(); | 696 } |
715 }, | 697 |
716 | 698 var longestAnim = null; |
| 699 for (var anim of this._animations) { |
| 700 if (!longestAnim || anim.endTime() > longestAnim.endTime()) |
| 701 longestAnim = anim; |
| 702 } |
| 703 return this.target().animationAgent().getCurrentTime(longestAnim.id(), callb
ack).catchException(0); |
| 704 } |
| 705 |
| 706 /** |
| 707 * @param {!WebInspector.AnimationModel.AnimationGroup} group |
| 708 * @return {boolean} |
| 709 */ |
| 710 _matches(group) { |
717 /** | 711 /** |
718 * @return {number} | 712 * @param {!WebInspector.AnimationModel.Animation} anim |
| 713 * @return {string} |
719 */ | 714 */ |
720 finiteDuration: function() | 715 function extractId(anim) { |
721 { | 716 if (anim.type() === WebInspector.AnimationModel.Animation.Type.WebAnimatio
n) |
722 var maxDuration = 0; | 717 return anim.type() + anim.id(); |
723 for (var i = 0; i < this._animations.length; ++i) | 718 else |
724 maxDuration = Math.max(maxDuration, this._animations[i]._finiteDurat
ion()); | 719 return anim._cssId(); |
725 return maxDuration; | 720 } |
726 }, | 721 |
727 | 722 if (this._animations.length !== group._animations.length) |
728 /** | 723 return false; |
729 * @param {number} currentTime | 724 var left = this._animations.map(extractId).sort(); |
730 */ | 725 var right = group._animations.map(extractId).sort(); |
731 seekTo: function(currentTime) | 726 for (var i = 0; i < left.length; i++) { |
732 { | 727 if (left[i] !== right[i]) |
733 this.target().animationAgent().seekAnimations(this._animationIds(), curr
entTime); | 728 return false; |
734 }, | 729 } |
735 | 730 return true; |
736 /** | 731 } |
737 * @return {boolean} | 732 |
738 */ | 733 /** |
739 paused: function() | 734 * @param {!WebInspector.AnimationModel.AnimationGroup} group |
740 { | 735 */ |
741 return this._paused; | 736 _update(group) { |
742 }, | 737 this._model._releaseAnimations(this._animationIds()); |
743 | 738 this._animations = group._animations; |
744 /** | 739 } |
745 * @param {boolean} paused | 740 |
746 */ | 741 /** |
747 togglePause: function(paused) | 742 * @return {!Array.<!Image>} |
748 { | 743 */ |
749 if (paused === this._paused) | 744 screenshots() { |
750 return; | 745 for (var i = 0; i < this._screenshots.length; ++i) { |
751 this._paused = paused; | 746 var image = new Image(); |
752 this.target().animationAgent().setPaused(this._animationIds(), paused); | 747 image.src = 'data:image/jpeg;base64,' + this._screenshots[i]; |
753 }, | 748 this._screenshotImages.push(image); |
754 | 749 } |
755 /** | 750 this._screenshots = []; |
756 * @return {!Promise.<number>} | 751 return this._screenshotImages; |
757 */ | 752 } |
758 currentTimePromise: function() | 753 }; |
759 { | |
760 /** | |
761 * @param {?Protocol.Error} error | |
762 * @param {number} currentTime | |
763 * @return {number} | |
764 */ | |
765 function callback(error, currentTime) | |
766 { | |
767 return !error ? currentTime : 0; | |
768 } | |
769 | |
770 var longestAnim = null; | |
771 for (var anim of this._animations) { | |
772 if (!longestAnim || anim.endTime() > longestAnim.endTime()) | |
773 longestAnim = anim; | |
774 } | |
775 return this.target().animationAgent().getCurrentTime(longestAnim.id(), c
allback).catchException(0); | |
776 }, | |
777 | |
778 /** | |
779 * @param {!WebInspector.AnimationModel.AnimationGroup} group | |
780 * @return {boolean} | |
781 */ | |
782 _matches: function(group) | |
783 { | |
784 /** | |
785 * @param {!WebInspector.AnimationModel.Animation} anim | |
786 * @return {string} | |
787 */ | |
788 function extractId(anim) | |
789 { | |
790 if (anim.type() === WebInspector.AnimationModel.Animation.Type.WebAn
imation) | |
791 return anim.type() + anim.id(); | |
792 else | |
793 return anim._cssId(); | |
794 } | |
795 | |
796 if (this._animations.length !== group._animations.length) | |
797 return false; | |
798 var left = this._animations.map(extractId).sort(); | |
799 var right = group._animations.map(extractId).sort(); | |
800 for (var i = 0; i < left.length; i++) { | |
801 if (left[i] !== right[i]) | |
802 return false; | |
803 } | |
804 return true; | |
805 }, | |
806 | |
807 /** | |
808 * @param {!WebInspector.AnimationModel.AnimationGroup} group | |
809 */ | |
810 _update: function(group) | |
811 { | |
812 this._model._releaseAnimations(this._animationIds()); | |
813 this._animations = group._animations; | |
814 }, | |
815 | |
816 /** | |
817 * @return {!Array.<!Image>} | |
818 */ | |
819 screenshots: function() | |
820 { | |
821 for (var i = 0; i < this._screenshots.length; ++i) { | |
822 var image = new Image(); | |
823 image.src = "data:image/jpeg;base64," + this._screenshots[i]; | |
824 this._screenshotImages.push(image); | |
825 } | |
826 this._screenshots = []; | |
827 return this._screenshotImages; | |
828 }, | |
829 | |
830 __proto__: WebInspector.SDKObject.prototype | |
831 }; | |
832 | |
833 | 754 |
834 /** | 755 /** |
835 * @constructor | |
836 * @implements {AnimationAgent.Dispatcher} | 756 * @implements {AnimationAgent.Dispatcher} |
| 757 * @unrestricted |
837 */ | 758 */ |
838 WebInspector.AnimationDispatcher = function(animationModel) | 759 WebInspector.AnimationDispatcher = class { |
839 { | 760 constructor(animationModel) { |
840 this._animationModel = animationModel; | 761 this._animationModel = animationModel; |
841 }; | 762 } |
842 | 763 |
843 WebInspector.AnimationDispatcher.prototype = { | 764 /** |
844 /** | 765 * @override |
845 * @override | 766 * @param {string} id |
846 * @param {string} id | 767 */ |
847 */ | 768 animationCreated(id) { |
848 animationCreated: function(id) | 769 this._animationModel.animationCreated(id); |
849 { | 770 } |
850 this._animationModel.animationCreated(id); | 771 |
851 }, | 772 /** |
852 | 773 * @override |
853 /** | 774 * @param {string} id |
854 * @override | 775 */ |
855 * @param {string} id | 776 animationCanceled(id) { |
856 */ | 777 this._animationModel._animationCanceled(id); |
857 animationCanceled: function(id) | 778 } |
858 { | 779 |
859 this._animationModel._animationCanceled(id); | 780 /** |
860 }, | 781 * @override |
861 | 782 * @param {!AnimationAgent.Animation} payload |
862 /** | 783 */ |
863 * @override | 784 animationStarted(payload) { |
864 * @param {!AnimationAgent.Animation} payload | 785 this._animationModel.animationStarted(payload); |
865 */ | 786 } |
866 animationStarted: function(payload) | |
867 { | |
868 this._animationModel.animationStarted(payload); | |
869 } | |
870 }; | 787 }; |
871 | 788 |
872 /** | 789 /** |
873 * @constructor | 790 * @unrestricted |
874 * @param {!WebInspector.Target} target | |
875 * @param {!WebInspector.AnimationModel} model | |
876 * @param {!WebInspector.ResourceTreeModel} resourceTreeModel | |
877 */ | 791 */ |
878 WebInspector.AnimationModel.ScreenshotCapture = function(target, model, resource
TreeModel) | 792 WebInspector.AnimationModel.ScreenshotCapture = class { |
879 { | 793 /** |
| 794 * @param {!WebInspector.Target} target |
| 795 * @param {!WebInspector.AnimationModel} model |
| 796 * @param {!WebInspector.ResourceTreeModel} resourceTreeModel |
| 797 */ |
| 798 constructor(target, model, resourceTreeModel) { |
880 this._target = target; | 799 this._target = target; |
881 /** @type {!Array<!WebInspector.AnimationModel.ScreenshotCapture.Request>} *
/ | 800 /** @type {!Array<!WebInspector.AnimationModel.ScreenshotCapture.Request>} *
/ |
882 this._requests = []; | 801 this._requests = []; |
883 resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.Events.Scr
eencastFrame, this._screencastFrame, this); | 802 resourceTreeModel.addEventListener( |
| 803 WebInspector.ResourceTreeModel.Events.ScreencastFrame, this._screencastF
rame, this); |
884 this._model = model; | 804 this._model = model; |
885 this._model.addEventListener(WebInspector.AnimationModel.Events.ModelReset,
this._stopScreencast, this); | 805 this._model.addEventListener(WebInspector.AnimationModel.Events.ModelReset,
this._stopScreencast, this); |
| 806 } |
| 807 |
| 808 /** |
| 809 * @param {number} duration |
| 810 * @param {!Array<string>} screenshots |
| 811 */ |
| 812 captureScreenshots(duration, screenshots) { |
| 813 var screencastDuration = Math.min(duration / this._model._playbackRate, 3000
); |
| 814 var endTime = screencastDuration + window.performance.now(); |
| 815 this._requests.push({endTime: endTime, screenshots: screenshots}); |
| 816 |
| 817 if (!this._endTime || endTime > this._endTime) { |
| 818 clearTimeout(this._stopTimer); |
| 819 this._stopTimer = setTimeout(this._stopScreencast.bind(this), screencastDu
ration); |
| 820 this._endTime = endTime; |
| 821 } |
| 822 |
| 823 if (this._capturing) |
| 824 return; |
| 825 this._capturing = true; |
| 826 this._target.pageAgent().startScreencast('jpeg', 80, undefined, 300, 2); |
| 827 } |
| 828 |
| 829 /** |
| 830 * @param {!WebInspector.Event} event |
| 831 */ |
| 832 _screencastFrame(event) { |
| 833 /** |
| 834 * @param {!WebInspector.AnimationModel.ScreenshotCapture.Request} request |
| 835 * @return {boolean} |
| 836 */ |
| 837 function isAnimating(request) { |
| 838 return request.endTime >= now; |
| 839 } |
| 840 |
| 841 if (!this._capturing) |
| 842 return; |
| 843 |
| 844 var base64Data = /** type {string} */ (event.data['data']); |
| 845 var now = window.performance.now(); |
| 846 this._requests = this._requests.filter(isAnimating); |
| 847 for (var request of this._requests) |
| 848 request.screenshots.push(base64Data); |
| 849 } |
| 850 |
| 851 _stopScreencast() { |
| 852 if (!this._capturing) |
| 853 return; |
| 854 |
| 855 delete this._stopTimer; |
| 856 delete this._endTime; |
| 857 this._requests = []; |
| 858 this._capturing = false; |
| 859 this._target.pageAgent().stopScreencast(); |
| 860 } |
886 }; | 861 }; |
887 | 862 |
888 /** @typedef {{ endTime: number, screenshots: !Array.<string>}} */ | 863 /** @typedef {{ endTime: number, screenshots: !Array.<string>}} */ |
889 WebInspector.AnimationModel.ScreenshotCapture.Request; | 864 WebInspector.AnimationModel.ScreenshotCapture.Request; |
890 | |
891 WebInspector.AnimationModel.ScreenshotCapture.prototype = { | |
892 /** | |
893 * @param {number} duration | |
894 * @param {!Array<string>} screenshots | |
895 */ | |
896 captureScreenshots: function(duration, screenshots) | |
897 { | |
898 var screencastDuration = Math.min(duration / this._model._playbackRate,
3000); | |
899 var endTime = screencastDuration + window.performance.now(); | |
900 this._requests.push({ endTime: endTime, screenshots: screenshots }); | |
901 | |
902 if (!this._endTime || endTime > this._endTime) { | |
903 clearTimeout(this._stopTimer); | |
904 this._stopTimer = setTimeout(this._stopScreencast.bind(this), screen
castDuration); | |
905 this._endTime = endTime; | |
906 } | |
907 | |
908 if (this._capturing) | |
909 return; | |
910 this._capturing = true; | |
911 this._target.pageAgent().startScreencast("jpeg", 80, undefined, 300, 2); | |
912 }, | |
913 | |
914 /** | |
915 * @param {!WebInspector.Event} event | |
916 */ | |
917 _screencastFrame: function(event) | |
918 { | |
919 /** | |
920 * @param {!WebInspector.AnimationModel.ScreenshotCapture.Request} reque
st | |
921 * @return {boolean} | |
922 */ | |
923 function isAnimating(request) | |
924 { | |
925 return request.endTime >= now; | |
926 } | |
927 | |
928 if (!this._capturing) | |
929 return; | |
930 | |
931 var base64Data = /** type {string} */(event.data["data"]); | |
932 var now = window.performance.now(); | |
933 this._requests = this._requests.filter(isAnimating); | |
934 for (var request of this._requests) | |
935 request.screenshots.push(base64Data); | |
936 }, | |
937 | |
938 _stopScreencast: function() | |
939 { | |
940 if (!this._capturing) | |
941 return; | |
942 | |
943 delete this._stopTimer; | |
944 delete this._endTime; | |
945 this._requests = []; | |
946 this._capturing = false; | |
947 this._target.pageAgent().stopScreencast(); | |
948 } | |
949 }; | |
OLD | NEW |