| 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 |