Merge m-c to b2g-inbound a=merge

This commit is contained in:
Wes Kocher 2015-01-13 17:46:54 -08:00
commit 3af458857c
361 changed files with 11475 additions and 17558 deletions

View File

@ -1088,3 +1088,6 @@ pref("dom.mozSettings.SettingsService.verbose.enabled", false);
// IndexedDB transactions to be opened as readonly or keep everything as
// readwrite.
pref("dom.mozSettings.allowForceReadOnly", false);
// RequestSync API is enabled by default on B2G.
pref("dom.requestSync.enabled", true);

View File

@ -15,6 +15,7 @@ Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
Cu.import('resource://gre/modules/Keyboard.jsm');
Cu.import('resource://gre/modules/ErrorPage.jsm');
Cu.import('resource://gre/modules/AlertsHelper.jsm');
Cu.import('resource://gre/modules/RequestSyncService.jsm');
#ifdef MOZ_WIDGET_GONK
Cu.import('resource://gre/modules/NetworkStatsService.jsm');
Cu.import('resource://gre/modules/ResourceStatsService.jsm');
@ -27,6 +28,7 @@ SignInToWebsiteController.init();
Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm');
Cu.import('resource://gre/modules/DownloadsAPI.jsm');
Cu.import('resource://gre/modules/MobileIdentityManager.jsm');
Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");

View File

@ -106,3 +106,7 @@ contract @mozilla.org/services/mobileid-ui-glue;1 {83dbe26a-81f3-4a75-9541-3d0b7
component {7211ece0-b458-4635-9afc-f8d7f376ee95} B2GAppMigrator.js
contract @mozilla.org/app-migrator;1 {7211ece0-b458-4635-9afc-f8d7f376ee95}
# B2GPresentationDevicePrompt.js
component {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} B2GPresentationDevicePrompt.js
contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48cf9bc4de1}

View File

@ -0,0 +1,87 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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";
function debug(aMsg) {
//dump("-*- B2GPresentationDevicePrompt: " + aMsg + "\n");
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1";
const kB2GPRESENTATIONDEVICEPROMPT_CID = Components.ID("{4a300c26-e99b-4018-ab9b-c48cf9bc4de1}");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
function B2GPresentationDevicePrompt() {}
B2GPresentationDevicePrompt.prototype = {
classID: kB2GPRESENTATIONDEVICEPROMPT_CID,
contractID: kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID,
classDescription: "B2G Presentation Device Prompt",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]),
// nsIPresentationDevicePrompt
promptDeviceSelection: function(aRequest) {
let self = this;
let requestId = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID().toString();
SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(aEvent) {
let detail = aEvent.detail;
if (detail.id !== requestId) {
return;
}
SystemAppProxy.removeEventListener("mozContentEvent", contentEvent);
switch (detail.type) {
case "presentation-select-result":
debug("device " + detail.deviceId + " is selected by user");
let device = self._getDeviceById(detail.deviceId);
if (!device) {
debug("cancel request because device is not found");
aRequest.cancel();
}
aRequest.select(device);
break;
case "presentation-select-deny":
debug("request canceled by user");
aRequest.cancel();
break;
}
});
let detail = {
type: "presentation-select-device",
origin: aRequest.origin,
requestURL: aRequest.requestURL,
id: requestId,
};
SystemAppProxy.dispatchEvent(detail);
},
_getDeviceById: function(aDeviceId) {
let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
let devices = deviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray);
for (let i = 0; i < devices.length; i++) {
let device = devices.queryElementAt(i, Ci.nsIPresentationDevice);
if (device.id === aDeviceId) {
return device;
}
}
return null;
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GPresentationDevicePrompt]);

View File

@ -11,6 +11,7 @@ EXTRA_COMPONENTS += [
'AlertsService.js',
'B2GAboutRedirector.js',
'B2GAppMigrator.js',
'B2GPresentationDevicePrompt.js',
'ContentPermissionPrompt.js',
'FilePicker.js',
'FxAccountsUIGlue.js',

View File

@ -5,6 +5,7 @@ support-files =
SandboxPromptTest.html
filepicker_path_handler_chrome.js
systemapp_helper.js
presentation_prompt_handler_chrome.js
[test_filepicker_path.html]
[test_permission_deny.html]
@ -12,3 +13,4 @@ support-files =
skip-if = true # Bug 1019572 - frequent timeouts
[test_sandbox_permission.html]
[test_systemapp.html]
[test_presentation_device_prompt.html]

View File

@ -0,0 +1,94 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
function debug(str) {
dump('presentation_prompt_handler_chrome: ' + str + '\n');
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm');
const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm');
const manager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
const prompt = Cc['@mozilla.org/presentation-device/prompt;1']
.getService(Ci.nsIPresentationDevicePrompt);
function TestPresentationDevice(options) {
this.id = options.id;
this.name = options.name;
this.type = options.type;
}
TestPresentationDevice.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
establishSessionTransport: function() {
return null;
},
};
function TestPresentationRequest(options) {
this.origin = options.origin;
this.requestURL = options.requestURL;
}
TestPresentationRequest.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceRequest]),
select: function(device) {
let result = {
type: 'select',
device: {
id: device.id,
name: device.name,
type: device.type,
},
};
sendAsyncMessage('presentation-select-result', result);
},
cancel: function() {
let result = {
type: 'cancel',
};
sendAsyncMessage('presentation-select-result', result);
},
};
var testDevice = null;
addMessageListener('setup', function(device_options) {
testDevice = new TestPresentationDevice(device_options);
manager.QueryInterface(Ci.nsIPresentationDeviceListener).addDevice(testDevice);
sendAsyncMessage('setup-complete');
});
let eventHandler = function(evt) {
if (!evt.detail || evt.detail.type !== 'presentation-select-device') {
return;
}
sendAsyncMessage('presentation-select-device', evt.detail);
};
SystemAppProxy.addEventListener('mozChromeEvent', eventHandler);
// need to remove ChromeEvent listener after test finished.
addMessageListener('teardown', function() {
if (testDevice) {
manager.removeDevice(testDevice);
}
SystemAppProxy.removeEventListener('mozChromeEvent', eventHandler);
});
addMessageListener('trigger-device-prompt', function(request_options) {
let request = new TestPresentationRequest(request_options);
prompt.promptDeviceSelection(request);
});
addMessageListener('presentation-select-response', function(detail) {
SystemAppProxy._sendCustomEvent('mozContentEvent', detail);
});

View File

@ -0,0 +1,145 @@
<!DOCTYPE HTML>
<html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Test for Presentation Device Selection</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Test for Presentation Device Selection</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
var contentEventHandler = null;
var gUrl = SimpleTest.getTestFileURL('presentation_prompt_handler_chrome.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testSetup() {
info('setup for device selection');
return new Promise(function(resolve, reject) {
let device = {
id: 'test-id',
name: 'test-name',
type: 'test-type',
};
gScript.addMessageListener('setup-complete', function() {
resolve(device);
});
gScript.sendAsyncMessage('setup', device);
});
}
function testSelected(device) {
info('test device selected by user');
return new Promise(function(resolve, reject) {
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
is(detail.origin, request.origin, 'expected origin');
is(detail.requestURL, request.requestURL, 'expected requestURL');
let response = {
id: detail.id,
type: 'presentation-select-result',
deviceId: device.id,
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'select', 'expect device selected');
is(result.device.id, device.id, 'expected device id');
is(result.device.name, device.name, 'expected device name');
is(result.device.type, device.type, 'expected devcie type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function testSelectedNotExisted() {
info('test selected device doesn\'t exist');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
let response = {
id: detail.id,
type: 'presentation-select-deny',
deviceId: undefined, // simulate device Id that doesn't exist
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'cancel', 'expect user cancel');
resolve();
});
});
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function testDenied() {
info('test denial of device selection');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
let response = {
id: detail.id,
type: 'presentation-select-deny',
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'cancel', 'expect user cancel');
resolve();
});
});
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function runTests() {
testSetup()
.then(testSelected)
.then(testSelectedNotExisted)
.then(testDenied)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown');
gScript.destroy();
SimpleTest.finish();
});
}
window.addEventListener('load', runTests);
</script>
</pre>
</body>
</html>

View File

@ -27,7 +27,8 @@
],
"env": {
"VARIANT": "user",
"MOZILLA_OFFICIAL": "1"
"MOZILLA_OFFICIAL": "1",
"B2G_UPDATE_CHANNEL": "nightly"
},
"b2g_manifest": "dolphin.xml",
"b2g_manifest_intree": true,

View File

@ -210,6 +210,7 @@
@BINPATH@/components/dom_xul.xpt
@BINPATH@/components/dom_time.xpt
@BINPATH@/components/dom_engineeringmode.xpt
@BINPATH@/components/dom_presentation.xpt
@BINPATH@/components/downloads.xpt
@BINPATH@/components/editor.xpt
@BINPATH@/components/embed_base.xpt
@ -342,6 +343,9 @@
@BINPATH@/components/zipwriter.xpt
; JavaScript components
@BINPATH@/components/RequestSync.manifest
@BINPATH@/components/RequestSyncManager.js
@BINPATH@/components/RequestSyncScheduler.js
@BINPATH@/components/ChromeNotifications.js
@BINPATH@/components/ChromeNotifications.manifest
@BINPATH@/components/ConsoleAPI.manifest
@ -373,7 +377,6 @@
@BINPATH@/components/nsBrowserGlue.js
@BINPATH@/components/nsSetDefaultBrowser.manifest
@BINPATH@/components/nsSetDefaultBrowser.js
@BINPATH@/components/BrowserPlaces.manifest
@BINPATH@/components/toolkitsearch.manifest
@BINPATH@/components/nsTryToClose.manifest
@BINPATH@/components/nsTryToClose.js
@ -401,6 +404,8 @@
@BINPATH@/components/nsAsyncShutdown.js
@BINPATH@/components/htmlMenuBuilder.js
@BINPATH@/components/htmlMenuBuilder.manifest
@BINPATH@/components/PresentationDeviceInfoManager.manifest
@BINPATH@/components/PresentationDeviceInfoManager.js
; WiFi, NetworkManager, NetworkStats
#ifdef MOZ_WIDGET_GONK
@ -497,7 +502,6 @@
@BINPATH@/components/UnifiedComplete.manifest
@BINPATH@/components/UnifiedComplete.js
@BINPATH@/components/nsPlacesExpiration.js
@BINPATH@/components/PlacesProtocolHandler.js
@BINPATH@/components/PlacesCategoriesStarter.js
@BINPATH@/components/nsDefaultCLH.manifest
@BINPATH@/components/nsDefaultCLH.js
@ -861,6 +865,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/components/InterAppCommUIGlue.js
@BINPATH@/components/SystemMessageGlue.js
@BINPATH@/components/B2GAppMigrator.js
@BINPATH@/components/B2GPresentationDevicePrompt.js
#ifndef MOZ_WIDGET_GONK
@BINPATH@/components/SimulatorScreen.js

View File

@ -1377,6 +1377,8 @@ pref("devtools.inspector.show_pseudo_elements", true);
pref("devtools.inspector.imagePreviewTooltipSize", 300);
// Enable user agent style inspection in rule-view
pref("devtools.inspector.showUserAgentStyles", false);
// Show all native anonymous content (like controls in <video> tags)
pref("devtools.inspector.showAllAnonymousContent", false);
// DevTools default color unit
pref("devtools.defaultColorUnit", "hex");
@ -1781,7 +1783,7 @@ pref("privacy.trackingprotection.ui.enabled", false);
#endif
#ifdef NIGHTLY_BUILD
pref("browser.tabs.remote.autostart.1", false);
pref("browser.tabs.remote.autostart.1", true);
#endif
// Temporary pref to allow printing in e10s windows on some platforms.

View File

@ -550,6 +550,7 @@
#endif
command="View:PageInfo"/>
<menu id="menu_mirrorTabCmd"
hidden="true"
accesskey="&mirrorTabCmd.accesskey;"
label="&mirrorTabCmd.label;">
<menupopup id="menu_mirrorTab-popup"

View File

@ -2940,7 +2940,7 @@ function BrowserFullScreen()
function mirrorShow(popup) {
let services = CastingApps.getServicesForMirroring();
popup.ownerDocument.getElementById("menu_mirrorTabCmd").disabled = !services.length;
popup.ownerDocument.getElementById("menu_mirrorTabCmd").hidden = !services.length;
}
function mirrorMenuItemClicked(event) {

View File

@ -249,7 +249,8 @@ Sanitizer.prototype = {
try {
var os = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
os.notifyObservers(null, "browser:purge-session-history", "");
let clearStartingTime = this.range ? String(this.range[0]) : "";
os.notifyObservers(null, "browser:purge-session-history", clearStartingTime);
}
catch (e) { }

View File

@ -254,5 +254,20 @@ let tests = [
this.notification2.remove();
},
onHidden: function(popup) { }
},
// The anchor icon should be shown for notifications in background windows.
{ id: "Test#13",
run: function() {
let notifyObj = new BasicNotification(this.id);
notifyObj.options.dismissed = true;
let win = gBrowser.replaceTabWithWindow(gBrowser.addTab("about:blank"));
whenDelayedStartupFinished(win, function() {
showNotification(notifyObj);
let anchor = document.getElementById("default-notification-icon");
is(anchor.getAttribute("showing"), "true", "the anchor is shown");
win.close();
goNext();
});
}
}
];

View File

@ -279,6 +279,8 @@ loop.store.ActiveRoomStore = (function() {
* granted and starts joining the room.
*/
gotMediaPermission: function() {
this.setStoreState({roomState: ROOM_STATES.JOINING});
this._mozLoop.rooms.join(this._storeState.roomToken,
function(error, responseData) {
if (error) {
@ -461,7 +463,8 @@ loop.store.ActiveRoomStore = (function() {
delete this._timeout;
}
if (this._storeState.roomState === ROOM_STATES.JOINED ||
if (this._storeState.roomState === ROOM_STATES.JOINING ||
this._storeState.roomState === ROOM_STATES.JOINED ||
this._storeState.roomState === ROOM_STATES.SESSION_CONNECTED ||
this._storeState.roomState === ROOM_STATES.HAS_PARTICIPANTS) {
this._mozLoop.rooms.leave(this._storeState.roomToken,

View File

@ -75,7 +75,7 @@ loop.shared.views.FeedbackView = (function(l10n) {
audio_quality: l10n.get("feedback_category_audio_quality"),
video_quality: l10n.get("feedback_category_video_quality"),
disconnected : l10n.get("feedback_category_was_disconnected"),
confusing: l10n.get("feedback_category_confusing"),
confusing: l10n.get("feedback_category_confusing2"),
other: l10n.get("feedback_category_other2")
};
},
@ -142,7 +142,7 @@ loop.shared.views.FeedbackView = (function(l10n) {
render: function() {
return (
React.createElement(FeedbackLayout, {title: l10n.get("feedback_what_makes_you_sad"),
React.createElement(FeedbackLayout, {title: l10n.get("feedback_category_list_heading"),
reset: this.props.reset},
React.createElement("form", {onSubmit: this.handleFormSubmit},
this._getCategoryFields(),

View File

@ -75,7 +75,7 @@ loop.shared.views.FeedbackView = (function(l10n) {
audio_quality: l10n.get("feedback_category_audio_quality"),
video_quality: l10n.get("feedback_category_video_quality"),
disconnected : l10n.get("feedback_category_was_disconnected"),
confusing: l10n.get("feedback_category_confusing"),
confusing: l10n.get("feedback_category_confusing2"),
other: l10n.get("feedback_category_other2")
};
},
@ -142,7 +142,7 @@ loop.shared.views.FeedbackView = (function(l10n) {
render: function() {
return (
<FeedbackLayout title={l10n.get("feedback_what_makes_you_sad")}
<FeedbackLayout title={l10n.get("feedback_category_list_heading")}
reset={this.props.reset}>
<form onSubmit={this.handleFormSubmit}>
{this._getCategoryFields()}

View File

@ -16,6 +16,8 @@ loop.store.ROOM_STATES = {
READY: "room-ready",
// Obtaining media from the user
MEDIA_WAIT: "room-media-wait",
// Joining the room is taking place
JOINING: "room-joining",
// The room is known to be joined on the loop-server
JOINED: "room-joined",
// The room is connected to the sdk server.

View File

@ -87,7 +87,9 @@ loop.CallConnectionWebSocket = (function() {
* should we call this.
*/
close: function() {
this.socket.close();
if (this.socket) {
this.socket.close();
}
},
_clearConnectionFlags: function() {

View File

@ -94,6 +94,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
)
);
}
case ROOM_STATES.JOINING:
case ROOM_STATES.JOINED:
case ROOM_STATES.SESSION_CONNECTED: {
return (
@ -294,7 +295,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
},
/**
* Watches for when we transition to JOINED room state, so we can request
* Watches for when we transition to MEDIA_WAIT room state, so we can request
* user media access.
*
* @param {Object} nextProps (Unused)

View File

@ -94,6 +94,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
</div>
);
}
case ROOM_STATES.JOINING:
case ROOM_STATES.JOINED:
case ROOM_STATES.SESSION_CONNECTED: {
return (
@ -294,7 +295,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
},
/**
* Watches for when we transition to JOINED room state, so we can request
* Watches for when we transition to MEDIA_WAIT room state, so we can request
* user media access.
*
* @param {Object} nextProps (Unused)

View File

@ -68,12 +68,12 @@ call_progress_ringing_description=Ringing…
fxos_app_needed=Please install the {{fxosAppName}} app from the Firefox Marketplace.
feedback_call_experience_heading2=How was your conversation?
feedback_what_makes_you_sad=What makes you sad?
feedback_thank_you_heading=Thank you for your feedback!
feedback_category_list_heading=What made you sad?
feedback_category_audio_quality=Audio quality
feedback_category_video_quality=Video quality
feedback_category_was_disconnected=Was disconnected
feedback_category_confusing=Confusing
feedback_category_confusing2=Confusing controls
feedback_category_other2=Other
feedback_custom_category_text_placeholder=What went wrong?
feedback_submit_button=Submit

View File

@ -355,6 +355,12 @@ describe("loop.store.ActiveRoomStore", function () {
store.setStoreState({roomToken: "tokenFake"});
});
it("should set the room state to JOINING", function() {
store.gotMediaPermission();
expect(store.getStoreState().roomState).eql(ROOM_STATES.JOINING);
});
it("should call rooms.join on mozLoop", function() {
store.gotMediaPermission();
@ -677,6 +683,17 @@ describe("loop.store.ActiveRoomStore", function () {
"fakeToken", "1627384950");
});
it("should call mozLoop.rooms.leave if the room state is JOINING",
function() {
store.setStoreState({roomState: ROOM_STATES.JOINING});
store.windowUnload();
sinon.assert.calledOnce(fakeMozLoop.rooms.leave);
sinon.assert.calledWithExactly(fakeMozLoop.rooms.leave,
"fakeToken", "1627384950");
});
it("should set the state to CLOSING", function() {
store.windowUnload();

View File

@ -2469,19 +2469,19 @@ let DefaultBrowserCheck = {
let promptTitle = shellBundle.getString("setDefaultBrowserTitle");
let promptMessage = shellBundle.getFormattedString("setDefaultBrowserMessage",
[brandShortName]);
let dontAskLabel = shellBundle.getFormattedString("setDefaultBrowserDontAsk",
[brandShortName]);
let askLabel = shellBundle.getFormattedString("setDefaultBrowserDontAsk",
[brandShortName]);
let ps = Services.prompt;
let dontAsk = { value: false };
let shouldAsk = { value: true };
let buttonFlags = (ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0) +
(ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_1) +
ps.BUTTON_POS_0_DEFAULT;
let rv = ps.confirmEx(win, promptTitle, promptMessage, buttonFlags,
yesButton, notNowButton, null, dontAskLabel, dontAsk);
yesButton, notNowButton, null, askLabel, shouldAsk);
if (rv == 0) {
this.setAsDefault();
} else if (dontAsk.value) {
} else if (!shouldAsk.value) {
ShellService.shouldCheckDefaultBrowser = false;
}
}
@ -2502,7 +2502,7 @@ let DefaultBrowserCheck = {
let E10SUINotification = {
// Increase this number each time we want to roll out an
// e10s testing period to Nightly users.
CURRENT_NOTICE_COUNT: 3,
CURRENT_NOTICE_COUNT: 4,
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",

View File

@ -1,2 +0,0 @@
component {6bcb9bde-9018-4443-a071-c32653469597} PlacesProtocolHandler.js
contract @mozilla.org/network/protocol;1?name=place {6bcb9bde-9018-4443-a071-c32653469597}

View File

@ -1,49 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
* vim: sw=2 ts=2 sts=2 et
* 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/. */
const Cc = Components.classes;
const Ci = Components.interfaces;
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const SCHEME = "place";
const URL = "chrome://browser/content/places/content-ui/controller.xhtml";
function PlacesProtocolHandler() {}
PlacesProtocolHandler.prototype = {
scheme: SCHEME,
defaultPort: -1,
protocolFlags: Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
Ci.nsIProtocolHandler.URI_NORELATIVE |
Ci.nsIProtocolHandler.URI_NOAUTH,
newURI: function PPH_newURI(aSpec, aOriginCharset, aBaseUri) {
let uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
uri.spec = aSpec;
return uri;
},
newChannel: function PPH_newChannel(aUri) {
let chan = NetUtil.newChannel(URL);
chan.originalURI = aUri;
return chan;
},
allowPort: function PPH_allowPort(aPort, aScheme) {
return false;
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIProtocolHandler
]),
classID: Components.ID("{6bcb9bde-9018-4443-a071-c32653469597}")
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PlacesProtocolHandler]);

View File

@ -826,12 +826,12 @@ this.PlacesUIUtils = {
* web panel.
* see also openUILinkIn
*/
openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aView) {
openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aView, aPrivate) {
let window = aView.ownerWindow;
this._openNodeIn(aNode, aWhere, window);
this._openNodeIn(aNode, aWhere, window, aPrivate);
},
_openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aWindow) {
_openNodeIn: function PUIU_openNodeIn(aNode, aWhere, aWindow, aPrivate=false) {
if (aNode && PlacesUtils.nodeIsURI(aNode) &&
this.checkURLSecurity(aNode, aWindow)) {
let isBookmark = PlacesUtils.nodeIsBookmark(aNode);
@ -855,8 +855,10 @@ this.PlacesUIUtils = {
}
}
}
aWindow.openUILinkIn(aNode.uri, aWhere, {
inBackground: Services.prefs.getBoolPref("browser.tabs.loadBookmarksInBackground")
inBackground: Services.prefs.getBoolPref("browser.tabs.loadBookmarksInBackground"),
private: aPrivate,
});
}
},

View File

@ -7,6 +7,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ForgetAboutSite",
"resource://gre/modules/ForgetAboutSite.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
// XXXmano: we should move most/all of these constants to PlacesUtils
const ORGANIZER_ROOT_BOOKMARKS = "place:folder=BOOKMARKS_MENU&excludeItems=1&queryType=1";
@ -178,6 +180,7 @@ PlacesController.prototype = {
return false;
case "placesCmd_open":
case "placesCmd_open:window":
case "placesCmd_open:privatewindow":
case "placesCmd_open:tab":
var selectedNode = this._view.selectedNode;
return selectedNode && PlacesUtils.nodeIsURI(selectedNode);
@ -263,6 +266,9 @@ PlacesController.prototype = {
case "placesCmd_open:window":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "window", this._view);
break;
case "placesCmd_open:privatewindow":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "window", this._view, true);
break;
case "placesCmd_open:tab":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "tab", this._view);
break;
@ -601,7 +607,10 @@ PlacesController.prototype = {
// We allow pasting into tag containers, so special case that.
var hideIfNoIP = item.getAttribute("hideifnoinsertionpoint") == "true" &&
noIp && !(ip && ip.isTag && item.id == "placesContext_paste");
var shouldHideItem = hideIfNoIP || !this._shouldShowMenuItem(item, metadata);
var hideIfPrivate = item.getAttribute("hideifprivatebrowsing") == "true" &&
PrivateBrowsingUtils.isWindowPrivate(window);
var shouldHideItem = hideIfNoIP || hideIfPrivate ||
!this._shouldShowMenuItem(item, metadata);
item.hidden = item.disabled = shouldHideItem;
if (!item.hidden) {
@ -1690,6 +1699,7 @@ function goUpdatePlacesCommands() {
updatePlacesCommand("placesCmd_open");
updatePlacesCommand("placesCmd_open:window");
updatePlacesCommand("placesCmd_open:privatewindow");
updatePlacesCommand("placesCmd_open:tab");
updatePlacesCommand("placesCmd_new:folder");
updatePlacesCommand("placesCmd_new:bookmark");

View File

@ -877,16 +877,21 @@ var gEditItemOverlay = {
switch (aEvent.type) {
case "CheckboxStateChange":
// Update the tags field when items are checked/unchecked in the listbox
var tags = this._getTagsArrayFromTagField();
let tags = this._getTagsArrayFromTagField();
let tagCheckbox = aEvent.target;
if (aEvent.target.checked) {
if (tags.indexOf(aEvent.target.label) == -1)
tags.push(aEvent.target.label);
let curTagIndex = tags.indexOf(tagCheckbox.label);
let tagsSelector = this._element("tagsSelector");
tagsSelector.selectedItem = tagCheckbox;
if (tagCheckbox.checked) {
if (curTagIndex == -1)
tags.push(tagCheckbox.label);
}
else {
var indexOfItem = tags.indexOf(aEvent.target.label);
if (indexOfItem != -1)
tags.splice(indexOfItem, 1);
if (curTagIndex != -1)
tags.splice(curTagIndex, 1);
}
this._element("tagsField").value = tags.join(", ");
this._updateTags();

View File

@ -54,6 +54,8 @@
oncommand="goDoPlacesCommand('placesCmd_open');"/>
<command id="placesCmd_open:window"
oncommand="goDoPlacesCommand('placesCmd_open:window');"/>
<command id="placesCmd_open:privatewindow"
oncommand="goDoPlacesCommand('placesCmd_open:privatewindow');"/>
<command id="placesCmd_open:tab"
oncommand="goDoPlacesCommand('placesCmd_open:tab');"/>
@ -129,6 +131,13 @@
accesskey="&cmd.open_window.accesskey;"
selectiontype="single"
selection="link"/>
<menuitem id="placesContext_open:newprivatewindow"
command="placesCmd_open:privatewindow"
label="&cmd.open_private_window.label;"
accesskey="&cmd.open_private_window.accesskey;"
selectiontype="single"
selection="link"
hideifprivatebrowsing="true"/>
<menuseparator id="placesContext_openSeparator"/>
<menuitem id="placesContext_new:bookmark"
command="placesCmd_new:bookmark"

View File

@ -10,11 +10,6 @@ BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
JAR_MANIFESTS += ['jar.mn']
EXTRA_COMPONENTS += [
'BrowserPlaces.manifest',
'PlacesProtocolHandler.js',
]
EXTRA_PP_JS_MODULES += [
'PlacesUIUtils.jsm',
]

View File

@ -24,6 +24,12 @@ var gSearchPane = {
document.getElementById("engineList").view = gEngineView;
this.buildDefaultEngineDropDown();
window.addEventListener("click", this, false);
window.addEventListener("command", this, false);
window.addEventListener("dragstart", this, false);
window.addEventListener("keypress", this, false);
window.addEventListener("select", this, false);
Services.obs.addObserver(this, "browser-search-engine-modified", false);
window.addEventListener("unload", () => {
Services.obs.removeObserver(this, "browser-search-engine-modified", false);
@ -63,6 +69,49 @@ var gSearchPane = {
});
},
handleEvent: function(aEvent) {
switch (aEvent.type) {
case "click":
if (aEvent.target.id == "addEngines" && aEvent.button == 0) {
Services.wm.getMostRecentWindow('navigator:browser')
.BrowserSearch.loadAddEngines();
}
break;
case "command":
switch (aEvent.target.id) {
case "":
if (aEvent.target.parentNode &&
aEvent.target.parentNode.parentNode &&
aEvent.target.parentNode.parentNode.id == "defaultEngine") {
gSearchPane.setDefaultEngine();
}
break;
case "restoreDefaultSearchEngines":
gSearchPane.onRestoreDefaults();
break;
case "removeEngineButton":
gSearchPane.remove();
break;
}
break;
case "dragstart":
if (aEvent.target.id == "engineChildren") {
onDragEngineStart(aEvent);
}
break;
case "keypress":
if (aEvent.target.id == "engineList") {
gSearchPane.onTreeKeyPress(aEvent);
}
break;
case "select":
if (aEvent.target.id == "engineList") {
gSearchPane.onTreeSelect();
}
break;
}
},
observe: function(aEngine, aTopic, aVerb) {
if (aTopic == "browser-search-engine-modified") {
aEngine.QueryInterface(Components.interfaces.nsISearchEngine);

View File

@ -28,7 +28,7 @@
<groupbox id="defaultEngineGroup" align="start" data-category="paneSearch">
<caption label="&defaultSearchEngine.label;"/>
<label>&chooseYourDefaultSearchEngine.label;</label>
<menulist id="defaultEngine" oncommand="gSearchPane.setDefaultEngine();">
<menulist id="defaultEngine">
<menupopup/>
</menulist>
<checkbox id="suggestionsInSearchFieldsCheckbox"
@ -42,12 +42,10 @@
<label>&chooseWhichOneToDisplay.label;</label>
<tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
seltype="single" onselect="gSearchPane.onTreeSelect();"
onkeypress="gSearchPane.onTreeKeyPress(event);">
<treechildren id="engineChildren" flex="1"
ondragstart="onDragEngineStart(event);"/>
seltype="single">
<treechildren id="engineChildren" flex="1"/>
<treecols>
<treecol id="engineShown" type="checkbox" style="min-width: 26px;" editable="true"/>
<treecol id="engineShown" type="checkbox" editable="true"/>
<treecol id="engineName" flex="4" label="&engineNameColumn.label;"/>
<treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"/>
</treecols>
@ -57,19 +55,18 @@
<button id="restoreDefaultSearchEngines"
label="&restoreDefaultSearchEngines.label;"
accesskey="&restoreDefaultSearchEngines.accesskey;"
oncommand="gSearchPane.onRestoreDefaults();"/>
/>
<spacer flex="1"/>
<button id="removeEngineButton"
label="&removeEngine.label;"
accesskey="&removeEngine.accesskey;"
disabled="true"
oncommand="gSearchPane.remove();"/>
/>
</hbox>
<separator class="thin"/>
<hbox pack="start" style="margin-bottom: 1em">
<label id="addEngines" class="text-link" value="&addMoreSearchEngines.label;"
onclick="if (event.button == 0) { Services.wm.getMostRecentWindow('navigator:browser').BrowserSearch.loadAddEngines(); }"/>
<hbox id="addEnginesBox" pack="start">
<label id="addEngines" class="text-link" value="&addMoreSearchEngines.label;"/>
</hbox>
</groupbox>

View File

@ -10,11 +10,14 @@ const SAMPLE_SIZE = 50; // no of lines
const INDENT_COUNT_THRESHOLD = 5; // percentage
const CHARACTER_LIMIT = 250; // line character limit
// Maps known URLs to friendly source group names
// Maps known URLs to friendly source group names and put them at the
// bottom of source list.
const KNOWN_SOURCE_GROUPS = {
"Add-on SDK": "resource://gre/modules/commonjs/",
};
KNOWN_SOURCE_GROUPS[L10N.getStr("evalGroupLabel")] = "eval";
/**
* Functions handling the sources UI.
*/
@ -170,14 +173,22 @@ SourcesView.prototype = Heritage.extend(WidgetMethods, {
let fullUrl = aSource.url || aSource.introductionUrl;
let url = fullUrl.split(" -> ").pop();
let label = aSource.addonPath ? aSource.addonPath : SourceUtils.getSourceLabel(url);
let group;
if (!aSource.url && aSource.introductionUrl) {
label += ' > eval';
label += ' > ' + aSource.introductionType;
group = L10N.getStr("evalGroupLabel");
}
else if(aSource.addonID) {
group = aSource.addonID;
}
else {
group = SourceUtils.getSourceGroup(url);
}
return {
label: label,
group: aSource.addonID ? aSource.addonID : SourceUtils.getSourceGroup(url),
group: group,
unicodeUrl: NetworkHelper.convertToUnicode(unescape(fullUrl))
};
},

View File

@ -28,6 +28,11 @@ function test() {
is(gSources.values.length, 2, "Should have 2 sources");
let item = gSources.getItemForAttachment(e => e.label.indexOf("> eval") !== -1);
ok(item, "Source label is incorrect.");
is(item.attachment.group, gDebugger.L10N.getStr('evalGroupLabel'),
'Source group is incorrect');
yield closeDebuggerAndFinish(gPanel);
});
});

View File

@ -32,7 +32,8 @@ function test() {
let item = gSources.getItemForAttachment(e => e.label == "bar.js");
ok(item, "Source label is incorrect.");
ok(item.attachment.group === 'http://example.com', 'Source group is incorrect');
is(item.attachment.group, 'http://example.com',
'Source group is incorrect');
let shown = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.SOURCE_SHOWN);
gSources.selectedItem = item;

View File

@ -51,6 +51,7 @@ function setPrefDefaults() {
Services.prefs.setBoolPref("devtools.inspector.showUserAgentStyles", true);
Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true);
Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", false);
Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
}
window.addEventListener("load", function() {

View File

@ -1503,7 +1503,9 @@ Toolbox.prototype = {
if (!this._initInspector) {
this._initInspector = Task.spawn(function*() {
this._inspector = InspectorFront(this._target.client, this._target.form);
this._walker = yield this._inspector.getWalker();
this._walker = yield this._inspector.getWalker(
{showAllAnonymousContent: Services.prefs.getBoolPref("devtools.inspector.showAllAnonymousContent")}
);
this._selection = new Selection(this._walker);
if (this.highlighterUtils.isRemoteHighlightable()) {

View File

@ -34,6 +34,7 @@ support-files =
[browser_markupview_anonymous_02.js]
skip-if = e10s # scratchpad.xul is not loading in e10s window
[browser_markupview_anonymous_03.js]
[browser_markupview_anonymous_04.js]
[browser_markupview_copy_image_data.js]
[browser_markupview_css_completion_style_attribute.js]
[browser_markupview_events.js]

View File

@ -27,4 +27,18 @@ add_task(function*() {
info ("Checking the ::after pseudo element");
let after = children.nodes[2];
yield isEditingMenuDisabled(after, inspector);
let native = yield getNodeFront("#native", inspector);
// Markup looks like: <div><video controls /></div>
let nativeChildren = yield inspector.walker.children(native);
is (nativeChildren.nodes.length, 1, "Children returned from walker");
info ("Checking the video element");
let video = nativeChildren.nodes[0];
ok (!video.isAnonymous, "<video> is not anonymous");
let videoChildren = yield inspector.walker.children(video);
is (videoChildren.nodes.length, 0,
"No native children returned from walker for <video> by default");
});

View File

@ -0,0 +1,36 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test native anonymous content in the markupview with devtools.inspector.showAllAnonymousContent
// set to true
const TEST_URL = TEST_URL_ROOT + "doc_markup_anonymous.html";
add_task(function*() {
Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let native = yield getNodeFront("#native", inspector);
// Markup looks like: <div><video controls /></div>
let nativeChildren = yield inspector.walker.children(native);
is (nativeChildren.nodes.length, 1, "Children returned from walker");
info ("Checking the video element");
let video = nativeChildren.nodes[0];
ok (!video.isAnonymous, "<video> is not anonymous");
let videoChildren = yield inspector.walker.children(video);
is (videoChildren.nodes.length, 3, "<video> has native anonymous children");
for (let node of videoChildren.nodes) {
ok (node.isAnonymous, "Child is anonymous");
ok (!node._form.isXBLAnonymous, "Child is not XBL anonymous");
ok (!node._form.isShadowAnonymous, "Child is not shadow anonymous");
ok (node._form.isNativeAnonymous, "Child is native anonymous");
yield isEditingMenuDisabled(node, inspector);
}
});

View File

@ -20,6 +20,8 @@
<div id="shadow">light dom</div>
<div id="native"><video controls></video></div>
<script>
var host = document.querySelector('#shadow');
if (host.createShadowRoot) {

View File

@ -32,6 +32,7 @@ registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.dump.emit");
Services.prefs.clearUserPref("devtools.markup.pagesize");
Services.prefs.clearUserPref("dom.webcomponents.enabled");
Services.prefs.clearUserPref("devtools.inspector.showAllAnonymousContent");
});
// Auto close the toolbox and close the test tabs when the test ends

View File

@ -18,7 +18,8 @@ loader.lazyImporter(this, "NetUtil",
// It isn't, of course, a definitive verification, but a Good Enough™
// approximation before continuing the import. Don't localize this.
const PERF_TOOL_SERIALIZER_IDENTIFIER = "Recorded Performance Data";
const PERF_TOOL_SERIALIZER_VERSION = 1;
const PERF_TOOL_SERIALIZER_LEGACY_VERSION = 1;
const PERF_TOOL_SERIALIZER_CURRENT_VERSION = 2;
/**
* Helpers for importing/exporting JSON.
@ -51,7 +52,7 @@ let PerformanceIO = {
let deferred = promise.defer();
recordingData.fileType = PERF_TOOL_SERIALIZER_IDENTIFIER;
recordingData.version = PERF_TOOL_SERIALIZER_VERSION;
recordingData.version = PERF_TOOL_SERIALIZER_CURRENT_VERSION;
let string = JSON.stringify(recordingData);
let inputStream = this.getUnicodeConverter().convertToInputStream(string);
@ -88,10 +89,13 @@ let PerformanceIO = {
deferred.reject(new Error("Unrecognized recording data file."));
return;
}
if (recordingData.version != PERF_TOOL_SERIALIZER_VERSION) {
if (!isValidSerializerVersion(recordingData.version)) {
deferred.reject(new Error("Unsupported recording data file version."));
return;
}
if (recordingData.version === PERF_TOOL_SERIALIZER_LEGACY_VERSION) {
recordingData = convertLegacyData(recordingData);
}
deferred.resolve(recordingData);
});
@ -100,3 +104,49 @@ let PerformanceIO = {
};
exports.PerformanceIO = PerformanceIO;
/**
* Returns a boolean indicating whether or not the passed in `version`
* is supported by this serializer.
*
* @param number version
* @return boolean
*/
function isValidSerializerVersion (version) {
return !!~[
PERF_TOOL_SERIALIZER_LEGACY_VERSION,
PERF_TOOL_SERIALIZER_CURRENT_VERSION
].indexOf(version);
}
/**
* Takes recording data (with version `1`, from the original profiler tool), and
* massages the data to be line with the current performance tool's property names
* and values.
*
* @param object legacyData
* @return object
*/
function convertLegacyData (legacyData) {
let { profilerData, ticksData, recordingDuration } = legacyData;
// The `profilerData` stays, and the previously unrecorded fields
// just are empty arrays.
let data = {
markers: [],
frames: [],
memory: [],
ticks: ticksData,
profilerData: profilerData,
// Data from the original profiler won't contain `interval` fields,
// but a recording duration, as well as the current time, which can be used
// to infer the interval startTime and endTime.
interval: {
startTime: profilerData.currentTime - recordingDuration,
endTime: profilerData.currentTime
}
};
return data;
}

View File

@ -39,3 +39,4 @@ support-files =
[browser_perf_recordings-io-01.js]
[browser_perf_recordings-io-02.js]
[browser_perf_recordings-io-03.js]
[browser_perf_recordings-io-04.js]

View File

@ -0,0 +1,90 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the performance tool can import profiler data from the
* original profiler tool.
*/
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
// Get data from the current profiler
let data = PerformanceController.getAllData();
// Create a structure from the data that mimics the old profiler's data.
// Different name for `ticks`, different way of storing time,
// and no memory, markers data.
let oldProfilerData = {
recordingDuration: data.interval.endTime - data.interval.startTime,
ticksData: data.ticks,
profilerData: data.profilerData,
fileType: "Recorded Performance Data",
version: 1
};
// Save recording as an old profiler data.
let file = FileUtils.getFile("TmpD", ["tmpprofile.json"]);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));
yield asyncCopy(oldProfilerData, file);
// Import recording.
let rerendered = waitForWidgetsRendered(panel);
let imported = once(PerformanceController, EVENTS.RECORDING_IMPORTED);
yield PerformanceController.importRecording("", file);
yield imported;
ok(true, "The original profiler data appears to have been successfully imported.");
yield rerendered;
ok(true, "The imported data was re-rendered.");
// Verify imported recording.
let importedData = PerformanceController.getAllData();
is(importedData.startTime, data.startTime,
"The imported legacy data was successfully converted for the current tool (1).");
is(importedData.endTime, data.endTime,
"The imported legacy data was successfully converted for the current tool (2).");
is(importedData.markers.toSource(), [].toSource(),
"The imported legacy data was successfully converted for the current tool (3).");
is(importedData.memory.toSource(), [].toSource(),
"The imported legacy data was successfully converted for the current tool (4).");
is(importedData.ticks.toSource(), data.ticks.toSource(),
"The imported legacy data was successfully converted for the current tool (5).");
is(importedData.profilerData.toSource(), data.profilerData.toSource(),
"The imported legacy data was successfully converted for the current tool (6).");
yield teardown(panel);
finish();
});
function getUnicodeConverter() {
let className = "@mozilla.org/intl/scriptableunicodeconverter";
let converter = Cc[className].createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
return converter;
}
function asyncCopy(data, file) {
let deferred = Promise.defer();
let string = JSON.stringify(data);
let inputStream = getUnicodeConverter().convertToInputStream(string);
let outputStream = FileUtils.openSafeFileOutputStream(file);
NetUtil.asyncCopy(inputStream, outputStream, status => {
if (!Components.isSuccessCode(status)) {
deferred.reject(new Error("Could not save data to file."));
}
deferred.resolve();
});
return deferred.promise;
}

View File

@ -146,6 +146,7 @@ skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests (exp
[browser_console_consolejsm_output.js]
[browser_console_dead_objects.js]
skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
[browser_console_copy_entire_message_context_menu.js]
[browser_console_error_source_click.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1042253 - webconsole e10s tests
[browser_console_filters.js]

View File

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test copying of the entire console message when right-clicked
// with no other text selected. See Bug 1100562.
function test() {
let hud;
let outputNode;
let contextMenu;
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
const TEST_FILE = TEST_URI.substr(TEST_URI.lastIndexOf("/"));
Task.spawn(runner).then(finishTest);
function* runner() {
const {tab} = yield loadTab(TEST_URI);
hud = yield openConsole(tab);
outputNode = hud.outputNode;
contextMenu = hud.iframeWindow.document.getElementById("output-contextmenu");
registerCleanupFunction(() => {
hud = outputNode = contextMenu = null;
});
hud.jsterm.clearOutput();
content.console.log("bug 1100562");
let [results] = yield waitForMessages({
webconsole: hud,
messages: [{
text: "bug 1100562",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}]
});
outputNode.focus();
let message = [...results.matched][0];
message.scrollIntoView();
yield waitForContextMenu(contextMenu, message, copyFromPopup, testContextMenuCopy);
function copyFromPopup() {
let copyItem = contextMenu.querySelector("#cMenu_copy");
copyItem.doCommand();
let controller = top.document.commandDispatcher.getControllerForCommand("cmd_copy");
is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
}
function testContextMenuCopy() {
waitForClipboard((str) => { return message.textContent.trim() == str.trim(); },
() => { goDoCommand("cmd_copy") },
() => {}, () => {}
);
}
yield closeConsole(tab);
}
}

View File

@ -2842,6 +2842,9 @@ WebConsoleFrame.prototype = {
* - linkOnly:
* An optional flag to copy only URL without timestamp and
* other meta-information. Default is false.
* - contextmenu:
* An optional flag to copy the last clicked item which brought
* up the context menu if nothing is selected. Default is false.
*/
copySelectedItems: function WCF_copySelectedItems(aOptions)
{
@ -2864,7 +2867,7 @@ WebConsoleFrame.prototype = {
strings.push(item.url);
}
else {
strings.push("[" + timestampString + "] " + item.clipboardText);
strings.push(item.clipboardText);
}
}
}
@ -4783,6 +4786,14 @@ CommandController.prototype = {
this.owner.copySelectedItems({ linkOnly: true, contextmenu: true });
},
/**
* Copies the last clicked message.
*/
copyLastClicked: function CommandController_copy()
{
this.owner.copySelectedItems({ linkOnly: false, contextmenu: true });
},
supportsCommand: function CommandController_supportsCommand(aCommand)
{
if (!this.owner || !this.owner.output) {
@ -4801,6 +4812,12 @@ CommandController.prototype = {
this.owner._contextMenuHandler.lastClickedMessage;
return selectedItem && "url" in selectedItem;
}
case "cmd_copy": {
// Only copy if we right-clicked the console and there's no selected text.
// With text selected, we want to fall back onto the default copy behavior.
return this.owner._contextMenuHandler.lastClickedMessage &&
!this.owner.output.getSelectedMessages(1)[0];
}
case "consoleCmd_clearOutput":
case "cmd_selectAll":
case "cmd_find":
@ -4826,6 +4843,9 @@ CommandController.prototype = {
case "consoleCmd_clearOutput":
this.owner.jsterm.clearOutput(true);
break;
case "cmd_copy":
this.copyLastClicked();
break;
case "cmd_find":
this.owner.filterBox.focus();
break;

View File

@ -47,8 +47,7 @@ function BuildItem(addon, type) {
status.textContent = Strings.GetStringFromName("addons_status_" + addon.status);
break;
case "failure":
console.error(arg);
window.alert(arg);
window.parent.UI.reportError("error_operationFail", arg);
break;
case "progress":
if (arg == -1) {

View File

@ -237,6 +237,7 @@
@RESPATH@/components/dom_gamepad.xpt
#endif
@RESPATH@/components/dom_payment.xpt
@RESPATH@/components/dom_presentation.xpt
@RESPATH@/components/downloads.xpt
@RESPATH@/components/editor.xpt
@RESPATH@/components/embed_base.xpt
@ -377,7 +378,6 @@
@RESPATH@/browser/components/nsSetDefaultBrowser.js
@RESPATH@/browser/components/BrowserDownloads.manifest
@RESPATH@/browser/components/DownloadsStartup.js
@RESPATH@/browser/components/BrowserPlaces.manifest
@RESPATH@/browser/components/devtools-clhandler.manifest
@RESPATH@/browser/components/devtools-clhandler.js
@RESPATH@/browser/components/webideCli.js
@ -452,7 +452,6 @@
@RESPATH@/components/UnifiedComplete.manifest
@RESPATH@/components/UnifiedComplete.js
@RESPATH@/components/nsPlacesExpiration.js
@RESPATH@/browser/components/PlacesProtocolHandler.js
@RESPATH@/components/PlacesCategoriesStarter.js
@RESPATH@/components/ColorAnalyzer.js
@RESPATH@/components/PageThumbsProtocol.js
@ -542,6 +541,10 @@
@RESPATH@/components/htmlMenuBuilder.js
@RESPATH@/components/htmlMenuBuilder.manifest
@RESPATH@/components/RequestSync.manifest
@RESPATH@/components/RequestSyncManager.js
@RESPATH@/components/RequestSyncScheduler.js
@RESPATH@/components/PermissionSettings.js
@RESPATH@/components/PermissionSettings.manifest
@RESPATH@/components/ContactManager.js
@ -604,6 +607,9 @@
@RESPATH@/components/nsAsyncShutdown.manifest
@RESPATH@/components/nsAsyncShutdown.js
@RESPATH@/components/PresentationDeviceInfoManager.manifest
@RESPATH@/components/PresentationDeviceInfoManager.js
; InputMethod API
@RESPATH@/components/MozKeyboard.js
@RESPATH@/components/InputMethod.manifest

View File

@ -315,3 +315,5 @@ functionSearchSeparatorLabel=←
# The substitution parameter is the URL of the last paused window that must be
# resumed first.
resumptionOrderPanelTitle=There are one or more paused debuggers. Please resume the most-recently paused debugger first at: %S
evalGroupLabel=Evaluated Sources

View File

@ -271,12 +271,12 @@ powered_by_beforeLogo=Powered by
powered_by_afterLogo=
feedback_call_experience_heading2=How was your conversation?
feedback_what_makes_you_sad=What makes you sad?
feedback_thank_you_heading=Thank you for your feedback!
feedback_category_list_heading=What made you sad?
feedback_category_audio_quality=Audio quality
feedback_category_video_quality=Video quality
feedback_category_was_disconnected=Was disconnected
feedback_category_confusing=Confusing
feedback_category_confusing2=Confusing controls
feedback_category_other2=Other
feedback_custom_category_text_placeholder=What went wrong?
feedback_submit_button=Submit

View File

@ -52,6 +52,8 @@
<!ENTITY cmd.open.accesskey "O">
<!ENTITY cmd.open_window.label "Open in a New Window">
<!ENTITY cmd.open_window.accesskey "N">
<!ENTITY cmd.open_private_window.label "Open in a New Private Window">
<!ENTITY cmd.open_private_window.accesskey "P">
<!ENTITY cmd.open_tab.label "Open in a New Tab">
<!ENTITY cmd.open_tab.accesskey "w">
<!ENTITY cmd.open_all_in_tabs.label "Open All in Tabs">

View File

@ -19,9 +19,9 @@
</DL><p>
<DT><H3 ID="rdf:#$ZvPhC3">@firefox_heading@</H3>
<DL><p>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/firefox/help/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$22iCK1">@firefox_help@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/firefox/customize/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$32iCK1">@firefox_customize@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/contribute/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$42iCK1">@firefox_community@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/about/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" ID="rdf:#$52iCK1">@firefox_about@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/firefox/help/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII=" ID="rdf:#$22iCK1">@firefox_help@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/firefox/customize/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII=" ID="rdf:#$32iCK1">@firefox_customize@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/contribute/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII=" ID="rdf:#$42iCK1">@firefox_community@</A>
<DT><A HREF="https://www.mozilla.org/@AB_CD@/about/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gwMDAsTBZbkNwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAABNElEQVQ4y8WSsU0DURBE3yyWIaAJaqAAN4DPSL6AlIACKIEOyJEgRsIgOOkiInJqgAKowNg7BHdn7MOksNl+zZ//dvbDf5cAiklp22BdVtXdeTEpDYDB9m1VzU6OJuVp2NdEQCaI96fH2YHG4+mDduKYNMYINTcjcGbXzQVDEAphG0k48zUsajIbnAiMIXThpW8EICE0RAK4dvoKg9NIcTiQ589otyHOZLnwqK5nLwBFUZ4igc3iM0d1ff8CMC6mZ6Ihiaqq3gi1aUAnArD00SW1fq5OLBg0ymYmSZsR2/t4e/rGyCLW0sbp3oq+yTYqVgytQWui2FS7XYF7GFprY921T4CNQt8zr47dNzCkIX7y/jBtH+v+RGMQrc828W8pApnZbmEVQp/Ae7BlOy2ttib81/UFc+WRWEbjckIAAAAASUVORK5CYII=" ID="rdf:#$52iCK1">@firefox_about@</A>
</DL><p>
</DL><p>

View File

@ -533,6 +533,7 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
list-style-image: url("moz-icon://stock/gtk-info?size=menu");
}
#placesContext_open\:newprivatewindow,
#privateBrowsingItem {
list-style-image: url("chrome://browser/skin/Privacy-16.png");
}
@ -1777,7 +1778,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
#TabsToolbar {
min-height: 0;
padding: 0;
margin-bottom: -@tabToolbarNavbarOverlap@;
margin-bottom: calc(-1 * var(--tab-toolbar-navbar-overlap));
}
#TabsToolbar:not(:-moz-lwtheme) {
@ -1852,7 +1853,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
.tabbrowser-arrowscrollbox > .scrollbutton-down {
-moz-appearance: none;
list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left.png");
margin: 0 0 @tabToolbarNavbarOverlap@;
margin: 0 0 var(--tab-toolbar-navbar-overlap);
}
#TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .scrollbutton-up,
@ -1880,7 +1881,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
}
#TabsToolbar .toolbarbutton-1 {
margin-bottom: @tabToolbarNavbarOverlap@;
margin-bottom: var(--tab-toolbar-navbar-overlap);
}
#alltabs-button {

View File

@ -200,6 +200,11 @@ menuitem[command="placesCmd_open:window"] {
-moz-image-region: rect(0px 80px 16px 64px);
}
#placesContext_open\:newprivatewindow,
menuitem[command="placesCmd_open:privatewindow"] {
list-style-image: url("chrome://browser/skin/Privacy-16.png");
}
#placesContext_open\:newtab,
menuitem[command="placesCmd_open:tab"] {
list-style-image: url("chrome://browser/skin/Toolbar-small.png");

View File

@ -117,7 +117,7 @@
* tabstrip can overlap it.
*/
#main-window[tabsintitlebar] > #titlebar {
min-height: calc(@tabMinHeight@ + var(--space-above-tabbar) - @tabToolbarNavbarOverlap@);
min-height: calc(var(--tab-min-height) + var(--space-above-tabbar) - var(--tab-toolbar-navbar-overlap));
}
/**
@ -191,7 +191,7 @@ toolbarseparator {
#TabsToolbar:not([collapsed="true"]) + #nav-bar:-moz-lwtheme {
border-top: 1px solid hsla(0,0%,0%,.3);
background-clip: padding-box;
margin-top: -@tabToolbarNavbarOverlap@;
margin-top: calc(-1 * var(--tab-toolbar-navbar-overlap));
/* Position the toolbar above the bottom of background tabs */
position: relative;
z-index: 1;
@ -203,7 +203,7 @@ toolbarseparator {
#main-window[tabsintitlebar] #TabsToolbar:not([collapsed="true"]) + #nav-bar:not(:-moz-lwtheme) {
border-top: 1px solid hsla(0,0%,0%,.2);
background-clip: padding-box;
margin-top: -@tabToolbarNavbarOverlap@;
margin-top: calc(-1 * var(--tab-toolbar-navbar-overlap));
/* Position the toolbar above the bottom of background tabs */
position: relative;
z-index: 1;
@ -3184,7 +3184,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
.tabbrowser-arrowscrollbox > .scrollbutton-up,
.tabbrowser-arrowscrollbox > .scrollbutton-down {
-moz-image-region: rect(0, 13px, 20px, 0);
margin: 0 0 @tabToolbarNavbarOverlap@;
margin: 0 0 var(--tab-toolbar-navbar-overlap);
padding: 0 4px;
border: none;
}
@ -3310,7 +3310,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
}
#TabsToolbar .toolbarbutton-1 {
margin-bottom: @tabToolbarNavbarOverlap@;
margin-bottom: var(--tab-toolbar-navbar-overlap);
}
#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
@ -4729,7 +4729,7 @@ window > chatbox {
@media (-moz-mac-lion-theme) {
#TabsToolbar > .private-browsing-indicator {
transform: translateY(calc(0px - var(--space-above-tabbar)));
transform: translateY(calc(-1 * var(--space-above-tabbar)));
/* We offset by 38px for mask graphic, plus 4px to account for the
* margin-left, which sums to 42px.
*/

View File

@ -11,5 +11,3 @@
%endif
%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
%define tabToolbarNavbarOverlap 1px
%define tabMinHeight 31px

View File

@ -27,16 +27,16 @@
<rect x="7px" y="11px" width="9px" height="2.5px" rx="1" ry="1"/>
</g>
<g id="details-call-tree">
<rect x="0px" y="3px" width="16px" height="2px"/>
<rect x="3px" y="6px" width="7px" height="2px"/>
<rect x="6px" y="9px" width="6px" height="2px"/>
<rect x="9px" y="12px" width="5px" height="2px"/>
<rect x="0px" y="3px" width="16px" height="2px" rx="1" ry="1"/>
<rect x="3px" y="6px" width="7px" height="2px" rx="1" ry="1"/>
<rect x="6px" y="9px" width="6px" height="2px" rx="1" ry="1"/>
<rect x="9px" y="12px" width="5px" height="2px" rx="1" ry="1"/>
</g>
<g id="details-flamegraph">
<rect x="0px" y="3px" width="16px" height="2px"/>
<rect x="0px" y="6px" width="8px" height="2px"/>
<rect x="10px" y="6px" width="6px" height="2px"/>
<rect x="2px" y="9px" width="6px" height="2px"/>
<rect x="5px" y="12px" width="3px" height="2px"/>
<rect x="0px" y="3px" width="16px" height="2px" rx="1" ry="1"/>
<rect x="0px" y="6px" width="8px" height="2px" rx="1" ry="1"/>
<rect x="10px" y="6px" width="6px" height="2px" rx="1" ry="1"/>
<rect x="2px" y="9px" width="6px" height="2px" rx="1" ry="1"/>
<rect x="5px" y="12px" width="3px" height="2px" rx="1" ry="1"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -43,3 +43,11 @@
height: 2px;
-moz-margin-start: 0;
}
#engineShown {
min-width: 26px;
}
#addEnginesBox {
margin-bottom: 1em;
}

View File

@ -4,6 +4,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
%endif
:root {
--tab-toolbar-navbar-overlap: 1px;
--tab-min-height: 31px;
}
%define tabCurveWidth 30px
%define tabCurveHalfWidth 15px
@ -20,7 +25,7 @@
}
#tabbrowser-tabs {
min-height: @tabMinHeight@;
min-height: var(--tab-min-height);
}
.tabbrowser-tab,
@ -118,7 +123,7 @@
background-image: url(chrome://browser/skin/tabbrowser/tab-overflow-indicator.png);
background-size: 100% 100%;
width: 14px;
margin-bottom: @tabToolbarNavbarOverlap@;
margin-bottom: var(--tab-toolbar-navbar-overlap);
pointer-events: none;
position: relative;
z-index: 3; /* the selected tab's z-index + 1 */
@ -155,7 +160,7 @@
.tab-background-end,
.tab-background-end[selected=true]::after,
.tab-background-end[selected=true]::before {
min-height: @tabMinHeight@;
min-height: var(--tab-min-height);
width: @tabCurveWidth@;
}
@ -295,7 +300,7 @@
.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, transparent 70%);
background-position: center bottom @tabToolbarNavbarOverlap@;
background-position: center bottom var(--tab-toolbar-navbar-overlap);
background-repeat: no-repeat;
background-size: 85% 100%;
}
@ -308,7 +313,7 @@
-moz-margin-start: -1.5px;
-moz-margin-end: -1.5px;
background-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
background-position: left bottom @tabToolbarNavbarOverlap@;
background-position: left bottom var(--tab-toolbar-navbar-overlap);
background-repeat: no-repeat;
background-size: 3px 100%;
content: "";

View File

@ -887,7 +887,7 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
}
#TabsToolbar .toolbarbutton-1 {
margin-bottom: @tabToolbarNavbarOverlap@;
margin-bottom: var(--tab-toolbar-navbar-overlap);
}
#TabsToolbar .toolbarbutton-1:not([disabled=true]):hover,
@ -1786,7 +1786,7 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
#TabsToolbar {
min-height: 0;
padding: 0;
margin-bottom: -@tabToolbarNavbarOverlap@; /* overlap the nav-bar's top border */
margin-bottom: calc(-1 * var(--tab-toolbar-navbar-overlap)); /* overlap the nav-bar's top border */
}
%ifndef WINDOWS_AERO
@ -1881,7 +1881,7 @@ toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
.tabbrowser-arrowscrollbox > .scrollbutton-up,
.tabbrowser-arrowscrollbox > .scrollbutton-down {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left.png");
margin: 0 0 @tabToolbarNavbarOverlap@;
margin: 0 0 var(--tab-toolbar-navbar-overlap);
}
#TabsToolbar[brighttext] > #tabbrowser-tabs > .tabbrowser-arrowscrollbox > .scrollbutton-up,

View File

@ -526,6 +526,12 @@ this.PermissionsTable = { geolocation: {
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"presentation-device-manage": {
app: DENY_ACTION,
trusted: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
}
};

View File

@ -129,10 +129,11 @@ AnonymousContent::GetElementById(const nsAString& aElementId)
return nullptr;
}
JSObject*
AnonymousContent::WrapObject(JSContext* aCx)
bool
AnonymousContent::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return AnonymousContentBinding::Wrap(aCx, this);
return AnonymousContentBinding::Wrap(aCx, this, aReflector);
}
} // dom namespace

View File

@ -27,7 +27,7 @@ public:
explicit AnonymousContent(Element* aContentNode);
nsCOMPtr<Element> GetContentNode();
void SetContentNode(Element* aContentNode);
JSObject* WrapObject(JSContext* aCx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
// WebIDL methods
void SetTextContentForElement(const nsAString& aElementId,

View File

@ -23,6 +23,11 @@ namespace dom {
static const double radPerDegree = 2.0 * M_PI / 360.0;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrixReadOnly, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrixReadOnly, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrixReadOnly, Release)
already_AddRefed<DOMMatrix>
DOMMatrixReadOnly::Translate(double aTx,
double aTy,
@ -303,11 +308,6 @@ DOMMatrixReadOnly::Stringify(nsAString& aResult)
aResult = matrixStr;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMMatrix, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMatrix, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMatrix, Release)
already_AddRefed<DOMMatrix>
DOMMatrix::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{

View File

@ -40,6 +40,9 @@ public:
}
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrixReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrixReadOnly)
#define GetMatrixMember(entry2D, entry3D, default) \
{ \
if (mMatrix3D) { \
@ -130,9 +133,8 @@ protected:
nsAutoPtr<gfx::Matrix> mMatrix2D;
nsAutoPtr<gfx::Matrix4x4> mMatrix3D;
~DOMMatrixReadOnly()
{
}
virtual ~DOMMatrixReadOnly() {}
private:
DOMMatrixReadOnly() = delete;
DOMMatrixReadOnly(const DOMMatrixReadOnly&) = delete;
@ -150,9 +152,6 @@ public:
: DOMMatrixReadOnly(aParent, other)
{}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMMatrix)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMMatrix)
static already_AddRefed<DOMMatrix>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
static already_AddRefed<DOMMatrix>
@ -246,8 +245,6 @@ public:
DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
private:
void Ensure3DMatrix();
~DOMMatrix() {}
};
}

View File

@ -12,10 +12,10 @@
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPoint, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPointReadOnly, mParent)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPoint, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPoint, Release)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPointReadOnly, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPointReadOnly, Release)
already_AddRefed<DOMPoint>
DOMPoint::Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,

View File

@ -33,29 +33,29 @@ public:
{
}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPointReadOnly)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPointReadOnly)
double X() const { return mX; }
double Y() const { return mY; }
double Z() const { return mZ; }
double W() const { return mW; }
protected:
virtual ~DOMPointReadOnly() {}
nsCOMPtr<nsISupports> mParent;
double mX, mY, mZ, mW;
};
class DOMPoint MOZ_FINAL : public DOMPointReadOnly
{
~DOMPoint() {}
public:
explicit DOMPoint(nsISupports* aParent, double aX = 0.0, double aY = 0.0,
double aZ = 0.0, double aW = 1.0)
: DOMPointReadOnly(aParent, aX, aY, aZ, aW)
{}
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DOMPoint)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(DOMPoint)
static already_AddRefed<DOMPoint>
Constructor(const GlobalObject& aGlobal, const DOMPointInit& aParams,
ErrorResult& aRV);

View File

@ -1847,6 +1847,33 @@ Navigator::MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv)
return result;
}
void
Navigator::MozSetMessageHandlerPromise(Promise& aPromise,
ErrorResult& aRv)
{
// The WebIDL binding is responsible for the pref check here.
aRv = EnsureMessagesManager();
if (NS_WARN_IF(aRv.Failed())) {
return;
}
bool result = false;
aRv = mMessagesManager->MozIsHandlingMessage(&result);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (!result) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return;
}
aRv = mMessagesManager->MozSetMessageHandlerPromise(&aPromise);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
void
Navigator::MozSetMessageHandler(const nsAString& aType,
systemMessageCallback* aCallback,

View File

@ -235,6 +235,8 @@ public:
systemMessageCallback* aCallback,
ErrorResult& aRv);
bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
void MozSetMessageHandlerPromise(Promise& aPromise, ErrorResult& aRv);
#ifdef MOZ_B2G
already_AddRefed<Promise> GetMobileIdAssertion(const MobileIdOptions& options,
ErrorResult& aRv);

View File

@ -288,10 +288,10 @@ void NodeIterator::ContentRemoved(nsIDocument *aDocument,
mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
}
JSObject*
NodeIterator::WrapObject(JSContext *cx)
bool
NodeIterator::WrapObject(JSContext *cx, JS::MutableHandle<JSObject*> aReflector)
{
return NodeIteratorBinding::Wrap(cx, this);
return NodeIteratorBinding::Wrap(cx, this, aReflector);
}
} // namespace dom

View File

@ -69,7 +69,7 @@ public:
}
// The XPCOM Detach() is fine for our purposes
JSObject* WrapObject(JSContext *cx);
bool WrapObject(JSContext *cx, JS::MutableHandle<JSObject*> aReflector);
private:
virtual ~NodeIterator();

View File

@ -450,10 +450,10 @@ TreeWalker::NextSiblingInternal(bool aReversed, ErrorResult& aResult)
}
}
JSObject*
TreeWalker::WrapObject(JSContext *cx)
bool
TreeWalker::WrapObject(JSContext *aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TreeWalkerBinding::Wrap(cx, this);
return TreeWalkerBinding::Wrap(aCx, this, aReflector);
}
} // namespace dom

View File

@ -65,7 +65,7 @@ public:
already_AddRefed<nsINode> PreviousNode(ErrorResult& aResult);
already_AddRefed<nsINode> NextNode(ErrorResult& aResult);
JSObject* WrapObject(JSContext *cx);
bool WrapObject(JSContext *aCx, JS::MutableHandle<JSObject*> aReflector);
private:
nsCOMPtr<nsINode> mCurrentNode;

View File

@ -46,10 +46,10 @@ URL::URL(nsIURI* aURI)
{
}
JSObject*
URL::WrapObject(JSContext* aCx)
bool
URL::WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return URLBinding::Wrap(aCx, this);
return URLBinding::Wrap(aCx, this, aReflector);
}
/* static */ already_AddRefed<URL>

View File

@ -43,8 +43,8 @@ public:
explicit URL(nsIURI* aURI);
// WebIDL methods
JSObject*
WrapObject(JSContext* aCx);
bool
WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
static already_AddRefed<URL>
Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,

View File

@ -646,13 +646,14 @@ WebSocketImpl::DoOnMessageAvailable(const nsACString& aMsg, bool isBinary)
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the message event");
}
} else {
// CLOSING should be the only other state where it's possible to get msgs
// from channel: Spec says to drop them.
MOZ_ASSERT(readyState == WebSocket::CLOSING,
"Received message while CONNECTING or CLOSED");
return NS_OK;
}
// CLOSING should be the only other state where it's possible to get msgs
// from channel: Spec says to drop them.
MOZ_ASSERT(readyState == WebSocket::CLOSING,
"Received message while CONNECTING or CLOSED");
return NS_OK;
}
@ -718,14 +719,17 @@ WebSocketImpl::OnStart(nsISupports* aContext)
mWebSocket->SetReadyState(WebSocket::OPEN);
// Let's keep the object alive because the webSocket can be CCed in the
// onopen callback.
nsRefPtr<WebSocket> webSocket = mWebSocket;
// Call 'onopen'
rv = mWebSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
rv = webSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("open"));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the open event");
}
mWebSocket->UpdateMustKeepAlive();
webSocket->UpdateMustKeepAlive();
return NS_OK;
}
@ -1596,23 +1600,27 @@ WebSocketImpl::DispatchConnectionCloseEvents()
mWebSocket->SetReadyState(WebSocket::CLOSED);
// Let's keep the object alive because the webSocket can be CCed in the
// onerror or in the onclose callback.
nsRefPtr<WebSocket> webSocket = mWebSocket;
// Call 'onerror' if needed
if (mFailed) {
nsresult rv =
mWebSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
webSocket->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error"));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the error event");
}
}
nsresult rv = mWebSocket->CreateAndDispatchCloseEvent(mCloseEventWasClean,
mCloseEventCode,
mCloseEventReason);
nsresult rv = webSocket->CreateAndDispatchCloseEvent(mCloseEventWasClean,
mCloseEventCode,
mCloseEventReason);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch the close event");
}
mWebSocket->UpdateMustKeepAlive();
webSocket->UpdateMustKeepAlive();
Disconnect();
}

View File

@ -5300,8 +5300,8 @@ nsIDocument::RemoveAnonymousContent(AnonymousContent& aContent,
return;
}
// Iterate over know customContents to get and remove the right one
for (int32_t i = mAnonymousContents.Length() - 1; i >= 0; --i) {
// Iterate over mAnonymousContents to find and remove the given node.
for (size_t i = 0, len = mAnonymousContents.Length(); i < len; ++i) {
if (mAnonymousContents[i] == &aContent) {
// Get the node from the customContent
nsCOMPtr<Element> node = aContent.GetContentNode();

View File

@ -2305,7 +2305,7 @@ nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
bool
nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
{
auto* tabParent = static_cast<TabParent*>(GetRemoteBrowser());
mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser();
if (tabParent) {
return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
}
@ -2421,7 +2421,13 @@ nsFrameLoader::EnsureMessageManager()
return rv;
}
if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) {
if (!mIsTopLevelContent &&
!OwnerIsBrowserOrAppFrame() &&
!mRemoteFrame &&
!(mOwnerContent->IsXUL() &&
mOwnerContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::forcemessagemanager,
nsGkAtoms::_true, eCaseMatters))) {
return NS_OK;
}

View File

@ -2117,6 +2117,7 @@ GK_ATOM(DisplayPort, "_displayport")
GK_ATOM(DisplayPortMargins, "_displayportmargins")
GK_ATOM(DisplayPortBase, "_displayportbase")
GK_ATOM(AsyncScrollLayerCreationFailed, "_asyncscrolllayercreationfailed")
GK_ATOM(forcemessagemanager, "forcemessagemanager")
// Names for system metrics
GK_ATOM(color_picker_available, "color-picker-available")

View File

@ -2299,9 +2299,9 @@ CreateNativeGlobalForInner(JSContext* aCx,
uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
flags |= nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;
aGlobal.set(WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
nsJSPrincipals::get(aPrincipal), false));
if (!aGlobal || !xpc::InitGlobalObject(aCx, aGlobal, flags)) {
if (!WindowBinding::Wrap(aCx, aNewInner, aNewInner, options,
nsJSPrincipals::get(aPrincipal), false, aGlobal) ||
!xpc::InitGlobalObject(aCx, aGlobal, flags)) {
return NS_ERROR_FAILURE;
}

View File

@ -667,47 +667,70 @@ DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx,
JS::Handle<JSObject*> obj,
const NativeProperties* properties);
#define HAS_MEMBER_TYPEDEFS \
private: \
typedef char yes[1]; \
typedef char no[2]
#ifdef _MSC_VER
#define HAS_MEMBER_CHECK(_name) \
template<typename V> static yes& Check(char (*)[(&V::_name == 0) + 1])
template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
#else
#define HAS_MEMBER_CHECK(_name) \
template<typename V> static yes& Check(char (*)[sizeof(&V::_name) + 1])
template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
#endif
#define HAS_MEMBER(_name) \
template<typename T> \
class Has##_name##Member { \
typedef char yes[1]; \
typedef char no[2]; \
HAS_MEMBER_CHECK(_name); \
template<typename V> static no& Check(...); \
#define HAS_MEMBER(_memberName, _valueName) \
private: \
HAS_MEMBER_CHECK(_memberName); \
template<typename V> static no& Check##_memberName(...); \
\
public: \
static bool const Value = sizeof(Check<T>(nullptr)) == sizeof(yes); \
static bool const _valueName = \
sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
template<class T>
struct NativeHasMember
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(GetParentObject, GetParentObject);
HAS_MEMBER(JSBindingFinalized, JSBindingFinalized);
HAS_MEMBER(WrapObject, WrapObject);
};
HAS_MEMBER(WrapObject)
// HasWrapObject<T>::Value will be true if T has a WrapObject member but it's
// not nsWrapperCache::WrapObject.
template<typename T>
struct HasWrapObject
template<class T>
struct IsSmartPtr
{
private:
typedef char yes[1];
typedef char no[2];
typedef JSObject* (nsWrapperCache::*WrapObject)(JSContext*,
JS::Handle<JSObject*>);
template<typename U, U> struct SFINAE;
template <typename V> static no& Check(SFINAE<WrapObject, &V::WrapObject>*);
template <typename V> static yes& Check(...);
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(get, value);
};
template<class T>
struct IsRefcounted
{
HAS_MEMBER_TYPEDEFS;
HAS_MEMBER(AddRef, HasAddref);
HAS_MEMBER(Release, HasRelease);
public:
static bool const Value = HasWrapObjectMember<T>::Value &&
sizeof(Check<T>(nullptr)) == sizeof(yes);
static bool const value = HasAddref && HasRelease;
private:
// This struct only works if T is fully declared (not just forward declared).
// The IsBaseOf check will ensure that, we don't really need it for any other
// reason (the static assert will of course always be true).
static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
"Classes derived from nsISupports are refcounted!");
};
#undef HAS_MEMBER
#undef HAS_MEMBER_CHECK
#undef HAS_MEMBER_TYPEDEFS
#ifdef DEBUG
template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
struct
@ -976,6 +999,7 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
T* value,
JS::MutableHandle<JS::Value> rval)
{
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
MOZ_ASSERT(value);
// We try to wrap in the compartment of the underlying object of "scope"
JS::Rooted<JSObject*> obj(cx);
@ -995,11 +1019,9 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
}
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
obj = value->WrapObject(cx);
}
if (!obj) {
return false;
if (!value->WrapObject(cx, &obj)) {
return false;
}
}
// We can end up here in all sorts of compartments, per above. Make
@ -1014,11 +1036,12 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx,
// is true if the JSObject took ownership
template <class T>
inline bool
WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
JS::Handle<JSObject*> scopeArg,
nsAutoPtr<T>& value,
JS::MutableHandle<JS::Value> rval)
WrapNewBindingNonWrapperCachedObject(JSContext* cx,
JS::Handle<JSObject*> scopeArg,
nsAutoPtr<T>& value,
JS::MutableHandle<JS::Value> rval)
{
static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
// We do a runtime check on value, because otherwise we might in
// fact end up wrapping a null and invoking methods on it later.
if (!value) {
@ -1041,17 +1064,12 @@ WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
ac.emplace(cx, scope);
}
bool tookOwnership = false;
MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
obj = value->WrapObject(cx, &tookOwnership);
MOZ_ASSERT_IF(obj, tookOwnership);
if (tookOwnership) {
value.forget();
if (!value->WrapObject(cx, &obj)) {
return false;
}
}
if (!obj) {
return false;
value.forget();
}
// We can end up here in all sorts of compartments, per above. Make
@ -1060,8 +1078,9 @@ WrapNewBindingNonWrapperCachedOwnedObject(JSContext* cx,
return JS_WrapValue(cx, rval);
}
// Helper for smart pointers (nsAutoPtr/nsRefPtr/nsCOMPtr).
template <template <typename> class SmartPtr, typename T>
// Helper for smart pointers (nsRefPtr/nsCOMPtr).
template <template <typename> class SmartPtr, typename T,
typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type>
inline bool
WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
const SmartPtr<T>& value,
@ -1100,9 +1119,8 @@ HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
// Helper for calling HandleNewBindingWrappingFailure with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
HAS_MEMBER(get)
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct HandleNewBindingWrappingFailureHelper
{
static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
@ -1467,7 +1485,7 @@ struct WrapNativeParentFallback<T, true >
// Wrapping of our native parent, for cases when it's a WebIDL object (though
// possibly preffed off).
template<typename T, bool hasWrapObject=HasWrapObject<T>::Value >
template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
struct WrapNativeParentHelper
{
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
@ -1493,7 +1511,7 @@ struct WrapNativeParentHelper
// Wrapping of our native parent, for cases when it's not a WebIDL object. In
// this case it must be nsISupports.
template<typename T>
struct WrapNativeParentHelper<T, false >
struct WrapNativeParentHelper<T, false>
{
static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
{
@ -1551,9 +1569,7 @@ WrapNativeParent(JSContext* cx, const T& p)
return WrapNativeParent(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
}
HAS_MEMBER(GetParentObject)
template<typename T, bool WrapperCached=HasGetParentObjectMember<T>::Value>
template<typename T, bool WrapperCached=NativeHasMember<T>::GetParentObject>
struct GetParentObject
{
static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
@ -1632,7 +1648,7 @@ WrapCallThisObject<JS::Rooted<JSObject*>>(JSContext* cx,
// Helper for calling GetOrCreateDOMReflector with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetOrCreateDOMReflectorHelper
{
static inline bool GetOrCreate(JSContext* cx, const T& value,
@ -1648,6 +1664,7 @@ struct GetOrCreateDOMReflectorHelper<T, false>
static inline bool GetOrCreate(JSContext* cx, T& value,
JS::MutableHandle<JS::Value> rval)
{
static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
return GetOrCreateDOMReflector(cx, &value, rval);
}
};
@ -1673,7 +1690,7 @@ GetOrCreateDOMReflector(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
// Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
// (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetOrCreateDOMReflectorNoWrapHelper
{
static inline bool GetOrCreate(JSContext* cx, const T& value,
@ -1712,7 +1729,7 @@ GetCallbackFromCallbackObject(T* aObj)
// Helper for getting the callback JSObject* of a smart ptr around a
// CallbackObject or a reference to a CallbackObject or something like
// that.
template <class T, bool isSmartPtr=HasgetMember<T>::Value>
template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
struct GetCallbackFromCallbackObjectHelper
{
static inline JSObject* Get(const T& aObj)
@ -2503,30 +2520,7 @@ HasConstructor(JSObject* obj)
}
#endif
// Transfer reference in ptr to smartPtr.
template<class T>
inline void
Take(nsRefPtr<T>& smartPtr, T* ptr)
{
smartPtr = dont_AddRef(ptr);
}
// Transfer ownership of ptr to smartPtr.
template<class T>
inline void
Take(nsAutoPtr<T>& smartPtr, T* ptr)
{
smartPtr = ptr;
}
inline void
MustInheritFromNonRefcountedDOMObject(NonRefcountedDOMObject*)
{
}
HAS_MEMBER(JSBindingFinalized)
template<class T, bool hasCallback=HasJSBindingFinalizedMember<T>::Value>
template<class T, bool hasCallback=NativeHasMember<T>::JSBindingFinalized>
struct JSBindingFinalized
{
static void Finalized(T* self)
@ -2753,11 +2747,119 @@ ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
aCache);
}
template<class T, template <typename> class SmartPtr,
// The BindingJSObjectCreator class is supposed to be used by a caller that
// wants to create and initialise a binding JSObject. After initialisation has
// been successfully completed it should call ForgetObject().
// The BindingJSObjectCreator object will root the JSObject until ForgetObject()
// is called on it. If the native object for the binding is refcounted it will
// also hold a strong reference to it, that reference is transferred to the
// JSObject (which holds the native in a slot) when ForgetObject() is called. If
// the BindingJSObjectCreator object is destroyed and ForgetObject() was never
// called on it then the JSObject's slot holding the native will be set to
// undefined, and for a refcounted native the strong reference will be released.
template<class T>
class MOZ_STACK_CLASS BindingJSObjectCreator
{
public:
explicit BindingJSObjectCreator(JSContext* aCx)
: mReflector(aCx)
{
}
~BindingJSObjectCreator()
{
if (mReflector) {
js::SetReservedOrProxyPrivateSlot(mReflector, DOM_OBJECT_SLOT,
JS::UndefinedValue());
}
}
void
CreateProxyObject(JSContext* aCx, const js::Class* aClass,
const DOMProxyHandler* aHandler,
JS::Handle<JSObject*> aProto,
JS::Handle<JSObject*> aParent, T* aNative,
JS::MutableHandle<JSObject*> aReflector)
{
js::ProxyOptions options;
options.setClass(aClass);
JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aNative));
aReflector.set(js::NewProxyObject(aCx, aHandler, proxyPrivateVal, aProto,
aParent, options));
if (aReflector) {
mNative = aNative;
mReflector = aReflector;
}
}
void
CreateObject(JSContext* aCx, const JSClass* aClass,
JS::Handle<JSObject*> aProto, JS::Handle<JSObject*> aParent,
T* aNative, JS::MutableHandle<JSObject*> aReflector)
{
aReflector.set(JS_NewObject(aCx, aClass, aProto, aParent));
if (aReflector) {
js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
mNative = aNative;
mReflector = aReflector;
}
}
void
InitializationSucceeded()
{
void* dummy;
mNative.forget(&dummy);
mReflector = nullptr;
}
private:
struct OwnedNative
{
// Make sure the native objects inherit from NonRefcountedDOMObject so
// that we log their ctor and dtor.
static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
"Non-refcounted objects with DOM bindings should inherit "
"from NonRefcountedDOMObject.");
OwnedNative&
operator=(T* aNative)
{
return *this;
}
// This signature sucks, but it's the only one that will make a nsRefPtr
// just forget about its pointer without warning.
void
forget(void**)
{
}
};
JS::Rooted<JSObject*> mReflector;
typename Conditional<IsRefcounted<T>::value, nsRefPtr<T>, OwnedNative>::Type mNative;
};
template<class T,
bool isISupports=IsBaseOf<nsISupports, T>::value>
class DeferredFinalizer
{
typedef nsTArray<SmartPtr<T> > SmartPtrArray;
typedef typename Conditional<IsRefcounted<T>::value,
nsRefPtr<T>, nsAutoPtr<T>>::Type SmartPtr;
typedef nsTArray<SmartPtr> SmartPtrArray;
template<class U>
static inline void
AppendAndTake(nsTArray<nsRefPtr<U>>& smartPtrArray, U* ptr)
{
smartPtrArray.AppendElement(dont_AddRef(ptr));
}
template<class U>
static inline void
AppendAndTake(nsTArray<nsAutoPtr<U>>& smartPtrArray, U* ptr)
{
smartPtrArray.AppendElement(ptr);
}
static void*
AppendDeferredFinalizePointer(void* aData, void* aObject)
@ -2766,11 +2868,7 @@ class DeferredFinalizer
if (!pointers) {
pointers = new SmartPtrArray();
}
T* self = static_cast<T*>(aObject);
SmartPtr<T>* defer = pointers->AppendElement();
Take(*defer, self);
AppendAndTake(*pointers, static_cast<T*>(aObject));
return pointers;
}
static bool
@ -2800,8 +2898,8 @@ public:
}
};
template<class T, template <typename> class SmartPtr>
class DeferredFinalizer<T, SmartPtr, true>
template<class T>
class DeferredFinalizer<T, true>
{
public:
static void
@ -2811,11 +2909,11 @@ public:
}
};
template<class T, template <typename> class SmartPtr>
template<class T>
static void
AddForDeferredFinalization(T* aObject)
{
DeferredFinalizer<T, SmartPtr>::AddForDeferredFinalization(aObject);
DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
}
// This returns T's CC participant if it participates in CC or null if it
@ -3109,17 +3207,26 @@ StrongOrRawPtr(already_AddRefed<S>&& aPtr)
return aPtr.template downcast<T>();
}
template<class T>
inline T*
template<class T,
class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
nsAutoPtr<T>>::Type>
inline ReturnType
StrongOrRawPtr(T* aPtr)
{
return aPtr;
return ReturnType(aPtr);
}
template<class T, template<typename> class SmartPtr, class S>
inline void
StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
template<class T>
struct StrongPtrForMember
{
typedef typename Conditional<IsRefcounted<T>::value,
nsRefPtr<T>, nsAutoPtr<T>>::Type Type;
};
inline
JSObject*
GetErrorPrototype(JSContext* aCx, JS::Handle<JSObject*> aForObj)

View File

@ -44,22 +44,6 @@
# Always true for worker descriptors for non-callback
# interfaces. Defaults to true for non-worker non-callback
# descriptors.
# * nativeOwnership: Describes how the native object is held. 3 possible
# types: worker object ('worker'), non-refcounted object
# ('owned'), refcounted object ('refcounted').
# Non-refcounted objects need to inherit from
# mozilla::dom::NonRefcountedDOMObject and preferably use
# MOZ_COUNT_CTOR/MOZ_COUNT_DTOR in their
# constructor/destructor so they participate in leak
# logging.
# This mostly determines how the finalizer releases the
# binding's hold on the native object. For a worker object
# it'll call Release, for a non-refcounted object it'll
# call delete through XPConnect's deferred finalization
# mechanism, for a refcounted object it'll call Release
# through XPConnect's deferred finalization mechanism.
# 'worker' opts into old style worker models. Defaults to
# 'refcounted'.
#
# The following fields are either a string, an array (defaults to an empty
# array) or a dictionary with three possible keys (all, getterOnly and
@ -1227,15 +1211,15 @@ DOMInterfaces = {
},
'TextDecoder': {
'nativeOwnership': 'owned',
'wrapperCache': False
},
'TextEncoder': {
'nativeOwnership': 'owned',
'wrapperCache': False
},
'TextMetrics': {
'nativeOwnership': 'owned',
'wrapperCache': False
},
'TimeRanges': {
@ -1271,8 +1255,13 @@ DOMInterfaces = {
'wrapperCache': False,
}],
'VRFieldOfView': {
'wrapperCache': False,
},
'VRFieldOfViewReadOnly': {
'concrete': False
'concrete': False,
'wrapperCache': False,
},
'VRDevice': {
@ -1589,7 +1578,6 @@ DOMInterfaces = {
'XPathExpression': {
'wrapperCache': False,
'nativeOwnership': 'owned',
},
'XSLTProcessor': {

View File

@ -1565,14 +1565,6 @@ class CGAddPropertyHook(CGAbstractClassHook):
""")
def DeferredFinalizeSmartPtr(descriptor):
if descriptor.nativeOwnership == 'owned':
smartPtr = 'nsAutoPtr'
else:
smartPtr = 'nsRefPtr'
return smartPtr
def finalizeHook(descriptor, hookName, freeOp):
finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType
if descriptor.wrapperCache:
@ -1581,8 +1573,8 @@ def finalizeHook(descriptor, hookName, freeOp):
finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n"
if descriptor.isGlobal():
finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp
finalize += ("AddForDeferredFinalization<%s, %s >(self);\n" %
(descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor)))
finalize += ("AddForDeferredFinalization<%s>(self);\n" %
descriptor.nativeType)
return CGIfWrapper(CGGeneric(finalize), "self")
@ -3065,50 +3057,35 @@ class CGConstructorEnabled(CGAbstractMethod):
def CreateBindingJSObject(descriptor, properties):
objDecl = "BindingJSObjectCreator<%s> creator(aCx);\n" % descriptor.nativeType
# We don't always need to root obj, but there are a variety
# of cases where we do, so for simplicity, just always root it.
objDecl = "JS::Rooted<JSObject*> obj(aCx);\n"
if descriptor.proxy:
create = dedent(
"""
JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject));
js::ProxyOptions options;
options.setClass(&Class.mBase);
obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
proxyPrivateVal, proto, global, options);
if (!obj) {
return nullptr;
creator.CreateProxyObject(aCx, &Class.mBase, DOMProxyHandler::getInstance(),
proto, global, aObject, aReflector);
if (!aReflector) {
return false;
}
""")
if descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
create += dedent("""
js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO,
js::SetProxyExtra(aReflector, JSPROXYSLOT_EXPANDO,
JS::PrivateValue(&aObject->mExpandoAndGeneration));
""")
else:
create = dedent(
"""
obj = JS_NewObject(aCx, Class.ToJSClass(), proto, global);
if (!obj) {
return nullptr;
creator.CreateObject(aCx, Class.ToJSClass(), proto, global, aObject, aReflector);
if (!aReflector) {
return false;
}
js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
""")
create = objDecl + create
if descriptor.nativeOwnership == 'refcounted':
create += "NS_ADDREF(aObject);\n"
else:
create += dedent("""
// Make sure the native objects inherit from NonRefcountedDOMObject so that we
// log their ctor and dtor.
MustInheritFromNonRefcountedDOMObject(aObject);
*aTookOwnership = true;
""")
return create
return objDecl + create
def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""):
@ -3181,7 +3158,7 @@ def InitUnforgeableProperties(descriptor, properties):
"// by the interface prototype object.\n")
else:
unforgeableProperties = CGWrapper(
InitUnforgeablePropertiesOnObject(descriptor, "obj", properties, "nullptr"),
InitUnforgeablePropertiesOnObject(descriptor, "aReflector", properties, "false"),
pre=(
"// Important: do unforgeable property setup after we have handed\n"
"// over ownership of the C++ object to obj as needed, so that if\n"
@ -3219,9 +3196,9 @@ def InitMemberSlots(descriptor, wrapperCache):
clearWrapper = " aCache->ClearWrapper();\n"
else:
clearWrapper = ""
return ("if (!UpdateMemberSlots(aCx, obj, aObject)) {\n"
return ("if (!UpdateMemberSlots(aCx, aReflector, aObject)) {\n"
"%s"
" return nullptr;\n"
" return false;\n"
"}\n" % clearWrapper)
@ -3235,8 +3212,9 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('nsWrapperCache*', 'aCache')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
Argument('nsWrapperCache*', 'aCache'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.properties = properties
def definition_body(self):
@ -3249,33 +3227,31 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
JS::Rooted<JSObject*> parent(aCx, WrapNativeParent(aCx, aObject->GetParentObject()));
if (!parent) {
return nullptr;
return false;
}
// That might have ended up wrapping us already, due to the wonders
// of XBL. Check for that, and bail out as needed. Scope so we don't
// collide with the "obj" we declare in CreateBindingJSObject.
{
JSObject* obj = aCache->GetWrapper();
if (obj) {
return obj;
}
// of XBL. Check for that, and bail out as needed.
aReflector.set(aCache->GetWrapper());
if (aReflector) {
return true;
}
JSAutoCompartment ac(aCx, parent);
JS::Rooted<JSObject*> global(aCx, js::GetGlobalForObjectCrossCompartment(parent));
JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
if (!proto) {
return nullptr;
return false;
}
$*{createObject}
$*{unforgeable}
aCache->SetWrapper(obj);
aCache->SetWrapper(aReflector);
$*{slots}
return obj;
creator.InitializationSucceeded();
return true;
""",
assertion=AssertInheritanceChain(self.descriptor),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
@ -3293,7 +3269,10 @@ class CGWrapMethod(CGAbstractMethod):
inline=True, templateArgs=["class T"])
def definition_body(self):
return "return Wrap(aCx, aObject, aObject);\n"
return dedent("""
JS::Rooted<JSObject*> reflector(aCx);
return Wrap(aCx, aObject, aObject, &reflector) ? reflector.get() : nullptr;
""")
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
@ -3307,10 +3286,9 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
# XXX can we wrap if we don't have an interface prototype object?
assert descriptor.interface.hasInterfacePrototypeObject()
args = [Argument('JSContext*', 'aCx'),
Argument(descriptor.nativeType + '*', 'aObject')]
if descriptor.nativeOwnership == 'owned':
args.append(Argument('bool*', 'aTookOwnership'))
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
Argument(descriptor.nativeType + '*', 'aObject'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.properties = properties
def definition_body(self):
@ -3321,7 +3299,7 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
JS::Handle<JSObject*> proto = GetProtoObjectHandle(aCx, global);
if (!proto) {
return nullptr;
return false;
}
$*{createObject}
@ -3329,7 +3307,8 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
$*{unforgeable}
$*{slots}
return obj;
creator.InitializationSucceeded();
return true;
""",
assertions=AssertInheritanceChain(self.descriptor),
createObject=CreateBindingJSObject(self.descriptor, self.properties),
@ -3351,8 +3330,9 @@ class CGWrapGlobalMethod(CGAbstractMethod):
Argument('nsWrapperCache*', 'aCache'),
Argument('JS::CompartmentOptions&', 'aOptions'),
Argument('JSPrincipals*', 'aPrincipal'),
Argument('bool', 'aInitStandardClasses')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
Argument('bool', 'aInitStandardClasses'),
Argument('JS::MutableHandle<JSObject*>', 'aReflector')]
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'bool', args)
self.descriptor = descriptor
self.properties = properties
@ -3368,7 +3348,7 @@ class CGWrapGlobalMethod(CGAbstractMethod):
if self.descriptor.workers:
fireOnNewGlobal = """// XXXkhuey can't do this yet until workers can lazy resolve.
// JS_FireOnNewGlobalObject(aCx, obj);
// JS_FireOnNewGlobalObject(aCx, aReflector);
"""
else:
fireOnNewGlobal = ""
@ -3379,7 +3359,6 @@ class CGWrapGlobalMethod(CGAbstractMethod):
MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
"nsISupports must be on our primary inheritance chain");
JS::Rooted<JSObject*> obj(aCx);
CreateGlobal<${nativeType}, GetProtoObjectHandle>(aCx,
aObject,
aCache,
@ -3387,24 +3366,24 @@ class CGWrapGlobalMethod(CGAbstractMethod):
aOptions,
aPrincipal,
aInitStandardClasses,
&obj);
if (!obj) {
return nullptr;
aReflector);
if (!aReflector) {
return false;
}
// obj is a new global, so has a new compartment. Enter it
// aReflector is a new global, so has a new compartment. Enter it
// before doing anything with it.
JSAutoCompartment ac(aCx, obj);
JSAutoCompartment ac(aCx, aReflector);
if (!DefineProperties(aCx, obj, ${properties}, ${chromeProperties})) {
return nullptr;
if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
return false;
}
$*{unforgeable}
$*{slots}
$*{fireOnNewGlobal}
return obj;
return true;
""",
assertions=AssertInheritanceChain(self.descriptor),
nativeType=self.descriptor.nativeType,
@ -4704,12 +4683,6 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
isMember or
isCallbackReturnValue)
if forceOwningType and descriptor.nativeOwnership == 'owned':
raise TypeError("Interface %s has 'owned' nativeOwnership, so we "
"don't know how to keep it alive in %s" %
(descriptor.interface.identifier.name,
sourceDescription))
typeName = descriptor.nativeType
typePtr = typeName + "*"
@ -4733,6 +4706,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
declType = "NonNull<" + typeName + ">"
templateBody = ""
if forceOwningType:
templateBody += 'static_assert(IsRefcounted<%s>::value, "We can only store refcounted classes.");' % typeName
if not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal():
if failureCode is not None:
templateBody += str(CastableObjectUnwrapper(
@ -5769,15 +5744,11 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if not descriptor.interface.isExternal() and not descriptor.skipGen:
if descriptor.wrapperCache:
assert descriptor.nativeOwnership != 'owned'
wrapMethod = "GetOrCreateDOMReflector"
else:
if not returnsNewObject:
raise MethodNotNewObjectError(descriptor.interface.identifier.name)
if descriptor.nativeOwnership == 'owned':
wrapMethod = "WrapNewBindingNonWrapperCachedOwnedObject"
else:
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
wrapMethod = "WrapNewBindingNonWrapperCachedObject"
wrap = "%s(cx, ${obj}, %s, ${jsvalHandle})" % (wrapMethod, result)
if not descriptor.hasXPConnectImpls:
# Can only fail to wrap as a new-binding object
@ -6098,11 +6069,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider,
result = CGGeneric(descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeType)
conversion = None
if descriptorProvider.getDescriptor(
returnType.unroll().inner.identifier.name).nativeOwnership == 'owned':
result = CGTemplatedType("nsAutoPtr", result)
elif isMember:
result = CGTemplatedType("nsRefPtr", result)
if isMember:
result = CGGeneric("StrongPtrForMember<%s>::Type" % result.define())
else:
conversion = CGGeneric("StrongOrRawPtr<%s>" % result.define())
result = CGGeneric("auto")
@ -6693,8 +6661,7 @@ class CGPerSignatureCall(CGThing):
returnsNewObject = memberReturnsNewObject(self.idlNode)
if (returnsNewObject and
self.returnType.isGeckoInterface() and
not self.descriptor.getDescriptor(self.returnType.unroll().inner.identifier.name).nativeOwnership == 'owned'):
self.returnType.isGeckoInterface()):
wrapCode += dedent(
"""
static_assert(!IsPointer<decltype(result)>::value,
@ -10994,16 +10961,17 @@ class CGDescriptor(CGThing):
assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
if descriptor.nativeOwnership == 'owned' and (
descriptor.interface.hasChildInterfaces() or
descriptor.interface.parent):
raise TypeError("Owned interface cannot have a parent or children")
self._deps = descriptor.interface.getDeps()
cgThings = []
cgThings.append(CGGeneric(declare="typedef %s NativeType;\n" %
descriptor.nativeType))
parent = descriptor.interface.parent
if parent:
cgThings.append(CGGeneric("static_assert(IsRefcounted<NativeType>::value == IsRefcounted<%s::NativeType>::value,\n"
" \"Can't inherit from an interface with a different ownership model.\");\n" %
toBindingNamespace(descriptor.parentPrototypeName)))
# These are set to true if at least one non-static
# method/getter/setter or jsonifier exist on the interface.
(hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter,
@ -12213,7 +12181,10 @@ class CGBindingRoot(CGThing):
declare or define to generate header or cpp code (respectively).
"""
def __init__(self, config, prefix, webIDLFile):
bindingHeaders = {}
bindingHeaders = dict.fromkeys((
'mozilla/dom/NonRefcountedDOMObject.h',
),
True)
bindingDeclareHeaders = dict.fromkeys((
'mozilla/dom/BindingDeclarations.h',
'mozilla/dom/Nullable.h',
@ -12255,8 +12226,6 @@ class CGBindingRoot(CGThing):
bindingHeaders["mozilla/Preferences.h"] = any(
descriptorRequiresPreferences(d) for d in descriptors)
bindingHeaders["mozilla/dom/NonRefcountedDOMObject.h"] = any(
d.nativeOwnership == 'owned' for d in descriptors)
bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any(
d.concrete and d.proxy for d in descriptors)
@ -13066,40 +13035,30 @@ class CGExampleClass(CGBindingImplClass):
CGExampleMethod, CGExampleGetter, CGExampleSetter,
wantGetParent=descriptor.wrapperCache)
self.refcounted = descriptor.nativeOwnership == "refcounted"
self.parentIface = descriptor.interface.parent
if self.parentIface:
self.parentDesc = descriptor.getDescriptor(
self.parentIface.identifier.name)
bases = [ClassBase(self.nativeLeafName(self.parentDesc))]
else:
bases = []
if self.refcounted:
bases.append(ClassBase("nsISupports /* Change nativeOwnership in the binding configuration if you don't want this */"))
if descriptor.wrapperCache:
bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
else:
bases.append(ClassBase("NonRefcountedDOMObject"))
bases = [ ClassBase("nsISupports /* or NonRefcountedDOMObject if this is a non-refcounted object */") ]
if descriptor.wrapperCache:
bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */"))
if self.refcounted:
destructorVisibility = "protected"
if self.parentIface:
extradeclarations = (
"public:\n"
" NS_DECL_ISUPPORTS_INHERITED\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
"\n" % (self.nativeLeafName(descriptor),
self.nativeLeafName(self.parentDesc)))
else:
extradeclarations = (
"public:\n"
" NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
"\n" % self.nativeLeafName(descriptor))
destructorVisibility = "protected"
if self.parentIface:
extradeclarations = (
"public:\n"
" NS_DECL_ISUPPORTS_INHERITED\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n"
"\n" % (self.nativeLeafName(descriptor),
self.nativeLeafName(self.parentDesc)))
else:
destructorVisibility = "public"
extradeclarations = ""
extradeclarations = (
"public:\n"
" NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n"
" NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n"
"\n" % self.nativeLeafName(descriptor))
if descriptor.interface.hasChildInterfaces():
decorators = ""
@ -13117,55 +13076,43 @@ class CGExampleClass(CGBindingImplClass):
def define(self):
# Just override CGClass and do our own thing
if self.refcounted:
ctordtor = dedent("""
${nativeType}::${nativeType}()
{
}
ctordtor = dedent("""
${nativeType}::${nativeType}()
{
// Add |MOZ_COUNT_CTOR(${nativeType});| for a non-refcounted object.
}
${nativeType}::~${nativeType}()
{
// Add |MOZ_COUNT_DTOR(${nativeType});| for a non-refcounted object.
}
""")
if self.parentIface:
ccImpl = dedent("""
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_INHERITED_0(${nativeType}, ${parentType})
NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_INTERFACE_MAP_END_INHERITING(${parentType})
${nativeType}::~${nativeType}()
{
}
""")
else:
ctordtor = dedent("""
${nativeType}::${nativeType}()
{
MOZ_COUNT_CTOR(${nativeType});
}
ccImpl = dedent("""
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
${nativeType}::~${nativeType}()
{
MOZ_COUNT_DTOR(${nativeType});
}
""")
if self.refcounted:
if self.parentIface:
ccImpl = dedent("""
NS_IMPL_CYCLE_COLLECTION_INHERITED_0(${nativeType}, ${parentType})
NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType})
NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_INTERFACE_MAP_END_INHERITING(${parentType})
""")
else:
ccImpl = dedent("""
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType})
NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType})
NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType})
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType})
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
""")
else:
ccImpl = ""
classImpl = ccImpl + ctordtor + "\n" + dedent("""
JSObject*
${nativeType}::WrapObject(JSContext* aCx)

View File

@ -468,16 +468,10 @@ class Descriptor(DescriptorProvider):
iface.setUserData('hasProxyDescendant', True)
iface = iface.parent
self.nativeOwnership = desc.get('nativeOwnership', 'refcounted')
if not self.nativeOwnership in ('owned', 'refcounted'):
raise TypeError("Descriptor for %s has unrecognized value (%s) "
"for nativeOwnership" %
(self.interface.identifier.name, self.nativeOwnership))
if desc.get('wantsQI', None) != None:
self._wantsQI = desc.get('wantsQI', None)
self.wrapperCache = (not self.interface.isCallback() and
(self.nativeOwnership != 'owned' and
desc.get('wrapperCache', True)))
desc.get('wrapperCache', True))
def make_name(name):
return name + "_workers" if self.workers else name

View File

@ -12,12 +12,12 @@
namespace mozilla {
namespace dom {
// Natives for DOM classes with 'owned' as the value for nativeOwnership in
// Bindings.conf need to inherit from this class.
// Natives for DOM classes that aren't refcounted need to inherit from this
// class.
// If you're seeing objects of this class leak then natives for one of the DOM
// classes with 'owned' as the value for nativeOwnership in Bindings.conf is
// leaking. If the native for that class has MOZ_COUNT_CTOR/DTOR in its
// constructor/destructor then it should show up in the leak log too.
// classes inheriting from it is leaking. If the native for that class has
// MOZ_COUNT_CTOR/DTOR in its constructor/destructor then it should show up in
// the leak log too.
class NonRefcountedDOMObject
{
protected:

View File

@ -32,7 +32,9 @@ ReadStructuredCloneImageData(JSContext* aCx, JSStructuredCloneReader* aReader)
nsRefPtr<ImageData> imageData = new ImageData(width, height,
dataArray.toObject());
// Wrap it in a JS::Value.
result = imageData->WrapObject(aCx);
if (!imageData->WrapObject(aCx, &result)) {
return nullptr;
}
}
return result;
}

View File

@ -90,7 +90,7 @@ class TestNonWrapperCacheInterface : public nsISupports
public:
NS_DECL_ISUPPORTS
virtual JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
};
class OnlyForUseInConstructor : public nsISupports,

View File

@ -108,10 +108,10 @@ ImageData::DropData()
}
}
JSObject*
ImageData::WrapObject(JSContext* cx)
bool
ImageData::WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return ImageDataBinding::Wrap(cx, this);
return ImageDataBinding::Wrap(aCx, this, aReflector);
}
} // namespace dom

View File

@ -73,7 +73,7 @@ public:
return mData;
}
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
private:
void HoldData();

View File

@ -30,9 +30,9 @@ public:
return width;
}
JSObject* WrapObject(JSContext* aCx, bool* aTookOwnership)
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector)
{
return TextMetricsBinding::Wrap(aCx, this, aTookOwnership);
return TextMetricsBinding::Wrap(aCx, this, aReflector);
}
private:

View File

@ -11,10 +11,11 @@
namespace mozilla {
JSObject*
WebGLActiveInfo::WrapObject(JSContext* cx)
bool
WebGLActiveInfo::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return dom::WebGLActiveInfoBinding::Wrap(cx, this);
return dom::WebGLActiveInfoBinding::Wrap(aCx, this, aReflector);
}
} // namespace mozilla

View File

@ -35,7 +35,7 @@ public:
retval = mName;
}
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)

View File

@ -10,10 +10,11 @@
namespace mozilla {
JSObject*
WebGLShaderPrecisionFormat::WrapObject(JSContext* cx)
bool
WebGLShaderPrecisionFormat::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return dom::WebGLShaderPrecisionFormatBinding::Wrap(cx, this);
return dom::WebGLShaderPrecisionFormatBinding::Wrap(aCx, this, aReflector);
}
} // namespace mozilla

View File

@ -24,7 +24,7 @@ public:
, mPrecision(precision)
{ }
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
// WebIDL WebGLShaderPrecisionFormat API
GLint RangeMin() const {

View File

@ -12,10 +12,11 @@
namespace mozilla {
JSObject*
WebGLUniformLocation::WrapObject(JSContext* cx)
bool
WebGLUniformLocation::WrapObject(JSContext* aCx,
JS::MutableHandle<JSObject*> aReflector)
{
return dom::WebGLUniformLocationBinding::Wrap(cx, this);
return dom::WebGLUniformLocationBinding::Wrap(aCx, this, aReflector);
}
WebGLUniformLocation::WebGLUniformLocation(WebGLContext* context,

View File

@ -31,7 +31,7 @@ public:
uint32_t ProgramGeneration() const { return mProgramGeneration; }
int ElementSize() const { return mElementSize; }
JSObject* WrapObject(JSContext* cx);
bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)

Some files were not shown because too many files have changed in this diff Show More