mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 964545 - Add-on SDK page-mods are now debuggable r=dcamp
This commit is contained in:
parent
6027a6223e
commit
7a50c351d5
@ -24,6 +24,7 @@ const xulApp = require('../system/xul-app');
|
||||
const USE_JS_PROXIES = !xulApp.versionInRange(xulApp.platformVersion,
|
||||
'17.0a2', '*');
|
||||
const { getTabForContentWindow } = require('../tabs/utils');
|
||||
const { getInnerId } = require('../window/utils');
|
||||
|
||||
// WeakMap of sandboxes so we can access private values
|
||||
const sandboxes = new WeakMap();
|
||||
@ -34,12 +35,13 @@ const sandboxes = new WeakMap();
|
||||
*/
|
||||
let prefix = module.uri.split('sandbox.js')[0];
|
||||
const CONTENT_WORKER_URL = prefix + 'content-worker.js';
|
||||
const metadata = require('@loader/options').metadata;
|
||||
|
||||
// Fetch additional list of domains to authorize access to for each content
|
||||
// script. It is stored in manifest `metadata` field which contains
|
||||
// package.json data. This list is originaly defined by authors in
|
||||
// `permissions` attribute of their package.json addon file.
|
||||
const permissions = require('@loader/options').metadata['permissions'] || {};
|
||||
const permissions = (metadata && metadata['permissions']) || {};
|
||||
const EXPANDED_PRINCIPALS = permissions['cross-domain-content'] || [];
|
||||
|
||||
const JS_VERSION = '1.8';
|
||||
@ -49,7 +51,7 @@ const WorkerSandbox = Class({
|
||||
implements: [
|
||||
EventTarget
|
||||
],
|
||||
|
||||
|
||||
/**
|
||||
* Emit a message to the worker content sandbox
|
||||
*/
|
||||
@ -131,10 +133,13 @@ const WorkerSandbox = Class({
|
||||
wantXrays: true,
|
||||
wantGlobalProperties: wantGlobalProperties,
|
||||
sameZoneAs: window,
|
||||
metadata: { SDKContentScript: true }
|
||||
metadata: {
|
||||
SDKContentScript: true,
|
||||
'inner-window-id': getInnerId(window)
|
||||
}
|
||||
});
|
||||
model.sandbox = content;
|
||||
|
||||
|
||||
// We have to ensure that window.top and window.parent are the exact same
|
||||
// object than window object, i.e. the sandbox global object. But not
|
||||
// always, in case of iframes, top and parent are another window object.
|
||||
|
@ -160,7 +160,10 @@ const WorkerSandbox = EventEmitter.compose({
|
||||
wantXrays: true,
|
||||
wantGlobalProperties: wantGlobalProperties,
|
||||
sameZoneAs: window,
|
||||
metadata: { SDKContentScript: true }
|
||||
metadata: {
|
||||
SDKContentScript: true,
|
||||
'inner-window-id': getInnerId(window)
|
||||
}
|
||||
});
|
||||
// We have to ensure that window.top and window.parent are the exact same
|
||||
// object than window object, i.e. the sandbox global object. But not
|
||||
|
@ -12,6 +12,12 @@ const systemPrincipal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
|
||||
const scriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
|
||||
getService(Ci.mozIJSSubScriptLoader);
|
||||
const self = require('sdk/self');
|
||||
const { getTabId, getTabForContentWindow } = require('../tabs/utils');
|
||||
const { getInnerId } = require('../window/utils');
|
||||
|
||||
const { gDevToolsExtensions: {
|
||||
addContentGlobal, removeContentGlobal
|
||||
} } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
|
||||
/**
|
||||
* Make a new sandbox that inherits given `source`'s principals. Source can be
|
||||
@ -23,7 +29,16 @@ function sandbox(target, options) {
|
||||
options.metadata.addonID = options.metadata.addonID ?
|
||||
options.metadata.addonID : self.id;
|
||||
|
||||
return Cu.Sandbox(target || systemPrincipal, options);
|
||||
let sandbox = Cu.Sandbox(target || systemPrincipal, options);
|
||||
Cu.setSandboxMetadata(sandbox, options.metadata);
|
||||
let innerWindowID = options.metadata['inner-window-id']
|
||||
if (innerWindowID) {
|
||||
addContentGlobal({
|
||||
global: sandbox,
|
||||
'inner-window-id': innerWindowID
|
||||
});
|
||||
}
|
||||
return sandbox;
|
||||
}
|
||||
exports.sandbox = sandbox;
|
||||
|
||||
|
@ -264,7 +264,7 @@ function getTabForWindow(window) {
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTabURL(tab) {
|
||||
|
@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Page Mod Debugger Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
unsafeWindow.runDebuggerStatement = function() {
|
||||
window.document.body.setAttribute('style', 'background-color: red');
|
||||
debugger;
|
||||
window.document.body.setAttribute('style', 'background-color: green');
|
||||
}
|
133
addon-sdk/source/test/addons/page-mod-debugger-post/main.js
Normal file
133
addon-sdk/source/test/addons/page-mod-debugger-post/main.js
Normal file
@ -0,0 +1,133 @@
|
||||
/* 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 { PageMod } = require('sdk/page-mod');
|
||||
const tabs = require('sdk/tabs');
|
||||
const promise = require('sdk/core/promise')
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { data } = require('sdk/self');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { DebuggerServer } = Cu.import('resource://gre/modules/devtools/dbg-server.jsm', {});
|
||||
const { DebuggerClient } = Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {});
|
||||
|
||||
let gClient;
|
||||
let ok;
|
||||
let testName = 'testDebugger';
|
||||
let iframeURL = 'data:text/html;charset=utf-8,' + testName;
|
||||
let TAB_URL = 'data:text/html;charset=utf-8,' + encodeURIComponent('<iframe src="' + iframeURL + '" />');
|
||||
TAB_URL = data.url('index.html');
|
||||
let mod;
|
||||
|
||||
exports.testDebugger = function(assert, done) {
|
||||
ok = assert.ok.bind(assert);
|
||||
assert.pass('starting test');
|
||||
set('devtools.debugger.log', true);
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(() => true);
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect((aType, aTraits) => {
|
||||
tabs.open({
|
||||
url: TAB_URL,
|
||||
onLoad: function(tab) {
|
||||
assert.pass('tab loaded');
|
||||
|
||||
attachTabActorForUrl(gClient, TAB_URL).
|
||||
then(_ => { assert.pass('attachTabActorForUrl called'); return _; }).
|
||||
then(attachThread).
|
||||
then(testDebuggerStatement).
|
||||
then(_ => { assert.pass('testDebuggerStatement called') }).
|
||||
then(closeConnection).
|
||||
then(_ => { assert.pass('closeConnection called') }).
|
||||
then(done).
|
||||
then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function attachThread([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Now attach and resume...
|
||||
gClient.request({ to: aResponse.threadActor, type: "attach" }, () => {
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "Pause wasn't called before we've attached.");
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testDebuggerStatement([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
ok(aGrip, 'aGrip existss')
|
||||
|
||||
gClient.addListener("paused", (aEvent, aPacket) => {
|
||||
ok(true, 'there was a pause event');
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "The pause handler was triggered on a debugger statement.");
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
mod = PageMod({
|
||||
include: TAB_URL,
|
||||
attachTo: ['existing', 'top', 'frame'],
|
||||
contentScriptFile: data.url('script.js'),
|
||||
onAttach: function(mod) {
|
||||
ok(true, 'the page-mod was attached to ' + mod.tab.url);
|
||||
|
||||
require('sdk/timers').setTimeout(function() {
|
||||
let debuggee = getMostRecentBrowserWindow().gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
debuggee.runDebuggerStatement();
|
||||
ok(true, 'called runDebuggerStatement');
|
||||
}, 500)
|
||||
}
|
||||
});
|
||||
ok(true, 'PageMod was created');
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
aClient.listTabs(aResponse => {
|
||||
let tabActor = aResponse.tabs.filter(aGrip => aGrip.url == aUrl).pop();
|
||||
deferred.resolve(tabActor);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function attachTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
getTabActorForUrl(aClient, aUrl).then(aGrip => {
|
||||
aClient.attachTab(aGrip.actor, aResponse => {
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function closeConnection() {
|
||||
let deferred = promise.defer();
|
||||
gClient.close(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"id": "test-page-mod-debugger",
|
||||
"author": "Erik Vold"
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Page Mod Debugger Test</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
unsafeWindow.runDebuggerStatement = function() {
|
||||
window.document.body.setAttribute('style', 'background-color: red');
|
||||
debugger;
|
||||
window.document.body.setAttribute('style', 'background-color: green');
|
||||
}
|
128
addon-sdk/source/test/addons/page-mod-debugger-pre/main.js
Normal file
128
addon-sdk/source/test/addons/page-mod-debugger-pre/main.js
Normal file
@ -0,0 +1,128 @@
|
||||
/* 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 { PageMod } = require('sdk/page-mod');
|
||||
const tabs = require('sdk/tabs');
|
||||
const promise = require('sdk/core/promise')
|
||||
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { data } = require('sdk/self');
|
||||
const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { DebuggerServer } = Cu.import('resource://gre/modules/devtools/dbg-server.jsm', {});
|
||||
const { DebuggerClient } = Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {});
|
||||
|
||||
let gClient;
|
||||
let ok;
|
||||
let testName = 'testDebugger';
|
||||
let iframeURL = 'data:text/html;charset=utf-8,' + testName;
|
||||
let TAB_URL = 'data:text/html;charset=utf-8,' + encodeURIComponent('<iframe src="' + iframeURL + '" />');
|
||||
TAB_URL = data.url('index.html');
|
||||
let mod;
|
||||
|
||||
exports.testDebugger = function(assert, done) {
|
||||
ok = assert.ok.bind(assert);
|
||||
assert.pass('starting test');
|
||||
set('devtools.debugger.log', true);
|
||||
|
||||
mod = PageMod({
|
||||
include: TAB_URL,
|
||||
attachTo: ['existing', 'top', 'frame'],
|
||||
contentScriptFile: data.url('script.js'),
|
||||
});
|
||||
ok(true, 'PageMod was created');
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(() => true);
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect((aType, aTraits) => {
|
||||
tabs.open({
|
||||
url: TAB_URL,
|
||||
onLoad: function(tab) {
|
||||
assert.pass('tab loaded');
|
||||
|
||||
attachTabActorForUrl(gClient, TAB_URL).
|
||||
then(_ => { assert.pass('attachTabActorForUrl called'); return _; }).
|
||||
then(attachThread).
|
||||
then(testDebuggerStatement).
|
||||
then(_ => { assert.pass('testDebuggerStatement called') }).
|
||||
then(closeConnection).
|
||||
then(_ => { assert.pass('closeConnection called') }).
|
||||
then(done).
|
||||
then(null, aError => {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function attachThread([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Now attach and resume...
|
||||
gClient.request({ to: aResponse.threadActor, type: "attach" }, () => {
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "Pause wasn't called before we've attached.");
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function testDebuggerStatement([aGrip, aResponse]) {
|
||||
let deferred = promise.defer();
|
||||
ok(aGrip, 'aGrip existss')
|
||||
|
||||
gClient.addListener("paused", (aEvent, aPacket) => {
|
||||
ok(true, 'there was a pause event');
|
||||
gClient.request({ to: aResponse.threadActor, type: "resume" }, () => {
|
||||
ok(true, "The pause handler was triggered on a debugger statement.");
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let debuggee = getMostRecentBrowserWindow().gBrowser.selectedTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
debuggee.runDebuggerStatement();
|
||||
ok(true, 'called runDebuggerStatement');
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
aClient.listTabs(aResponse => {
|
||||
let tabActor = aResponse.tabs.filter(aGrip => aGrip.url == aUrl).pop();
|
||||
deferred.resolve(tabActor);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function attachTabActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
getTabActorForUrl(aClient, aUrl).then(aGrip => {
|
||||
aClient.attachTab(aGrip.actor, aResponse => {
|
||||
deferred.resolve([aGrip, aResponse]);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function closeConnection() {
|
||||
let deferred = promise.defer();
|
||||
gClient.close(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"id": "test-page-mod-debugger",
|
||||
"author": "Erik Vold"
|
||||
}
|
@ -9,8 +9,12 @@ const { Loader } = require('sdk/test/loader');
|
||||
const tabs = require("sdk/tabs");
|
||||
const timer = require("sdk/timers");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { open, getFrames, getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const windowUtils = require('sdk/deprecated/window-utils');
|
||||
const {
|
||||
open,
|
||||
getFrames,
|
||||
getMostRecentBrowserWindow,
|
||||
getInnerId
|
||||
} = require('sdk/window/utils');
|
||||
const { getTabContentWindow, getActiveTab, setTabURL, openTab, closeTab } = require('sdk/tabs/utils');
|
||||
const xulApp = require("sdk/system/xul-app");
|
||||
const { isPrivateBrowsingSupported } = require('sdk/self');
|
||||
@ -24,6 +28,8 @@ const { URL } = require("sdk/url");
|
||||
const { waitUntil } = require("sdk/test/utils");
|
||||
const data = require("./fixtures");
|
||||
|
||||
const { gDevToolsExtensions } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
|
||||
const testPageURI = data.url("test.html");
|
||||
|
||||
// The following adds Debugger constructor to the global namespace.
|
||||
@ -464,7 +470,7 @@ exports.testExistingOnlyFrameMatchesInclude = function(assert, done) {
|
||||
include: iframeURL,
|
||||
attachTo: ['existing', 'frame'],
|
||||
onAttach: function(worker) {
|
||||
assert.equal(iframeURL, worker.url,
|
||||
assert.equal(iframeURL, worker.url,
|
||||
"PageMod attached to existing iframe when only it matches include rules");
|
||||
pagemod.destroy();
|
||||
tab.close(done);
|
||||
@ -602,7 +608,7 @@ exports.testAttachToTabsOnly = function(assert, done) {
|
||||
|
||||
function openBrowserIframe() {
|
||||
console.info('Open iframe in browser window');
|
||||
let window = require('sdk/deprecated/window-utils').activeBrowserWindow;
|
||||
let window = getMostRecentBrowserWindow();
|
||||
let document = window.document;
|
||||
let iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('type', 'content');
|
||||
@ -850,7 +856,7 @@ exports.testPageModCssAutomaticDestroy = function(assert, done) {
|
||||
url: "data:text/html;charset=utf-8,<div style='width:200px'>css test</div>",
|
||||
|
||||
onReady: function onReady(tab) {
|
||||
let browserWindow = windowUtils.activeBrowserWindow;
|
||||
let browserWindow = getMostRecentBrowserWindow();
|
||||
let win = getTabContentWindow(getActiveTab(browserWindow));
|
||||
|
||||
let div = win.document.querySelector("div");
|
||||
@ -1182,12 +1188,12 @@ exports.testDebugMetadata = function(assert, done) {
|
||||
include: "about:",
|
||||
contentScriptWhen: "start",
|
||||
contentScript: "null;",
|
||||
}],
|
||||
function(win, done) {
|
||||
}], function(win, done) {
|
||||
assert.ok(globalDebuggees.some(function(global) {
|
||||
try {
|
||||
let metadata = Cu.getSandboxMetadata(global.unsafeDereference());
|
||||
return metadata && metadata.addonID && metadata.SDKContentScript;
|
||||
return metadata && metadata.addonID && metadata.SDKContentScript &&
|
||||
metadata['inner-window-id'] == getInnerId(win);
|
||||
} catch(e) {
|
||||
// Some of the globals might not be Sandbox instances and thus
|
||||
// will cause getSandboxMetadata to fail.
|
||||
@ -1199,4 +1205,16 @@ exports.testDebugMetadata = function(assert, done) {
|
||||
);
|
||||
};
|
||||
|
||||
exports.testDevToolsExtensionsGetContentGlobals = function(assert, done) {
|
||||
let mods = testPageMod(assert, done, "about:", [{
|
||||
include: "about:",
|
||||
contentScriptWhen: "start",
|
||||
contentScript: "null;",
|
||||
}], function(win, done) {
|
||||
assert.equal(gDevToolsExtensions.getContentGlobals({ 'inner-window-id': getInnerId(win) }).length, 1);
|
||||
done();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
46
toolkit/devtools/DevToolsExtensions.jsm
Normal file
46
toolkit/devtools/DevToolsExtensions.jsm
Normal file
@ -0,0 +1,46 @@
|
||||
/* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["gDevToolsExtensions"];
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let globalsCache = {};
|
||||
|
||||
const gDevToolsExtensions = {
|
||||
addContentGlobal: function(options) {
|
||||
if (!options || !options.global || !options['inner-window-id']) {
|
||||
throw Error('Invalid arguments');
|
||||
}
|
||||
let cache = getGlobalCache(options['inner-window-id']);
|
||||
cache.push(options.global);
|
||||
return undefined;
|
||||
},
|
||||
getContentGlobals: function(options) {
|
||||
if (!options || !options['inner-window-id']) {
|
||||
throw Error('Invalid arguments');
|
||||
}
|
||||
return Array.slice(getGlobalCache(options['inner-window-id']));
|
||||
},
|
||||
removeContentGlobal: function(options) {
|
||||
if (!options || !options.global || !options['inner-window-id']) {
|
||||
throw Error('Invalid arguments');
|
||||
}
|
||||
let cache = getGlobalCache(options['inner-window-id']);
|
||||
let index = cache.indexOf(options.global);
|
||||
cache.splice(index, 1);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
function getGlobalCache(aInnerWindowID) {
|
||||
return globalsCache[aInnerWindowID] = globalsCache[aInnerWindowID] || [];
|
||||
}
|
||||
|
||||
// when the window is destroyed, eliminate the associated globals cache
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
let id = subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data;
|
||||
delete globalsCache[id];
|
||||
}, 'inner-window-destroyed', false);
|
@ -3,7 +3,6 @@
|
||||
/* 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";
|
||||
|
||||
let TYPED_ARRAY_CLASSES = ["Uint8Array", "Uint8ClampedArray", "Uint16Array",
|
||||
@ -621,22 +620,45 @@ ThreadActor.prototype = {
|
||||
*/
|
||||
globalManager: {
|
||||
findGlobals: function () {
|
||||
const { gDevToolsExtensions: {
|
||||
getContentGlobals
|
||||
} } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
|
||||
this.globalDebugObject = this._addDebuggees(this.global);
|
||||
// global may not be a window
|
||||
try {
|
||||
let id = getInnerId(this.global);
|
||||
getContentGlobals({ 'inner-window-id': id }).forEach(this.addDebuggee.bind(this));
|
||||
}
|
||||
catch(e) {}
|
||||
},
|
||||
|
||||
/**
|
||||
* A function that the engine calls when a new global object has been
|
||||
* created.
|
||||
* A function that the engine calls when a new global object
|
||||
* (for example a sandbox) has been created.
|
||||
*
|
||||
* @param aGlobal Debugger.Object
|
||||
* The new global object that was created.
|
||||
*/
|
||||
onNewGlobal: function (aGlobal) {
|
||||
let metadata = {};
|
||||
try {
|
||||
metadata = Cu.getSandboxMetadata(aGlobal.unsafeDereference());
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
let id;
|
||||
try {
|
||||
id = getInnerId(this.global);
|
||||
} catch(e) {}
|
||||
|
||||
// Content debugging only cares about new globals in the contant window,
|
||||
// like iframe children.
|
||||
if (aGlobal.hostAnnotations &&
|
||||
if ((metadata['inner-window-id'] &&
|
||||
metadata['inner-window-id'] == id) ||
|
||||
(aGlobal.hostAnnotations &&
|
||||
aGlobal.hostAnnotations.type == "document" &&
|
||||
aGlobal.hostAnnotations.element === this.global) {
|
||||
aGlobal.hostAnnotations.element === this.global)) {
|
||||
this.addDebuggee(aGlobal);
|
||||
// Notify the client.
|
||||
this.conn.send({
|
||||
@ -5129,3 +5151,8 @@ function makeDebuggeeValueIfNeeded(obj, value) {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function getInnerId(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
|
||||
};
|
||||
|
@ -1 +1,2 @@
|
||||
[test_devtools_extensions.html]
|
||||
[test_loader_paths.html]
|
||||
|
117
toolkit/devtools/tests/mochitest/test_devtools_extensions.html
Normal file
117
toolkit/devtools/tests/mochitest/test_devtools_extensions.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { gDevToolsExtensions } = Cu.import("resource://gre/modules/devtools/DevToolsExtensions.jsm", {});
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
const { require } = devtools;
|
||||
const tabs = require('sdk/tabs');
|
||||
const { getMostRecentBrowserWindow, getInnerId } = require('sdk/window/utils');
|
||||
const { PageMod } = require('sdk/page-mod');
|
||||
|
||||
var _tests = [];
|
||||
function addTest(test) {
|
||||
_tests.push(test);
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (_tests.length == 0) {
|
||||
SimpleTest.finish()
|
||||
return;
|
||||
}
|
||||
_tests.shift()();
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
addTest(function () {
|
||||
let TEST_URL = 'data:text/html;charset=utf-8,test';
|
||||
|
||||
let mod = PageMod({
|
||||
include: TEST_URL,
|
||||
contentScriptWhen: 'ready',
|
||||
contentScript: 'null;'
|
||||
});
|
||||
|
||||
tabs.open({
|
||||
url: TEST_URL,
|
||||
onLoad: function(tab) {
|
||||
let id = getInnerId(getMostRecentBrowserWindow().gBrowser.selectedTab.linkedBrowser.contentWindow);
|
||||
|
||||
// getting
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': id
|
||||
}).length, 1, 'found a global for inner-id = ' + id);
|
||||
|
||||
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||
if (id == subject.QueryInterface(Components.interfaces.nsISupportsPRUint64).data) {
|
||||
Services.obs.removeObserver(observer, 'inner-window-destroyed');
|
||||
setTimeout(function() {
|
||||
// closing the tab window should have removed the global
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': id
|
||||
}).length, 0, 'did not find a global for inner-id = ' + id);
|
||||
|
||||
mod.destroy();
|
||||
runNextTest();
|
||||
})
|
||||
}
|
||||
}, 'inner-window-destroyed', false);
|
||||
|
||||
tab.close();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
addTest(function testAddRemoveGlobal() {
|
||||
let global = {};
|
||||
let globalDetails = {
|
||||
global: global,
|
||||
'inner-window-id': 5
|
||||
};
|
||||
|
||||
// adding
|
||||
gDevToolsExtensions.addContentGlobal(globalDetails);
|
||||
|
||||
// getting
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': 5
|
||||
}).length, 1, 'found a global for inner-id = 5');
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': 4
|
||||
}).length, 0, 'did not find a global for inner-id = 4');
|
||||
|
||||
// remove
|
||||
gDevToolsExtensions.removeContentGlobal(globalDetails);
|
||||
|
||||
// getting again
|
||||
is(gDevToolsExtensions.getContentGlobals({
|
||||
'inner-window-id': 5
|
||||
}).length, 0, 'did not find a global for inner-id = 5');
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user