Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2016-09-20 12:02:20 +02:00
commit 17d545681a
87 changed files with 1731 additions and 1327 deletions

View File

@ -32,6 +32,7 @@ addons = [
'e10s-remote',
'e10s-tabs',
'e10s',
'embedded-webextension',
'l10n-properties',
'l10n',
'layout-change',
@ -183,6 +184,10 @@ EXTRA_JS_MODULES.commonjs += [
'source/lib/test.js',
]
EXTRA_JS_MODULES.commonjs.sdk += [
'source/lib/sdk/webextension.js',
]
EXTRA_JS_MODULES.commonjs.dev += [
'source/lib/dev/debuggee.js',
'source/lib/dev/frame-script.js',

View File

@ -257,6 +257,9 @@ function startup(data, reasonCode) {
let module = cuddlefish.Module('sdk/loader/cuddlefish', cuddlefishURI);
let require = cuddlefish.Require(loader, module);
// Init the 'sdk/webextension' module from the bootstrap addon parameter.
require("sdk/webextension").initFromBootstrapAddonParam(data);
require('sdk/addon/runner').startup(reason, {
loader: loader,
main: main,

View File

@ -123,7 +123,7 @@ Bootstrap.prototype = {
manifest: metadata,
metadata: metadata,
modules: {
"@test/options": {}
"@test/options": {},
},
noQuit: prefs.get(`extensions.${id}.sdk.test.no-quit`, false)
});
@ -134,6 +134,9 @@ Bootstrap.prototype = {
const main = command === "test" ? "sdk/test/runner" : null;
const prefsURI = `${baseURI}defaults/preferences/prefs.js`;
// Init the 'sdk/webextension' module from the bootstrap addon parameter.
require("sdk/webextension").initFromBootstrapAddonParam(addon);
const { startup } = require("sdk/addon/runner");
startup(reason, {loader, main, prefsURI});
}.bind(this)).catch(error => {

View File

@ -0,0 +1,43 @@
/* 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";
module.metadata = {
"stability": "experimental"
};
let webExtension;
let waitForWebExtensionAPI;
module.exports = {
initFromBootstrapAddonParam(data) {
if (webExtension) {
throw new Error("'sdk/webextension' module has been already initialized");
}
webExtension = data.webExtension;
},
startup() {
if (!webExtension) {
return Promise.reject(new Error(
"'sdk/webextension' module is currently disabled. " +
"('hasEmbeddedWebExtension' option is missing or set to false)"
));
}
// NOTE: calling `startup` more than once raises an "Embedded Extension already started"
// error, but given that SDK addons are going to have access to the startup method through
// an SDK module that can be required in any part of the addon, it will be nicer if any
// additional startup calls return the startup promise instead of raising an exception,
// so that the SDK addon can access the API object in the other addon modules without the
// need to manually pass this promise around.
if (!waitForWebExtensionAPI) {
waitForWebExtensionAPI = webExtension.startup();
}
return waitForWebExtensionAPI;
}
};

View File

@ -133,6 +133,11 @@ def gen_manifest(template_root_dir, target_cfg, jid,
# booleans in the .json file, not strings.
manifest.set("em:unpack", "true" if target_cfg.get("unpack") else "false")
if target_cfg.get('hasEmbeddedWebExtension', False):
elem = dom.createElement("em:hasEmbeddedWebExtension");
elem.appendChild(dom.createTextNode("true"))
dom.documentElement.getElementsByTagName("Description")[0].appendChild(elem)
for translator in target_cfg.get("translators", [ ]):
elem = dom.createElement("em:translator");
elem.appendChild(dom.createTextNode(translator))

View File

@ -48,13 +48,12 @@ def build_xpi(template_root_dir, manifest, xpi_path,
if os.path.isfile(os.path.join(pkgdir, 'chrome.manifest')):
files_to_copy['chrome.manifest'] = os.path.join(pkgdir, 'chrome.manifest')
# chrome folder (would contain content, skin, and locale folders typically)
folder = 'chrome'
if os.path.exists(os.path.join(pkgdir, folder)):
dirs_to_create.add('chrome')
# cp -r folder
abs_dirname = os.path.join(pkgdir, folder)
for dirpath, dirnames, filenames in os.walk(abs_dirname):
def add_special_dir(folder):
if os.path.exists(os.path.join(pkgdir, folder)):
dirs_to_create.add(folder)
# cp -r folder
abs_dirname = os.path.join(pkgdir, folder)
for dirpath, dirnames, filenames in os.walk(abs_dirname):
goodfiles = list(filter_filenames(filenames, IGNORED_FILES))
dirnames[:] = filter_dirnames(dirnames)
for dirname in dirnames:
@ -69,6 +68,12 @@ def build_xpi(template_root_dir, manifest, xpi_path,
])
files_to_copy[str(arcpath)] = str(abspath)
# chrome folder (would contain content, skin, and locale folders typically)
add_special_dir('chrome')
# optionally include a `webextension/` dir from the add-on dir.
add_special_dir('webextension')
for dirpath, dirnames, filenames in os.walk(template_root_dir):
if template_root_dir == dirpath:
filenames = list(filter_filenames(filenames, IGNORED_TOP_LVL_FILES))

View File

@ -0,0 +1,159 @@
const tabs = require("sdk/tabs");
const webExtension = require('sdk/webextension');
exports.testEmbeddedWebExtensionModuleInitializedException = function (assert) {
let actualErr;
assert.throws(
() => webExtension.initFromBootstrapAddonParam({webExtension: null}),
/'sdk\/webextension' module has been already initialized/,
"Got the expected exception if the module is initialized twice"
);
};
exports.testEmbeddedWebExtensionBackgroungPage = function* (assert) {
try {
const api = yield webExtension.startup();
assert.ok(api, `webextension waitForStartup promise successfully resolved`);
const apiSecondStartup = yield webExtension.startup();
assert.equal(api, apiSecondStartup, "Got the same API object from the second startup call");
const {browser} = api;
let messageListener;
let waitForBackgroundPageMessage = new Promise((resolve, reject) => {
let numExpectedMessage = 2;
messageListener = (msg, sender, sendReply) => {
numExpectedMessage -= 1;
if (numExpectedMessage == 1) {
assert.equal(msg, "bg->sdk message",
"Got the expected message from the background page");
sendReply("sdk reply");
} else if (numExpectedMessage == 0) {
assert.equal(msg, "sdk reply",
"The background page received the expected reply message");
resolve();
} else {
console.error("Unexpected message received", {msg,sender, numExpectedMessage});
assert.ok(false, `unexpected message received`);
reject();
}
};
browser.runtime.onMessage.addListener(messageListener);
});
let portListener;
let waitForBackgroundPagePort = new Promise((resolve, reject) => {
portListener = (port) => {
let numExpectedMessages = 2;
port.onMessage.addListener((msg) => {
numExpectedMessages -= 1;
if (numExpectedMessages == 1) {
// Check that the legacy context has been able to receive the first port message
// and reply with a port message to the background page.
assert.equal(msg, "bg->sdk port message",
"Got the expected port message from the background page");
port.postMessage("sdk->bg port message");
} else if (numExpectedMessages == 0) {
// Check that the background page has received the above port message.
assert.equal(msg, "bg received sdk->bg port message",
"The background page received the expected port message");
}
});
port.onDisconnect.addListener(() => {
assert.equal(numExpectedMessages, 0, "Got the expected number of port messages");
resolve();
});
};
browser.runtime.onConnect.addListener(portListener);
});
yield Promise.all([
waitForBackgroundPageMessage,
waitForBackgroundPagePort,
]).then(() => {
browser.runtime.onMessage.removeListener(messageListener);
browser.runtime.onConnect.removeListener(portListener);
});
} catch (err) {
assert.fail(`Unexpected webextension startup exception: ${err} - ${err.stack}`);
}
};
exports.testEmbeddedWebExtensionContentScript = function* (assert, done) {
try {
const {browser} = yield webExtension.startup();
assert.ok(browser, `webextension startup promise resolved successfully to the API object`);
let messageListener;
let waitForContentScriptMessage = new Promise((resolve, reject) => {
let numExpectedMessage = 2;
messageListener = (msg, sender, sendReply) => {
numExpectedMessage -= 1;
if (numExpectedMessage == 1) {
assert.equal(msg, "content script->sdk message",
"Got the expected message from the content script");
sendReply("sdk reply");
} else if (numExpectedMessage == 0) {
assert.equal(msg, "sdk reply",
"The content script received the expected reply message");
resolve();
} else {
console.error("Unexpected message received", {msg,sender, numExpectedMessage});
assert.ok(false, `unexpected message received`);
reject();
}
};
browser.runtime.onMessage.addListener(messageListener);
});
let portListener;
let waitForContentScriptPort = new Promise((resolve, reject) => {
portListener = (port) => {
let numExpectedMessages = 2;
port.onMessage.addListener((msg) => {
numExpectedMessages -= 1;
if (numExpectedMessages == 1) {
assert.equal(msg, "content script->sdk port message",
"Got the expected message from the content script port");
port.postMessage("sdk->content script port message");
} else if (numExpectedMessages == 0) {
assert.equal(msg, "content script received sdk->content script port message",
"The content script received the expected port message");
}
});
port.onDisconnect.addListener(() => {
assert.equal(numExpectedMessages, 0, "Got the epected number of port messages");
resolve();
});
};
browser.runtime.onConnect.addListener(portListener);
});
let url = "data:text/html;charset=utf-8,<h1>Test Page</h1>";
var openedTab;
tabs.once('open', function onOpen(tab) {
openedTab = tab;
});
tabs.open(url);
yield Promise.all([
waitForContentScriptMessage,
waitForContentScriptPort,
]).then(() => {
browser.runtime.onMessage.removeListener(messageListener);
browser.runtime.onConnect.removeListener(portListener);
openedTab.close();
});
} catch (err) {
assert.fail(`Unexpected webextension startup exception: ${err} - ${err.stack}`);
}
};
require("sdk/test/runner").runTestsFromModule(module);

View File

@ -0,0 +1,6 @@
{
"id": "embedded-webextension@jetpack",
"version": "0.1.0",
"main": "./main.js",
"hasEmbeddedWebExtension": true
}

View File

@ -0,0 +1,10 @@
browser.runtime.sendMessage("bg->sdk message", (reply) => {
browser.runtime.sendMessage(reply);
});
let port = browser.runtime.connect();
port.onMessage.addListener((msg) => {
port.postMessage(`bg received ${msg}`);
port.disconnect();
});
port.postMessage("bg->sdk port message");

View File

@ -0,0 +1,10 @@
browser.runtime.sendMessage("content script->sdk message", (reply) => {
browser.runtime.sendMessage(reply);
});
let port = browser.runtime.connect();
port.onMessage.addListener((msg) => {
port.postMessage(`content script received ${msg}`);
port.disconnect();
});
port.postMessage("content script->sdk port message");

View File

@ -0,0 +1,18 @@
{
"name": "Test SDK Embedded WebExtension",
"description": "",
"version": "0.1.0",
"applications": {
"gecko": {
"id": "embedded-webextension@jetpack"
}
},
"manifest_version": 2,
"permissions": ["tabs"],
"background": {
"scripts": ["background-page.js"]
},
"content_scripts": [
{"matches": ["<all_urls>"], "js": ["content-script.js"]}
]
}

View File

@ -17,6 +17,7 @@ skip-if = true
skip-if = true
[e10s-tabs.xpi]
skip-if = true
[embedded-webextension.xpi]
[l10n.xpi]
[l10n-properties.xpi]
[layout-change.xpi]

View File

@ -931,7 +931,9 @@ BrowserGlue.prototype = {
}
if (SCALING_PROBE_NAME) {
let scaling = aWindow.devicePixelRatio * 100;
Services.telemetry.getHistogramById(SCALING_PROBE_NAME).add(scaling);
try {
Services.telemetry.getHistogramById(SCALING_PROBE_NAME).add(scaling);
} catch (ex) {}
}
},

View File

@ -1290,8 +1290,8 @@
case "popuphidden":
Services.tm.mainThread.dispatch(() => {
this.selectedButton = null;
this._contextEngine = null;
}, Ci.nsIThread.DISPATCH_NORMAL);
this._contextEngine = null;
break;
}
]]></body>

View File

@ -29,6 +29,7 @@ skip-if = os == "mac" # bug 967013
[browser_healthreport.js]
[browser_hiddenOneOffs_cleanup.js]
[browser_hiddenOneOffs_diacritics.js]
[browser_oneOffContextMenu.js]
[browser_oneOffHeader.js]
[browser_private_search_perwindowpb.js]
[browser_yahoo.js]

View File

@ -0,0 +1,99 @@
"use strict";
const TEST_ENGINE_NAME = "Foo";
const TEST_ENGINE_BASENAME = "testEngine.xml";
const searchbar = document.getElementById("searchbar");
const searchPopup = document.getElementById("PopupSearchAutoComplete");
const searchIcon = document.getAnonymousElementByAttribute(
searchbar, "anonid", "searchbar-search-button"
);
const oneOffBinding = document.getAnonymousElementByAttribute(
searchPopup, "anonid", "search-one-off-buttons"
);
const contextMenu = document.getAnonymousElementByAttribute(
oneOffBinding, "anonid", "search-one-offs-context-menu"
);
const oneOffButtons = document.getAnonymousElementByAttribute(
oneOffBinding, "anonid", "search-panel-one-offs"
);
const searchInNewTabMenuItem = document.getAnonymousElementByAttribute(
oneOffBinding, "anonid", "search-one-offs-context-open-in-new-tab"
);
add_task(function* init() {
yield promiseNewEngine(TEST_ENGINE_BASENAME, {
setAsCurrent: false,
});
});
add_task(function* extendedTelemetryDisabled() {
yield SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", false]]});
yield doTest();
checkTelemetry("other");
});
add_task(function* extendedTelemetryEnabled() {
yield SpecialPowers.pushPrefEnv({set: [["toolkit.telemetry.enabled", true]]});
yield doTest();
checkTelemetry("other-" + TEST_ENGINE_NAME);
});
function* doTest() {
// Open the popup.
let promise = promiseEvent(searchPopup, "popupshown");
info("Opening search panel");
EventUtils.synthesizeMouseAtCenter(searchIcon, {});
yield promise;
// Get the one-off button for the test engine.
let oneOffButton;
for (let node of oneOffButtons.childNodes) {
if (node.engine && node.engine.name == TEST_ENGINE_NAME) {
oneOffButton = node;
break;
}
}
Assert.notEqual(oneOffButton, undefined,
"One-off for test engine should exist");
// Open the context menu on the one-off.
promise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(oneOffButton, {
type: "contextmenu",
button: 2,
});
yield promise;
// Click the Search in New Tab menu item.
promise = BrowserTestUtils.waitForNewTab(gBrowser);
EventUtils.synthesizeMouseAtCenter(searchInNewTabMenuItem, {});
let tab = yield promise;
// Check the loaded tab.
Assert.equal(tab.linkedBrowser.currentURI.spec,
"http://mochi.test:8888/browser/browser/components/search/test/",
"Expected search tab should have loaded");
yield BrowserTestUtils.removeTab(tab);
// Move the cursor out of the panel area to avoid messing with other tests.
yield EventUtils.synthesizeNativeMouseMove(searchbar);
}
function checkTelemetry(expectedEngineName) {
let propertyPath = [
"countableEvents",
"__DEFAULT__",
"search-oneoff",
expectedEngineName + ".oneoff-context-searchbar",
"unknown",
"tab-background",
];
let telem = BrowserUITelemetry.getToolbarMeasures();
for (let prop of propertyPath) {
Assert.ok(prop in telem, "Property " + prop + " should be in the telemetry");
telem = telem[prop];
}
Assert.equal(telem, 1, "Click count");
}

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@ var Debugger =
/***/ 0:
/***/ function(module, exports, __webpack_require__) {
var prettyFast = __webpack_require__(365);
var prettyFast = __webpack_require__(366);
self.onmessage = function (msg) {
var _prettyPrint = prettyPrint(msg.data);
@ -100,7 +100,7 @@ var Debugger =
/***/ },
/***/ 365:
/***/ 366:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/* -*- indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
@ -122,8 +122,8 @@ var Debugger =
}(this, function () {
"use strict";
var acorn = this.acorn || __webpack_require__(366);
var sourceMap = this.sourceMap || __webpack_require__(367);
var acorn = this.acorn || __webpack_require__(367);
var sourceMap = this.sourceMap || __webpack_require__(368);
var SourceNode = sourceMap.SourceNode;
// If any of these tokens are seen before a "[" token, we know that "[" token
@ -982,7 +982,7 @@ var Debugger =
/***/ },
/***/ 366:
/***/ 367:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Acorn is a tiny, fast JavaScript parser written in JavaScript.
@ -3642,7 +3642,7 @@ var Debugger =
/***/ },
/***/ 367:
/***/ 368:
/***/ function(module, exports, __webpack_require__) {
/*
@ -3650,14 +3650,14 @@ var Debugger =
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
exports.SourceMapGenerator = __webpack_require__(368).SourceMapGenerator;
exports.SourceMapConsumer = __webpack_require__(374).SourceMapConsumer;
exports.SourceNode = __webpack_require__(376).SourceNode;
exports.SourceMapGenerator = __webpack_require__(369).SourceMapGenerator;
exports.SourceMapConsumer = __webpack_require__(375).SourceMapConsumer;
exports.SourceNode = __webpack_require__(377).SourceNode;
/***/ },
/***/ 368:
/***/ 369:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -3671,10 +3671,10 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var base64VLQ = __webpack_require__(369);
var util = __webpack_require__(371);
var ArraySet = __webpack_require__(372).ArraySet;
var MappingList = __webpack_require__(373).MappingList;
var base64VLQ = __webpack_require__(370);
var util = __webpack_require__(372);
var ArraySet = __webpack_require__(373).ArraySet;
var MappingList = __webpack_require__(374).MappingList;
/**
* An instance of the SourceMapGenerator represents a source map which is
@ -4064,7 +4064,7 @@ var Debugger =
/***/ },
/***/ 369:
/***/ 370:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4108,7 +4108,7 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var base64 = __webpack_require__(370);
var base64 = __webpack_require__(371);
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
@ -4213,7 +4213,7 @@ var Debugger =
/***/ },
/***/ 370:
/***/ 371:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4262,7 +4262,7 @@ var Debugger =
/***/ },
/***/ 371:
/***/ 372:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4588,7 +4588,7 @@ var Debugger =
/***/ },
/***/ 372:
/***/ 373:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4602,7 +4602,7 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var util = __webpack_require__(371);
var util = __webpack_require__(372);
/**
* A data structure which is a combination of an array and a set. Adding a new
@ -4692,7 +4692,7 @@ var Debugger =
/***/ },
/***/ 373:
/***/ 374:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4706,7 +4706,7 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var util = __webpack_require__(371);
var util = __webpack_require__(372);
/**
* Determine whether mappingB is after mappingA with respect to generated
@ -4785,7 +4785,7 @@ var Debugger =
/***/ },
/***/ 374:
/***/ 375:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4799,10 +4799,10 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var util = __webpack_require__(371);
var binarySearch = __webpack_require__(375);
var ArraySet = __webpack_require__(372).ArraySet;
var base64VLQ = __webpack_require__(369);
var util = __webpack_require__(372);
var binarySearch = __webpack_require__(376);
var ArraySet = __webpack_require__(373).ArraySet;
var base64VLQ = __webpack_require__(370);
/**
* A SourceMapConsumer instance represents a parsed source map which we can
@ -5367,7 +5367,7 @@ var Debugger =
/***/ },
/***/ 375:
/***/ 376:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -5454,7 +5454,7 @@ var Debugger =
/***/ },
/***/ 376:
/***/ 377:
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* -*- Mode: js; js-indent-level: 2; -*- */
@ -5468,8 +5468,8 @@ var Debugger =
}
!(__WEBPACK_AMD_DEFINE_RESULT__ = function (require, exports, module) {
var SourceMapGenerator = __webpack_require__(368).SourceMapGenerator;
var util = __webpack_require__(371);
var SourceMapGenerator = __webpack_require__(369).SourceMapGenerator;
var util = __webpack_require__(372);
// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
// operating systems these days (capturing the result).

View File

@ -48,19 +48,19 @@ var Debugger =
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _require = __webpack_require__(377);
var _require = __webpack_require__(378);
var SourceMapConsumer = _require.SourceMapConsumer;
var SourceNode = _require.SourceNode;
var SourceMapGenerator = _require.SourceMapGenerator;
var _require2 = __webpack_require__(216);
var _require2 = __webpack_require__(217);
var makeOriginalSource = _require2.makeOriginalSource;
var getGeneratedSourceId = _require2.getGeneratedSourceId;
var toPairs = __webpack_require__(312);
var toPairs = __webpack_require__(313);
var sourceMapConsumers = new Map();
var sourceNodes = new Map();
@ -657,7 +657,7 @@ var Debugger =
/***/ },
/***/ 216:
/***/ 217:
/***/ function(module, exports) {
@ -687,11 +687,11 @@ var Debugger =
/***/ },
/***/ 312:
/***/ 313:
/***/ function(module, exports, __webpack_require__) {
var createToPairs = __webpack_require__(313),
keys = __webpack_require__(323);
var createToPairs = __webpack_require__(314),
keys = __webpack_require__(324);
/**
* Creates an array of own enumerable string keyed-value pairs for `object`
@ -724,13 +724,13 @@ var Debugger =
/***/ },
/***/ 313:
/***/ 314:
/***/ function(module, exports, __webpack_require__) {
var baseToPairs = __webpack_require__(314),
getTag = __webpack_require__(316),
mapToArray = __webpack_require__(321),
setToPairs = __webpack_require__(322);
var baseToPairs = __webpack_require__(315),
getTag = __webpack_require__(317),
mapToArray = __webpack_require__(322),
setToPairs = __webpack_require__(323);
/** `Object#toString` result references. */
var mapTag = '[object Map]',
@ -761,10 +761,10 @@ var Debugger =
/***/ },
/***/ 314:
/***/ 315:
/***/ function(module, exports, __webpack_require__) {
var arrayMap = __webpack_require__(315);
var arrayMap = __webpack_require__(316);
/**
* The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
@ -786,7 +786,7 @@ var Debugger =
/***/ },
/***/ 315:
/***/ 316:
/***/ function(module, exports) {
/**
@ -814,14 +814,14 @@ var Debugger =
/***/ },
/***/ 316:
/***/ 317:
/***/ function(module, exports, __webpack_require__) {
var DataView = __webpack_require__(317),
var DataView = __webpack_require__(318),
Map = __webpack_require__(82),
Promise = __webpack_require__(318),
Set = __webpack_require__(319),
WeakMap = __webpack_require__(320),
Promise = __webpack_require__(319),
Set = __webpack_require__(320),
WeakMap = __webpack_require__(321),
toSource = __webpack_require__(68);
/** `Object#toString` result references. */
@ -891,7 +891,7 @@ var Debugger =
/***/ },
/***/ 317:
/***/ 318:
/***/ function(module, exports, __webpack_require__) {
var getNative = __webpack_require__(60),
@ -905,7 +905,7 @@ var Debugger =
/***/ },
/***/ 318:
/***/ 319:
/***/ function(module, exports, __webpack_require__) {
var getNative = __webpack_require__(60),
@ -919,7 +919,7 @@ var Debugger =
/***/ },
/***/ 319:
/***/ 320:
/***/ function(module, exports, __webpack_require__) {
var getNative = __webpack_require__(60),
@ -933,7 +933,7 @@ var Debugger =
/***/ },
/***/ 320:
/***/ 321:
/***/ function(module, exports, __webpack_require__) {
var getNative = __webpack_require__(60),
@ -947,7 +947,7 @@ var Debugger =
/***/ },
/***/ 321:
/***/ 322:
/***/ function(module, exports) {
/**
@ -972,7 +972,7 @@ var Debugger =
/***/ },
/***/ 322:
/***/ 323:
/***/ function(module, exports) {
/**
@ -997,15 +997,15 @@ var Debugger =
/***/ },
/***/ 323:
/***/ 324:
/***/ function(module, exports, __webpack_require__) {
var baseHas = __webpack_require__(324),
baseKeys = __webpack_require__(325),
indexKeys = __webpack_require__(326),
isArrayLike = __webpack_require__(330),
isIndex = __webpack_require__(335),
isPrototype = __webpack_require__(336);
var baseHas = __webpack_require__(325),
baseKeys = __webpack_require__(326),
indexKeys = __webpack_require__(327),
isArrayLike = __webpack_require__(331),
isIndex = __webpack_require__(336),
isPrototype = __webpack_require__(337);
/**
* Creates an array of the own enumerable property names of `object`.
@ -1060,7 +1060,7 @@ var Debugger =
/***/ },
/***/ 324:
/***/ 325:
/***/ function(module, exports, __webpack_require__) {
var getPrototype = __webpack_require__(5);
@ -1093,7 +1093,7 @@ var Debugger =
/***/ },
/***/ 325:
/***/ 326:
/***/ function(module, exports) {
/* Built-in method references for those with the same name as other `lodash` methods. */
@ -1116,14 +1116,14 @@ var Debugger =
/***/ },
/***/ 326:
/***/ 327:
/***/ function(module, exports, __webpack_require__) {
var baseTimes = __webpack_require__(327),
isArguments = __webpack_require__(328),
var baseTimes = __webpack_require__(328),
isArguments = __webpack_require__(329),
isArray = __webpack_require__(52),
isLength = __webpack_require__(333),
isString = __webpack_require__(334);
isLength = __webpack_require__(334),
isString = __webpack_require__(335);
/**
* Creates an array of index keys for `object` values of arrays,
@ -1147,7 +1147,7 @@ var Debugger =
/***/ },
/***/ 327:
/***/ 328:
/***/ function(module, exports) {
/**
@ -1174,10 +1174,10 @@ var Debugger =
/***/ },
/***/ 328:
/***/ 329:
/***/ function(module, exports, __webpack_require__) {
var isArrayLikeObject = __webpack_require__(329);
var isArrayLikeObject = __webpack_require__(330);
/** `Object#toString` result references. */
var argsTag = '[object Arguments]';
@ -1227,10 +1227,10 @@ var Debugger =
/***/ },
/***/ 329:
/***/ 330:
/***/ function(module, exports, __webpack_require__) {
var isArrayLike = __webpack_require__(330),
var isArrayLike = __webpack_require__(331),
isObjectLike = __webpack_require__(7);
/**
@ -1267,12 +1267,12 @@ var Debugger =
/***/ },
/***/ 330:
/***/ 331:
/***/ function(module, exports, __webpack_require__) {
var getLength = __webpack_require__(331),
var getLength = __webpack_require__(332),
isFunction = __webpack_require__(62),
isLength = __webpack_require__(333);
isLength = __webpack_require__(334);
/**
* Checks if `value` is array-like. A value is considered array-like if it's
@ -1308,10 +1308,10 @@ var Debugger =
/***/ },
/***/ 331:
/***/ 332:
/***/ function(module, exports, __webpack_require__) {
var baseProperty = __webpack_require__(332);
var baseProperty = __webpack_require__(333);
/**
* Gets the "length" property value of `object`.
@ -1331,7 +1331,7 @@ var Debugger =
/***/ },
/***/ 332:
/***/ 333:
/***/ function(module, exports) {
/**
@ -1352,7 +1352,7 @@ var Debugger =
/***/ },
/***/ 333:
/***/ 334:
/***/ function(module, exports) {
/** Used as references for various `Number` constants. */
@ -1395,7 +1395,7 @@ var Debugger =
/***/ },
/***/ 334:
/***/ 335:
/***/ function(module, exports, __webpack_require__) {
var isArray = __webpack_require__(52),
@ -1442,7 +1442,7 @@ var Debugger =
/***/ },
/***/ 335:
/***/ 336:
/***/ function(module, exports) {
/** Used as references for various `Number` constants. */
@ -1471,7 +1471,7 @@ var Debugger =
/***/ },
/***/ 336:
/***/ 337:
/***/ function(module, exports) {
/** Used for built-in method references. */
@ -1496,7 +1496,7 @@ var Debugger =
/***/ },
/***/ 377:
/***/ 378:
/***/ function(module, exports, __webpack_require__) {
/*
@ -1504,14 +1504,14 @@ var Debugger =
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
exports.SourceMapGenerator = __webpack_require__(378).SourceMapGenerator;
exports.SourceMapConsumer = __webpack_require__(384).SourceMapConsumer;
exports.SourceNode = __webpack_require__(387).SourceNode;
exports.SourceMapGenerator = __webpack_require__(379).SourceMapGenerator;
exports.SourceMapConsumer = __webpack_require__(385).SourceMapConsumer;
exports.SourceNode = __webpack_require__(388).SourceNode;
/***/ },
/***/ 378:
/***/ 379:
/***/ function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -1521,10 +1521,10 @@ var Debugger =
* http://opensource.org/licenses/BSD-3-Clause
*/
var base64VLQ = __webpack_require__(379);
var util = __webpack_require__(381);
var ArraySet = __webpack_require__(382).ArraySet;
var MappingList = __webpack_require__(383).MappingList;
var base64VLQ = __webpack_require__(380);
var util = __webpack_require__(382);
var ArraySet = __webpack_require__(383).ArraySet;
var MappingList = __webpack_require__(384).MappingList;
/**
* An instance of the SourceMapGenerator represents a source map which is
@ -1922,7 +1922,7 @@ var Debugger =
/***/ },
/***/ 379:
/***/ 380:
/***/ function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -1962,7 +1962,7 @@ var Debugger =
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var base64 = __webpack_require__(380);
var base64 = __webpack_require__(381);
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
@ -2069,7 +2069,7 @@ var Debugger =
/***/ },
/***/ 380:
/***/ 381:
/***/ function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -2143,7 +2143,7 @@ var Debugger =
/***/ },
/***/ 381:
/***/ 382:
/***/ function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -2567,7 +2567,7 @@ var Debugger =
/***/ },
/***/ 382:
/***/ 383:
/***/ function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -2577,7 +2577,7 @@ var Debugger =
* http://opensource.org/licenses/BSD-3-Clause
*/
var util = __webpack_require__(381);
var util = __webpack_require__(382);
var has = Object.prototype.hasOwnProperty;
/**
@ -2678,7 +2678,7 @@ var Debugger =
/***/ },
/***/ 383:
/***/ 384:
/***/ function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -2688,7 +2688,7 @@ var Debugger =
* http://opensource.org/licenses/BSD-3-Clause
*/
var util = __webpack_require__(381);
var util = __webpack_require__(382);
/**
* Determine whether mappingB is after mappingA with respect to generated
@ -2764,7 +2764,7 @@ var Debugger =
/***/ },
/***/ 384:
/***/ 385:
/***/ function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -2774,11 +2774,11 @@ var Debugger =
* http://opensource.org/licenses/BSD-3-Clause
*/
var util = __webpack_require__(381);
var binarySearch = __webpack_require__(385);
var ArraySet = __webpack_require__(382).ArraySet;
var base64VLQ = __webpack_require__(379);
var quickSort = __webpack_require__(386).quickSort;
var util = __webpack_require__(382);
var binarySearch = __webpack_require__(386);
var ArraySet = __webpack_require__(383).ArraySet;
var base64VLQ = __webpack_require__(380);
var quickSort = __webpack_require__(387).quickSort;
function SourceMapConsumer(aSourceMap) {
var sourceMap = aSourceMap;
@ -3853,7 +3853,7 @@ var Debugger =
/***/ },
/***/ 385:
/***/ 386:
/***/ function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -3971,7 +3971,7 @@ var Debugger =
/***/ },
/***/ 386:
/***/ 387:
/***/ function(module, exports) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4092,7 +4092,7 @@ var Debugger =
/***/ },
/***/ 387:
/***/ 388:
/***/ function(module, exports, __webpack_require__) {
/* -*- Mode: js; js-indent-level: 2; -*- */
@ -4102,8 +4102,8 @@ var Debugger =
* http://opensource.org/licenses/BSD-3-Clause
*/
var SourceMapGenerator = __webpack_require__(378).SourceMapGenerator;
var util = __webpack_require__(381);
var SourceMapGenerator = __webpack_require__(379).SourceMapGenerator;
var util = __webpack_require__(382);
// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other
// operating systems these days (capturing the result).

View File

@ -427,15 +427,22 @@ ul.sources-list {
.split-box .splitter {
background-color: var(--theme-splitter-color);
border-bottom-width: 0;
border-color: white;
border-left-width: 0;
border-right-width: 0;
border-style: solid;
border-top-width: 0;
box-sizing: content-box;
cursor: ew-resize;
flex: 0 0 1px;
position: relative;
}
/* The actual handle that users drag is a transparent element that's slightly wider than
the splitter element itself, so it's easier to grab it. */
.split-box .splitter .splitter-handle {
cursor: ew-resize;
position: absolute;
top: 0;
left: -4px;
width: 8px;
height: 100%;
/* Stack above the code-mirror editor so it's actually possible to grab the handle. */
z-index: 5;
}
.breakpoints-list .breakpoint {
@ -937,6 +944,13 @@ ul.sources-list {
margin: 0;
padding: 0;
}
.source-footer {
border-top: 1px solid var(--theme-splitter-color);
left: 0;
opacity: 1;
width: 100%;
}
.source-footer .prettyPrint.pretty {
stroke: var(--theme-highlight-blue);
}

View File

@ -47,11 +47,13 @@
"isPaused": false,
"assertPausedLocation": false,
"assertHighlightLocation": false,
"createDebuggerContext": false,
"initDebugger": false,
"invokeInTab": false,
"findSource": false,
"findElement": false,
"findAllElements": false,
"openNewTabAndToolbox": false,
"selectSource": false,
"stepOver": false,
"stepIn": false,

View File

@ -17,6 +17,8 @@ support-files =
examples/code-script-switching-02.js
examples/code-script-switching-01.js
[browser_dbg-breaking.js]
[browser_dbg-breaking-from-console.js]
[browser_dbg-editor-gutter.js]
[browser_dbg-editor-mode.js]
[browser_dbg-editor-select.js]

View File

@ -0,0 +1,31 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that `debugger` statements are hit before the debugger even
// initializes and it properly highlights the right location in the
// debugger.
add_task(function* () {
const url = EXAMPLE_URL + "doc-script-switching.html";
const toolbox = yield openNewTabAndToolbox(url, "webconsole");
// Type "debugger" into console
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
jsterm.execute("debugger");
// Wait for the debugger to be selected and make sure it's paused
yield new Promise((resolve) => {
toolbox.on("jsdebugger-selected", resolve);
});
is(toolbox.threadClient.state, "paused");
// Create a dbg context
const dbg = createDebuggerContext(toolbox);
const { selectors: { getSelectedSource }, getState } = dbg;
// Make sure the thread is paused in the right source and location
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
is(dbg.win.cm.getValue(), "debugger");
const source = getSelectedSource(getState()).toJS();
assertPausedLocation(dbg, source, 1);
});

View File

@ -0,0 +1,33 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests the breakpoints are hit in various situations.
add_task(function* () {
const dbg = yield initDebugger("doc-scripts.html", "scripts.html");
const { selectors: { getSelectedSource }, getState } = dbg;
// Make sure we can set a top-level breakpoint and it will be hit on
// reload.
yield addBreakpoint(dbg, "scripts.html", 18);
reload(dbg);
yield waitForPaused(dbg);
assertPausedLocation(dbg, "scripts.html", 18);
yield resume(dbg);
const paused = waitForPaused(dbg);
// Create an eval script that pauses itself.
invokeInTab("doEval");
yield paused;
yield resume(dbg);
const source = getSelectedSource(getState()).toJS();
// TODO: The url of an eval source should be null.
ok(source.url.indexOf("SOURCE") === 0, "It is an eval source");
yield addBreakpoint(dbg, source, 5);
invokeInTab("evaledFunc");
yield waitForPaused(dbg);
assertPausedLocation(dbg, source, 5);
});

View File

@ -11,15 +11,13 @@ function countSources(dbg) {
* navigating while paused will reset the pause state and sources
*/
add_task(function* () {
const dbg = yield initDebugger(
"doc-script-switching.html",
"script-switching-01.js"
);
const dbg = yield initDebugger("doc-script-switching.html");
const { selectors: { getSelectedSource, getPause }, getState } = dbg;
invokeInTab("firstCall");
yield waitForPaused(dbg);
yield navigate(dbg, "doc-scripts.html", "simple1.js", "long.js");
yield navigate(dbg, "doc-scripts.html", "simple1.js");
yield addBreakpoint(dbg, "simple1.js", 4);
invokeInTab("main");
yield waitForPaused(dbg);
@ -29,6 +27,7 @@ add_task(function* () {
yield navigate(dbg, "about:blank");
yield waitForDispatch(dbg, "NAVIGATE");
is(countSources(dbg), 0, "0 sources are loaded.");
ok(!getPause(getState()), "No pause state exists");
yield navigate(dbg,
"doc-scripts.html",
@ -39,4 +38,10 @@ add_task(function* () {
);
is(countSources(dbg), 4, "4 sources are loaded.");
// Test that the current select source persists across reloads
yield selectSource(dbg, "long.js");
yield reload(dbg, "long.js");
ok(getSelectedSource(getState()).get("url").includes("long.js"),
"Selected source is long.js");
});

View File

@ -5,3 +5,27 @@ function main() {
const result = func();
return result;
}
function doEval() {
eval("(" + function() {
debugger;
window.evaledFunc = function() {
var foo = 1;
var bar = 2;
return foo + bar;
};
}.toString() + ")()");
}
function doNamedEval() {
eval("(" + function() {
debugger;
window.evaledFunc = function() {
var foo = 1;
var bar = 2;
return foo + bar;
};
}.toString() + ")();\n //# sourceURL=evaled.js");
}

View File

@ -118,7 +118,7 @@ function assertPausedLocation(dbg, source, line) {
source = findSource(dbg, source);
// Check the selected source
is(getSelectedSource(getState()).get("url"), source.url);
is(getSelectedSource(getState()).get("id"), source.id);
// Check the pause location
const location = getPause(getState()).getIn(["frame", "location"]);
@ -172,25 +172,26 @@ function waitForPaused(dbg) {
});
};
function createDebuggerContext(toolbox) {
const win = toolbox.getPanel("jsdebugger").panelWin;
const store = win.Debugger.store;
return {
actions: win.Debugger.actions,
selectors: win.Debugger.selectors,
getState: store.getState,
store: store,
client: win.Debugger.client,
toolbox: toolbox,
win: win
};
}
function initDebugger(url, ...sources) {
return Task.spawn(function* () {
const toolbox = yield openNewTabAndToolbox(EXAMPLE_URL + url, "jsdebugger");
const win = toolbox.getPanel("jsdebugger").panelWin;
const store = win.Debugger.store;
const { getSources } = win.Debugger.selectors;
const dbg = {
actions: win.Debugger.actions,
selectors: win.Debugger.selectors,
getState: store.getState,
store: store,
client: win.Debugger.client,
toolbox: toolbox,
win: win
};
const dbg = createDebuggerContext(toolbox);
yield waitForSources(dbg, ...sources);
return dbg;
});
};
@ -256,8 +257,8 @@ function resume(dbg) {
return waitForThreadEvents(dbg, "resumed");
}
function reload(dbg) {
return dbg.client.reload();
function reload(dbg, ...sources) {
return dbg.client.reload().then(() => waitForSources(...sources));
}
function navigate(dbg, url, ...sources) {

View File

@ -634,7 +634,7 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
// Destroy toolboxes for closed window
for (let [target, toolbox] of gDevTools._toolboxes) {
if (toolbox.win == win) {
if (toolbox.win.top == win) {
toolbox.destroy();
}
}

View File

@ -619,6 +619,9 @@ TabTarget.prototype = {
this._form = null;
this._remote = null;
this._root = null;
this._title = null;
this._url = null;
this.threadActor = null;
},
toString: function () {

View File

@ -78,14 +78,16 @@ add_task(function* themeInOptionsPanel() {
});
add_task(function* themeUnregistration() {
let panelWin = toolbox.getCurrentPanel().panelWin;
let onUnRegisteredTheme = once(gDevTools, "theme-unregistered");
let onThemeSwitchComplete = once(panelWin, "theme-switch-complete");
gDevTools.unregisterTheme("test-theme");
yield onUnRegisteredTheme;
yield onThemeSwitchComplete;
ok(!gDevTools.getThemeDefinitionMap().has("test-theme"),
"theme removed from map");
let panelWin = toolbox.getCurrentPanel().panelWin;
let doc = panelWin.frameElement.contentDocument;
let themeBox = doc.getElementById("devtools-theme-box");

View File

@ -173,6 +173,9 @@ BottomHost.prototype = {
Services.prefs.setIntPref(this.heightPref, this.frame.height);
this._nbox.removeChild(this._splitter);
this._nbox.removeChild(this.frame);
this.frame = null;
this._nbox = null;
this._splitter = null;
}
return promise.resolve(null);

View File

@ -98,24 +98,26 @@ OptionsPanel.prototype = {
}),
_addListeners: function () {
gDevTools.on("pref-changed", this._prefChanged);
Services.prefs.addObserver("devtools.cache.disabled", this._prefChanged, false);
Services.prefs.addObserver("devtools.theme", this._prefChanged, false);
gDevTools.on("theme-registered", this._themeRegistered);
gDevTools.on("theme-unregistered", this._themeUnregistered);
},
_removeListeners: function () {
gDevTools.off("pref-changed", this._prefChanged);
Services.prefs.removeObserver("devtools.cache.disabled", this._prefChanged);
Services.prefs.removeObserver("devtools.theme", this._prefChanged);
gDevTools.off("theme-registered", this._themeRegistered);
gDevTools.off("theme-unregistered", this._themeUnregistered);
},
_prefChanged: function (event, data) {
if (data.pref === "devtools.cache.disabled") {
_prefChanged: function (subject, topic, prefName) {
if (prefName === "devtools.cache.disabled") {
let cacheDisabled = data.newValue;
let cbx = this.panelDoc.getElementById("devtools-disable-cache");
cbx.checked = cacheDisabled;
} else if (data.pref === "devtools.theme") {
} else if (prefName === "devtools.theme") {
this.updateCurrentTheme();
}
},
@ -254,6 +256,7 @@ OptionsPanel.prototype = {
setupThemeList: function () {
let themeBox = this.panelDoc.getElementById("devtools-theme-box");
themeBox.innerHTML = "";
let createThemeOption = theme => {
let inputLabel = this.panelDoc.createElement("label");
@ -350,11 +353,11 @@ OptionsPanel.prototype = {
let themeRadioInput = themeBox.querySelector(`[value=${currentTheme}]`);
if (themeRadioInput) {
themeRadioInput.click();
themeRadioInput.checked = true;
} else {
// If the current theme does not exist anymore, switch to light theme
let lightThemeInputRadio = themeBox.querySelector("[value=light]");
lightThemeInputRadio.click();
lightThemeInputRadio.checked = true;
}
},

View File

@ -823,9 +823,7 @@ Toolbox.prototype = {
button.className = "toolbox-dock-button devtools-button";
button.setAttribute("title", L10N.getStr("toolboxDockButtons." +
position + ".tooltip"));
button.addEventListener("click", () => {
this.switchHost(position);
});
button.addEventListener("click", this.switchHost.bind(this, position));
dockBox.appendChild(button);
}
@ -1136,9 +1134,7 @@ Toolbox.prototype = {
radio.setAttribute("icon-invertable", "dark-theme");
}
radio.addEventListener("command", () => {
this.selectTool(id);
});
radio.addEventListener("command", this.selectTool.bind(this, id));
// spacer lets us center the image and label, while allowing cropping
let spacer = this.doc.createElement("spacer");
@ -2052,6 +2048,8 @@ Toolbox.prototype = {
if (this._destroyer) {
return this._destroyer;
}
let deferred = defer();
this._destroyer = deferred.promise;
this.emit("destroy");
@ -2076,13 +2074,23 @@ Toolbox.prototype = {
this._saveSplitConsoleHeight();
this.webconsolePanel.removeEventListener("resize",
this._saveSplitConsoleHeight);
this.webconsolePanel = null;
}
if (this.closeButton) {
this.closeButton.removeEventListener("click", this.destroy, true);
this.closeButton = null;
}
if (this.textboxContextMenuPopup) {
this.textboxContextMenuPopup.removeEventListener("popupshowing",
this._updateTextboxMenuItems, true);
this.textboxContextMenuPopup = null;
}
if (this.tabbar) {
this.tabbar.removeEventListener("focus", this._onTabbarFocus, true);
this.tabbar.removeEventListener("click", this._onTabbarFocus, true);
this.tabbar.removeEventListener("keypress", this._onTabbarArrowKeypress);
this.tabbar = null;
}
this.closeButton.removeEventListener("click", this.destroy, true);
this.textboxContextMenuPopup.removeEventListener("popupshowing",
this._updateTextboxMenuItems, true);
this.tabbar.removeEventListener("focus", this._onTabbarFocus, true);
this.tabbar.removeEventListener("click", this._onTabbarFocus, true);
this.tabbar.removeEventListener("keypress", this._onTabbarArrowKeypress);
let outstanding = [];
for (let [id, panel] of this._toolPanels) {
@ -2137,7 +2145,7 @@ Toolbox.prototype = {
// Finish all outstanding tasks (which means finish destroying panels and
// then destroying the host, successfully or not) before destroying the
// target.
this._destroyer = settleAll(outstanding)
deferred.resolve(settleAll(outstanding)
.catch(console.error)
.then(() => this.destroyHost())
.catch(console.error)
@ -2171,7 +2179,7 @@ Toolbox.prototype = {
.getInterface(Ci.nsIDOMWindowUtils)
.garbageCollect();
}
}).then(null, console.error);
}).then(null, console.error));
let leakCheckObserver = ({wrappedJSObject: barrier}) => {
// Make the leak detector wait until this toolbox is properly destroyed.

View File

@ -16,36 +16,23 @@ registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.toolbox.footer.height");
});
/**
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node
* FIXME: Delete this function and use inspector/test/head.js' getNode instead,
* and fix all box model view tests to use nodeFronts instead of CPOWs.
* @param {String|DOMNode} nodeOrSelector
* @return {DOMNode}
*/
function getNode(nodeOrSelector) {
return typeof nodeOrSelector === "string" ?
content.document.querySelector(nodeOrSelector) :
nodeOrSelector;
}
/**
* Highlight a node and set the inspector's current selection to the node or
* the first match of the given css selector.
* @param {String|DOMNode} nodeOrSelector
* @param {String|NodeFront} selectorOrNodeFront
* The selector for the node to be set, or the nodeFront
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves when the inspector is updated with the new
* node
*/
function selectAndHighlightNode(nodeOrSelector, inspector) {
info("Highlighting and selecting the node " + nodeOrSelector);
function* selectAndHighlightNode(selectorOrNodeFront, inspector) {
info("Highlighting and selecting the node " + selectorOrNodeFront);
let node = getNode(nodeOrSelector);
let nodeFront = yield getNodeFront(selectorOrNodeFront, inspector);
let updated = inspector.toolbox.once("highlighter-ready");
inspector.selection.setNode(node, "test-highlight");
return updated;
inspector.selection.setNodeFront(nodeFront, "test-highlight");
yield updated;
}
/**

View File

@ -16,10 +16,9 @@
//
// Some listeners do not send a response message back.
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var {utils: Cu} = Components;
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
var {isContentStylesheet} = require("devtools/shared/inspector/css-logic");
var defer = require("devtools/shared/defer");
/**
@ -49,32 +48,6 @@ addMessageListener("Test:GetRulePropertyValue", function (msg) {
sendAsyncMessage("Test:GetRulePropertyValue", value);
});
/**
* Get information about all the stylesheets that contain rules that apply to
* a given node. The information contains the sheet href and whether or not the
* sheet is a content sheet or not
* @param {Object} objects Expects a 'target' CPOW object
* @return {Array} A list of stylesheet info objects
*/
addMessageListener("Test:GetStyleSheetsInfoForNode", function (msg) {
let target = msg.objects.target;
let sheets = [];
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let domRules = domUtils.getCSSStyleRules(target);
for (let i = 0, n = domRules.Count(); i < n; i++) {
let sheet = domRules.GetElementAt(i).parentStyleSheet;
sheets.push({
href: sheet.href,
isContentSheet: isContentStylesheet(sheet)
});
}
sendAsyncMessage("Test:GetStyleSheetsInfoForNode", sheets);
});
/**
* Get the property value from the computed style for an element.
* @param {Object} data Expects a data object with the following properties

View File

@ -25,21 +25,19 @@ add_task(function* () {
info("Checking stylesheets on HTML document");
yield addTab(TEST_URI_HTML);
let target = getNode("#target");
let {inspector} = yield openInspector();
let {inspector, testActor} = yield openInspector();
yield selectNode("#target", inspector);
info("Checking stylesheets");
yield checkSheets(target);
yield checkSheets("#target", testActor);
info("Checking authored stylesheets");
yield addTab(TEST_URI_AUTHOR);
({inspector} = yield openInspector());
target = getNode("#target");
yield selectNode("#target", inspector);
yield checkSheets(target);
yield checkSheets("#target", testActor);
info("Checking stylesheets on XUL document");
info("Allowing XUL content");
@ -47,10 +45,9 @@ add_task(function* () {
yield addTab(TEST_URI_XUL);
({inspector} = yield openInspector());
target = getNode("#target");
yield selectNode("#target", inspector);
yield checkSheets(target);
yield checkSheets("#target", testActor);
info("Disallowing XUL content");
disallowXUL();
});
@ -67,9 +64,8 @@ function disallowXUL() {
Ci.nsIPermissionManager.DENY_ACTION);
}
function* checkSheets(target) {
let sheets = yield executeInContent("Test:GetStyleSheetsInfoForNode", {},
{target});
function* checkSheets(targetSelector, testActor) {
let sheets = yield testActor.getStyleSheetsInfoForNode(targetSelector);
for (let sheet of sheets) {
if (!sheet.href ||

View File

@ -16,10 +16,8 @@
//
// Some listeners do not send a response message back.
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var {utils: Cu} = Components;
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
var {isContentStylesheet} = require("devtools/shared/inspector/css-logic");
var defer = require("devtools/shared/defer");
/**
@ -49,32 +47,6 @@ addMessageListener("Test:GetRulePropertyValue", function (msg) {
sendAsyncMessage("Test:GetRulePropertyValue", value);
});
/**
* Get information about all the stylesheets that contain rules that apply to
* a given node. The information contains the sheet href and whether or not the
* sheet is a content sheet or not
* @param {Object} objects Expects a 'target' CPOW object
* @return {Array} A list of stylesheet info objects
*/
addMessageListener("Test:GetStyleSheetsInfoForNode", function (msg) {
let target = msg.objects.target;
let sheets = [];
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let domRules = domUtils.getCSSStyleRules(target);
for (let i = 0, n = domRules.Count(); i < n; i++) {
let sheet = domRules.GetElementAt(i).parentStyleSheet;
sheets.push({
href: sheet.href,
isContentSheet: isContentStylesheet(sheet)
});
}
sendAsyncMessage("Test:GetStyleSheetsInfoForNode", sheets);
});
/**
* Get the property value from the computed style for an element.
* @param {Object} data Expects a data object with the following properties

View File

@ -29,12 +29,12 @@ add_task(function* () {
let tab = yield addTab(TEST_URI);
let testActor = yield getTestActorWithoutToolbox(tab);
yield testToolboxInitialization(tab);
yield testToolboxInitialization(testActor, tab);
yield testContextMenuInitialization(testActor);
yield testContextMenuInspectorAlreadyOpen(testActor);
});
function* testToolboxInitialization(tab) {
function* testToolboxInitialization(testActor, tab) {
let target = TargetFactory.forTab(tab);
info("Opening inspector with gDevTools.");
@ -50,8 +50,7 @@ function* testToolboxInitialization(tab) {
yield testMarkupView("p", inspector);
yield testBreadcrumbs("p", inspector);
let span = getNode("span");
span.scrollIntoView();
yield testActor.scrollIntoView("span");
yield selectNode("span", inspector);
yield testMarkupView("span", inspector);

View File

@ -66,41 +66,6 @@ var navigateTo = function (toolbox, url) {
return activeTab.navigateTo(url);
};
/**
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node
* @param {String|DOMNode} nodeOrSelector
* @param {Object} options
* An object containing any of the following options:
* - document: HTMLDocument that should be queried for the selector.
* Default: content.document.
* - expectNoMatch: If true and a node matches the given selector, a
* failure is logged for an unexpected match.
* If false and nothing matches the given selector, a
* failure is logged for a missing match.
* Default: false.
* @return {DOMNode}
*/
function getNode(nodeOrSelector, options = {}) {
let document = options.document || content.document;
let noMatches = !!options.expectNoMatch;
if (typeof nodeOrSelector === "string") {
info("Looking for a node that matches selector " + nodeOrSelector);
let node = document.querySelector(nodeOrSelector);
if (noMatches) {
ok(!node, "Selector " + nodeOrSelector + " didn't match any nodes.");
} else {
ok(node, "Selector " + nodeOrSelector + " matched a node.");
}
return node;
}
info("Looking for a node but selector was not a string.");
return nodeOrSelector;
}
/**
* Start the element picker and focus the content window.
* @param {Toolbox} toolbox

View File

@ -105,9 +105,8 @@ var CommandUtils = {
button.setAttribute("title", command.description);
}
button.addEventListener("click", () => {
requisition.updateExec(typed);
}, false);
button.addEventListener("click",
requisition.updateExec.bind(requisition, typed));
button.addEventListener("keypress", (event) => {
if (ViewHelpers.isSpaceOrReturn(event)) {
@ -117,6 +116,7 @@ var CommandUtils = {
}, false);
// Allow the command button to be toggleable
let onChange = null;
if (command.state) {
button.setAttribute("autocheck", false);
@ -126,7 +126,7 @@ var CommandUtils = {
* applies to. For legacy reasons the event object can also contain
* a tab property.
*/
let onChange = (eventName, ev) => {
onChange = (eventName, ev) => {
if (ev.target == target || ev.tab == target.tab) {
let updateChecked = (checked) => {
@ -155,12 +155,14 @@ var CommandUtils = {
command.state.onChange(target, onChange);
onChange("", { target: target });
document.defaultView.addEventListener("unload", () => {
if (command.state.offChange) {
command.state.offChange(target, onChange);
}
}, false);
}
};
document.defaultView.addEventListener("unload", function (event) {
if (onChange && command.state.offChange) {
command.state.offChange(target, onChange);
}
button.remove();
button = null;
}, { once: true });
requisition.clear();

View File

@ -10,6 +10,7 @@ var { Cc, Ci, Cu, Cr } = require("chrome");
const {getRect, getElementFromPoint, getAdjustedQuads} = require("devtools/shared/layout/utils");
const defer = require("devtools/shared/defer");
const {Task} = require("devtools/shared/task");
const {isContentStylesheet} = require("devtools/shared/inspector/css-logic");
var DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
@ -144,6 +145,12 @@ var testSpec = protocol.generateActorSpec({
},
response: {}
},
scrollIntoView: {
request: {
args: Arg(0, "string")
},
response: {}
},
hasPseudoClassLock: {
request: {
selector: Arg(0, "string"),
@ -260,6 +267,14 @@ var testSpec = protocol.generateActorSpec({
response: {
value: RetVal("json")
}
},
getStyleSheetsInfoForNode: {
request: {
selector: Arg(0, "string")
},
response: {
value: RetVal("json")
}
}
}
});
@ -498,6 +513,15 @@ var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
EventUtils.synthesizeKey(key, options, this.content);
},
/**
* Scroll an element into view.
* @param {String} selector The selector for the node to scroll into view.
*/
scrollIntoView: function (selector) {
let node = this._querySelector(selector);
node.scrollIntoView();
},
/**
* Check that an element currently has a pseudo-class lock.
* @param {String} selector The node selector to get the pseudo-class from
@ -725,6 +749,32 @@ var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
}
return info;
},
/**
* Get information about the stylesheets which have CSS rules that apply to a given DOM
* element, identified by a selector.
* @param {String} selector The CSS selector to get the node (can be an array
* of selectors to get elements in an iframe).
* @return {Array} A list of stylesheet objects, each having the following properties:
* - {String} href.
* - {Boolean} isContentSheet.
*/
getStyleSheetsInfoForNode: function (selector) {
let node = this._querySelector(selector);
let domRules = DOMUtils.getCSSStyleRules(node);
let sheets = [];
for (let i = 0, n = domRules.Count(); i < n; i++) {
let sheet = domRules.GetElementAt(i).parentStyleSheet;
sheets.push({
href: sheet.href,
isContentSheet: isContentStylesheet(sheet)
});
}
return sheets;
}
});

View File

@ -27,6 +27,7 @@
}
let devtoolsStyleSheets = new WeakMap();
let gOldTheme = "";
function forceStyle() {
let computedStyle = window.getComputedStyle(documentElement);
@ -83,10 +84,12 @@
* Apply all the sheets from `newTheme` and remove all of the sheets
* from `oldTheme`
*/
function switchTheme(newTheme, oldTheme) {
if (newTheme === oldTheme) {
function switchTheme(newTheme) {
if (newTheme === gOldTheme) {
return;
}
let oldTheme = gOldTheme;
gOldTheme = newTheme;
let oldThemeDef = gDevTools.getThemeDefinition(oldTheme);
let newThemeDef = gDevTools.getThemeDefinition(newTheme);
@ -156,10 +159,8 @@
}, console.error.bind(console));
}
function handlePrefChange(event, data) {
if (data.pref == "devtools.theme") {
switchTheme(data.newValue, data.oldValue);
}
function handlePrefChange() {
switchTheme(Services.prefs.getCharPref("devtools.theme"));
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
@ -174,10 +175,10 @@
} else {
switchTheme(Services.prefs.getCharPref("devtools.theme"));
gDevTools.on("pref-changed", handlePrefChange);
Services.prefs.addObserver("devtools.theme", handlePrefChange, false);
window.addEventListener("unload", function () {
gDevTools.off("pref-changed", handlePrefChange);
});
Services.prefs.removeObserver("devtools.theme", handlePrefChange);
}, { once: true });
}
watchCSS(window);

View File

@ -107,7 +107,11 @@ WebConsolePanel.prototype = {
}
this._destroyer = this.hud.destroy();
this._destroyer.then(() => this.emit("destroyed"));
this._destroyer.then(() => {
this._frameWindow = null;
this._toolbox = null;
this.emit("destroyed");
});
return this._destroyer;
},

View File

@ -223,7 +223,23 @@ public:
// Event handlers for various events.
// Return true if the event is handled by this state object.
virtual bool HandleDormant(bool aDormant) { return false; }
virtual bool HandleDormant(bool aDormant)
{
if (!aDormant) {
return true;
}
mMaster->mQueuedSeek.mTarget =
SeekTarget(mMaster->mCurrentPosition,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
// need to create the promise even it is not used at all.
RefPtr<MediaDecoder::SeekPromise> unused =
mMaster->mQueuedSeek.mPromise.Ensure(__func__);
SetState(DECODER_STATE_DORMANT);
return true;
}
virtual bool HandleCDMProxyReady() { return false; }
protected:
@ -408,6 +424,15 @@ public:
{
return DECODER_STATE_DORMANT;
}
bool HandleDormant(bool aDormant) override
{
if (!aDormant) {
// Exit dormant state.
SetState(DECODER_STATE_DECODING_METADATA);
}
return true;
}
};
class MediaDecoderStateMachine::DecodingFirstFrameState
@ -459,6 +484,26 @@ public:
{
return DECODER_STATE_SEEKING;
}
bool HandleDormant(bool aDormant) override
{
if (!aDormant) {
return true;
}
MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
MOZ_ASSERT(mMaster->mCurrentSeek.Exists());
// Because both audio and video decoders are going to be reset in this
// method later, we treat a VideoOnly seek task as a normal Accurate
// seek task so that while it is resumed, both audio and video playback
// are handled.
if (mMaster->mCurrentSeek.mTarget.IsVideoOnly()) {
mMaster->mCurrentSeek.mTarget.SetType(SeekTarget::Accurate);
mMaster->mCurrentSeek.mTarget.SetVideoOnly(false);
}
mMaster->mQueuedSeek = Move(mMaster->mCurrentSeek);
SetState(DECODER_STATE_DORMANT);
return true;
}
};
class MediaDecoderStateMachine::BufferingState
@ -530,6 +575,11 @@ public:
{
return DECODER_STATE_SHUTDOWN;
}
bool HandleDormant(bool aDormant) override
{
return true;
}
};
#define INIT_WATCHABLE(name, val) \
@ -1317,20 +1367,33 @@ MediaDecoderStateMachine::MaybeStartBuffering()
MOZ_ASSERT(mSentFirstFrameLoadedEvent);
MOZ_ASSERT(mState == DECODER_STATE_DECODING);
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
mResource->IsExpectingMoreData()) {
bool shouldBuffer;
if (mReader->UseBufferingHeuristics()) {
shouldBuffer = HasLowDecodedData(EXHAUSTED_DATA_MARGIN_USECS) &&
(JustExitedQuickBuffering() || HasLowUndecodedData());
} else {
MOZ_ASSERT(mReader->IsWaitForDataSupported());
shouldBuffer = (OutOfDecodedAudio() && mReader->IsWaitingAudioData()) ||
(OutOfDecodedVideo() && mReader->IsWaitingVideoData());
}
if (shouldBuffer) {
SetState(DECODER_STATE_BUFFERING);
}
// Don't enter buffering when MediaDecoder is not playing.
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
return;
}
// Don't enter buffering while prerolling so that the decoder has a chance to
// enqueue some decoded data before we give up and start buffering.
if (!IsPlaying()) {
return;
}
// No more data to download. No need to enter buffering.
if (!mResource->IsExpectingMoreData()) {
return;
}
bool shouldBuffer;
if (mReader->UseBufferingHeuristics()) {
shouldBuffer = HasLowDecodedData(EXHAUSTED_DATA_MARGIN_USECS) &&
(JustExitedQuickBuffering() || HasLowUndecodedData());
} else {
MOZ_ASSERT(mReader->IsWaitForDataSupported());
shouldBuffer = (OutOfDecodedAudio() && mReader->IsWaitingAudioData()) ||
(OutOfDecodedVideo() && mReader->IsWaitingVideoData());
}
if (shouldBuffer) {
SetState(DECODER_STATE_BUFFERING);
}
}
@ -1488,51 +1551,7 @@ void
MediaDecoderStateMachine::SetDormant(bool aDormant)
{
MOZ_ASSERT(OnTaskQueue());
if (IsShutdown()) {
return;
}
if (mStateObj->HandleDormant(aDormant)) {
return;
}
bool wasDormant = mState == DECODER_STATE_DORMANT;
if (wasDormant == aDormant) {
return;
}
DECODER_LOG("SetDormant=%d", aDormant);
// Enter dormant state.
if (aDormant) {
if (mState == DECODER_STATE_SEEKING) {
MOZ_ASSERT(!mQueuedSeek.Exists());
MOZ_ASSERT(mCurrentSeek.Exists());
// Because both audio and video decoders are going to be reset in this
// method later, we treat a VideoOnly seek task as a normal Accurate
// seek task so that while it is resumed, both audio and video playback
// are handled.
if (mCurrentSeek.mTarget.IsVideoOnly()) {
mCurrentSeek.mTarget.SetType(SeekTarget::Accurate);
mCurrentSeek.mTarget.SetVideoOnly(false);
}
mQueuedSeek = Move(mCurrentSeek);
} else {
mQueuedSeek.mTarget = SeekTarget(mCurrentPosition,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
// need to create the promise even it is not used at all.
RefPtr<MediaDecoder::SeekPromise> unused = mQueuedSeek.mPromise.Ensure(__func__);
}
SetState(DECODER_STATE_DORMANT);
return;
}
// Exit dormant state.
SetState(DECODER_STATE_DECODING_METADATA);
mStateObj->HandleDormant(aDormant);
}
RefPtr<ShutdownPromise>

View File

@ -37,7 +37,7 @@ skip-if(B2G) include pngsuite-zlib/reftest-stylo.list
#skip-if(Android) include bmp/reftest-stylo.list
# ICO tests
skip-if(Android) include ico/reftest-stylo.list
#skip-if(Android) include ico/reftest-stylo.list
# JPEG tests
# include jpeg/reftest-stylo.list

View File

@ -199,6 +199,7 @@ XPCCallContext::SystemIsBeingShutDown()
NS_WARNING("Shutting Down XPConnect even through there is a live XPCCallContext");
mXPCJSContext = nullptr;
mState = SYSTEM_SHUTDOWN;
mSet = nullptr;
mInterface = nullptr;
if (mPrevCallContext)

View File

@ -446,18 +446,6 @@ XPCNativeSet::MatchesSetUpToInterface(const XPCNativeSet* other,
return false;
}
inline void XPCNativeSet::Mark()
{
mMarked = 1;
}
#ifdef DEBUG
inline void XPCNativeSet::ASSERT_NotMarked()
{
MOZ_ASSERT(!IsMarked(), "bad");
}
#endif
/***************************************************************************/
inline

View File

@ -784,19 +784,6 @@ XPCJSContext::FinalizeCallback(JSFreeOp* fop,
MOZ_ASSERT(!self->mGCIsRunning, "bad state");
self->mGCIsRunning = true;
// We use this occasion to mark and sweep NativeInterfaces,
// NativeSets, and the WrappedNativeJSClasses...
// Do the marking...
XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos();
// Mark the sets used in the call contexts. There is a small
// chance that a wrapper's set will change *while* a call is
// happening which uses that wrapper's old interfface set. So,
// we need to do this marking to avoid collecting those sets
// that might no longer be otherwise reachable from the wrappers
// or the wrapperprotos.
// Skip this part if XPConnect is shutting down. We get into
// bad locking problems with the thread iteration otherwise.
if (!nsXPConnect::XPConnect()->IsShuttingDown()) {
@ -804,57 +791,8 @@ XPCJSContext::FinalizeCallback(JSFreeOp* fop,
// Mark those AutoMarkingPtr lists!
if (AutoMarkingPtr* roots = Get()->mAutoRoots)
roots->MarkAfterJSFinalizeAll();
XPCCallContext* ccxp = XPCJSContext::Get()->GetCallContext();
while (ccxp) {
// Deal with the strictness of callcontext that
// complains if you ask for a set when
// it is in a state where the set could not
// possibly be valid.
if (ccxp->CanGetSet()) {
XPCNativeSet* set = ccxp->GetSet();
if (set)
set->Mark();
}
ccxp = ccxp->GetPrevCallContext();
}
}
// Do the sweeping. During a zone GC, only WrappedNativeProtos in
// collected zones will be marked. Therefore, some reachable
// NativeInterfaces will not be marked, so it is not safe to sweep
// them. We still need to unmark them, since the ones pointed to by
// WrappedNativeProtos in a zone being collected will be marked.
//
// Ideally, if NativeInterfaces from different zones were kept
// separate, we could sweep only the ones belonging to zones being
// collected. Currently, though, NativeInterfaces are shared between
// zones. This ought to be fixed.
bool doSweep = !isZoneGC;
if (doSweep) {
for (auto i = self->mClassInfo2NativeSetMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<ClassInfo2NativeSetMap::Entry*>(i.Get());
if (!entry->value->IsMarked())
i.Remove();
}
}
for (auto i = self->mNativeSetMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<NativeSetMap::Entry*>(i.Get());
XPCNativeSet* set = entry->key_value;
if (set->IsMarked()) {
set->Unmark();
} else if (doSweep) {
XPCNativeSet::DestroyInstance(set);
i.Remove();
}
}
#ifdef DEBUG
XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked();
#endif
// Now we are going to recycle any unused WrappedNativeTearoffs.
// We do this by iterating all the live callcontexts
// and marking the tearoffs in use. And then we

View File

@ -201,6 +201,33 @@ IID2NativeInterfaceMap::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
/***************************************************************************/
// implement ClassInfo2NativeSetMap...
// static
bool ClassInfo2NativeSetMap::Entry::Match(const PLDHashEntryHdr* aEntry,
const void* aKey)
{
return static_cast<const Entry*>(aEntry)->key == aKey;
}
// static
void ClassInfo2NativeSetMap::Entry::Clear(PLDHashTable* aTable,
PLDHashEntryHdr* aEntry)
{
auto entry = static_cast<Entry*>(aEntry);
NS_RELEASE(entry->value);
entry->key = nullptr;
entry->value = nullptr;
}
const PLDHashTableOps ClassInfo2NativeSetMap::Entry::sOps =
{
PLDHashTable::HashVoidPtrKeyStub,
Match,
PLDHashTable::MoveEntryStub,
Clear,
nullptr
};
// static
ClassInfo2NativeSetMap*
ClassInfo2NativeSetMap::newMap(int length)
@ -209,7 +236,7 @@ ClassInfo2NativeSetMap::newMap(int length)
}
ClassInfo2NativeSetMap::ClassInfo2NativeSetMap(int length)
: mTable(PLDHashTable::StubOps(), sizeof(Entry), length)
: mTable(&ClassInfo2NativeSetMap::Entry::sOps, sizeof(Entry), length)
{
}

View File

@ -278,7 +278,12 @@ public:
struct Entry : public PLDHashEntryHdr
{
nsIClassInfo* key;
XPCNativeSet* value;
XPCNativeSet* value; // strong reference
static const PLDHashTableOps sOps;
private:
static bool Match(const PLDHashEntryHdr* aEntry, const void* aKey);
static void Clear(PLDHashTable* aTable, PLDHashEntryHdr* aEntry);
};
static ClassInfo2NativeSetMap* newMap(int length);
@ -298,7 +303,7 @@ public:
if (entry->key)
return entry->value;
entry->key = info;
entry->value = set;
NS_ADDREF(entry->value = set);
return set;
}
@ -310,8 +315,6 @@ public:
inline uint32_t Count() { return mTable.EntryCount(); }
PLDHashTable::Iterator Iter() { return mTable.Iter(); }
// ClassInfo2NativeSetMap holds pointers to *some* XPCNativeSets.
// So we don't want to count those XPCNativeSets, because they are better
// counted elsewhere (i.e. in XPCJSContext::mNativeSetMap, which holds

View File

@ -431,15 +431,15 @@ XPCWrappedNative::GetNewOrUsed(xpcObjectHelper& helper,
if (!iface)
iface = XPCNativeInterface::GetISupports();
AutoMarkingNativeSetPtr set(cx);
XPCNativeSetKey key(iface);
set = XPCNativeSet::GetNewOrUsed(&key);
RefPtr<XPCNativeSet> set =
XPCNativeSet::GetNewOrUsed(&key);
if (!set)
return NS_ERROR_FAILURE;
wrapper =
new XPCWrappedNative(helper.forgetCanonical(), Scope, set);
wrapper = new XPCWrappedNative(helper.forgetCanonical(), Scope,
set.forget());
}
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(parent),
@ -566,7 +566,7 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
// This ctor is used if this object will NOT have a proto.
XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
XPCWrappedNativeScope* aScope,
XPCNativeSet* aSet)
already_AddRefed<XPCNativeSet>&& aSet)
: mMaybeScope(TagScope(aScope)),
mSet(aSet),
@ -578,7 +578,7 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
mFlatJSObject.setFlags(FLAT_JS_OBJECT_VALID);
MOZ_ASSERT(aScope, "bad ctor param");
MOZ_ASSERT(aSet, "bad ctor param");
MOZ_ASSERT(mSet, "bad ctor param");
}
XPCWrappedNative::~XPCWrappedNative()
@ -1014,16 +1014,14 @@ private:
bool
XPCWrappedNative::ExtendSet(XPCNativeInterface* aInterface)
{
AutoJSContext cx;
if (!mSet->HasInterface(aInterface)) {
AutoMarkingNativeSetPtr newSet(cx);
XPCNativeSetKey key(mSet, aInterface);
newSet = XPCNativeSet::GetNewOrUsed(&key);
RefPtr<XPCNativeSet> newSet =
XPCNativeSet::GetNewOrUsed(&key);
if (!newSet)
return false;
mSet = newSet;
mSet = newSet.forget();
}
return true;
}
@ -2164,7 +2162,7 @@ NS_IMETHODIMP XPCWrappedNative::DebugDump(int16_t depth)
if (depth && mSet)
mSet->DebugDump(depth);
else
XPC_LOG_ALWAYS(("mSet @ %x", mSet));
XPC_LOG_ALWAYS(("mSet @ %x", mSet.get()));
XPC_LOG_ALWAYS(("mFlatJSObject of %x", mFlatJSObject.getPtr()));
XPC_LOG_ALWAYS(("mIdentity of %x", mIdentity.get()));

View File

@ -462,13 +462,21 @@ XPCNativeSetKey::Hash() const
/***************************************************************************/
// XPCNativeSet
XPCNativeSet::~XPCNativeSet()
{
// Remove |this| before we clear the interfaces to ensure that the
// hashtable look up is correct.
XPCJSContext::Get()->GetNativeSetMap()->Remove(this);
for (int i = 0; i < mInterfaceCount; i++) {
NS_RELEASE(mInterfaces[i]);
}
}
// static
XPCNativeSet*
already_AddRefed<XPCNativeSet>
XPCNativeSet::GetNewOrUsed(const nsIID* iid)
{
AutoJSContext cx;
AutoMarkingNativeSetPtr set(cx);
RefPtr<XPCNativeInterface> iface =
XPCNativeInterface::GetNewOrUsed(iid);
if (!iface)
@ -481,10 +489,10 @@ XPCNativeSet::GetNewOrUsed(const nsIID* iid)
if (!map)
return nullptr;
set = map->Find(&key);
RefPtr<XPCNativeSet> set = map->Find(&key);
if (set)
return set;
return set.forget();
set = NewInstance({iface.forget()});
if (!set)
@ -492,29 +500,25 @@ XPCNativeSet::GetNewOrUsed(const nsIID* iid)
if (!map->AddNew(&key, set)) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
}
return set;
return set.forget();
}
// static
XPCNativeSet*
already_AddRefed<XPCNativeSet>
XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
{
AutoJSContext cx;
AutoMarkingNativeSetPtr set(cx);
XPCJSContext* xpccx = XPCJSContext::Get();
ClassInfo2NativeSetMap* map = xpccx->GetClassInfo2NativeSetMap();
if (!map)
return nullptr;
set = map->Find(classInfo);
RefPtr<XPCNativeSet> set = map->Find(classInfo);
if (set)
return set;
return set.forget();
nsIID** iidArray = nullptr;
uint32_t iidCount = 0;
@ -567,14 +571,12 @@ XPCNativeSet::GetNewOrUsed(nsIClassInfo* classInfo)
XPCNativeSet* set2 = map2->Add(&key, set);
if (!set2) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
goto out;
}
// It is okay to find an existing entry here because
// we did not look for one before we called Add().
if (set2 != set) {
DestroyInstance(set);
set = set2;
}
}
@ -596,7 +598,7 @@ out:
if (iidArray)
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(iidCount, iidArray);
return set;
return set.forget();
}
// static
@ -610,20 +612,17 @@ XPCNativeSet::ClearCacheEntryForClassInfo(nsIClassInfo* classInfo)
}
// static
XPCNativeSet*
already_AddRefed<XPCNativeSet>
XPCNativeSet::GetNewOrUsed(XPCNativeSetKey* key)
{
AutoJSContext cx;
AutoMarkingNativeSetPtr set(cx);
XPCJSContext* xpccx = XPCJSContext::Get();
NativeSetMap* map = xpccx->GetNativeSetMap();
NativeSetMap* map = XPCJSContext::Get()->GetNativeSetMap();
if (!map)
return nullptr;
set = map->Find(key);
RefPtr<XPCNativeSet> set = map->Find(key);
if (set)
return set;
return set.forget();
if (key->GetBaseSet())
set = NewInstanceMutate(key);
@ -635,15 +634,14 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSetKey* key)
if (!map->AddNew(key, set)) {
NS_ERROR("failed to add our set!");
DestroyInstance(set);
set = nullptr;
}
return set;
return set.forget();
}
// static
XPCNativeSet*
already_AddRefed<XPCNativeSet>
XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet,
XPCNativeSet* secondSet,
bool preserveFirstSetOrder)
@ -658,12 +656,12 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet,
// If everything in secondSet was a duplicate, we can just use the first
// set.
if (uniqueCount == firstSet->mInterfaceCount)
return firstSet;
return RefPtr<XPCNativeSet>(firstSet).forget();
// If the secondSet is just a superset of the first, we can use it provided
// that the caller doesn't care about ordering.
if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount)
return secondSet;
return RefPtr<XPCNativeSet>(secondSet).forget();
// Ok, darn. Now we have to make a new set.
//
@ -672,7 +670,7 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet,
// a lot of stuff assumes that sets are created by adding one interface to an
// existing set. So let's just do the slow and easy thing and hope that the
// above optimizations handle the common cases.
XPCNativeSet* currentSet = firstSet;
RefPtr<XPCNativeSet> currentSet = firstSet;
for (uint32_t i = 0; i < secondSet->mInterfaceCount; ++i) {
XPCNativeInterface* iface = secondSet->mInterfaces[i];
if (!currentSet->HasInterface(iface)) {
@ -686,11 +684,11 @@ XPCNativeSet::GetNewOrUsed(XPCNativeSet* firstSet,
// We've got the union set. Hand it back to the caller.
MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount);
return currentSet;
return currentSet.forget();
}
// static
XPCNativeSet*
already_AddRefed<XPCNativeSet>
XPCNativeSet::NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array)
{
if (array.Length() == 0)
@ -715,7 +713,7 @@ XPCNativeSet::NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array)
if (slots > 1)
size += (slots - 1) * sizeof(XPCNativeInterface*);
void* place = new char[size];
XPCNativeSet* obj = new(place) XPCNativeSet();
RefPtr<XPCNativeSet> obj = new(place) XPCNativeSet();
// Stick the nsISupports in front and skip additional nsISupport(s)
XPCNativeInterface** outp = (XPCNativeInterface**) &obj->mInterfaces;
@ -733,11 +731,11 @@ XPCNativeSet::NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array)
obj->mMemberCount = memberCount;
obj->mInterfaceCount = slots;
return obj;
return obj.forget();
}
// static
XPCNativeSet*
already_AddRefed<XPCNativeSet>
XPCNativeSet::NewInstanceMutate(XPCNativeSetKey* key)
{
XPCNativeSet* otherSet = key->GetBaseSet();
@ -753,7 +751,7 @@ XPCNativeSet::NewInstanceMutate(XPCNativeSetKey* key)
int size = sizeof(XPCNativeSet);
size += otherSet->mInterfaceCount * sizeof(XPCNativeInterface*);
void* place = new char[size];
XPCNativeSet* obj = new(place) XPCNativeSet();
RefPtr<XPCNativeSet> obj = new(place) XPCNativeSet();
obj->mMemberCount = otherSet->GetMemberCount() +
newInterface->GetMemberCount();
@ -766,7 +764,7 @@ XPCNativeSet::NewInstanceMutate(XPCNativeSetKey* key)
}
NS_ADDREF(*dest++ = newInterface);
return obj;
return obj.forget();
}
// static

View File

@ -17,7 +17,7 @@ int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount = 0;
XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
nsIClassInfo* ClassInfo,
XPCNativeSet* Set)
already_AddRefed<XPCNativeSet>&& Set)
: mScope(Scope),
mJSProtoObject(nullptr),
mClassInfo(ClassInfo),
@ -166,12 +166,11 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
if (proto)
return proto;
AutoMarkingNativeSetPtr set(cx);
set = XPCNativeSet::GetNewOrUsed(classInfo);
RefPtr<XPCNativeSet> set = XPCNativeSet::GetNewOrUsed(classInfo);
if (!set)
return nullptr;
proto = new XPCWrappedNativeProto(scope, classInfo, set);
proto = new XPCWrappedNativeProto(scope, classInfo, set.forget());
if (!proto || !proto->Init(scriptableCreateInfo, callPostCreatePrototype)) {
delete proto.get();
@ -193,7 +192,7 @@ XPCWrappedNativeProto::DebugDump(int16_t depth)
XPC_LOG_ALWAYS(("gDEBUG_LiveProtoCount is %d", gDEBUG_LiveProtoCount));
XPC_LOG_ALWAYS(("mScope @ %x", mScope));
XPC_LOG_ALWAYS(("mJSProtoObject @ %x", mJSProtoObject.get()));
XPC_LOG_ALWAYS(("mSet @ %x", mSet));
XPC_LOG_ALWAYS(("mSet @ %x", mSet.get()));
XPC_LOG_ALWAYS(("mScriptableInfo @ %x", mScriptableInfo));
if (depth && mScriptableInfo) {
XPC_LOG_INDENT();

View File

@ -574,42 +574,6 @@ XPCWrappedNativeScope::UpdateWeakPointersAfterGC(XPCJSContext* cx)
}
}
// static
void
XPCWrappedNativeScope::MarkAllWrappedNativesAndProtos()
{
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
entry->value->Mark();
}
// We need to explicitly mark all the protos too because some protos may be
// alive in the hashtable but not currently in use by any wrapper
for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
entry->value->Mark();
}
}
}
#ifdef DEBUG
// static
void
XPCWrappedNativeScope::ASSERT_NoInterfaceSetsAreMarked()
{
for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
for (auto i = cur->mWrappedNativeMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<Native2WrappedNativeMap::Entry*>(i.Get());
entry->value->ASSERT_SetsNotMarked();
}
for (auto i = cur->mWrappedNativeProtoMap->Iter(); !i.Done(); i.Next()) {
auto entry = static_cast<ClassInfo2WrappedNativeProtoMap::Entry*>(i.Get());
entry->value->ASSERT_SetNotMarked();
}
}
}
#endif
// static
void
XPCWrappedNativeScope::SweepAllWrappedNativeTearOffs()

View File

@ -793,7 +793,7 @@ private:
XPCNativeScriptableInfo* mScriptableInfo;
XPCNativeSet* mSet;
RefPtr<XPCNativeSet> mSet;
RefPtr<XPCNativeInterface> mInterface;
XPCNativeMember* mMember;
@ -928,14 +928,6 @@ public:
static void
SuspectAllWrappers(XPCJSContext* cx, nsCycleCollectionNoteRootCallback& cb);
static void
MarkAllWrappedNativesAndProtos();
#ifdef DEBUG
static void
ASSERT_NoInterfaceSetsAreMarked();
#endif
static void
SweepAllWrappedNativeTearOffs();
@ -1281,7 +1273,7 @@ private:
// It represents a new XPCNativeSet we are considering constructing, without
// requiring that the set actually be built.
class XPCNativeSetKey final
class MOZ_STACK_CLASS XPCNativeSetKey final
{
public:
// This represents an existing set |baseSet|.
@ -1314,8 +1306,8 @@ public:
// Allow shallow copy
private:
XPCNativeSet* mBaseSet;
XPCNativeInterface* mAddition;
RefPtr<XPCNativeSet> mBaseSet;
RefPtr<XPCNativeInterface> mAddition;
};
/***************************************************************************/
@ -1324,9 +1316,12 @@ private:
class XPCNativeSet final
{
public:
static XPCNativeSet* GetNewOrUsed(const nsIID* iid);
static XPCNativeSet* GetNewOrUsed(nsIClassInfo* classInfo);
static XPCNativeSet* GetNewOrUsed(XPCNativeSetKey* key);
NS_INLINE_DECL_REFCOUNTING_WITH_DESTROY(XPCNativeSet,
DestroyInstance(this))
static already_AddRefed<XPCNativeSet> GetNewOrUsed(const nsIID* iid);
static already_AddRefed<XPCNativeSet> GetNewOrUsed(nsIClassInfo* classInfo);
static already_AddRefed<XPCNativeSet> GetNewOrUsed(XPCNativeSetKey* key);
// This generates a union set.
//
@ -1335,9 +1330,9 @@ class XPCNativeSet final
// algorithm is applied; but if we detect that |secondSet| is a superset of
// |firstSet|, we return |secondSet| without worrying about whether the
// ordering might differ from |firstSet|.
static XPCNativeSet* GetNewOrUsed(XPCNativeSet* firstSet,
XPCNativeSet* secondSet,
bool preserveFirstSetOrder);
static already_AddRefed<XPCNativeSet> GetNewOrUsed(XPCNativeSet* firstSet,
XPCNativeSet* secondSet,
bool preserveFirstSetOrder);
static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo);
@ -1377,50 +1372,25 @@ class XPCNativeSet final
inline bool MatchesSetUpToInterface(const XPCNativeSet* other,
XPCNativeInterface* iface) const;
inline void Mark();
// NOP. This is just here to make the AutoMarkingPtr code compile.
inline void TraceJS(JSTracer* trc) {}
inline void AutoTrace(JSTracer* trc) {}
public:
void Unmark() {
mMarked = 0;
}
bool IsMarked() const {
return !!mMarked;
}
#ifdef DEBUG
inline void ASSERT_NotMarked();
#endif
void DebugDump(int16_t depth);
static void DestroyInstance(XPCNativeSet* inst);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
protected:
static XPCNativeSet* NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array);
static XPCNativeSet* NewInstanceMutate(XPCNativeSetKey* key);
static already_AddRefed<XPCNativeSet> NewInstance(nsTArray<RefPtr<XPCNativeInterface>>&& array);
static already_AddRefed<XPCNativeSet> NewInstanceMutate(XPCNativeSetKey* key);
XPCNativeSet()
: mMemberCount(0), mInterfaceCount(0), mMarked(0)
{
MOZ_COUNT_CTOR(XPCNativeSet);
}
~XPCNativeSet() {
for (int i = 0; i < mInterfaceCount; i++) {
NS_RELEASE(mInterfaces[i]);
}
MOZ_COUNT_DTOR(XPCNativeSet);
}
: mMemberCount(0), mInterfaceCount(0)
{}
~XPCNativeSet();
void* operator new(size_t, void* p) CPP_THROW_NEW {return p;}
static void DestroyInstance(XPCNativeSet* inst);
private:
uint16_t mMemberCount;
uint16_t mInterfaceCount : 15;
uint16_t mMarked : 1;
uint16_t mInterfaceCount;
// Always last - object sized for array.
// These are strong references.
XPCNativeInterface* mInterfaces[1];
@ -1653,10 +1623,6 @@ public:
}
void TraceInside(JSTracer* trc) {
if (trc->isMarkingTracer()) {
mSet->Mark();
}
GetScope()->TraceSelf(trc);
}
@ -1672,14 +1638,9 @@ public:
}
// NOP. This is just here to make the AutoMarkingPtr code compile.
void Mark() const {}
inline void AutoTrace(JSTracer* trc) {}
void Mark() const {mSet->Mark();}
#ifdef DEBUG
void ASSERT_SetNotMarked() const {mSet->ASSERT_NotMarked();}
#endif
~XPCWrappedNativeProto();
protected:
@ -1690,7 +1651,7 @@ protected:
// hide ctor
XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
nsIClassInfo* ClassInfo,
XPCNativeSet* Set);
already_AddRefed<XPCNativeSet>&& Set);
bool Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
bool callPostCreatePrototype);
@ -1704,7 +1665,7 @@ private:
XPCWrappedNativeScope* mScope;
JS::ObjectPtr mJSProtoObject;
nsCOMPtr<nsIClassInfo> mClassInfo;
XPCNativeSet* mSet;
RefPtr<XPCNativeSet> mSet;
XPCNativeScriptableInfo* mScriptableInfo;
};
@ -1856,7 +1817,7 @@ public:
GetSet() const {return mSet;}
void
SetSet(XPCNativeSet* set) {mSet = set;}
SetSet(already_AddRefed<XPCNativeSet> set) {mSet = set;}
static XPCWrappedNative* Get(JSObject* obj) {
MOZ_ASSERT(IS_WN_REFLECTOR(obj));
@ -1931,16 +1892,9 @@ public:
nsresult* pError = nullptr);
XPCWrappedNativeTearOff* FindTearOff(const nsIID& iid);
void Mark() const
{
mSet->Mark();
if (HasProto()) GetProto()->Mark();
}
void Mark() const {}
inline void TraceInside(JSTracer* trc) {
if (trc->isMarkingTracer()) {
mSet->Mark();
}
if (HasProto())
GetProto()->TraceSelf(trc);
else
@ -1969,12 +1923,6 @@ public:
TraceSelf(trc);
}
#ifdef DEBUG
void ASSERT_SetsNotMarked() const
{mSet->ASSERT_NotMarked();
if (HasProto()){GetProto()->ASSERT_SetNotMarked();}}
#endif
inline void SweepTearOffs();
// Returns a string that shuld be free'd using JS_smprintf_free (or null).
@ -1999,7 +1947,7 @@ protected:
// This ctor is used if this object will NOT have a proto.
XPCWrappedNative(already_AddRefed<nsISupports>&& aIdentity,
XPCWrappedNativeScope* aScope,
XPCNativeSet* aSet);
already_AddRefed<XPCNativeSet>&& aSet);
virtual ~XPCWrappedNative();
void Destroy();
@ -2035,7 +1983,7 @@ private:
XPCWrappedNativeScope* mMaybeScope;
XPCWrappedNativeProto* mMaybeProto;
};
XPCNativeSet* mSet;
RefPtr<XPCNativeSet> mSet;
JS::TenuredHeap<JSObject*> mFlatJSObject;
XPCNativeScriptableInfo* mScriptableInfo;
XPCWrappedNativeTearOff mFirstTearOff;
@ -2881,7 +2829,6 @@ class TypedAutoMarkingPtr : public AutoMarkingPtr
T* mPtr;
};
typedef TypedAutoMarkingPtr<XPCNativeSet> AutoMarkingNativeSetPtr;
typedef TypedAutoMarkingPtr<XPCWrappedNative> AutoMarkingWrappedNativePtr;
typedef TypedAutoMarkingPtr<XPCWrappedNativeTearOff> AutoMarkingWrappedNativeTearOffPtr;
typedef TypedAutoMarkingPtr<XPCWrappedNativeProto> AutoMarkingWrappedNativeProtoPtr;

View File

@ -313,12 +313,12 @@ WrapperFactory::PrepareForWrapping(JSContext* cx, HandleObject scope,
// give the destination object the union of the two native sets. We try
// to do this cleverly in the common case to avoid too much overhead.
XPCWrappedNative* newwn = XPCWrappedNative::Get(obj);
XPCNativeSet* unionSet = XPCNativeSet::GetNewOrUsed(newwn->GetSet(),
wn->GetSet(), false);
RefPtr<XPCNativeSet> unionSet = XPCNativeSet::GetNewOrUsed(newwn->GetSet(),
wn->GetSet(), false);
if (!unionSet) {
return;
}
newwn->SetSet(unionSet);
newwn->SetSet(unionSet.forget());
retObj.set(waive ? WaiveXray(cx, obj) : obj);
}

View File

@ -1073,7 +1073,7 @@ fails skip == 403656-4.html 403656-4.html
#== 403657-1.html 403657-1.html
# Fails depending on the fonts...
== 403733-1.html 403733-1.html
== 403962-1.xhtml 403962-1.xhtml
skip == 403962-1.xhtml 403962-1.xhtml
== 404030-1.html 404030-1.html
== 404030-1-notref.html 404030-1-notref.html
== 404030-1-notref2.html 404030-1-notref2.html

View File

@ -9,7 +9,7 @@ random pref(layout.css.display-contents.enabled,true) == display-contents-acid-d
pref(layout.css.display-contents.enabled,true) == display-contents-generated-content.html display-contents-generated-content.html
pref(layout.css.display-contents.enabled,true) == display-contents-generated-content-2.html display-contents-generated-content-2.html
pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1.html display-contents-style-inheritance-1.html
pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-stylechange.html
skip pref(layout.css.display-contents.enabled,true) == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-stylechange.html
skip pref(layout.css.display-contents.enabled,true) fuzzy-if(winWidget,12,100) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-dom-mutations.html
pref(layout.css.display-contents.enabled,true) == display-contents-tables.xhtml display-contents-tables.xhtml
pref(layout.css.display-contents.enabled,true) == display-contents-tables-2.xhtml display-contents-tables-2.xhtml

View File

@ -40,10 +40,10 @@ skip-if(Android) == grid-placement-definite-implicit-001.html grid-placement-def
== grid-placement-definite-implicit-002.html grid-placement-definite-implicit-002.html
skip-if(Android) fuzzy-if(winWidget,1,32) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001.html
== grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001.html
pref(layout.css.vertical-text.enabled,true) == rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001.html
pref(layout.css.vertical-text.enabled,true) == rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001.html
pref(layout.css.vertical-text.enabled,true) == vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001.html
pref(layout.css.vertical-text.enabled,true) == vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001.html
== rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001.html
== rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001.html
== vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001.html
== vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001.html
== grid-relpos-items-001.html grid-relpos-items-001.html
== grid-item-sizing-percent-001.html grid-item-sizing-percent-001.html
== grid-item-sizing-px-001.html grid-item-sizing-px-001.html

View File

@ -48,8 +48,8 @@ skip load nested-ruby-1.html
== ruby-align-2.html ruby-align-2.html
== ruby-align-2a.html ruby-align-2a.html
== ruby-position-horizontal.html ruby-position-horizontal.html
pref(layout.css.vertical-text.enabled,true) == ruby-position-vertical-lr.html ruby-position-vertical-lr.html
pref(layout.css.vertical-text.enabled,true) == ruby-position-vertical-rl.html ruby-position-vertical-rl.html
== ruby-position-vertical-lr.html ruby-position-vertical-lr.html
== ruby-position-vertical-rl.html ruby-position-vertical-rl.html
== ruby-reflow-1-opaqueruby.html ruby-reflow-1-opaqueruby.html
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),13,1) == ruby-reflow-1-transparentruby.html ruby-reflow-1-transparentruby.html
== ruby-span-1.html ruby-span-1.html

View File

@ -59,7 +59,7 @@ fails fuzzy-if(skiaContent,1,12000) == float-in-rtl-4d.html float-in-rtl-4d.html
# XXX The default-preferences setting here can be removed after the
# pref has been made true by default for all channels (bug 1138384).
default-preferences pref(layout.css.vertical-text.enabled,true)
== float-in-rtl-vlr-1a.html float-in-rtl-vlr-1a.html
== float-in-rtl-vlr-1b.html float-in-rtl-vlr-1b.html

View File

@ -14,8 +14,8 @@ skip-if(!Android&&!B2G&&!Mulet) == number-same-as-text-unthemed.html number-same
# should look the same as type=text, except for the spin box
skip == number-similar-to-text-unthemed.html number-similar-to-text-unthemed.html
skip == number-similar-to-text-unthemed-rtl.html number-similar-to-text-unthemed-rtl.html
skip pref(layout.css.vertical-text.enabled,true) == number-similar-to-text-unthemed-vertical-lr.html number-similar-to-text-unthemed-vertical-lr.html
skip pref(layout.css.vertical-text.enabled,true) == number-similar-to-text-unthemed-vertical-rl.html number-similar-to-text-unthemed-vertical-rl.html
skip == number-similar-to-text-unthemed-vertical-lr.html number-similar-to-text-unthemed-vertical-lr.html
skip == number-similar-to-text-unthemed-vertical-rl.html number-similar-to-text-unthemed-vertical-rl.html
# dynamic type changes:
fuzzy-if(/^Windows\x20NT\x205\.1/.test(http.oscpu),64,4) fuzzy-if(cocoaWidget,63,4) fuzzy-if(skiaContent,2,5) == to-number-from-other-type-unthemed-1.html to-number-from-other-type-unthemed-1.html

View File

@ -37,7 +37,7 @@ fails-if(B2G||Mulet||Android) == moz-range-progress-1.html moz-range-progress-1.
# Tests for block and inline orientation in combination with writing-mode
# XXX Remove default-preferences setting here after bug 1138384 makes
# it the default for all channels
default-preferences pref(layout.css.vertical-text.enabled,true)
== range-orient-horizontal.html range-orient-horizontal.html
== range-orient-horizontal.html range-orient-horizontal.html
== range-orient-block.html range-orient-block.html

View File

@ -32,7 +32,7 @@ include default-style/reftest-stylo.list
# Tests for block and inline orientation in combination with writing-mode
# XXX Remove default-preferences setting here after bug 1138384 makes
# it the default for all channels
default-preferences pref(layout.css.vertical-text.enabled,true)
== meter-orient-vertical.html meter-orient-vertical.html
== meter-orient-horizontal.html meter-orient-horizontal.html
== meter-orient-block.html meter-orient-block.html

View File

@ -31,7 +31,7 @@ skip-if(B2G||Mulet) == bar-pseudo-element-vertical.html bar-pseudo-element-verti
# Tests for block and inline orientation in combination with writing-mode
# XXX Remove default-preferences setting here after bug 1138384 makes
# it the default for all channels
default-preferences pref(layout.css.vertical-text.enabled,true)
== progress-orient-horizontal.html progress-orient-horizontal.html
skip == progress-orient-vertical.html progress-orient-vertical.html
# only OS X currently has direction-dependent rendering here

View File

@ -132,7 +132,7 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.[12]/
== text-shadow.svg text-shadow.svg
# vertical text
pref(layout.css.vertical-text.enabled,true) == vertical-01.svg vertical-01.svg
== vertical-01.svg vertical-01.svg
# tests for ignoring various properties
== ignore-border.svg ignore-border.svg

View File

@ -44,11 +44,11 @@ skip-if(Android||B2G||Mulet) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,12352)
HTTP(..) == combobox-zoom.html combobox-zoom.html
# The vertical-text pref setting can be removed after bug 1138384 lands
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-1.html vertical-decorations-1.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-2.html vertical-decorations-2.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-1.html vertical-decorations-1.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-2.html vertical-decorations-2.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-3.html vertical-decorations-3.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-4.html vertical-decorations-4.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-3.html vertical-decorations-3.html
pref(layout.css.vertical-text.enabled,true) == vertical-decorations-4.html vertical-decorations-4.html
== vertical-decorations-1.html vertical-decorations-1.html
== vertical-decorations-2.html vertical-decorations-2.html
== vertical-decorations-1.html vertical-decorations-1.html
== vertical-decorations-2.html vertical-decorations-2.html
== vertical-decorations-3.html vertical-decorations-3.html
== vertical-decorations-4.html vertical-decorations-4.html
== vertical-decorations-3.html vertical-decorations-3.html
== vertical-decorations-4.html vertical-decorations-4.html

View File

@ -195,12 +195,12 @@ random == flexbox-mbp-horiz-002b.xhtml flexbox-mbp-horiz-002b.xhtml
== flexbox-with-pseudo-elements-003.html flexbox-with-pseudo-elements-003.html
# Tests for combined influence of 'writing-mode' & 'direction' on flex axes
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-001.html flexbox-writing-mode-001.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-002.html flexbox-writing-mode-002.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-003.html flexbox-writing-mode-003.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-004.html flexbox-writing-mode-004.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-005.html flexbox-writing-mode-005.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-006.html flexbox-writing-mode-006.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-007.html flexbox-writing-mode-007.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-008.html flexbox-writing-mode-008.html
test-pref(layout.css.vertical-text.enabled,true) == flexbox-writing-mode-009.html flexbox-writing-mode-009.html
== flexbox-writing-mode-001.html flexbox-writing-mode-001.html
== flexbox-writing-mode-002.html flexbox-writing-mode-002.html
== flexbox-writing-mode-003.html flexbox-writing-mode-003.html
== flexbox-writing-mode-004.html flexbox-writing-mode-004.html
== flexbox-writing-mode-005.html flexbox-writing-mode-005.html
== flexbox-writing-mode-006.html flexbox-writing-mode-006.html
== flexbox-writing-mode-007.html flexbox-writing-mode-007.html
== flexbox-writing-mode-008.html flexbox-writing-mode-008.html
== flexbox-writing-mode-009.html flexbox-writing-mode-009.html

View File

@ -1,5 +1,5 @@
# DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
default-preferences pref(layout.css.vertical-text.enabled,true)
== ruby-text-decoration-01.html ruby-text-decoration-01.html
== text-decoration-propagation-01.html text-decoration-propagation-01.html

View File

@ -2,7 +2,7 @@
# This directory contains tests for position:absolute and vertical writing modes.
# They require the vertical-text pref to be true, otherwise lots of them will fail.
# (See bug 1079151 for the origin of these testcases by Gérard Talbot.)
default-preferences pref(layout.css.vertical-text.enabled,true)
# All of these are fuzzy-if on skia content on OS X due to subpixel text positioning.
fails fuzzy-if(cocoaWidget,15,5) fuzzy-if(d2d,102,164) fuzzy-if(skiaContent,255,248) == s71-abs-pos-non-replaced-vlr-003.xht s71-abs-pos-non-replaced-vlr-003.xht

View File

@ -1,7 +1,7 @@
# DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
# This directory contains tests for vertical text and logical layout coordinates.
# They require the vertical-text pref to be true, otherwise lots of them will fail.
default-preferences pref(layout.css.vertical-text.enabled,true)
HTTP(..) == 1079154-1-vertical-rl-columns.html 1079154-1-vertical-rl-columns.html
== 1082844.html 1082844.html

View File

@ -11,21 +11,24 @@ CONFIGURE_SUBST_FILES += ['adjust_sdk_app_token']
include('android-services.mozbuild')
geckoview_source_dir = TOPSRCDIR + '/mobile/android/geckoview/src/main/'
geckoview_thirdparty_source_dir = TOPSRCDIR + '/mobile/android/geckoview/src/thirdparty/'
thirdparty_source_dir = TOPSRCDIR + '/mobile/android/thirdparty/'
constants_jar = add_java_jar('constants')
constants_jar.sources = ['java/org/mozilla/gecko/' + x for x in [
'adjust/AdjustHelperInterface.java',
'adjust/AttributionHelperListener.java',
constants_jar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x for x in [
'annotation/JNITarget.java',
'annotation/ReflectionTarget.java',
'annotation/RobocopTarget.java',
'annotation/WebRTCJNITarget.java',
'annotation/WrapForJNI.java',
'SysInfo.java',
]]
constants_jar.sources += ['java/org/mozilla/gecko/' + x for x in [
'adjust/AdjustHelperInterface.java',
'adjust/AttributionHelperListener.java',
'db/BrowserContract.java',
'LocaleManager.java',
'Locales.java',
'SysInfo.java',
]]
constants_jar.generated_sources = [
'preprocessed/org/mozilla/gecko/AdjustConstants.java',
@ -289,10 +292,10 @@ gvjar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x
'widget/SwipeDismissListViewTouchListener.java',
]]
gvjar.sources += [thirdparty_source_dir + f for f in [
'com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.java',
'com/googlecode/eyesfree/braille/selfbraille/SelfBrailleClient.java',
'com/googlecode/eyesfree/braille/selfbraille/WriteData.java',
gvjar.sources += [geckoview_thirdparty_source_dir + f for f in [
'java/com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.java',
'java/com/googlecode/eyesfree/braille/selfbraille/SelfBrailleClient.java',
'java/com/googlecode/eyesfree/braille/selfbraille/WriteData.java',
]]
gvjar.extra_jars += [

View File

@ -25,6 +25,8 @@ android {
manifest.srcFile 'AndroidManifest.xml'
java {
srcDir '.'
srcDir "${topsrcdir}/mobile/android/geckoview/src/thirdparty/java"
if (!mozconfig.substs.MOZ_INSTALL_TRACKING) {
exclude 'com/adjust/**'
}

View File

@ -17,7 +17,6 @@ from mozharness.base.script import ScriptMixin
class GetAPK(BaseScript, VirtualenvMixin):
all_actions = [
'create-virtualenv',
"test",
'download-apk'
]
@ -37,6 +36,18 @@ class GetAPK(BaseScript, VirtualenvMixin):
"help": "Specify version number to download (e.g. 23.0b7)",
"default": "None"
}],
[["--latest-nightly"], {
"dest": "latest_nightly",
"help": "Download the latest nightly version",
"action": "store_true",
"default": False
}],
[["--latest-aurora"], {
"dest": "latest_aurora",
"help": "Download the latest aurora version",
"action": "store_true",
"default": False
}],
[["--arch"], {
"dest": "arch",
"help": "Specify which architecture to get the apk for",
@ -57,7 +68,7 @@ class GetAPK(BaseScript, VirtualenvMixin):
arch_values = ["arm", "x86"]
multi_api_archs = ["arm"]
multi_apis = ["api-15"] # v11 has been dropped in fx 46 (1155801)
multi_apis = ["api-15"] # v11 has been dropped in fx 46 (1155801)
# v9 has been dropped in fx 48 (1220184)
download_dir = "apk-download"
@ -66,6 +77,9 @@ class GetAPK(BaseScript, VirtualenvMixin):
checksums_ext = ".checksums"
android_prefix = "android-"
base_url = "https://ftp.mozilla.org/pub/mobile"
json_version_url = "https://product-details.mozilla.org/1.0/firefox_versions.json"
# Cleanup half downloaded files on Ctrl+C
def signal_handler(self, signal, frame):
print("You pressed Ctrl+C!")
@ -112,7 +126,8 @@ class GetAPK(BaseScript, VirtualenvMixin):
if self.config["version"] == "None":
if self.config["clean"]:
sys.exit(0)
self.fatal("Version is required")
if self.config["version"] != "None" and (self.config["latest_nightly"] or self.config["latest_aurora"]):
self.fatal("Cannot set a version and --latest-nightly or --latest-aurora")
if self.config["arch"] not in self.arch_values and not self.config["arch"] == "all":
error = self.config["arch"] + " is not a valid arch. " \
@ -122,6 +137,9 @@ class GetAPK(BaseScript, VirtualenvMixin):
error += "Or don't use the --arch option to download all the archs"
self.fatal(error)
if self.config["latest_nightly"] and self.config["latest_aurora"]:
self.fatal("Conflicting options. Cannot use --latest-nightly with --latest-aurora")
# Checksum check the APK
def check_apk(self, apk_file, checksum_file):
self.info("The checksum for the APK is being checked....")
@ -139,9 +157,12 @@ class GetAPK(BaseScript, VirtualenvMixin):
# Helper functions
def generate_url(self, version, build, locale, api_suffix, arch_file):
return "https://ftp.mozilla.org/pub/mozilla.org/mobile/candidates/" + version + "-candidates/build" + build + \
"/" + self.android_prefix + api_suffix + "/" + locale + "/fennec-" + version + "." + locale + \
"." + self.android_prefix + arch_file
if self.config["latest_nightly"] or self.config["latest_aurora"]:
code = "central" if self.config["latest_nightly"] else "aurora"
return ("%s/nightly/latest-mozilla-%s-android-%s/fennec-%s.%s.android-%s") % (self.base_url, code, api_suffix, version, locale, arch_file)
return ("%s/candidates/%s-candidates/build%s/%s%s/%s/fennec-%s.%s.%s%s") % (self.base_url, version, build, self.android_prefix, api_suffix, locale, version, locale, self.android_prefix, arch_file)
def get_api_suffix(self, arch):
if arch in self.multi_api_archs:
@ -178,14 +199,23 @@ class GetAPK(BaseScript, VirtualenvMixin):
filename_apk = os.path.join(self.download_dir, filename + self.apk_ext)
filename_checksums = os.path.join(self.download_dir, filename + self.checksums_ext)
# Download the APK
retry_config = {'attempts': 1, 'cleanup': self.download_error}
ScriptMixin.download_file(self, apk_url, filename_apk, retry_config=retry_config)
# Download the checksum of the APK
retry_config = {'attempts': 1, 'cleanup': self.download_error}
ScriptMixin.download_file(self, checksum_url, filename_checksums, retry_config=retry_config)
self.check_apk(filename_apk, filename_checksums)
def get_version_name(self):
if self.config["latest_nightly"] or self.config["latest_aurora"]:
json = self.load_json_url(self.json_version_url)
version_code = json['FIREFOX_NIGHTLY'] if self.config["latest_nightly"] else json['FIREFOX_AURORA']
return version_code
return self.config["version"]
# Download all the archs if none is given
def download_all(self, version, build, locale):
for arch in self.arch_values:
@ -194,7 +224,7 @@ class GetAPK(BaseScript, VirtualenvMixin):
# Download apk initial action
def download_apk(self):
self.check_argument()
version = self.config["version"]
version = self.get_version_name()
arch = self.config["arch"]
build = str(self.config["build"])
locale = self.config["locale"]
@ -225,8 +255,9 @@ class GetAPK(BaseScript, VirtualenvMixin):
url = self.generate_url("43.0", "2", "multi", "x86", "i386")
correcturl = "https://ftp.mozilla.org/pub/mozilla.org/mobile/candidates/43.0-candidates/build2/"\
+ self.android_prefix + "x86/multi/fennec-43.0.multi." + self.android_prefix + "i386"
if not url == correcturl:
self.fatal("get_url test failed!")
self.fatal(("get_url test failed! %s != %s") % (url, correcturl))
if not self.get_api_suffix(self.multi_api_archs[0]) == self.multi_apis:
self.fatal("get_api_suffix test failed!")

View File

@ -50,9 +50,12 @@ results = []
def process_line(line):
# Escape slashes otherwise JSON conversion will not work
line = line.replace('\\', '\\\\')
try:
res = json.loads(line)
except ValueError:
print('Non JSON output from linter, will not be processed: {}'.format(line))
return
if 'code' in res:

View File

@ -1096,7 +1096,7 @@ double nsWindow::GetDefaultScaleInternal()
if (mDefaultScale <= 0.0) {
mDefaultScale = WinUtils::LogToPhysFactor(mWnd);
}
return WinUtils::LogToPhysFactor(mWnd);
return mDefaultScale;
}
int32_t nsWindow::LogToPhys(double aValue)
@ -2785,8 +2785,8 @@ NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor,
return NS_ERROR_NOT_AVAILABLE;
HCURSOR cursor;
// No scaling
IntSize size(0, 0);
double scale = GetDefaultScale().scale;
IntSize size = RoundedToInt(Size(width * scale, height * scale));
rv = nsWindowGfx::CreateIcon(aCursor, true, aHotspotX, aHotspotY, size, &cursor);
NS_ENSURE_SUCCESS(rv, rv);