Bug 1129454 - 1 - Adds [play|pause]All methods to the AnimationsActor to pause/play all running animations; r=miker

This commit is contained in:
Patrick Brosset 2015-02-12 16:28:42 +01:00
Родитель 5738bd910f
Коммит 20f47d548f
5 изменённых файлов: 201 добавлений и 1 удалений

Просмотреть файл

@ -25,12 +25,14 @@
*/
const {Cu} = require("chrome");
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const {setInterval, clearInterval} = require("sdk/timers");
const protocol = require("devtools/server/protocol");
const {ActorClass, Actor, FrontClass, Front, Arg, method, RetVal} = protocol;
const {NodeActor} = require("devtools/server/actors/inspector");
const EventEmitter = require("devtools/toolkit/event-emitter");
const events = require("sdk/event/core");
const PLAYER_DEFAULT_AUTO_REFRESH_TIMEOUT = 500; // ms
@ -149,7 +151,9 @@ let AnimationPlayerActor = ActorClass({
iterationText = iterationText.split(",")[this.playerIndex];
}
return parseInt(iterationText, 10);
return iterationText === "infinite"
? null
: parseInt(iterationText, 10);
},
/**
@ -379,10 +383,17 @@ let AnimationsActor = exports.AnimationsActor = ActorClass({
initialize: function(conn, tabActor) {
Actor.prototype.initialize.call(this, conn);
this.tabActor = tabActor;
this.allAnimationsPaused = false;
this.onNavigate = this.onNavigate.bind(this);
events.on(this.tabActor, "navigate", this.onNavigate);
},
destroy: function() {
Actor.prototype.destroy.call(this);
events.off(this.tabActor, "navigate", this.onNavigate);
this.tabActor = null;
},
/**
@ -417,6 +428,77 @@ let AnimationsActor = exports.AnimationsActor = ActorClass({
response: {
players: RetVal("array:animationplayer")
}
}),
/**
* Iterates through all nodes in all of the tabActor's window documents and
* finds all existing animation players.
* This is currently used to allow playing/pausing all animations at once
* until the WebAnimations API provides a way to play/pause via the document
* timeline (alternatively, when bug 1123524 is fixed, we will be able to
* only iterate once and then listen for changes).
*/
getAllAnimationPlayers: function() {
let players = [];
// These loops shouldn't be as bad as they look.
// Typically, there will be very few windows, and getElementsByTagName is
// really fast even on large DOM trees.
for (let window of this.tabActor.windows) {
let root = window.document.body || window.document;
for (let element of root.getElementsByTagNameNS("*", "*")) {
players = [...players, ...element.getAnimationPlayers()];
}
}
return players;
},
onNavigate: function({isTopLevel}) {
if (isTopLevel) {
this.allAnimationsPaused = false;
}
},
/**
* Pause all animations in the current tabActor's frames.
*/
pauseAll: method(function() {
for (let player of this.getAllAnimationPlayers()) {
player.pause();
}
this.allAnimationsPaused = true;
}, {
request: {},
response: {}
}),
/**
* Play all animations in the current tabActor's frames.
* This method only returns when the animations have left their pending states.
*/
playAll: method(function() {
let readyPromises = [];
for (let player of this.getAllAnimationPlayers()) {
player.play();
readyPromises.push(player.ready);
}
this.allAnimationsPaused = false;
return promise.all(readyPromises);
}, {
request: {},
response: {}
}),
toggleAll: method(function() {
if (this.allAnimationsPaused) {
return this.playAll();
} else {
return this.pauseAll();
}
}, {
request: {},
response: {}
})
});

Просмотреть файл

@ -22,6 +22,8 @@ support-files =
[browser_animation_actors_05.js]
[browser_animation_actors_06.js]
[browser_animation_actors_07.js]
[browser_animation_actors_08.js]
[browser_animation_actors_09.js]
[browser_navigateEvents.js]
[browser_storage_dynamic_windows.js]
[browser_storage_listings.js]

Просмотреть файл

@ -21,6 +21,9 @@ add_task(function*() {
ok(front, "The AnimationsFront was created");
ok(front.getAnimationPlayersForNode, "The getAnimationPlayersForNode method exists");
ok(front.toggleAll, "The toggleAll method exists");
ok(front.playAll, "The playAll method exists");
ok(front.pauseAll, "The pauseAll method exists");
let didThrow = false;
try {

Просмотреть файл

@ -0,0 +1,55 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Check that the AnimationsActor can pause/play all animations at once.
const {AnimationsFront} = require("devtools/server/actors/animation");
const {InspectorFront} = require("devtools/server/actors/inspector");
add_task(function*() {
let doc = yield addTab(MAIN_DOMAIN + "animation.html");
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let inspector = InspectorFront(client, form);
let walker = yield inspector.getWalker();
let front = AnimationsFront(client, form);
info("Pause all animations in the test document");
yield front.pauseAll();
yield checkAllAnimationsStates(walker, front, "paused");
info("Play all animations in the test document");
yield front.playAll();
yield checkAllAnimationsStates(walker, front, "running");
info("Pause all animations in the test document using toggleAll");
yield front.toggleAll();
yield checkAllAnimationsStates(walker, front, "paused");
info("Play all animations in the test document using toggleAll");
yield front.toggleAll();
yield checkAllAnimationsStates(walker, front, "running");
yield closeDebuggerClient(client);
gBrowser.removeCurrentTab();
});
function* checkAllAnimationsStates(walker, front, playState) {
info("Checking the playState of all the nodes that have infinite running animations");
let selectors = [".simple-animation", ".multiple-animations", ".delayed-animation"];
for (let selector of selectors) {
info("Getting the AnimationPlayerFront for node " + selector);
let node = yield walker.querySelector(walker.rootNode, selector);
let [player] = yield front.getAnimationPlayersForNode(node);
yield player.ready;
let state = yield player.getCurrentState();
is(state.playState, playState,
"The playState of node " + selector + " is " + playState);
}
}

Просмотреть файл

@ -0,0 +1,58 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Check that the AnimationsActor can pause/play all animations even those
// within iframes.
const {AnimationsFront} = require("devtools/server/actors/animation");
const {InspectorFront} = require("devtools/server/actors/inspector");
const URL = MAIN_DOMAIN + "animation.html";
add_task(function*() {
info("Creating a test document with 2 iframes containing animated nodes");
let doc = yield addTab("data:text/html;charset=utf-8," +
"<iframe id='i1' src='" + URL + "'></iframe>" +
"<iframe id='i2' src='" + URL + "'></iframe>");
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let inspector = InspectorFront(client, form);
let walker = yield inspector.getWalker();
let front = AnimationsFront(client, form);
info("Getting the 2 iframe container nodes and animated nodes in them");
let nodeInFrame1 = yield getNodeInFrame(walker, "#i1", ".simple-animation");
let nodeInFrame2 = yield getNodeInFrame(walker, "#i2", ".simple-animation");
info("Pause all animations in the test document");
yield front.pauseAll();
yield checkState(front, nodeInFrame1, "paused");
yield checkState(front, nodeInFrame2, "paused");
info("Play all animations in the test document");
yield front.playAll();
yield checkState(front, nodeInFrame1, "running");
yield checkState(front, nodeInFrame2, "running");
yield closeDebuggerClient(client);
gBrowser.removeCurrentTab();
});
function* checkState(front, nodeFront, playState) {
info("Getting the AnimationPlayerFront for the test node");
let [player] = yield front.getAnimationPlayersForNode(nodeFront);
yield player.ready;
let state = yield player.getCurrentState();
is(state.playState, playState, "The playState of the test node is " + playState);
}
function* getNodeInFrame(walker, frameSelector, nodeSelector) {
let iframe = yield walker.querySelector(walker.rootNode, frameSelector);
let {nodes} = yield walker.children(iframe);
return walker.querySelector(nodes[0], nodeSelector);
}