gecko/toolkit/devtools/server/actors/framerate.js

143 lines
4.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Cc, Ci, Cu, Cr} = require("chrome");
const Services = require("Services");
const events = require("sdk/event/core");
const protocol = require("devtools/server/protocol");
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils.js");
const {on, once, off, emit} = events;
const {method, custom, Arg, Option, RetVal} = protocol;
/**
* A very simple utility for monitoring framerate.
*/
let FramerateActor = exports.FramerateActor = protocol.ActorClass({
typeName: "framerate",
initialize: function(conn, tabActor) {
protocol.Actor.prototype.initialize.call(this, conn);
this.tabActor = tabActor;
this._contentWin = tabActor.window;
this._onRefreshDriverTick = this._onRefreshDriverTick.bind(this);
this._onGlobalCreated = this._onGlobalCreated.bind(this);
on(this.tabActor, "window-ready", this._onGlobalCreated);
},
destroy: function(conn) {
off(this.tabActor, "window-ready", this._onGlobalCreated);
protocol.Actor.prototype.destroy.call(this, conn);
this.stopRecording();
},
/**
* Starts monitoring framerate, storing the frames per second.
*/
startRecording: method(function() {
if (this._recording) {
return;
}
this._recording = true;
this._ticks = [];
this._startTime = this._contentWin.performance.now();
this._rafID = this._contentWin.requestAnimationFrame(this._onRefreshDriverTick);
}, {
}),
/**
* Stops monitoring framerate, returning the recorded values.
*/
stopRecording: method(function(beginAt = 0, endAt = Number.MAX_SAFE_INTEGER) {
if (!this._recording) {
return [];
}
let ticks = this.getPendingTicks(beginAt, endAt);
this.cancelRecording();
return ticks;
}, {
request: {
beginAt: Arg(0, "nullable:number"),
endAt: Arg(1, "nullable:number")
},
response: { ticks: RetVal("array:number") }
}),
/**
* Stops monitoring framerate, without returning the recorded values.
*/
cancelRecording: method(function() {
this._contentWin.cancelAnimationFrame(this._rafID);
this._recording = false;
this._ticks = null;
this._rafID = -1;
}, {
}),
/**
* Returns whether this actor is currently active.
*/
isRecording: method(function() {
return !!this._recording;
}, {
response: { recording: RetVal("boolean") }
}),
/**
* Gets the refresh driver ticks recorded so far.
*/
getPendingTicks: method(function(beginAt = 0, endAt = Number.MAX_SAFE_INTEGER) {
if (!this._ticks) {
return [];
}
return this._ticks.filter(e => e >= beginAt && e <= endAt);
}, {
request: {
beginAt: Arg(0, "nullable:number"),
endAt: Arg(1, "nullable:number")
},
response: { ticks: RetVal("array:number") }
}),
/**
* Function invoked along with the refresh driver.
*/
_onRefreshDriverTick: function() {
if (!this._recording) {
return;
}
this._rafID = this._contentWin.requestAnimationFrame(this._onRefreshDriverTick);
// Store the amount of time passed since the recording started.
let currentTime = this._contentWin.performance.now();
// Store _elapsedTime so we can use this as a new starting time on a page refresh
// to normalize times.
this._elapsedTime = currentTime - this._startTime;
this._ticks.push(this._elapsedTime);
},
/**
* When the content window for the tab actor is created.
*/
_onGlobalCreated: function (win) {
if (this._recording) {
// Set _startTime to the currently elapsed time so we can get a wholistic
// elapsed time in _onRefreshDriverTick.
this._startTime = -this._elapsedTime;
this._rafID = this._contentWin.requestAnimationFrame(this._onRefreshDriverTick);
}
}
});
/**
* The corresponding Front object for the FramerateActor.
*/
let FramerateFront = exports.FramerateFront = protocol.FrontClass(FramerateActor, {
initialize: function(client, { framerateActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: framerateActor });
this.manage(this);
}
});