import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,67 @@
/* 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 { components } = require("chrome");
const Services = require("Services");
const { actorActorSpec, actorRegistrySpec } = require("devtools/shared/specs/actor-registry");
const protocol = require("devtools/shared/protocol");
const { custom } = protocol;
loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
const ActorActorFront = protocol.FrontClassWithSpec(actorActorSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
}
});
exports.ActorActorFront = ActorActorFront;
function request(uri) {
return new Promise((resolve, reject) => {
try {
uri = Services.io.newURI(uri, null, null);
} catch (e) {
reject(e);
}
NetUtil.asyncFetch({
uri,
loadUsingSystemPrincipal: true,
}, (stream, status, req) => {
if (!components.isSuccessCode(status)) {
reject(new Error("Request failed with status code = "
+ status
+ " after NetUtil.asyncFetch for url = "
+ uri));
return;
}
let source = NetUtil.readInputStreamToString(stream, stream.available());
stream.close();
resolve(source);
});
});
}
const ActorRegistryFront = protocol.FrontClassWithSpec(actorRegistrySpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client,
{ actor: form.actorRegistryActor });
this.manage(this);
},
registerActor: custom(function (uri, options) {
return request(uri, options)
.then(sourceText => {
return this._registerActor(sourceText, uri, options);
});
}, {
impl: "_registerActor"
})
});
exports.ActorRegistryFront = ActorRegistryFront;

View file

@ -0,0 +1,17 @@
/* 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 {addonsSpec} = require("devtools/shared/specs/addons");
const protocol = require("devtools/shared/protocol");
const AddonsFront = protocol.FrontClassWithSpec(addonsSpec, {
initialize: function (client, {addonsActor}) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = addonsActor;
this.manage(this);
}
});
exports.AddonsFront = AddonsFront;

View file

@ -0,0 +1,140 @@
/* 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 {
Front,
FrontClassWithSpec,
custom,
preEvent
} = require("devtools/shared/protocol");
const {
animationPlayerSpec,
animationsSpec
} = require("devtools/shared/specs/animation");
const { Task } = require("devtools/shared/task");
const AnimationPlayerFront = FrontClassWithSpec(animationPlayerSpec, {
initialize: function (conn, form, detail, ctx) {
Front.prototype.initialize.call(this, conn, form, detail, ctx);
this.state = {};
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
this.state = this.initialState;
},
destroy: function () {
Front.prototype.destroy.call(this);
},
/**
* If the AnimationsActor was given a reference to the WalkerActor previously
* then calling this getter will return the animation target NodeFront.
*/
get animationTargetNodeFront() {
if (!this._form.animationTargetNodeActorID) {
return null;
}
return this.conn.getActor(this._form.animationTargetNodeActorID);
},
/**
* Getter for the initial state of the player. Up to date states can be
* retrieved by calling the getCurrentState method.
*/
get initialState() {
return {
type: this._form.type,
startTime: this._form.startTime,
previousStartTime: this._form.previousStartTime,
currentTime: this._form.currentTime,
playState: this._form.playState,
playbackRate: this._form.playbackRate,
name: this._form.name,
duration: this._form.duration,
delay: this._form.delay,
endDelay: this._form.endDelay,
iterationCount: this._form.iterationCount,
iterationStart: this._form.iterationStart,
easing: this._form.easing,
fill: this._form.fill,
direction: this._form.direction,
isRunningOnCompositor: this._form.isRunningOnCompositor,
propertyState: this._form.propertyState,
documentCurrentTime: this._form.documentCurrentTime
};
},
/**
* Executed when the AnimationPlayerActor emits a "changed" event. Used to
* update the local knowledge of the state.
*/
onChanged: preEvent("changed", function (partialState) {
let {state} = this.reconstructState(partialState);
this.state = state;
}),
/**
* Refresh the current state of this animation on the client from information
* found on the server. Doesn't return anything, just stores the new state.
*/
refreshState: Task.async(function* () {
let data = yield this.getCurrentState();
if (this.currentStateHasChanged) {
this.state = data;
}
}),
/**
* getCurrentState interceptor re-constructs incomplete states since the actor
* only sends the values that have changed.
*/
getCurrentState: custom(function () {
this.currentStateHasChanged = false;
return this._getCurrentState().then(partialData => {
let {state, hasChanged} = this.reconstructState(partialData);
this.currentStateHasChanged = hasChanged;
return state;
});
}, {
impl: "_getCurrentState"
}),
reconstructState: function (data) {
let hasChanged = false;
for (let key in this.state) {
if (typeof data[key] === "undefined") {
data[key] = this.state[key];
} else if (data[key] !== this.state[key]) {
hasChanged = true;
}
}
return {state: data, hasChanged};
}
});
exports.AnimationPlayerFront = AnimationPlayerFront;
const AnimationsFront = FrontClassWithSpec(animationsSpec, {
initialize: function (client, {animationsActor}) {
Front.prototype.initialize.call(this, client, {actor: animationsActor});
this.manage(this);
},
destroy: function () {
Front.prototype.destroy.call(this);
}
});
exports.AnimationsFront = AnimationsFront;

View file

@ -0,0 +1,226 @@
/* 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 { functionCallSpec, callWatcherSpec } = require("devtools/shared/specs/call-watcher");
const protocol = require("devtools/shared/protocol");
/**
* The corresponding Front object for the FunctionCallActor.
*/
const FunctionCallFront = protocol.FrontClassWithSpec(functionCallSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
},
/**
* Adds some generic information directly to this instance,
* to avoid extra roundtrips.
*/
form: function (form) {
this.actorID = form.actor;
this.type = form.type;
this.name = form.name;
this.file = form.file;
this.line = form.line;
this.timestamp = form.timestamp;
this.callerPreview = form.callerPreview;
this.argsPreview = form.argsPreview;
this.resultPreview = form.resultPreview;
}
});
exports.FunctionCallFront = FunctionCallFront;
/**
* The corresponding Front object for the CallWatcherActor.
*/
var CallWatcherFront =
exports.CallWatcherFront =
protocol.FrontClassWithSpec(callWatcherSpec, {
initialize: function (client, { callWatcherActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: callWatcherActor });
this.manage(this);
}
});
/**
* Constants.
*/
CallWatcherFront.METHOD_FUNCTION = 0;
CallWatcherFront.GETTER_FUNCTION = 1;
CallWatcherFront.SETTER_FUNCTION = 2;
CallWatcherFront.KNOWN_METHODS = {};
CallWatcherFront.KNOWN_METHODS.CanvasRenderingContext2D = {
asyncDrawXULElement: {
enums: new Set([6]),
},
drawWindow: {
enums: new Set([6])
},
};
CallWatcherFront.KNOWN_METHODS.WebGLRenderingContext = {
activeTexture: {
enums: new Set([0]),
},
bindBuffer: {
enums: new Set([0]),
},
bindFramebuffer: {
enums: new Set([0]),
},
bindRenderbuffer: {
enums: new Set([0]),
},
bindTexture: {
enums: new Set([0]),
},
blendEquation: {
enums: new Set([0]),
},
blendEquationSeparate: {
enums: new Set([0, 1]),
},
blendFunc: {
enums: new Set([0, 1]),
},
blendFuncSeparate: {
enums: new Set([0, 1, 2, 3]),
},
bufferData: {
enums: new Set([0, 1, 2]),
},
bufferSubData: {
enums: new Set([0, 1]),
},
checkFramebufferStatus: {
enums: new Set([0]),
},
clear: {
enums: new Set([0]),
},
compressedTexImage2D: {
enums: new Set([0, 2]),
},
compressedTexSubImage2D: {
enums: new Set([0, 6]),
},
copyTexImage2D: {
enums: new Set([0, 2]),
},
copyTexSubImage2D: {
enums: new Set([0]),
},
createShader: {
enums: new Set([0]),
},
cullFace: {
enums: new Set([0]),
},
depthFunc: {
enums: new Set([0]),
},
disable: {
enums: new Set([0]),
},
drawArrays: {
enums: new Set([0]),
},
drawElements: {
enums: new Set([0, 2]),
},
enable: {
enums: new Set([0]),
},
framebufferRenderbuffer: {
enums: new Set([0, 1, 2]),
},
framebufferTexture2D: {
enums: new Set([0, 1, 2]),
},
frontFace: {
enums: new Set([0]),
},
generateMipmap: {
enums: new Set([0]),
},
getBufferParameter: {
enums: new Set([0, 1]),
},
getParameter: {
enums: new Set([0]),
},
getFramebufferAttachmentParameter: {
enums: new Set([0, 1, 2]),
},
getProgramParameter: {
enums: new Set([1]),
},
getRenderbufferParameter: {
enums: new Set([0, 1]),
},
getShaderParameter: {
enums: new Set([1]),
},
getShaderPrecisionFormat: {
enums: new Set([0, 1]),
},
getTexParameter: {
enums: new Set([0, 1]),
},
getVertexAttrib: {
enums: new Set([1]),
},
getVertexAttribOffset: {
enums: new Set([1]),
},
hint: {
enums: new Set([0, 1]),
},
isEnabled: {
enums: new Set([0]),
},
pixelStorei: {
enums: new Set([0]),
},
readPixels: {
enums: new Set([4, 5]),
},
renderbufferStorage: {
enums: new Set([0, 1]),
},
stencilFunc: {
enums: new Set([0]),
},
stencilFuncSeparate: {
enums: new Set([0, 1]),
},
stencilMaskSeparate: {
enums: new Set([0]),
},
stencilOp: {
enums: new Set([0, 1, 2]),
},
stencilOpSeparate: {
enums: new Set([0, 1, 2, 3]),
},
texImage2D: {
enums: args => args.length > 6 ? new Set([0, 2, 6, 7]) : new Set([0, 2, 3, 4]),
},
texParameterf: {
enums: new Set([0, 1]),
},
texParameteri: {
enums: new Set([0, 1, 2]),
},
texSubImage2D: {
enums: args => args.length === 9 ? new Set([0, 6, 7]) : new Set([0, 4, 5]),
},
vertexAttribPointer: {
enums: new Set([2])
},
};

View file

@ -0,0 +1,91 @@
/* 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 {
frameSnapshotSpec,
canvasSpec,
CANVAS_CONTEXTS,
ANIMATION_GENERATORS,
LOOP_GENERATORS,
DRAW_CALLS,
INTERESTING_CALLS,
} = require("devtools/shared/specs/canvas");
const protocol = require("devtools/shared/protocol");
const promise = require("promise");
/**
* The corresponding Front object for the FrameSnapshotActor.
*/
const FrameSnapshotFront = protocol.FrontClassWithSpec(frameSnapshotSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
this._animationFrameEndScreenshot = null;
this._cachedScreenshots = new WeakMap();
},
/**
* This implementation caches the animation frame end screenshot to optimize
* frontend requests to `generateScreenshotFor`.
*/
getOverview: protocol.custom(function () {
return this._getOverview().then(data => {
this._animationFrameEndScreenshot = data.screenshot;
return data;
});
}, {
impl: "_getOverview"
}),
/**
* This implementation saves a roundtrip to the backend if the screenshot
* was already generated and retrieved once.
*/
generateScreenshotFor: protocol.custom(function (functionCall) {
if (CanvasFront.ANIMATION_GENERATORS.has(functionCall.name) ||
CanvasFront.LOOP_GENERATORS.has(functionCall.name)) {
return promise.resolve(this._animationFrameEndScreenshot);
}
let cachedScreenshot = this._cachedScreenshots.get(functionCall);
if (cachedScreenshot) {
return cachedScreenshot;
}
let screenshot = this._generateScreenshotFor(functionCall);
this._cachedScreenshots.set(functionCall, screenshot);
return screenshot;
}, {
impl: "_generateScreenshotFor"
})
});
exports.FrameSnapshotFront = FrameSnapshotFront;
/**
* The corresponding Front object for the CanvasActor.
*/
const CanvasFront = protocol.FrontClassWithSpec(canvasSpec, {
initialize: function (client, { canvasActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: canvasActor });
this.manage(this);
}
});
/**
* Constants.
*/
CanvasFront.CANVAS_CONTEXTS = new Set(CANVAS_CONTEXTS);
CanvasFront.ANIMATION_GENERATORS = new Set(ANIMATION_GENERATORS);
CanvasFront.LOOP_GENERATORS = new Set(LOOP_GENERATORS);
CanvasFront.DRAW_CALLS = new Set(DRAW_CALLS);
CanvasFront.INTERESTING_CALLS = new Set(INTERESTING_CALLS);
CanvasFront.THUMBNAIL_SIZE = 50;
CanvasFront.WEBGL_SCREENSHOT_MAX_HEIGHT = 256;
CanvasFront.INVALID_SNAPSHOT_IMAGE = {
index: -1,
width: 0,
height: 0,
pixels: []
};
exports.CanvasFront = CanvasFront;

View file

@ -0,0 +1,323 @@
/* 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 { FrontClassWithSpec, Front } = require("devtools/shared/protocol");
const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
const { Task } = require("devtools/shared/task");
const { CSS_PROPERTIES_DB } = require("devtools/shared/css/properties-db");
const { cssColors } = require("devtools/shared/css/color-db");
/**
* Build up a regular expression that matches a CSS variable token. This is an
* ident token that starts with two dashes "--".
*
* https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
*/
var NON_ASCII = "[^\\x00-\\x7F]";
var ESCAPE = "\\\\[^\n\r]";
var FIRST_CHAR = ["[_a-z]", NON_ASCII, ESCAPE].join("|");
var TRAILING_CHAR = ["[_a-z0-9-]", NON_ASCII, ESCAPE].join("|");
var IS_VARIABLE_TOKEN = new RegExp(`^--(${FIRST_CHAR})(${TRAILING_CHAR})*$`,
"i");
/**
* Check that this is a CSS variable.
*
* @param {String} input
* @return {Boolean}
*/
function isCssVariable(input) {
return !!input.match(IS_VARIABLE_TOKEN);
}
var cachedCssProperties = new WeakMap();
/**
* The CssProperties front provides a mechanism to have a one-time asynchronous
* load of a CSS properties database. This is then fed into the CssProperties
* interface that provides synchronous methods for finding out what CSS
* properties the current server supports.
*/
const CssPropertiesFront = FrontClassWithSpec(cssPropertiesSpec, {
initialize: function (client, { cssPropertiesActor }) {
Front.prototype.initialize.call(this, client, {actor: cssPropertiesActor});
this.manage(this);
}
});
/**
* Ask questions to a CSS database. This class does not care how the database
* gets loaded in, only the questions that you can ask to it.
* Prototype functions are bound to 'this' so they can be passed around as helper
* functions.
*
* @param {Object} db
* A database of CSS properties
* @param {Object} inheritedList
* The key is the property name, the value is whether or not
* that property is inherited.
*/
function CssProperties(db) {
this.properties = db.properties;
this.pseudoElements = db.pseudoElements;
this.isKnown = this.isKnown.bind(this);
this.isInherited = this.isInherited.bind(this);
this.supportsType = this.supportsType.bind(this);
this.isValidOnClient = this.isValidOnClient.bind(this);
// A weakly held dummy HTMLDivElement to test CSS properties on the client.
this._dummyElements = new WeakMap();
}
CssProperties.prototype = {
/**
* Checks to see if the property is known by the browser. This function has
* `this` already bound so that it can be passed around by reference.
*
* @param {String} property The property name to be checked.
* @return {Boolean}
*/
isKnown(property) {
return !!this.properties[property] || isCssVariable(property);
},
/**
* Quickly check if a CSS name/value combo is valid on the client.
*
* @param {String} Property name.
* @param {String} Property value.
* @param {Document} The client's document object.
* @return {Boolean}
*/
isValidOnClient(name, value, doc) {
let dummyElement = this._dummyElements.get(doc);
if (!dummyElement) {
dummyElement = doc.createElement("div");
this._dummyElements.set(doc, dummyElement);
}
// `!important` is not a valid value when setting a style declaration in the
// CSS Object Model.
const sanitizedValue = ("" + value).replace(/!\s*important\s*$/, "");
// Test the style on the element.
dummyElement.style[name] = sanitizedValue;
const isValid = !!dummyElement.style[name];
// Reset the state of the dummy element;
dummyElement.style[name] = "";
return isValid;
},
/**
* Get a function that will check the validity of css name/values for a given document.
* Useful for injecting isValidOnClient into components when needed.
*
* @param {Document} The client's document object.
* @return {Function} this.isValidOnClient with the document pre-set.
*/
getValidityChecker(doc) {
return (name, value) => this.isValidOnClient(name, value, doc);
},
/**
* Checks to see if the property is an inherited one.
*
* @param {String} property The property name to be checked.
* @return {Boolean}
*/
isInherited(property) {
return this.properties[property] && this.properties[property].isInherited;
},
/**
* Checks if the property supports the given CSS type.
* CSS types should come from devtools/shared/css/properties-db.js' CSS_TYPES.
*
* @param {String} property The property to be checked.
* @param {Number} type One of the type values from CSS_TYPES.
* @return {Boolean}
*/
supportsType(property, type) {
return this.properties[property] && this.properties[property].supports.includes(type);
},
/**
* Gets the CSS values for a given property name.
*
* @param {String} property The property to use.
* @return {Array} An array of strings.
*/
getValues(property) {
return this.properties[property] ? this.properties[property].values : [];
},
/**
* Gets the CSS property names.
*
* @return {Array} An array of strings.
*/
getNames(property) {
return Object.keys(this.properties);
},
/**
* Return a list of subproperties for the given property. If |name|
* does not name a valid property, an empty array is returned. If
* the property is not a shorthand property, then array containing
* just the property itself is returned.
*
* @param {String} name The property to query
* @return {Array} An array of subproperty names.
*/
getSubproperties(name) {
if (this.isKnown(name)) {
if (this.properties[name] && this.properties[name].subproperties) {
return this.properties[name].subproperties;
}
return [name];
}
return [];
},
};
/**
* Create a CssProperties object with a fully loaded CSS database. The
* CssProperties interface can be queried synchronously, but the initialization
* is potentially async and should be handled up-front when the tool is created.
*
* The front is returned only with this function so that it can be destroyed
* once the toolbox is destroyed.
*
* @param {Toolbox} The current toolbox.
* @returns {Promise} Resolves to {cssProperties, cssPropertiesFront}.
*/
const initCssProperties = Task.async(function* (toolbox) {
const client = toolbox.target.client;
if (cachedCssProperties.has(client)) {
return cachedCssProperties.get(client);
}
let db, front;
// Get the list dynamically if the cssProperties actor exists.
if (toolbox.target.hasActor("cssProperties")) {
front = CssPropertiesFront(client, toolbox.target.form);
const serverDB = yield front.getCSSDatabase();
// Ensure the database was returned in a format that is understood.
// Older versions of the protocol could return a blank database.
if (!serverDB.properties && !serverDB.margin) {
db = CSS_PROPERTIES_DB;
} else {
db = serverDB;
}
} else {
// The target does not support this actor, so require a static list of supported
// properties.
db = CSS_PROPERTIES_DB;
}
const cssProperties = new CssProperties(normalizeCssData(db));
cachedCssProperties.set(client, {cssProperties, front});
return {cssProperties, front};
});
/**
* Synchronously get a cached and initialized CssProperties.
*
* @param {Toolbox} The current toolbox.
* @returns {CssProperties}
*/
function getCssProperties(toolbox) {
if (!cachedCssProperties.has(toolbox.target.client)) {
throw new Error("The CSS database has not been initialized, please make " +
"sure initCssDatabase was called once before for this " +
"toolbox.");
}
return cachedCssProperties.get(toolbox.target.client).cssProperties;
}
/**
* Get a client-side CssProperties. This is useful for dependencies in tests, or parts
* of the codebase that don't particularly need to match every known CSS property on
* the target.
* @return {CssProperties}
*/
function getClientCssProperties() {
return new CssProperties(normalizeCssData(CSS_PROPERTIES_DB));
}
/**
* Even if the target has the cssProperties actor, the returned data may not be in the
* same shape or have all of the data we need. This normalizes the data and fills in
* any missing information like color values.
*
* @return {Object} The normalized CSS database.
*/
function normalizeCssData(db) {
if (db !== CSS_PROPERTIES_DB) {
// Firefox 49's getCSSDatabase() just returned the properties object, but
// now it returns an object with multiple types of CSS information.
if (!db.properties) {
db = { properties: db };
}
// Fill in any missing DB information from the static database.
db = Object.assign({}, CSS_PROPERTIES_DB, db);
for (let name in db.properties) {
// Skip the current property if we can't find it in CSS_PROPERTIES_DB.
if (typeof CSS_PROPERTIES_DB.properties[name] !== "object") {
continue;
}
// Add "supports" information to the css properties if it's missing.
if (!db.properties.color.supports) {
db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports;
}
// Add "values" information to the css properties if it's missing.
if (!db.properties.color.values) {
db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values;
}
// Add "subproperties" information to the css properties if it's missing.
if (!db.properties.background.subproperties) {
db.properties[name].subproperties =
CSS_PROPERTIES_DB.properties[name].subproperties;
}
}
}
reattachCssColorValues(db);
return db;
}
/**
* Color values are omitted to save on space. Add them back here.
* @param {Object} The CSS database.
*/
function reattachCssColorValues(db) {
if (db.properties.color.values[0] === "COLOR") {
const colors = Object.keys(cssColors);
for (let name in db.properties) {
const property = db.properties[name];
// "values" can be undefined if {name} was not found in CSS_PROPERTIES_DB.
if (property.values && property.values[0] === "COLOR") {
property.values.shift();
property.values = property.values.concat(colors).sort();
}
}
}
}
module.exports = {
CssPropertiesFront,
CssProperties,
getCssProperties,
getClientCssProperties,
initCssProperties
};

View file

@ -0,0 +1,125 @@
/* 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 {cssUsageSpec} = require("devtools/shared/specs/csscoverage");
const protocol = require("devtools/shared/protocol");
const {custom} = protocol;
const {LocalizationHelper} = require("devtools/shared/l10n");
const L10N = new LocalizationHelper("devtools/shared/locales/csscoverage.properties");
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
/**
* Allow: let foo = l10n.lookup("csscoverageFoo");
*/
const l10n = exports.l10n = {
lookup: (msg) => L10N.getStr(msg)
};
/**
* Running more than one usage report at a time is probably bad for performance
* and it isn't particularly useful, and it's confusing from a notification POV
* so we only allow one.
*/
var isRunning = false;
var notification;
var target;
var chromeWindow;
/**
* Front for CSSUsageActor
*/
const CSSUsageFront = protocol.FrontClassWithSpec(cssUsageSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
this.actorID = form.cssUsageActor;
this.manage(this);
},
_onStateChange: protocol.preEvent("state-change", function (ev) {
isRunning = ev.isRunning;
ev.target = target;
if (isRunning) {
let gnb = chromeWindow.document.getElementById("global-notificationbox");
notification = gnb.getNotificationWithValue("csscoverage-running");
if (notification == null) {
let notifyStop = reason => {
if (reason == "removed") {
this.stop();
}
};
let msg = l10n.lookup("csscoverageRunningReply");
notification = gnb.appendNotification(msg, "csscoverage-running",
"",
gnb.PRIORITY_INFO_HIGH,
null,
notifyStop);
}
} else {
if (notification) {
notification.remove();
notification = undefined;
}
gDevTools.showToolbox(target, "styleeditor");
target = undefined;
}
}),
/**
* Server-side start is above. Client-side start adds a notification box
*/
start: custom(function (newChromeWindow, newTarget, noreload = false) {
target = newTarget;
chromeWindow = newChromeWindow;
return this._start(noreload);
}, {
impl: "_start"
}),
/**
* Server-side start is above. Client-side start adds a notification box
*/
toggle: custom(function (newChromeWindow, newTarget) {
target = newTarget;
chromeWindow = newChromeWindow;
return this._toggle();
}, {
impl: "_toggle"
}),
/**
* We count STARTING and STOPPING as 'running'
*/
isRunning: function () {
return isRunning;
}
});
exports.CSSUsageFront = CSSUsageFront;
const knownFronts = new WeakMap();
/**
* Create a CSSUsageFront only when needed (returns a promise)
* For notes on target.makeRemote(), see
* https://bugzilla.mozilla.org/show_bug.cgi?id=1016330#c7
*/
exports.getUsage = function (trgt) {
return trgt.makeRemote().then(() => {
let front = knownFronts.get(trgt.client);
if (front == null && trgt.form.cssUsageActor != null) {
front = new CSSUsageFront(trgt.client, trgt.form);
knownFronts.set(trgt.client, front);
}
return front;
});
};

View file

@ -0,0 +1,54 @@
/* 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} = require("chrome");
const {deviceSpec} = require("devtools/shared/specs/device");
const protocol = require("devtools/shared/protocol");
const defer = require("devtools/shared/defer");
const DeviceFront = protocol.FrontClassWithSpec(deviceSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = form.deviceActor;
this.manage(this);
},
screenshotToBlob: function () {
return this.screenshotToDataURL().then(longstr => {
return longstr.string().then(dataURL => {
let deferred = defer();
longstr.release().then(null, Cu.reportError);
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
req.open("GET", dataURL, true);
req.responseType = "blob";
req.onload = () => {
deferred.resolve(req.response);
};
req.onerror = () => {
deferred.reject(req.status);
};
req.send();
return deferred.promise;
});
});
},
});
const _knownDeviceFronts = new WeakMap();
exports.getDeviceFront = function (client, form) {
if (!form.deviceActor) {
return null;
}
if (_knownDeviceFronts.has(client)) {
return _knownDeviceFronts.get(client);
}
let front = new DeviceFront(client, form);
_knownDeviceFronts.set(client, front);
return front;
};

View file

@ -0,0 +1,47 @@
/* 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 {
messagePortSpec,
directorScriptSpec,
directorManagerSpec,
} = require("devtools/shared/specs/director-manager");
const protocol = require("devtools/shared/protocol");
/**
* The corresponding Front object for the MessagePortActor.
*/
const MessagePortFront = protocol.FrontClassWithSpec(messagePortSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
}
});
exports.MessagePortFront = MessagePortFront;
/**
* The corresponding Front object for the DirectorScriptActor.
*/
const DirectorScriptFront = protocol.FrontClassWithSpec(directorScriptSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
}
});
exports.DirectorScriptFront = DirectorScriptFront;
/**
* The corresponding Front object for the DirectorManagerActor.
*/
const DirectorManagerFront = protocol.FrontClassWithSpec(directorManagerSpec, {
initialize: function (client, { directorManagerActor }) {
protocol.Front.prototype.initialize.call(this, client, {
actor: directorManagerActor
});
this.manage(this);
}
});
exports.DirectorManagerFront = DirectorManagerFront;

View file

@ -0,0 +1,21 @@
/* 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 {directorRegistrySpec} = require("devtools/shared/specs/director-registry");
const protocol = require("devtools/shared/protocol");
/**
* The corresponding Front object for the DirectorRegistryActor.
*/
const DirectorRegistryFront = protocol.FrontClassWithSpec(directorRegistrySpec, {
initialize: function (client, { directorRegistryActor }) {
protocol.Front.prototype.initialize.call(this, client, {
actor: directorRegistryActor
});
this.manage(this);
}
});
exports.DirectorRegistryFront = DirectorRegistryFront;

View file

@ -0,0 +1,24 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { emulationSpec } = require("devtools/shared/specs/emulation");
/**
* The corresponding Front object for the EmulationActor.
*/
const EmulationFront = FrontClassWithSpec(emulationSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client);
this.actorID = form.emulationActor;
this.manage(this);
},
destroy: function () {
Front.prototype.destroy.call(this);
},
});
exports.EmulationFront = EmulationFront;

View file

@ -0,0 +1,15 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { eventLoopLagSpec } = require("devtools/shared/specs/eventlooplag");
exports.EventLoopLagFront = FrontClassWithSpec(eventLoopLagSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client);
this.actorID = form.eventLoopLagActor;
this.manage(this);
},
});

View file

@ -0,0 +1,19 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { framerateSpec } = require("devtools/shared/specs/framerate");
/**
* The corresponding Front object for the FramerateActor.
*/
var FramerateFront = exports.FramerateFront = FrontClassWithSpec(framerateSpec, {
initialize: function (client, { framerateActor }) {
Front.prototype.initialize.call(this, client, { actor: framerateActor });
this.manage(this);
}
});
exports.FramerateFront = FramerateFront;

View file

@ -0,0 +1,40 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { gcliSpec } = require("devtools/shared/specs/gcli");
/**
*
*/
const GcliFront = exports.GcliFront = FrontClassWithSpec(gcliSpec, {
initialize: function (client, tabForm) {
Front.prototype.initialize.call(this, client);
this.actorID = tabForm.gcliActor;
// XXX: This is the first actor type in its hierarchy to use the protocol
// library, so we're going to self-own on the client side for now.
this.manage(this);
},
});
// A cache of created fronts: WeakMap<Client, Front>
const knownFronts = new WeakMap();
/**
* Create a GcliFront only when needed (returns a promise)
* For notes on target.makeRemote(), see
* https://bugzilla.mozilla.org/show_bug.cgi?id=1016330#c7
*/
exports.GcliFront.create = function (target) {
return target.makeRemote().then(() => {
let front = knownFronts.get(target.client);
if (front == null && target.form.gcliActor != null) {
front = new GcliFront(target.client, target.form);
knownFronts.set(target.client, front);
}
return front;
});
};

View file

@ -0,0 +1,34 @@
/* 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 { FrontClassWithSpec, custom } = require("devtools/shared/protocol");
const {
customHighlighterSpec,
highlighterSpec
} = require("devtools/shared/specs/highlighters");
const HighlighterFront = FrontClassWithSpec(highlighterSpec, {
// Update the object given a form representation off the wire.
form: function (json) {
this.actorID = json.actor;
// FF42+ HighlighterActors starts exposing custom form, with traits object
this.traits = json.traits || {};
},
pick: custom(function (doFocus) {
if (doFocus && this.pickAndFocus) {
return this.pickAndFocus();
}
return this._pick();
}, {
impl: "_pick"
})
});
exports.HighlighterFront = HighlighterFront;
const CustomHighlighterFront = FrontClassWithSpec(customHighlighterSpec, {});
exports.CustomHighlighterFront = CustomHighlighterFront;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
/* 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 { FrontClassWithSpec } = require("devtools/shared/protocol");
const { gridSpec, layoutSpec } = require("devtools/shared/specs/layout");
const GridFront = FrontClassWithSpec(gridSpec, {
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
},
/**
* Getter for the grid fragments data.
*/
get gridFragments() {
return this._form.gridFragments;
}
});
const LayoutFront = FrontClassWithSpec(layoutSpec, {});
exports.GridFront = GridFront;
exports.LayoutFront = LayoutFront;

View file

@ -0,0 +1,92 @@
/* 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 { memorySpec } = require("devtools/shared/specs/memory");
const { Task } = require("devtools/shared/task");
const protocol = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm", true);
loader.lazyRequireGetter(this, "HeapSnapshotFileUtils",
"devtools/shared/heapsnapshot/HeapSnapshotFileUtils");
const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
initialize: function (client, form, rootForm = null) {
protocol.Front.prototype.initialize.call(this, client, form);
this._client = client;
this.actorID = form.memoryActor;
this.heapSnapshotFileActorID = rootForm
? rootForm.heapSnapshotFileActor
: null;
this.manage(this);
},
/**
* Save a heap snapshot, transfer it from the server to the client if the
* server and client do not share a file system, and return the local file
* path to the heap snapshot.
*
* Note that this is safe to call for actors inside sandoxed child processes,
* as we jump through the correct IPDL hoops.
*
* @params Boolean options.forceCopy
* Always force a bulk data copy of the saved heap snapshot, even when
* the server and client share a file system.
*
* @params {Object|undefined} options.boundaries
* The boundaries for the heap snapshot. See
* ThreadSafeChromeUtils.webidl for more details.
*
* @returns Promise<String>
*/
saveHeapSnapshot: protocol.custom(Task.async(function* (options = {}) {
const snapshotId = yield this._saveHeapSnapshotImpl(options.boundaries);
if (!options.forceCopy &&
(yield HeapSnapshotFileUtils.haveHeapSnapshotTempFile(snapshotId))) {
return HeapSnapshotFileUtils.getHeapSnapshotTempFilePath(snapshotId);
}
return yield this.transferHeapSnapshot(snapshotId);
}), {
impl: "_saveHeapSnapshotImpl"
}),
/**
* Given that we have taken a heap snapshot with the given id, transfer the
* heap snapshot file to the client. The path to the client's local file is
* returned.
*
* @param {String} snapshotId
*
* @returns Promise<String>
*/
transferHeapSnapshot: protocol.custom(function (snapshotId) {
if (!this.heapSnapshotFileActorID) {
throw new Error("MemoryFront initialized without a rootForm");
}
const request = this._client.request({
to: this.heapSnapshotFileActorID,
type: "transferHeapSnapshot",
snapshotId
});
return new Promise((resolve, reject) => {
const outFilePath =
HeapSnapshotFileUtils.getNewUniqueHeapSnapshotTempFilePath();
const outFile = new FileUtils.File(outFilePath);
const outFileStream = FileUtils.openSafeFileOutputStream(outFile);
request.on("bulk-reply", Task.async(function* ({ copyTo }) {
yield copyTo(outFileStream);
FileUtils.closeSafeFileOutputStream(outFileStream);
resolve(outFilePath);
}));
});
})
});
exports.MemoryFront = MemoryFront;

View file

@ -0,0 +1,41 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DevToolsModules(
'actor-registry.js',
'addons.js',
'animation.js',
'call-watcher.js',
'canvas.js',
'css-properties.js',
'csscoverage.js',
'device.js',
'director-manager.js',
'director-registry.js',
'emulation.js',
'eventlooplag.js',
'framerate.js',
'gcli.js',
'highlighters.js',
'inspector.js',
'layout.js',
'memory.js',
'performance-entries.js',
'performance-recording.js',
'performance.js',
'preference.js',
'profiler.js',
'promises.js',
'reflow.js',
'settings.js',
'storage.js',
'string.js',
'styles.js',
'stylesheets.js',
'timeline.js',
'webaudio.js',
'webgl.js'
)

View file

@ -0,0 +1,17 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const performanceSpec = require("devtools/shared/specs/performance-entries");
var PerformanceEntriesFront = FrontClassWithSpec(performanceSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client);
this.actorID = form.performanceEntriesActor;
this.manage(this);
},
});
exports.PerformanceEntriesFront = PerformanceEntriesFront;

View file

@ -0,0 +1,152 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording");
loader.lazyRequireGetter(this, "PerformanceIO",
"devtools/client/performance/modules/io");
loader.lazyRequireGetter(this, "PerformanceRecordingCommon",
"devtools/shared/performance/recording-common", true);
loader.lazyRequireGetter(this, "RecordingUtils",
"devtools/shared/performance/recording-utils");
loader.lazyRequireGetter(this, "merge", "sdk/util/object", true);
/**
* This can be used on older Profiler implementations, but the methods cannot
* be changed -- you must introduce a new method, and detect the server.
*/
const PerformanceRecordingFront = FrontClassWithSpec(performanceRecordingSpec, merge({
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
this._configuration = form.configuration;
this._startingBufferStatus = form.startingBufferStatus;
this._console = form.console;
this._label = form.label;
this._startTime = form.startTime;
this._localStartTime = form.localStartTime;
this._recording = form.recording;
this._completed = form.completed;
this._duration = form.duration;
if (form.finalizedData) {
this._profile = form.profile;
this._systemHost = form.systemHost;
this._systemClient = form.systemClient;
}
// Sort again on the client side if we're using realtime markers and the recording
// just finished. This is because GC/Compositing markers can come into the array out
// of order with the other markers, leading to strange collapsing in waterfall view.
if (this._completed && !this._markersSorted) {
this._markers = this._markers.sort((a, b) => (a.start > b.start));
this._markersSorted = true;
}
},
initialize: function (client, form, config) {
Front.prototype.initialize.call(this, client, form);
this._markers = [];
this._frames = [];
this._memory = [];
this._ticks = [];
this._allocations = { sites: [], timestamps: [], frames: [], sizes: [] };
},
destroy: function () {
Front.prototype.destroy.call(this);
},
/**
* Saves the current recording to a file.
*
* @param nsILocalFile file
* The file to stream the data into.
*/
exportRecording: function (file) {
let recordingData = this.getAllData();
return PerformanceIO.saveRecordingToFile(recordingData, file);
},
/**
* Fired whenever the PerformanceFront emits markers, memory or ticks.
*/
_addTimelineData: function (eventName, data) {
let config = this.getConfiguration();
switch (eventName) {
// Accumulate timeline markers into an array. Furthermore, the timestamps
// do not have a zero epoch, so offset all of them by the start time.
case "markers": {
if (!config.withMarkers) {
break;
}
let { markers } = data;
RecordingUtils.offsetMarkerTimes(markers, this._startTime);
RecordingUtils.pushAll(this._markers, markers);
break;
}
// Accumulate stack frames into an array.
case "frames": {
if (!config.withMarkers) {
break;
}
let { frames } = data;
RecordingUtils.pushAll(this._frames, frames);
break;
}
// Accumulate memory measurements into an array. Furthermore, the timestamp
// does not have a zero epoch, so offset it by the actor's start time.
case "memory": {
if (!config.withMemory) {
break;
}
let { delta, measurement } = data;
this._memory.push({
delta: delta - this._startTime,
value: measurement.total / 1024 / 1024
});
break;
}
// Save the accumulated refresh driver ticks.
case "ticks": {
if (!config.withTicks) {
break;
}
let { timestamps } = data;
this._ticks = timestamps;
break;
}
// Accumulate allocation sites into an array.
case "allocations": {
if (!config.withAllocations) {
break;
}
let {
allocations: sites,
allocationsTimestamps: timestamps,
allocationSizes: sizes,
frames,
} = data;
RecordingUtils.offsetAndScaleTimestamps(timestamps, this._startTime);
RecordingUtils.pushAll(this._allocations.sites, sites);
RecordingUtils.pushAll(this._allocations.timestamps, timestamps);
RecordingUtils.pushAll(this._allocations.frames, frames);
RecordingUtils.pushAll(this._allocations.sizes, sizes);
break;
}
}
},
toString: () => "[object PerformanceRecordingFront]"
}, PerformanceRecordingCommon));
exports.PerformanceRecordingFront = PerformanceRecordingFront;

View file

@ -0,0 +1,148 @@
/* 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 { Cu } = require("chrome");
const { Front, FrontClassWithSpec, custom, preEvent } = require("devtools/shared/protocol");
const { PerformanceRecordingFront } = require("devtools/shared/fronts/performance-recording");
const { performanceSpec } = require("devtools/shared/specs/performance");
const { Task } = require("devtools/shared/task");
loader.lazyRequireGetter(this, "PerformanceIO",
"devtools/client/performance/modules/io");
loader.lazyRequireGetter(this, "LegacyPerformanceFront",
"devtools/client/performance/legacy/front", true);
loader.lazyRequireGetter(this, "getSystemInfo",
"devtools/shared/system", true);
const PerformanceFront = FrontClassWithSpec(performanceSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client, form);
this.actorID = form.performanceActor;
this.manage(this);
},
destroy: function () {
Front.prototype.destroy.call(this);
},
/**
* Conenct to the server, and handle once-off tasks like storing traits
* or system info.
*/
connect: custom(Task.async(function* () {
let systemClient = yield getSystemInfo();
let { traits } = yield this._connect({ systemClient });
this._traits = traits;
return this._traits;
}), {
impl: "_connect"
}),
get traits() {
if (!this._traits) {
Cu.reportError("Cannot access traits of PerformanceFront before " +
"calling `connect()`.");
}
return this._traits;
},
/**
* Pass in a PerformanceRecording and get a normalized value from 0 to 1 of how much
* of this recording's lifetime remains without being overwritten.
*
* @param {PerformanceRecording} recording
* @return {number?}
*/
getBufferUsageForRecording: function (recording) {
if (!recording.isRecording()) {
return void 0;
}
let {
position: currentPosition,
totalSize,
generation: currentGeneration
} = this._currentBufferStatus;
let {
position: origPosition,
generation: origGeneration
} = recording.getStartingBufferStatus();
let normalizedCurrent = (totalSize * (currentGeneration - origGeneration)) +
currentPosition;
let percent = (normalizedCurrent - origPosition) / totalSize;
// Clamp between 0 and 1; can get negative percentage values when a new
// recording starts and the currentBufferStatus has not yet been updated. Rather
// than fetching another status update, just clamp to 0, and this will be updated
// on the next profiler-status event.
if (percent < 0) {
return 0;
} else if (percent > 1) {
return 1;
}
return percent;
},
/**
* Loads a recording from a file.
*
* @param {nsILocalFile} file
* The file to import the data from.
* @return {Promise<PerformanceRecordingFront>}
*/
importRecording: function (file) {
return PerformanceIO.loadRecordingFromFile(file).then(recordingData => {
let model = new PerformanceRecordingFront();
model._imported = true;
model._label = recordingData.label || "";
model._duration = recordingData.duration;
model._markers = recordingData.markers;
model._frames = recordingData.frames;
model._memory = recordingData.memory;
model._ticks = recordingData.ticks;
model._allocations = recordingData.allocations;
model._profile = recordingData.profile;
model._configuration = recordingData.configuration || {};
model._systemHost = recordingData.systemHost;
model._systemClient = recordingData.systemClient;
return model;
});
},
/**
* Store profiler status when the position has been update so we can
* calculate recording's buffer percentage usage after emitting the event.
*/
_onProfilerStatus: preEvent("profiler-status", function (data) {
this._currentBufferStatus = data;
}),
/**
* For all PerformanceRecordings that are recording, and needing realtime markers,
* apply the timeline data to the front PerformanceRecording (so we only have one event
* for each timeline data chunk as they could be shared amongst several recordings).
*/
_onTimelineEvent: preEvent("timeline-data", function (type, data, recordings) {
for (let recording of recordings) {
recording._addTimelineData(type, data);
}
}),
});
exports.PerformanceFront = PerformanceFront;
exports.createPerformanceFront = function createPerformanceFront(target) {
// If we force legacy mode, or the server does not have a performance actor (< Fx42),
// use our LegacyPerformanceFront which will handle
// the communication over RDP to other underlying actors.
if (target.TEST_PERFORMANCE_LEGACY_FRONT || !target.form.performanceActor) {
return new LegacyPerformanceFront(target);
}
// If our server has a PerformanceActor implementation, set this
// up like a normal front.
return new PerformanceFront(target.client, target.form);
};

View file

@ -0,0 +1,31 @@
/* 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 {preferenceSpec} = require("devtools/shared/specs/preference");
const protocol = require("devtools/shared/protocol");
const PreferenceFront = protocol.FrontClassWithSpec(preferenceSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = form.preferenceActor;
this.manage(this);
},
});
const _knownPreferenceFronts = new WeakMap();
exports.getPreferenceFront = function (client, form) {
if (!form.preferenceActor) {
return null;
}
if (_knownPreferenceFronts.has(client)) {
return _knownPreferenceFronts.get(client);
}
let front = new PreferenceFront(client, form);
_knownPreferenceFronts.set(client, front);
return front;
};

View file

@ -0,0 +1,80 @@
/* 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 { Cu } = require("chrome");
const {
Front,
FrontClassWithSpec,
custom
} = require("devtools/shared/protocol");
const { profilerSpec } = require("devtools/shared/specs/profiler");
loader.lazyRequireGetter(this, "events", "sdk/event/core");
loader.lazyRequireGetter(this, "extend", "sdk/util/object", true);
/**
* This can be used on older Profiler implementations, but the methods cannot
* be changed -- you must introduce a new method, and detect the server.
*/
exports.ProfilerFront = FrontClassWithSpec(profilerSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client, form);
this.actorID = form.profilerActor;
this.manage(this);
this._onProfilerEvent = this._onProfilerEvent.bind(this);
events.on(this, "*", this._onProfilerEvent);
},
destroy: function () {
events.off(this, "*", this._onProfilerEvent);
Front.prototype.destroy.call(this);
},
/**
* If using the protocol.js Fronts, then make stringify default,
* since the read/write mechanisms will expose it as an object anyway, but
* this lets other consumers who connect directly (xpcshell tests, Gecko Profiler) to
* have unchanged behaviour.
*/
getProfile: custom(function (options) {
return this._getProfile(extend({ stringify: true }, options));
}, {
impl: "_getProfile"
}),
/**
* Also emit an old `eventNotification` for older consumers of the profiler.
*/
_onProfilerEvent: function (eventName, data) {
// If this event already passed through once, don't repropagate
if (data.relayed) {
return;
}
data.relayed = true;
if (eventName === "eventNotification") {
// If this is `eventNotification`, this is coming from an older Gecko (<Fx42)
// that doesn't use protocol.js style events. Massage it to emit a protocol.js
// style event as well.
events.emit(this, data.topic, data);
} else {
// Otherwise if a modern protocol.js event, emit it also as `eventNotification`
// for compatibility reasons on the client (like for any add-ons/Gecko Profiler
// using this event) and log a deprecation message if there is a listener.
this.conn.emit("eventNotification", {
subject: data.subject,
topic: data.topic,
data: data.data,
details: data.details
});
if (this.conn._getListeners("eventNotification").length) {
Cu.reportError(`
ProfilerActor's "eventNotification" on the DebuggerClient has been deprecated.
Use the ProfilerFront found in "devtools/server/actors/profiler".`);
}
}
},
});

View file

@ -0,0 +1,27 @@
/* 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 {
Front,
FrontClassWithSpec,
} = require("devtools/shared/protocol");
const { promisesSpec } = require("devtools/shared/specs/promises");
/**
* PromisesFront, the front for the PromisesActor.
*/
const PromisesFront = FrontClassWithSpec(promisesSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client, form);
this.actorID = form.promisesActor;
this.manage(this);
},
destroy: function () {
Front.prototype.destroy.call(this);
}
});
exports.PromisesFront = PromisesFront;

View file

@ -0,0 +1,29 @@
/* 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 {reflowSpec} = require("devtools/shared/specs/reflow");
const protocol = require("devtools/shared/protocol");
/**
* Usage example of the reflow front:
*
* let front = ReflowFront(toolbox.target.client, toolbox.target.form);
* front.on("reflows", this._onReflows);
* front.start();
* // now wait for events to come
*/
const ReflowFront = protocol.FrontClassWithSpec(reflowSpec, {
initialize: function (client, {reflowActor}) {
protocol.Front.prototype.initialize.call(this, client, {actor: reflowActor});
this.manage(this);
},
destroy: function () {
protocol.Front.prototype.destroy.call(this);
},
});
exports.ReflowFront = ReflowFront;

View file

@ -0,0 +1,29 @@
/* 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 {settingsSpec} = require("devtools/shared/specs/settings");
const protocol = require("devtools/shared/protocol");
const SettingsFront = protocol.FrontClassWithSpec(settingsSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = form.settingsActor;
this.manage(this);
},
});
const _knownSettingsFronts = new WeakMap();
exports.getSettingsFront = function (client, form) {
if (!form.settingsActor) {
return null;
}
if (_knownSettingsFronts.has(client)) {
return _knownSettingsFronts.get(client);
}
let front = new SettingsFront(client, form);
_knownSettingsFronts.set(client, front);
return front;
};

View file

@ -0,0 +1,32 @@
/* 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 protocol = require("devtools/shared/protocol");
const specs = require("devtools/shared/specs/storage");
for (let childSpec of Object.values(specs.childSpecs)) {
protocol.FrontClassWithSpec(childSpec, {
form(form, detail) {
if (detail === "actorid") {
this.actorID = form;
return null;
}
this.actorID = form.actor;
this.hosts = form.hosts;
return null;
}
});
}
const StorageFront = protocol.FrontClassWithSpec(specs.storageSpec, {
initialize(client, tabForm) {
protocol.Front.prototype.initialize.call(this, client);
this.actorID = tabForm.storageActor;
this.manage(this);
}
});
exports.StorageFront = StorageFront;

View file

@ -0,0 +1,47 @@
/* 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 {DebuggerServer} = require("devtools/server/main");
const promise = require("promise");
const {longStringSpec, SimpleStringFront} = require("devtools/shared/specs/string");
const protocol = require("devtools/shared/protocol");
const LongStringFront = protocol.FrontClassWithSpec(longStringSpec, {
initialize: function (client) {
protocol.Front.prototype.initialize.call(this, client);
},
destroy: function () {
this.initial = null;
this.length = null;
this.strPromise = null;
protocol.Front.prototype.destroy.call(this);
},
form: function (form) {
this.actorID = form.actor;
this.initial = form.initial;
this.length = form.length;
},
string: function () {
if (!this.strPromise) {
let promiseRest = (thusFar) => {
if (thusFar.length === this.length) {
return promise.resolve(thusFar);
}
return this.substring(thusFar.length,
thusFar.length + DebuggerServer.LONG_STRING_READ_LENGTH)
.then((next) => promiseRest(thusFar + next));
};
this.strPromise = promiseRest(this.initial);
}
return this.strPromise;
}
});
exports.LongStringFront = LongStringFront;
exports.SimpleStringFront = SimpleStringFront;

View file

@ -0,0 +1,113 @@
/* 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 { SimpleStringFront } = require("devtools/shared/fronts/string");
const { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const {
oldStyleSheetSpec,
styleEditorSpec
} = require("devtools/shared/specs/styleeditor");
const promise = require("promise");
const defer = require("devtools/shared/defer");
const events = require("sdk/event/core");
/**
* StyleSheetFront is the client-side counterpart to a StyleSheetActor.
*/
const OldStyleSheetFront = FrontClassWithSpec(oldStyleSheetSpec, {
initialize: function (conn, form, ctx, detail) {
Front.prototype.initialize.call(this, conn, form, ctx, detail);
this._onPropertyChange = this._onPropertyChange.bind(this);
events.on(this, "property-change", this._onPropertyChange);
},
destroy: function () {
events.off(this, "property-change", this._onPropertyChange);
Front.prototype.destroy.call(this);
},
_onPropertyChange: function (property, value) {
this._form[property] = value;
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
},
getText: function () {
let deferred = defer();
events.once(this, "source-load", (source) => {
let longStr = new SimpleStringFront(source);
deferred.resolve(longStr);
});
this.fetchSource();
return deferred.promise;
},
getOriginalSources: function () {
return promise.resolve([]);
},
get href() {
return this._form.href;
},
get nodeHref() {
return this._form.nodeHref;
},
get disabled() {
return !!this._form.disabled;
},
get title() {
return this._form.title;
},
get isSystem() {
return this._form.system;
},
get styleSheetIndex() {
return this._form.styleSheetIndex;
},
get ruleCount() {
return this._form.ruleCount;
}
});
exports.OldStyleSheetFront = OldStyleSheetFront;
/**
* The corresponding Front object for the StyleEditorActor.
*/
const StyleEditorFront = FrontClassWithSpec(styleEditorSpec, {
initialize: function (client, tabForm) {
Front.prototype.initialize.call(this, client);
this.actorID = tabForm.styleEditorActor;
this.manage(this);
},
getStyleSheets: function () {
let deferred = defer();
events.once(this, "document-load", (styleSheets) => {
deferred.resolve(styleSheets);
});
this.newDocument();
return deferred.promise;
},
addStyleSheet: function (text) {
return this.newStyleSheet(text);
}
});
exports.StyleEditorFront = StyleEditorFront;

View file

@ -0,0 +1,421 @@
/* 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";
require("devtools/shared/fronts/stylesheets");
const {
Front,
FrontClassWithSpec,
custom,
preEvent
} = require("devtools/shared/protocol");
const {
pageStyleSpec,
styleRuleSpec
} = require("devtools/shared/specs/styles");
const promise = require("promise");
const { Task } = require("devtools/shared/task");
const { Class } = require("sdk/core/heritage");
const { RuleRewriter } = require("devtools/shared/css/parsing-utils");
/**
* PageStyleFront, the front object for the PageStyleActor
*/
const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
initialize: function (conn, form, ctx, detail) {
Front.prototype.initialize.call(this, conn, form, ctx, detail);
this.inspector = this.parent();
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this._form = form;
},
destroy: function () {
Front.prototype.destroy.call(this);
},
get walker() {
return this.inspector.walker;
},
get supportsAuthoredStyles() {
return this._form.traits && this._form.traits.authoredStyles;
},
getMatchedSelectors: custom(function (node, property, options) {
return this._getMatchedSelectors(node, property, options).then(ret => {
return ret.matched;
});
}, {
impl: "_getMatchedSelectors"
}),
getApplied: custom(Task.async(function* (node, options = {}) {
// If the getApplied method doesn't recreate the style cache itself, this
// means a call to cssLogic.highlight is required before trying to access
// the applied rules. Issue a request to getLayout if this is the case.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1103993#c16.
if (!this._form.traits || !this._form.traits.getAppliedCreatesStyleCache) {
yield this.getLayout(node);
}
let ret = yield this._getApplied(node, options);
return ret.entries;
}), {
impl: "_getApplied"
}),
addNewRule: custom(function (node, pseudoClasses) {
let addPromise;
if (this.supportsAuthoredStyles) {
addPromise = this._addNewRule(node, pseudoClasses, true);
} else {
addPromise = this._addNewRule(node, pseudoClasses);
}
return addPromise.then(ret => {
return ret.entries[0];
});
}, {
impl: "_addNewRule"
})
});
exports.PageStyleFront = PageStyleFront;
/**
* StyleRuleFront, the front for the StyleRule actor.
*/
const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
initialize: function (client, form, ctx, detail) {
Front.prototype.initialize.call(this, client, form, ctx, detail);
},
destroy: function () {
Front.prototype.destroy.call(this);
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
if (this._mediaText) {
this._mediaText = null;
}
},
/**
* Ensure _form is updated when location-changed is emitted.
*/
_locationChangedPre: preEvent("location-changed", function (line, column) {
this._clearOriginalLocation();
this._form.line = line;
this._form.column = column;
}),
/**
* Return a new RuleModificationList or RuleRewriter for this node.
* A RuleRewriter will be returned when the rule's canSetRuleText
* trait is true; otherwise a RuleModificationList will be
* returned.
*
* @param {CssPropertiesFront} cssProperties
* This is needed by the RuleRewriter.
* @return {RuleModificationList}
*/
startModifyingProperties: function (cssProperties) {
if (this.canSetRuleText) {
return new RuleRewriter(cssProperties.isKnown, this, this.authoredText);
}
return new RuleModificationList(this);
},
get type() {
return this._form.type;
},
get line() {
return this._form.line || -1;
},
get column() {
return this._form.column || -1;
},
get cssText() {
return this._form.cssText;
},
get authoredText() {
return this._form.authoredText || this._form.cssText;
},
get declarations() {
return this._form.declarations || [];
},
get keyText() {
return this._form.keyText;
},
get name() {
return this._form.name;
},
get selectors() {
return this._form.selectors;
},
get media() {
return this._form.media;
},
get mediaText() {
if (!this._form.media) {
return null;
}
if (this._mediaText) {
return this._mediaText;
}
this._mediaText = this.media.join(", ");
return this._mediaText;
},
get parentRule() {
return this.conn.getActor(this._form.parentRule);
},
get parentStyleSheet() {
return this.conn.getActor(this._form.parentStyleSheet);
},
get element() {
return this.conn.getActor(this._form.element);
},
get href() {
if (this._form.href) {
return this._form.href;
}
let sheet = this.parentStyleSheet;
return sheet ? sheet.href : "";
},
get nodeHref() {
let sheet = this.parentStyleSheet;
return sheet ? sheet.nodeHref : "";
},
get supportsModifySelectorUnmatched() {
return this._form.traits && this._form.traits.modifySelectorUnmatched;
},
get canSetRuleText() {
return this._form.traits && this._form.traits.canSetRuleText;
},
get location() {
return {
source: this.parentStyleSheet,
href: this.href,
line: this.line,
column: this.column
};
},
_clearOriginalLocation: function () {
this._originalLocation = null;
},
getOriginalLocation: function () {
if (this._originalLocation) {
return promise.resolve(this._originalLocation);
}
let parentSheet = this.parentStyleSheet;
if (!parentSheet) {
// This rule doesn't belong to a stylesheet so it is an inline style.
// Inline styles do not have any mediaText so we can return early.
return promise.resolve(this.location);
}
return parentSheet.getOriginalLocation(this.line, this.column)
.then(({ fromSourceMap, source, line, column }) => {
let location = {
href: source,
line: line,
column: column,
mediaText: this.mediaText
};
if (fromSourceMap === false) {
location.source = this.parentStyleSheet;
}
if (!source) {
location.href = this.href;
}
this._originalLocation = location;
return location;
});
},
modifySelector: custom(Task.async(function* (node, value) {
let response;
if (this.supportsModifySelectorUnmatched) {
// If the debugee supports adding unmatched rules (post FF41)
if (this.canSetRuleText) {
response = yield this.modifySelector2(node, value, true);
} else {
response = yield this.modifySelector2(node, value);
}
} else {
response = yield this._modifySelector(value);
}
if (response.ruleProps) {
response.ruleProps = response.ruleProps.entries[0];
}
return response;
}), {
impl: "_modifySelector"
}),
setRuleText: custom(function (newText) {
this._form.authoredText = newText;
return this._setRuleText(newText);
}, {
impl: "_setRuleText"
})
});
exports.StyleRuleFront = StyleRuleFront;
/**
* Convenience API for building a list of attribute modifications
* for the `modifyProperties` request. A RuleModificationList holds a
* list of modifications that will be applied to a StyleRuleActor.
* The modifications are processed in the order in which they are
* added to the RuleModificationList.
*
* Objects of this type expose the same API as @see RuleRewriter.
* This lets the inspector use (mostly) the same code, regardless of
* whether the server implements setRuleText.
*/
var RuleModificationList = Class({
/**
* Initialize a RuleModificationList.
* @param {StyleRuleFront} rule the associated rule
*/
initialize: function (rule) {
this.rule = rule;
this.modifications = [];
},
/**
* Apply the modifications in this object to the associated rule.
*
* @return {Promise} A promise which will be resolved when the modifications
* are complete; @see StyleRuleActor.modifyProperties.
*/
apply: function () {
return this.rule.modifyProperties(this.modifications);
},
/**
* Add a "set" entry to the modification list.
*
* @param {Number} index index of the property in the rule.
* This can be -1 in the case where
* the rule does not support setRuleText;
* generally for setting properties
* on an element's style.
* @param {String} name the property's name
* @param {String} value the property's value
* @param {String} priority the property's priority, either the empty
* string or "important"
*/
setProperty: function (index, name, value, priority) {
this.modifications.push({
type: "set",
name: name,
value: value,
priority: priority
});
},
/**
* Add a "remove" entry to the modification list.
*
* @param {Number} index index of the property in the rule.
* This can be -1 in the case where
* the rule does not support setRuleText;
* generally for setting properties
* on an element's style.
* @param {String} name the name of the property to remove
*/
removeProperty: function (index, name) {
this.modifications.push({
type: "remove",
name: name
});
},
/**
* Rename a property. This implementation acts like
* |removeProperty|, because |setRuleText| is not available.
*
* @param {Number} index index of the property in the rule.
* This can be -1 in the case where
* the rule does not support setRuleText;
* generally for setting properties
* on an element's style.
* @param {String} name current name of the property
*
* This parameter is also passed, but as it is not used in this
* implementation, it is omitted. It is documented here as this
* code also defined the interface implemented by @see RuleRewriter.
* @param {String} newName new name of the property
*/
renameProperty: function (index, name) {
this.removeProperty(index, name);
},
/**
* Enable or disable a property. This implementation acts like
* |removeProperty| when disabling, or a no-op when enabling,
* because |setRuleText| is not available.
*
* @param {Number} index index of the property in the rule.
* This can be -1 in the case where
* the rule does not support setRuleText;
* generally for setting properties
* on an element's style.
* @param {String} name current name of the property
* @param {Boolean} isEnabled true if the property should be enabled;
* false if it should be disabled
*/
setPropertyEnabled: function (index, name, isEnabled) {
if (!isEnabled) {
this.removeProperty(index, name);
}
},
/**
* Create a new property. This implementation does nothing, because
* |setRuleText| is not available.
*
* These parameters are passed, but as they are not used in this
* implementation, they are omitted. They are documented here as
* this code also defined the interface implemented by @see
* RuleRewriter.
*
* @param {Number} index index of the property in the rule.
* This can be -1 in the case where
* the rule does not support setRuleText;
* generally for setting properties
* on an element's style.
* @param {String} name name of the new property
* @param {String} value value of the new property
* @param {String} priority priority of the new property; either
* the empty string or "important"
* @param {Boolean} enabled True if the new property should be
* enabled, false if disabled
*/
createProperty: function () {
// Nothing.
},
});

View file

@ -0,0 +1,184 @@
/* 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 { Front, FrontClassWithSpec } = require("devtools/shared/protocol");
const {
getIndentationFromPrefs,
getIndentationFromString
} = require("devtools/shared/indentation");
const {
originalSourceSpec,
mediaRuleSpec,
styleSheetSpec,
styleSheetsSpec
} = require("devtools/shared/specs/stylesheets");
const promise = require("promise");
const { Task } = require("devtools/shared/task");
const events = require("sdk/event/core");
/**
* The client-side counterpart for an OriginalSourceActor.
*/
const OriginalSourceFront = FrontClassWithSpec(originalSourceSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client, form);
this.isOriginalSource = true;
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
},
get href() {
return this._form.url;
},
get url() {
return this._form.url;
}
});
exports.OriginalSourceFront = OriginalSourceFront;
/**
* Corresponding client-side front for a MediaRuleActor.
*/
const MediaRuleFront = FrontClassWithSpec(mediaRuleSpec, {
initialize: function (client, form) {
Front.prototype.initialize.call(this, client, form);
this._onMatchesChange = this._onMatchesChange.bind(this);
events.on(this, "matches-change", this._onMatchesChange);
},
_onMatchesChange: function (matches) {
this._form.matches = matches;
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
},
get mediaText() {
return this._form.mediaText;
},
get conditionText() {
return this._form.conditionText;
},
get matches() {
return this._form.matches;
},
get line() {
return this._form.line || -1;
},
get column() {
return this._form.column || -1;
},
get parentStyleSheet() {
return this.conn.getActor(this._form.parentStyleSheet);
}
});
exports.MediaRuleFront = MediaRuleFront;
/**
* StyleSheetFront is the client-side counterpart to a StyleSheetActor.
*/
const StyleSheetFront = FrontClassWithSpec(styleSheetSpec, {
initialize: function (conn, form) {
Front.prototype.initialize.call(this, conn, form);
this._onPropertyChange = this._onPropertyChange.bind(this);
events.on(this, "property-change", this._onPropertyChange);
},
destroy: function () {
events.off(this, "property-change", this._onPropertyChange);
Front.prototype.destroy.call(this);
},
_onPropertyChange: function (property, value) {
this._form[property] = value;
},
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this._form = form;
},
get href() {
return this._form.href;
},
get nodeHref() {
return this._form.nodeHref;
},
get disabled() {
return !!this._form.disabled;
},
get title() {
return this._form.title;
},
get isSystem() {
return this._form.system;
},
get styleSheetIndex() {
return this._form.styleSheetIndex;
},
get ruleCount() {
return this._form.ruleCount;
},
/**
* Get the indentation to use for edits to this style sheet.
*
* @return {Promise} A promise that will resolve to a string that
* should be used to indent a block in this style sheet.
*/
guessIndentation: function () {
let prefIndent = getIndentationFromPrefs();
if (prefIndent) {
let {indentUnit, indentWithTabs} = prefIndent;
return promise.resolve(indentWithTabs ? "\t" : " ".repeat(indentUnit));
}
return Task.spawn(function* () {
let longStr = yield this.getText();
let source = yield longStr.string();
let {indentUnit, indentWithTabs} = getIndentationFromString(source);
return indentWithTabs ? "\t" : " ".repeat(indentUnit);
}.bind(this));
}
});
exports.StyleSheetFront = StyleSheetFront;
/**
* The corresponding Front object for the StyleSheetsActor.
*/
const StyleSheetsFront = FrontClassWithSpec(styleSheetsSpec, {
initialize: function (client, tabForm) {
Front.prototype.initialize.call(this, client);
this.actorID = tabForm.styleSheetsActor;
this.manage(this);
}
});
exports.StyleSheetsFront = StyleSheetsFront;

View file

@ -0,0 +1,25 @@
/* 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 {
Front,
FrontClassWithSpec,
} = require("devtools/shared/protocol");
const { timelineSpec } = require("devtools/shared/specs/timeline");
/**
* TimelineFront, the front for the TimelineActor.
*/
const TimelineFront = FrontClassWithSpec(timelineSpec, {
initialize: function (client, { timelineActor }) {
Front.prototype.initialize.call(this, client, { actor: timelineActor });
this.manage(this);
},
destroy: function () {
Front.prototype.destroy.call(this);
},
});
exports.TimelineFront = TimelineFront;

View file

@ -0,0 +1,83 @@
/* 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 {
audionodeSpec,
webAudioSpec,
AUTOMATION_METHODS,
NODE_CREATION_METHODS,
NODE_ROUTING_METHODS,
} = require("devtools/shared/specs/webaudio");
const protocol = require("devtools/shared/protocol");
const AUDIO_NODE_DEFINITION = require("devtools/server/actors/utils/audionodes.json");
/**
* The corresponding Front object for the AudioNodeActor.
*
* @attribute {String} type
* The type of audio node, like "OscillatorNode", "MediaElementAudioSourceNode"
* @attribute {Boolean} source
* Boolean indicating if the node is a source node, like BufferSourceNode,
* MediaElementAudioSourceNode, OscillatorNode, etc.
* @attribute {Boolean} bypassable
* Boolean indicating if the audio node is bypassable (splitter,
* merger and destination nodes, for example, are not)
*/
const AudioNodeFront = protocol.FrontClassWithSpec(audionodeSpec, {
form: function (form, detail) {
if (detail === "actorid") {
this.actorID = form;
return;
}
this.actorID = form.actor;
this.type = form.type;
this.source = form.source;
this.bypassable = form.bypassable;
},
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
// if we were manually passed a form, this was created manually and
// needs to own itself for now.
if (form) {
this.manage(this);
}
}
});
exports.AudioNodeFront = AudioNodeFront;
/**
* The corresponding Front object for the WebAudioActor.
*/
const WebAudioFront = protocol.FrontClassWithSpec(webAudioSpec, {
initialize: function (client, { webaudioActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: webaudioActor });
this.manage(this);
},
/**
* If connecting to older geckos (<Fx43), where audio node actor's do not
* contain `type`, `source` and `bypassable` properties, fetch
* them manually here.
*/
_onCreateNode: protocol.preEvent("create-node", function (audionode) {
if (!audionode.type) {
return audionode.getType().then(type => {
audionode.type = type;
audionode.source = !!AUDIO_NODE_DEFINITION[type].source;
audionode.bypassable = !AUDIO_NODE_DEFINITION[type].unbypassable;
});
}
return null;
}),
});
WebAudioFront.AUTOMATION_METHODS = new Set(AUTOMATION_METHODS);
WebAudioFront.NODE_CREATION_METHODS = new Set(NODE_CREATION_METHODS);
WebAudioFront.NODE_ROUTING_METHODS = new Set(NODE_ROUTING_METHODS);
exports.WebAudioFront = WebAudioFront;

View file

@ -0,0 +1,45 @@
/* 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 {
shaderSpec,
programSpec,
webGLSpec,
} = require("devtools/shared/specs/webgl");
const protocol = require("devtools/shared/protocol");
/**
* The corresponding Front object for the ShaderActor.
*/
const ShaderFront = protocol.FrontClassWithSpec(shaderSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
}
});
exports.ShaderFront = ShaderFront;
/**
* The corresponding Front object for the ProgramActor.
*/
const ProgramFront = protocol.FrontClassWithSpec(programSpec, {
initialize: function (client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
}
});
exports.ProgramFront = ProgramFront;
/**
* The corresponding Front object for the WebGLActor.
*/
const WebGLFront = protocol.FrontClassWithSpec(webGLSpec, {
initialize: function (client, { webglActor }) {
protocol.Front.prototype.initialize.call(this, client, { actor: webglActor });
this.manage(this);
}
});
exports.WebGLFront = WebGLFront;