mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 00:08:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
67
devtools/shared/fronts/actor-registry.js
Normal file
67
devtools/shared/fronts/actor-registry.js
Normal 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;
|
||||
17
devtools/shared/fronts/addons.js
Normal file
17
devtools/shared/fronts/addons.js
Normal 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;
|
||||
140
devtools/shared/fronts/animation.js
Normal file
140
devtools/shared/fronts/animation.js
Normal 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;
|
||||
226
devtools/shared/fronts/call-watcher.js
Normal file
226
devtools/shared/fronts/call-watcher.js
Normal 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])
|
||||
},
|
||||
};
|
||||
91
devtools/shared/fronts/canvas.js
Normal file
91
devtools/shared/fronts/canvas.js
Normal 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;
|
||||
323
devtools/shared/fronts/css-properties.js
Normal file
323
devtools/shared/fronts/css-properties.js
Normal 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
|
||||
};
|
||||
125
devtools/shared/fronts/csscoverage.js
Normal file
125
devtools/shared/fronts/csscoverage.js
Normal 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;
|
||||
});
|
||||
};
|
||||
54
devtools/shared/fronts/device.js
Normal file
54
devtools/shared/fronts/device.js
Normal 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;
|
||||
};
|
||||
47
devtools/shared/fronts/director-manager.js
Normal file
47
devtools/shared/fronts/director-manager.js
Normal 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;
|
||||
21
devtools/shared/fronts/director-registry.js
Normal file
21
devtools/shared/fronts/director-registry.js
Normal 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;
|
||||
24
devtools/shared/fronts/emulation.js
Normal file
24
devtools/shared/fronts/emulation.js
Normal 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;
|
||||
15
devtools/shared/fronts/eventlooplag.js
Normal file
15
devtools/shared/fronts/eventlooplag.js
Normal 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);
|
||||
},
|
||||
});
|
||||
19
devtools/shared/fronts/framerate.js
Normal file
19
devtools/shared/fronts/framerate.js
Normal 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;
|
||||
40
devtools/shared/fronts/gcli.js
Normal file
40
devtools/shared/fronts/gcli.js
Normal 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;
|
||||
});
|
||||
};
|
||||
34
devtools/shared/fronts/highlighters.js
Normal file
34
devtools/shared/fronts/highlighters.js
Normal 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;
|
||||
1007
devtools/shared/fronts/inspector.js
Normal file
1007
devtools/shared/fronts/inspector.js
Normal file
File diff suppressed because it is too large
Load diff
30
devtools/shared/fronts/layout.js
Normal file
30
devtools/shared/fronts/layout.js
Normal 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;
|
||||
92
devtools/shared/fronts/memory.js
Normal file
92
devtools/shared/fronts/memory.js
Normal 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;
|
||||
41
devtools/shared/fronts/moz.build
Normal file
41
devtools/shared/fronts/moz.build
Normal 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'
|
||||
)
|
||||
17
devtools/shared/fronts/performance-entries.js
Normal file
17
devtools/shared/fronts/performance-entries.js
Normal 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;
|
||||
152
devtools/shared/fronts/performance-recording.js
Normal file
152
devtools/shared/fronts/performance-recording.js
Normal 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;
|
||||
148
devtools/shared/fronts/performance.js
Normal file
148
devtools/shared/fronts/performance.js
Normal 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);
|
||||
};
|
||||
31
devtools/shared/fronts/preference.js
Normal file
31
devtools/shared/fronts/preference.js
Normal 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;
|
||||
};
|
||||
80
devtools/shared/fronts/profiler.js
Normal file
80
devtools/shared/fronts/profiler.js
Normal 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".`);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
27
devtools/shared/fronts/promises.js
Normal file
27
devtools/shared/fronts/promises.js
Normal 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;
|
||||
29
devtools/shared/fronts/reflow.js
Normal file
29
devtools/shared/fronts/reflow.js
Normal 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;
|
||||
29
devtools/shared/fronts/settings.js
Normal file
29
devtools/shared/fronts/settings.js
Normal 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;
|
||||
};
|
||||
32
devtools/shared/fronts/storage.js
Normal file
32
devtools/shared/fronts/storage.js
Normal 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;
|
||||
47
devtools/shared/fronts/string.js
Normal file
47
devtools/shared/fronts/string.js
Normal 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;
|
||||
113
devtools/shared/fronts/styleeditor.js
Normal file
113
devtools/shared/fronts/styleeditor.js
Normal 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;
|
||||
421
devtools/shared/fronts/styles.js
Normal file
421
devtools/shared/fronts/styles.js
Normal 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.
|
||||
},
|
||||
});
|
||||
184
devtools/shared/fronts/stylesheets.js
Normal file
184
devtools/shared/fronts/stylesheets.js
Normal 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;
|
||||
25
devtools/shared/fronts/timeline.js
Normal file
25
devtools/shared/fronts/timeline.js
Normal 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;
|
||||
83
devtools/shared/fronts/webaudio.js
Normal file
83
devtools/shared/fronts/webaudio.js
Normal 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;
|
||||
45
devtools/shared/fronts/webgl.js
Normal file
45
devtools/shared/fronts/webgl.js
Normal 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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue