зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound
This commit is contained in:
Коммит
90581b5c82
|
@ -28,7 +28,7 @@
|
|||
oncommand="MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);"/>
|
||||
|
||||
<command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
|
||||
<command id="cmd_print" oncommand="PrintUtils.print(window.gBrowser.selectedBrowser.contentWindowAsCPOW, window.gBrowser.selectedBrowser);"/>
|
||||
<command id="cmd_print" oncommand="PrintUtils.printWindow(window.gBrowser.selectedBrowser.outerWindowID, window.gBrowser.selectedBrowser);"/>
|
||||
<command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
|
||||
<command id="cmd_close" oncommand="BrowserCloseTabOrWindow()" reserved="true"/>
|
||||
<command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()" reserved="true"/>
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
let TrackingProtection = {
|
||||
PREF_ENABLED: "privacy.trackingprotection.enabled",
|
||||
PREF_ENABLED_GLOBALLY: "privacy.trackingprotection.enabled",
|
||||
PREF_ENABLED_IN_PRIVATE_WINDOWS: "privacy.trackingprotection.pbmode.enabled",
|
||||
enabledGlobally: false,
|
||||
enabledInPrivateWindows: false,
|
||||
|
||||
init() {
|
||||
let $ = selector => document.querySelector(selector);
|
||||
|
@ -11,21 +14,32 @@ let TrackingProtection = {
|
|||
this.content = $("#tracking-protection-content");
|
||||
|
||||
this.updateEnabled();
|
||||
Services.prefs.addObserver(this.PREF_ENABLED, this, false);
|
||||
Services.prefs.addObserver(this.PREF_ENABLED_GLOBALLY, this, false);
|
||||
Services.prefs.addObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this, false);
|
||||
|
||||
this.enabledHistogram.add(this.enabled);
|
||||
this.enabledHistogram.add(this.enabledGlobally);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.prefs.removeObserver(this.PREF_ENABLED, this);
|
||||
Services.prefs.removeObserver(this.PREF_ENABLED_GLOBALLY, this);
|
||||
Services.prefs.removeObserver(this.PREF_ENABLED_IN_PRIVATE_WINDOWS, this);
|
||||
},
|
||||
|
||||
observe() {
|
||||
this.updateEnabled();
|
||||
},
|
||||
|
||||
get enabled() {
|
||||
return this.enabledGlobally ||
|
||||
(this.enabledInPrivateWindows &&
|
||||
PrivateBrowsingUtils.isWindowPrivate(window));
|
||||
},
|
||||
|
||||
updateEnabled() {
|
||||
this.enabled = Services.prefs.getBoolPref(this.PREF_ENABLED);
|
||||
this.enabledGlobally =
|
||||
Services.prefs.getBoolPref(this.PREF_ENABLED_GLOBALLY);
|
||||
this.enabledInPrivateWindows =
|
||||
Services.prefs.getBoolPref(this.PREF_ENABLED_IN_PRIVATE_WINDOWS);
|
||||
this.container.hidden = !this.enabled;
|
||||
},
|
||||
|
||||
|
|
|
@ -1787,8 +1787,8 @@ function HandleAppCommandEvent(evt) {
|
|||
BrowserOpenFileWindow();
|
||||
break;
|
||||
case "Print":
|
||||
PrintUtils.print(gBrowser.selectedBrowser.contentWindowAsCPOW,
|
||||
gBrowser.selectedBrowser);
|
||||
PrintUtils.printWindow(gBrowser.selectedBrowser.outerWindowID,
|
||||
gBrowser.selectedBrowser);
|
||||
break;
|
||||
case "Save":
|
||||
saveDocument(gBrowser.selectedBrowser.contentDocumentAsCPOW);
|
||||
|
|
|
@ -1681,7 +1681,7 @@ nsContextMenu.prototype = {
|
|||
},
|
||||
|
||||
printFrame: function CM_printFrame() {
|
||||
PrintUtils.print(this.target.ownerDocument.defaultView, this.browser);
|
||||
PrintUtils.printWindow(this.frameOuterWindowID, this.browser);
|
||||
},
|
||||
|
||||
switchPageDirection: function CM_switchPageDirection() {
|
||||
|
|
|
@ -410,10 +410,17 @@ skip-if = e10s # Bug 1100664 - test relies on linkedBrowser.docShell
|
|||
[browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js]
|
||||
run-if = e10s
|
||||
[browser_trackingUI_1.js]
|
||||
tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
benignPage.html
|
||||
[browser_trackingUI_2.js]
|
||||
tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
benignPage.html
|
||||
[browser_trackingUI_3.js]
|
||||
tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
benignPage.html
|
||||
|
|
|
@ -7,34 +7,40 @@
|
|||
// * A page with no tracking elements is loaded.
|
||||
// * A page with tracking elements is loaded and they are blocked.
|
||||
// * A page with tracking elements is loaded and they are not blocked.
|
||||
// See also Bugs 1175327 and 1043801.
|
||||
// See also Bugs 1175327, 1043801, 1178985
|
||||
|
||||
let PREF = "privacy.trackingprotection.enabled";
|
||||
let BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
|
||||
let TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
const PREF = "privacy.trackingprotection.enabled";
|
||||
const PB_PREF = "privacy.trackingprotection.pbmode.enabled";
|
||||
const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
|
||||
const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
let TrackingProtection = null;
|
||||
let browser = null;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
TrackingProtection = null;
|
||||
TrackingProtection = browser = null;
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
gBrowser.removeCurrentTab();
|
||||
Services.prefs.clearUserPref(PB_PREF);
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
});
|
||||
|
||||
function hidden(sel) {
|
||||
let win = gBrowser.ownerGlobal;
|
||||
let win = browser.ownerGlobal;
|
||||
let el = win.document.querySelector(sel);
|
||||
let display = win.getComputedStyle(el).getPropertyValue("display", null);
|
||||
return display === "none";
|
||||
}
|
||||
|
||||
function clickButton(sel) {
|
||||
let win = gBrowser.ownerGlobal;
|
||||
let win = browser.ownerGlobal;
|
||||
let el = win.document.querySelector(sel);
|
||||
el.doCommand();
|
||||
}
|
||||
|
||||
function testBenignPage() {
|
||||
info("Non-tracking content must not be blocked");
|
||||
ok (!TrackingProtection.container.hidden, "The container is visible");
|
||||
ok (!TrackingProtection.content.hasAttribute("block-disabled"), "blocking not disabled");
|
||||
ok (!TrackingProtection.content.hasAttribute("block-active"), "blocking is not active");
|
||||
|
||||
|
@ -49,6 +55,7 @@ function testBenignPage() {
|
|||
|
||||
function testTrackingPage() {
|
||||
info("Tracking content must be blocked");
|
||||
ok (!TrackingProtection.container.hidden, "The container is visible");
|
||||
ok (!TrackingProtection.content.hasAttribute("block-disabled"), "blocking not disabled");
|
||||
ok (TrackingProtection.content.hasAttribute("block-active"), "blocking is active");
|
||||
|
||||
|
@ -63,6 +70,7 @@ function testTrackingPage() {
|
|||
|
||||
function testTrackingPageWhitelisted() {
|
||||
info("Tracking content must be white-listed and not blocked");
|
||||
ok (!TrackingProtection.container.hidden, "The container is visible");
|
||||
ok (TrackingProtection.content.hasAttribute("block-disabled"), "blocking is disabled");
|
||||
ok (!TrackingProtection.content.hasAttribute("block-active"), "blocking is not active");
|
||||
|
||||
|
@ -75,19 +83,7 @@ function testTrackingPageWhitelisted() {
|
|||
ok (hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
yield updateTrackingProtectionDatabase();
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "Functionality is attached to the browser window");
|
||||
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
|
||||
"TP.enabled is based on the original pref value");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled after setting the pref");
|
||||
|
||||
function* testTrackingProtectionForTab(tab) {
|
||||
info("Load a test page not containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
testBenignPage();
|
||||
|
@ -109,4 +105,45 @@ add_task(function* () {
|
|||
info("Wait for tab to reload following TP black-listing");
|
||||
yield promiseTabLoadEvent(tab);
|
||||
testTrackingPage();
|
||||
}
|
||||
|
||||
add_task(function* testNormalBrowsing() {
|
||||
yield updateTrackingProtectionDatabase();
|
||||
|
||||
browser = gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "TP is attached to the browser window");
|
||||
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
|
||||
"TP.enabled is based on the original pref value");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled after setting the pref");
|
||||
|
||||
yield testTrackingProtectionForTab(tab);
|
||||
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled after setting the pref");
|
||||
});
|
||||
|
||||
add_task(function* testPrivateBrowsing() {
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
browser = privateWin.gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "TP is attached to the private window");
|
||||
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PB_PREF),
|
||||
"TP.enabled is based on the pb pref value");
|
||||
|
||||
Services.prefs.setBoolPref(PB_PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled after setting the pref");
|
||||
|
||||
yield testTrackingProtectionForTab(tab);
|
||||
|
||||
Services.prefs.setBoolPref(PB_PREF, false);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled after setting the pref");
|
||||
|
||||
privateWin.close();
|
||||
});
|
||||
|
|
|
@ -4,45 +4,73 @@
|
|||
|
||||
// Test that the Tracking Protection section is never visible in the
|
||||
// Control Center when the feature is off.
|
||||
// See also Bugs 1175327 and 1043801.
|
||||
// See also Bugs 1175327, 1043801, 1178985.
|
||||
|
||||
let PREF = "privacy.trackingprotection.enabled";
|
||||
let BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
|
||||
let TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
const PREF = "privacy.trackingprotection.enabled";
|
||||
const PB_PREF = "privacy.trackingprotection.pbmode.enabled";
|
||||
const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
|
||||
const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
let TrackingProtection = null;
|
||||
let browser = null;
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
TrackingProtection = null;
|
||||
TrackingProtection = browser = null;
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
gBrowser.removeCurrentTab();
|
||||
Services.prefs.clearUserPref(PB_PREF);
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
});
|
||||
|
||||
function testTrackingPageOff() {
|
||||
ok (TrackingProtection.container.hidden, "The container is hidden");
|
||||
}
|
||||
|
||||
function testBenignPageOff() {
|
||||
ok (TrackingProtection.container.hidden, "The container is hidden");
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
add_task(function* testNormalBrowsing() {
|
||||
yield updateTrackingProtectionDatabase();
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
browser = gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "TP is attached to the browser window");
|
||||
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
|
||||
"TP.enabled is based on the original pref value");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled after setting the pref");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled after setting the pref");
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
testTrackingPageOff();
|
||||
ok (TrackingProtection.container.hidden, "The container is hidden");
|
||||
|
||||
info("Load a test page not containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
testBenignPageOff();
|
||||
ok (TrackingProtection.container.hidden, "The container is hidden");
|
||||
});
|
||||
|
||||
add_task(function* testPrivateBrowsing() {
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
browser = privateWin.gBrowser;
|
||||
let tab = browser.selectedTab = browser.addTab();
|
||||
|
||||
TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "TP is attached to the private window");
|
||||
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PB_PREF),
|
||||
"TP.enabled is based on the pb pref value");
|
||||
|
||||
Services.prefs.setBoolPref(PB_PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled after setting the pref");
|
||||
|
||||
Services.prefs.setBoolPref(PB_PREF, false);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled after setting the pref");
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
ok (TrackingProtection.container.hidden, "The container is hidden");
|
||||
|
||||
info("Load a test page not containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
ok (TrackingProtection.container.hidden, "The container is hidden");
|
||||
|
||||
privateWin.close();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* 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/. */
|
||||
|
||||
// Test that the Tracking Protection is correctly enabled / disabled
|
||||
// in both normal and private windows given all possible states of the prefs:
|
||||
// privacy.trackingprotection.enabled
|
||||
// privacy.trackingprotection.pbmode.enabled
|
||||
// See also Bug 1178985.
|
||||
|
||||
const PREF = "privacy.trackingprotection.enabled";
|
||||
const PB_PREF = "privacy.trackingprotection.pbmode.enabled";
|
||||
const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
|
||||
const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
Services.prefs.clearUserPref(PB_PREF);
|
||||
});
|
||||
|
||||
add_task(function* testNormalBrowsing() {
|
||||
let browser = gBrowser;
|
||||
let TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "TP is attached to the browser window");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
Services.prefs.setBoolPref(PB_PREF, false);
|
||||
ok (TrackingProtection.enabled, "TP is enabled (ENABLED=true,PB=false)");
|
||||
Services.prefs.setBoolPref(PB_PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled (ENABLED=true,PB=true)");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
Services.prefs.setBoolPref(PB_PREF, false);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled (ENABLED=false,PB=false)");
|
||||
Services.prefs.setBoolPref(PB_PREF, true);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled (ENABLED=false,PB=true)");
|
||||
});
|
||||
|
||||
add_task(function* testPrivateBrowsing() {
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
let browser = privateWin.gBrowser;
|
||||
|
||||
let TrackingProtection = browser.ownerGlobal.TrackingProtection;
|
||||
ok (TrackingProtection, "TP is attached to the browser window");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
Services.prefs.setBoolPref(PB_PREF, false);
|
||||
ok (TrackingProtection.enabled, "TP is enabled (ENABLED=true,PB=false)");
|
||||
Services.prefs.setBoolPref(PB_PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled (ENABLED=true,PB=true)");
|
||||
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
Services.prefs.setBoolPref(PB_PREF, false);
|
||||
ok (!TrackingProtection.enabled, "TP is disabled (ENABLED=false,PB=false)");
|
||||
Services.prefs.setBoolPref(PB_PREF, true);
|
||||
ok (TrackingProtection.enabled, "TP is enabled (ENABLED=false,PB=true)");
|
||||
|
||||
privateWin.close();
|
||||
});
|
|
@ -52,3 +52,43 @@ add_task(function* () {
|
|||
});
|
||||
ok(!overlayIsVisible, "overlay should be hidden.");
|
||||
});
|
||||
|
||||
// Test that the overlay cannot be interacted with after the user closes the overlay
|
||||
add_task(function* () {
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
|
||||
|
||||
yield promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_test.html");
|
||||
|
||||
// Work around for delayed PluginBindingAttached
|
||||
yield promiseUpdatePluginBindings(gBrowser.selectedBrowser);
|
||||
|
||||
let overlayHidden = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
|
||||
let doc = content.document;
|
||||
let plugin = doc.getElementById("test");
|
||||
let overlay = doc.getAnonymousElementByAttribute(plugin, "anonid", "main");
|
||||
let closeIcon = doc.getAnonymousElementByAttribute(plugin, "anonid", "closeIcon")
|
||||
let closeIconBounds = closeIcon.getBoundingClientRect();
|
||||
let overlayBounds = overlay.getBoundingClientRect();
|
||||
let overlayLeft = (overlayBounds.left + overlayBounds.right) / 2;
|
||||
let overlayTop = (overlayBounds.left + overlayBounds.right) / 2 ;
|
||||
let closeIconLeft = (closeIconBounds.left + closeIconBounds.right) / 2;
|
||||
let closeIconTop = (closeIconBounds.top + closeIconBounds.bottom) / 2;
|
||||
let utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
// Simulate clicking on the close icon.
|
||||
utils.sendMouseEvent("mousedown", closeIconLeft, closeIconTop, 0, 1, 0, false, 0, 0);
|
||||
utils.sendMouseEvent("mouseup", closeIconLeft, closeIconTop, 0, 1, 0, false, 0, 0);
|
||||
|
||||
// Simulate clicking on the overlay.
|
||||
utils.sendMouseEvent("mousedown", overlayLeft, overlayTop, 0, 1, 0, false, 0, 0);
|
||||
utils.sendMouseEvent("mouseup", overlayLeft, overlayTop, 0, 1, 0, false, 0, 0);
|
||||
|
||||
return plugin && !overlay.classList.contains("visible");
|
||||
});
|
||||
|
||||
let notification = PopupNotifications.getNotification("click-to-play-plugins");
|
||||
|
||||
ok(notification.dismissed, "No notification should be shown");
|
||||
ok(overlayHidden, "Overlay should be hidden");
|
||||
});
|
||||
|
|
|
@ -4,54 +4,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
|
||||
// shared-head.js handles imports, constants, and utility functions
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/browser/devtools/framework/test/shared-head.js", this);
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/browser/browser/devtools/fontinspector/test/"
|
||||
|
||||
// All test are asynchronous
|
||||
waitForExplicitFinish();
|
||||
|
||||
DevToolsUtils.testing = true;
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
DevToolsUtils.testing = false;
|
||||
});
|
||||
|
||||
registerCleanupFunction(function*() {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
yield gDevTools.closeToolbox(target);
|
||||
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add a new test tab in the browser and load the given url.
|
||||
* @param {String} url The url to be loaded in the new tab
|
||||
* @return a promise that resolves to the tab object when the url is loaded
|
||||
*/
|
||||
function loadTab(url) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
deferred.resolve({tab: tab, browser: browser});
|
||||
}, true);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the toolbox, with the inspector tool visible.
|
||||
* @param {Function} cb Optional callback, if you don't want to use the returned
|
||||
|
@ -114,7 +71,7 @@ let openInspector = Task.async(function*(cb) {
|
|||
*/
|
||||
let openFontInspectorForURL = Task.async(function* (url) {
|
||||
info("Opening tab " + url);
|
||||
yield loadTab(url);
|
||||
yield addTab(url);
|
||||
|
||||
let { toolbox, inspector } = yield openInspector();
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.doc is undefine
|
|||
|
||||
// Tests devtools API
|
||||
|
||||
const Cu = Components.utils;
|
||||
const toolId1 = "test-tool-1";
|
||||
const toolId2 = "test-tool-2";
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
// Tests devtools API
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
function test() {
|
||||
addTab("about:blank").then(runTests);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
// Tests devtools API
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
let toolbox, target;
|
||||
|
||||
let tempScope = {};
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
// Test that the sidebar widget auto-registers existing tabs.
|
||||
|
||||
const Cu = Components.utils;
|
||||
const {ToolSidebar} = devtools.require("devtools/framework/sidebar");
|
||||
|
||||
const testToolURL = "data:text/xml;charset=utf8,<?xml version='1.0'?>" +
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This shared-head.js file is used for multiple directories in devtools.
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
const {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const {ScratchpadManager} = Cu.import("resource:///modules/devtools/scratchpad-manager.jsm", {});
|
||||
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const {require} = devtools;
|
||||
const {TargetFactory} = devtools;
|
||||
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils");
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
const promise = require("promise");
|
||||
|
||||
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
const CHROME_URL_ROOT = TEST_DIR + "/";
|
||||
|
@ -38,13 +42,15 @@ registerCleanupFunction(() => {
|
|||
Services.prefs.clearUserPref("devtools.toolbox.previousHost");
|
||||
});
|
||||
|
||||
registerCleanupFunction(function cleanup() {
|
||||
registerCleanupFunction(function* cleanup() {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
yield gDevTools.closeToolbox(target);
|
||||
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Add a new test tab in the browser and load the given url.
|
||||
* @param {String} url The url to be loaded in the new tab
|
||||
|
@ -54,13 +60,12 @@ function addTab(url) {
|
|||
info("Adding a new tab with URL: '" + url + "'");
|
||||
let def = promise.defer();
|
||||
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
info("URL '" + url + "' loading complete");
|
||||
def.resolve(tab);
|
||||
}, true);
|
||||
content.location = url;
|
||||
|
||||
return def.promise;
|
||||
}
|
||||
|
|
|
@ -623,10 +623,13 @@ PluginContent.prototype = {
|
|||
let plugin = document.getBindingParent(event.target);
|
||||
let contentWindow = plugin.ownerDocument.defaultView.top;
|
||||
let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
|
||||
let overlay = this.getPluginUI(plugin, "main");
|
||||
// Have to check that the target is not the link to update the plugin
|
||||
if (!(event.originalTarget instanceof contentWindow.HTMLAnchorElement) &&
|
||||
(event.originalTarget.getAttribute('anonid') != 'closeIcon') &&
|
||||
event.button == 0 && event.isTrusted) {
|
||||
overlay.classList.contains('visible') &&
|
||||
event.button == 0 &&
|
||||
event.isTrusted) {
|
||||
this._showClickToPlayNotification(plugin, true);
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
|
|
@ -246,13 +246,15 @@ public:
|
|||
* still running but we only consider it playing when it is in its active
|
||||
* interval. This definition is used for fetching the animations that are
|
||||
* candidates for running on the compositor (since we don't ship animations
|
||||
* to the compositor when they are in their delay phase or paused).
|
||||
* to the compositor when they are in their delay phase or paused including
|
||||
* being effectively paused due to having a zero playback rate).
|
||||
*/
|
||||
bool IsPlaying() const
|
||||
{
|
||||
// We need to have an effect in its active interval, and
|
||||
// be either running or waiting to run.
|
||||
// be either running or waiting to run with a non-zero playback rate.
|
||||
return HasInPlayEffect() &&
|
||||
mPlaybackRate != 0.0 &&
|
||||
(PlayState() == AnimationPlayState::Running ||
|
||||
mPendingState == PendingState::PlayPending);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,10 @@ public:
|
|||
NS_DECL_NSIREQUEST
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
// missing from NS_DECL_NSIEVENTTARGET because MSVC
|
||||
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
|
||||
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
|
||||
}
|
||||
|
||||
explicit WebSocketImpl(WebSocket* aWebSocket)
|
||||
: mWebSocket(aWebSocket)
|
||||
|
@ -2582,7 +2586,7 @@ class WorkerRunnableDispatcher final : public WorkerRunnable
|
|||
|
||||
public:
|
||||
WorkerRunnableDispatcher(WebSocketImpl* aImpl, WorkerPrivate* aWorkerPrivate,
|
||||
nsIRunnable* aEvent)
|
||||
already_AddRefed<nsIRunnable>&& aEvent)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mWebSocketImpl(aImpl)
|
||||
, mEvent(aEvent)
|
||||
|
@ -2627,11 +2631,19 @@ private:
|
|||
} // anonymous namespace
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
WebSocketImpl::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||
return Dispatch(event.forget(), aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event_ref(aEvent);
|
||||
// If the target is the main-thread we can just dispatch the runnable.
|
||||
if (mIsMainThread) {
|
||||
return NS_DispatchToMainThread(aEvent);
|
||||
return NS_DispatchToMainThread(event_ref.forget());
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
@ -2648,7 +2660,7 @@ WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
|||
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
|
||||
// runnable.
|
||||
nsRefPtr<WorkerRunnableDispatcher> event =
|
||||
new WorkerRunnableDispatcher(this, mWorkerPrivate, aEvent);
|
||||
new WorkerRunnableDispatcher(this, mWorkerPrivate, event_ref.forget());
|
||||
|
||||
if (!event->Dispatch(nullptr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -1629,14 +1629,24 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
|
|||
nsIFrame* contentFrame = content->GetPrimaryFrame();
|
||||
nsIObjectFrame* objectFrame = do_QueryFrame(contentFrame);
|
||||
if (aAdjustWidgets && objectFrame && !sTestMode) {
|
||||
// note that the presshell's widget is being retrieved here, not the one
|
||||
// for the object frame.
|
||||
nsViewManager* vm = presShell->GetViewManager();
|
||||
if (vm) {
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget)
|
||||
widget->SetFocus(false);
|
||||
if (XRE_IsContentProcess()) {
|
||||
// set focus to the top level window via the chrome process.
|
||||
nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
|
||||
if (tabChild) {
|
||||
static_cast<TabChild*>(tabChild.get())->SendDispatchFocusToTopLevelWindow();
|
||||
}
|
||||
} else {
|
||||
// note that the presshell's widget is being retrieved here, not the one
|
||||
// for the object frame.
|
||||
nsViewManager* vm = presShell->GetViewManager();
|
||||
if (vm) {
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
// set focus to the top level window but don't raise it.
|
||||
widget->SetFocus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,7 +230,7 @@ public:
|
|||
* MayStartLayout() until SetMayStartLayout(true) is called on it. Making
|
||||
* sure this happens is the responsibility of the caller of
|
||||
* StartDocumentLoad().
|
||||
*/
|
||||
*/
|
||||
virtual nsresult StartDocumentLoad(const char* aCommand,
|
||||
nsIChannel* aChannel,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
|
@ -356,8 +356,8 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the document's character encoding. |aCharSetID| should be canonical.
|
||||
* That is, callers are responsible for the charset alias resolution.
|
||||
* Set the document's character encoding. |aCharSetID| should be canonical.
|
||||
* That is, callers are responsible for the charset alias resolution.
|
||||
*/
|
||||
virtual void SetDocumentCharacterSet(const nsACString& aCharSetID) = 0;
|
||||
|
||||
|
@ -456,7 +456,7 @@ public:
|
|||
{
|
||||
mBidiEnabled = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the document contains (or has contained) any MathML elements.
|
||||
*/
|
||||
|
@ -464,7 +464,7 @@ public:
|
|||
{
|
||||
return mMathMLEnabled;
|
||||
}
|
||||
|
||||
|
||||
void SetMathMLEnabled()
|
||||
{
|
||||
mMathMLEnabled = true;
|
||||
|
@ -477,7 +477,7 @@ public:
|
|||
{
|
||||
return mIsInitialDocumentInWindow;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tell this document that it's the initial document in its window. See
|
||||
* comments on mIsInitialDocumentInWindow for when this should be called.
|
||||
|
@ -486,7 +486,7 @@ public:
|
|||
{
|
||||
mIsInitialDocumentInWindow = aIsInitialDocument;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the bidi options for this document.
|
||||
|
@ -687,7 +687,7 @@ public:
|
|||
{
|
||||
mParentDocument = aParent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Are plugins allowed in this document ?
|
||||
*/
|
||||
|
@ -838,7 +838,7 @@ public:
|
|||
Element* GetHeadElement() {
|
||||
return GetHtmlChildElement(nsGkAtoms::head);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Accessors to the collection of stylesheets owned by this document.
|
||||
* Style sheets are ordered, most significant last.
|
||||
|
@ -873,7 +873,7 @@ public:
|
|||
* @throws no exceptions
|
||||
*/
|
||||
virtual int32_t GetNumberOfStyleSheets() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Get a particular stylesheet
|
||||
* @param aIndex the index the stylesheet lives at. This is zero-based
|
||||
|
@ -881,7 +881,7 @@ public:
|
|||
* @throws no exceptions
|
||||
*/
|
||||
virtual nsIStyleSheet* GetStyleSheetAt(int32_t aIndex) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Insert a sheet at a particular spot in the stylesheet list (zero-based)
|
||||
* @param aSheet the sheet to insert
|
||||
|
@ -925,7 +925,7 @@ public:
|
|||
* and that observers should be notified and style sets updated
|
||||
*/
|
||||
virtual void SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
|
||||
bool aApplicable) = 0;
|
||||
bool aApplicable) = 0;
|
||||
|
||||
enum additionalSheetType {
|
||||
eAgentSheet,
|
||||
|
@ -1029,7 +1029,7 @@ public:
|
|||
nsPIDOMWindow* outer = mWindow ? mWindow->GetOuterWindow() : nullptr;
|
||||
return outer && outer->IsBackground();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the inner window used as the script compilation scope for
|
||||
* this document. If you're not absolutely sure you need this, use
|
||||
|
@ -1060,7 +1060,7 @@ public:
|
|||
|
||||
/**
|
||||
* Get the script loader for this document
|
||||
*/
|
||||
*/
|
||||
virtual nsScriptLoader* ScriptLoader() = 0;
|
||||
|
||||
/**
|
||||
|
@ -1159,7 +1159,7 @@ public:
|
|||
* exit fullscreen.
|
||||
*
|
||||
* If aDocument is non null, all documents from aDocument's fullscreen root
|
||||
* to the fullscreen leaf exit fullscreen.
|
||||
* to the fullscreen leaf exit fullscreen.
|
||||
*
|
||||
* Note that the fullscreen leaf is the bottom-most document which is
|
||||
* fullscreen, it may have non-fullscreen child documents. The fullscreen
|
||||
|
@ -1474,7 +1474,7 @@ public:
|
|||
* The document should save form control state.
|
||||
*/
|
||||
virtual void RemovedFromDocShell() = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Get the layout history state that should be used to save and restore state
|
||||
* for nodes in this document. This may return null; if that happens state
|
||||
|
@ -1583,7 +1583,7 @@ public:
|
|||
nsCompatibility GetCompatibilityMode() const {
|
||||
return mCompatMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether we've ever fired a DOMTitleChanged event for this
|
||||
* document.
|
||||
|
@ -1717,7 +1717,7 @@ public:
|
|||
{
|
||||
return mDisplayDocument;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the display document for this document. aDisplayDocument must not be
|
||||
* null.
|
||||
|
@ -1759,7 +1759,7 @@ public:
|
|||
return mObservers;
|
||||
}
|
||||
protected:
|
||||
nsAutoTArray< nsCOMPtr<nsIObserver>, 8 > mObservers;
|
||||
nsAutoTArray< nsCOMPtr<nsIObserver>, 8 > mObservers;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2169,9 +2169,9 @@ public:
|
|||
|
||||
virtual Element* FindImageMap(const nsAString& aNormalizedMapName) = 0;
|
||||
|
||||
// Add aLink to the set of links that need their status resolved.
|
||||
// Add aLink to the set of links that need their status resolved.
|
||||
void RegisterPendingLinkUpdate(mozilla::dom::Link* aLink);
|
||||
|
||||
|
||||
// Remove aLink from the set of links that need their status resolved.
|
||||
// This function must be called when links are removed from the document.
|
||||
void UnregisterPendingLinkUpdate(mozilla::dom::Link* aElement);
|
||||
|
@ -2203,7 +2203,7 @@ public:
|
|||
uint32_t aParamsLength = 0) const;
|
||||
|
||||
virtual void PostVisibilityUpdateEvent() = 0;
|
||||
|
||||
|
||||
bool IsSyntheticDocument() const { return mIsSyntheticDocument; }
|
||||
|
||||
void SetNeedLayoutFlush() {
|
||||
|
@ -2708,7 +2708,7 @@ protected:
|
|||
// If true, whoever is creating the document has gotten it to the
|
||||
// point where it's safe to start layout on it.
|
||||
bool mMayStartLayout;
|
||||
|
||||
|
||||
// True iff we've ever fired a DOMTitleChanged event for this document
|
||||
bool mHaveFiredTitleChange;
|
||||
|
||||
|
@ -2727,7 +2727,7 @@ protected:
|
|||
// True iff DNS prefetch is allowed for this document. Note that if the
|
||||
// document has no window, DNS prefetch won't be performed no matter what.
|
||||
bool mAllowDNSPrefetch;
|
||||
|
||||
|
||||
// True when this document is a static clone of a normal document
|
||||
bool mIsStaticDocument;
|
||||
|
||||
|
@ -2875,7 +2875,7 @@ protected:
|
|||
// if this document is part of a multipart document,
|
||||
// the ID can be used to distinguish it from the other parts.
|
||||
uint32_t mPartID;
|
||||
|
||||
|
||||
// Cycle collector generation in which we're certain that this document
|
||||
// won't be collected
|
||||
uint32_t mMarkedCCGeneration;
|
||||
|
@ -3024,8 +3024,8 @@ NS_NewVideoDocument(nsIDocument** aInstancePtrResult);
|
|||
// Also, both aDocumentURI and aBaseURI must not be null.
|
||||
nsresult
|
||||
NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
|
||||
const nsAString& aNamespaceURI,
|
||||
const nsAString& aQualifiedName,
|
||||
const nsAString& aNamespaceURI,
|
||||
const nsAString& aQualifiedName,
|
||||
nsIDOMDocumentType* aDoctype,
|
||||
nsIURI* aDocumentURI,
|
||||
nsIURI* aBaseURI,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
#include "js/Class.h"
|
||||
#include "js/Proxy.h"
|
||||
#include "mozilla/dom/DOMJSProxyHandler.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
|
@ -15,6 +16,14 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* static */ bool
|
||||
nsWrapperCache::HasJSObjectMovedOp(JSObject* aWrapper)
|
||||
{
|
||||
return js::HasObjectMovedOp(aWrapper);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */ void
|
||||
nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder,
|
||||
nsScriptObjectTracer* aTracer)
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "js/Class.h"
|
||||
#include "js/Id.h" // must come before js/RootingAPI.h
|
||||
#include "js/Value.h" // must come before js/RootingAPI.h
|
||||
#include "js/RootingAPI.h"
|
||||
|
@ -66,6 +65,7 @@ class nsWindowRoot;
|
|||
* have to include some JS headers that don't play nicely with the rest of the
|
||||
* codebase. Include nsWrapperCacheInlines.h if you need to call those methods.
|
||||
*/
|
||||
|
||||
class nsWrapperCache
|
||||
{
|
||||
public:
|
||||
|
@ -103,11 +103,18 @@ public:
|
|||
return GetWrapperJSObject();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
private:
|
||||
static bool HasJSObjectMovedOp(JSObject* aWrapper);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
void SetWrapper(JSObject* aWrapper)
|
||||
{
|
||||
MOZ_ASSERT(!PreservingWrapper(), "Clearing a preserved wrapper!");
|
||||
MOZ_ASSERT(aWrapper, "Use ClearWrapper!");
|
||||
MOZ_ASSERT(js::HasObjectMovedOp(aWrapper),
|
||||
MOZ_ASSERT(HasJSObjectMovedOp(aWrapper),
|
||||
"Object has not provided the hook to update the wrapper if it is moved");
|
||||
|
||||
SetWrapperJSObject(aWrapper);
|
||||
|
|
|
@ -108,6 +108,28 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
|||
NamesOfInterfacesWithProtos(aProtoId));
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowMethodFailed(JSContext* cx, ErrorResult& rv)
|
||||
{
|
||||
if (rv.IsUncatchableException()) {
|
||||
// Nuke any existing exception on aCx, to make sure we're uncatchable.
|
||||
JS_ClearPendingException(cx);
|
||||
// Don't do any reporting. Just return false, to create an
|
||||
// uncatchable exception.
|
||||
return false;
|
||||
}
|
||||
if (rv.IsErrorWithMessage()) {
|
||||
rv.ReportErrorWithMessage(cx);
|
||||
return false;
|
||||
}
|
||||
if (rv.IsJSException()) {
|
||||
rv.ReportJSException(cx);
|
||||
return false;
|
||||
}
|
||||
rv.ReportGenericError(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
|
||||
{
|
||||
|
@ -289,17 +311,6 @@ ErrorResult::StealJSException(JSContext* cx,
|
|||
mResult = NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ErrorResult::ReportNotEnoughArgsError(JSContext* cx,
|
||||
const char* ifaceName,
|
||||
const char* memberName)
|
||||
{
|
||||
MOZ_ASSERT(ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
|
||||
nsPrintfCString errorMessage("%s.%s", ifaceName, memberName);
|
||||
ThrowErrorMessage(cx, dom::MSG_MISSING_ARGUMENTS, errorMessage.get());
|
||||
}
|
||||
|
||||
void
|
||||
ErrorResult::ReportGenericError(JSContext* cx)
|
||||
{
|
||||
|
@ -2657,7 +2668,7 @@ ConvertExceptionToPromise(JSContext* cx,
|
|||
if (rv.Failed()) {
|
||||
// We just give up. Make sure to not leak memory on the
|
||||
// ErrorResult, but then just put the original exception back.
|
||||
ThrowMethodFailedWithDetails(cx, rv, "", "");
|
||||
ThrowMethodFailed(cx, rv);
|
||||
JS_SetPendingException(cx, exn);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -89,33 +89,8 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
|
|||
const ErrNum aErrorNumber,
|
||||
prototypes::ID aProtoId);
|
||||
|
||||
inline bool
|
||||
ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
|
||||
const char* ifaceName,
|
||||
const char* memberName)
|
||||
{
|
||||
if (rv.IsUncatchableException()) {
|
||||
// Nuke any existing exception on aCx, to make sure we're uncatchable.
|
||||
JS_ClearPendingException(cx);
|
||||
// Don't do any reporting. Just return false, to create an
|
||||
// uncatchable exception.
|
||||
return false;
|
||||
}
|
||||
if (rv.IsErrorWithMessage()) {
|
||||
rv.ReportErrorWithMessage(cx);
|
||||
return false;
|
||||
}
|
||||
if (rv.IsJSException()) {
|
||||
rv.ReportJSException(cx);
|
||||
return false;
|
||||
}
|
||||
if (rv.IsNotEnoughArgsError()) {
|
||||
rv.ReportNotEnoughArgsError(cx, ifaceName, memberName);
|
||||
return false;
|
||||
}
|
||||
rv.ReportGenericError(cx);
|
||||
return false;
|
||||
}
|
||||
bool
|
||||
ThrowMethodFailed(JSContext* cx, ErrorResult& rv);
|
||||
|
||||
// Returns true if the JSClass is used for DOM objects.
|
||||
inline bool
|
||||
|
|
|
@ -1709,7 +1709,7 @@ class CGConstructNavigatorObject(CGAbstractMethod):
|
|||
nsRefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv);
|
||||
rv.WouldReportJSException();
|
||||
if (rv.Failed()) {
|
||||
ThrowMethodFailedWithDetails(aCx, rv, "${descriptorName}", "navigatorConstructor");
|
||||
ThrowMethodFailed(aCx, rv);
|
||||
return nullptr;
|
||||
}
|
||||
if (!GetOrCreateDOMReflector(aCx, result, &v)) {
|
||||
|
@ -7012,9 +7012,7 @@ class CGPerSignatureCall(CGThing):
|
|||
return wrapCode
|
||||
|
||||
def getErrorReport(self):
|
||||
return CGGeneric('return ThrowMethodFailedWithDetails(cx, rv, "%s", "%s");\n'
|
||||
% (self.descriptor.interface.identifier.name,
|
||||
self.idlNode.identifier.name))
|
||||
return CGGeneric('return ThrowMethodFailed(cx, rv);\n')
|
||||
|
||||
def define(self):
|
||||
return (self.cgRoot.define() + self.wrap_return_value())
|
||||
|
@ -7969,7 +7967,7 @@ class CGEnumerateHook(CGAbstractBindingMethod):
|
|||
self->GetOwnPropertyNames(cx, names, rv);
|
||||
rv.WouldReportJSException();
|
||||
if (rv.Failed()) {
|
||||
return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate");
|
||||
return ThrowMethodFailed(cx, rv);
|
||||
}
|
||||
bool dummy;
|
||||
for (uint32_t i = 0; i < names.Length(); ++i) {
|
||||
|
@ -10026,7 +10024,7 @@ class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod):
|
|||
self->GetOwnPropertyNames(cx, names, rv);
|
||||
rv.WouldReportJSException();
|
||||
if (rv.Failed()) {
|
||||
return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate");
|
||||
return ThrowMethodFailed(cx, rv);
|
||||
}
|
||||
// OK to pass null as "proxy" because it's ignored if
|
||||
// shadowPrototypeProperties is true
|
||||
|
|
|
@ -110,12 +110,6 @@ public:
|
|||
void ReportJSException(JSContext* cx);
|
||||
bool IsJSException() const { return ErrorCode() == NS_ERROR_DOM_JS_EXCEPTION; }
|
||||
|
||||
void ThrowNotEnoughArgsError() { mResult = NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
|
||||
void ReportNotEnoughArgsError(JSContext* cx,
|
||||
const char* ifaceName,
|
||||
const char* memberName);
|
||||
bool IsNotEnoughArgsError() const { return ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
|
||||
|
||||
// Report a generic error. This should only be used if we're not
|
||||
// some more specific exception type.
|
||||
void ReportGenericError(JSContext* cx);
|
||||
|
@ -189,8 +183,7 @@ private:
|
|||
MOZ_ASSERT(!IsErrorWithMessage(), "Don't overwrite errors with message");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_DOM_JS_EXCEPTION, "Use ThrowJSException()");
|
||||
MOZ_ASSERT(!IsJSException(), "Don't overwrite JS exceptions");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "Use ThrowNotEnoughArgsError()");
|
||||
MOZ_ASSERT(!IsNotEnoughArgsError(), "Don't overwrite not enough args error");
|
||||
MOZ_ASSERT(aRv != NS_ERROR_XPC_NOT_ENOUGH_ARGS, "May need to bring back ThrowNotEnoughArgsError");
|
||||
mResult = aRv;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ ToJSValue(JSContext* aCx,
|
|||
MOZ_ASSERT(!aArgument.IsUncatchableException(),
|
||||
"Doesn't make sense to convert uncatchable exception to a JS value!");
|
||||
AutoForceSetExceptionOnContext forceExn(aCx);
|
||||
DebugOnly<bool> throwResult = ThrowMethodFailedWithDetails(aCx, aArgument, "", "");
|
||||
DebugOnly<bool> throwResult = ThrowMethodFailed(aCx, aArgument);
|
||||
MOZ_ASSERT(!throwResult);
|
||||
DebugOnly<bool> getPendingResult = JS_GetPendingException(aCx, aValue);
|
||||
MOZ_ASSERT(getPendingResult);
|
||||
|
|
|
@ -1047,7 +1047,7 @@ ContentParent::RecvBridgeToChildProcess(const ContentParentId& aCpId)
|
|||
ContentParentId parentId;
|
||||
if (cpm->GetParentProcessId(cp->ChildID(), &parentId) &&
|
||||
parentId == this->ChildID()) {
|
||||
return PContentBridge::Bridge(this, cp);
|
||||
return NS_SUCCEEDED(PContentBridge::Bridge(this, cp));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,13 @@ parent:
|
|||
*/
|
||||
sync GetWidgetNativeData() returns (WindowsHandle value);
|
||||
|
||||
/**
|
||||
* When content moves focus from a native plugin window that's a child
|
||||
* of the native browser window we need to move native focus to the
|
||||
* browser. Otherwise the plugin window will never relinquish focus.
|
||||
*/
|
||||
sync DispatchFocusToTopLevelWindow();
|
||||
|
||||
parent:
|
||||
/**
|
||||
* When child sends this message, parent should move focus to
|
||||
|
|
|
@ -2473,10 +2473,9 @@ TabParent::RecvGetMaxTouchPoints(uint32_t* aTouchPoints)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
already_AddRefed<nsIWidget>
|
||||
TabParent::GetTopLevelWidget()
|
||||
{
|
||||
*aValue = 0;
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
|
||||
if (content) {
|
||||
nsIPresShell* shell = content->OwnerDoc()->GetShell();
|
||||
|
@ -2484,12 +2483,31 @@ TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
|||
nsViewManager* vm = shell->GetViewManager();
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
vm->GetRootWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
*aValue = reinterpret_cast<WindowsHandle>(
|
||||
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
|
||||
}
|
||||
return widget.forget();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue)
|
||||
{
|
||||
*aValue = 0;
|
||||
nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
|
||||
if (widget) {
|
||||
*aValue = reinterpret_cast<WindowsHandle>(
|
||||
widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::RecvDispatchFocusToTopLevelWindow()
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetTopLevelWidget();
|
||||
if (widget) {
|
||||
widget->SetFocus(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ public:
|
|||
}
|
||||
|
||||
already_AddRefed<nsILoadContext> GetLoadContext();
|
||||
|
||||
already_AddRefed<nsIWidget> GetTopLevelWidget();
|
||||
nsIXULBrowserWindow* GetXULBrowserWindow();
|
||||
|
||||
void Destroy();
|
||||
|
@ -218,6 +218,7 @@ public:
|
|||
virtual bool RecvGetDefaultScale(double* aValue) override;
|
||||
virtual bool RecvGetMaxTouchPoints(uint32_t* aTouchPoints) override;
|
||||
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue) override;
|
||||
virtual bool RecvDispatchFocusToTopLevelWindow() override;
|
||||
virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
|
||||
const ViewID& aViewId,
|
||||
const CSSRect& aRect) override;
|
||||
|
|
|
@ -199,7 +199,8 @@ AudioSink::AudioLoop()
|
|||
CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime, mInfo.mRate);
|
||||
|
||||
// Calculate the number of frames that have been pushed onto the audio hardware.
|
||||
CheckedInt64 playedFrames = UsecsToFrames(mStartTime, mInfo.mRate) + mWritten;
|
||||
CheckedInt64 playedFrames = UsecsToFrames(mStartTime, mInfo.mRate) +
|
||||
static_cast<int64_t>(mWritten);
|
||||
|
||||
CheckedInt64 missingFrames = sampleTime - playedFrames;
|
||||
if (!missingFrames.isValid() || !sampleTime.isValid()) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -116,7 +117,7 @@ private:
|
|||
const int64_t mStartTime;
|
||||
|
||||
// PCM frames written to the stream so far.
|
||||
int64_t mWritten;
|
||||
Atomic<int64_t> mWritten;
|
||||
|
||||
// Keep the last good position returned from the audio stream. Used to ensure
|
||||
// position returned by GetPosition() is mono-increasing in spite of audio
|
||||
|
|
|
@ -74,9 +74,16 @@ void FileBlockCache::Close()
|
|||
// opening more streams, while the media cache is shutting down and
|
||||
// releasing memory etc! Also note we close mFD in the destructor so
|
||||
// as to not disturb any IO that's currently running.
|
||||
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mThread);
|
||||
mThread = nullptr;
|
||||
NS_DispatchToMainThread(event);
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
if (mainThread) {
|
||||
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mThread);
|
||||
mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
// we're on Mainthread already, *and* the event queues are already
|
||||
// shut down, so no events should occur - certainly not creations of
|
||||
// new streams.
|
||||
mThread->Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1409,8 +1409,14 @@ MediaCache::QueueUpdate()
|
|||
if (mUpdateQueued)
|
||||
return;
|
||||
mUpdateQueued = true;
|
||||
nsCOMPtr<nsIRunnable> event = new UpdateEvent();
|
||||
NS_DispatchToMainThread(event);
|
||||
// XXX MediaCache does updates when decoders are still running at
|
||||
// shutdown and get freed in the final cycle-collector cleanup. So
|
||||
// don't leak a runnable in that case.
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
if (mainThread) {
|
||||
nsCOMPtr<nsIRunnable> event = new UpdateEvent();
|
||||
mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -647,19 +647,19 @@ void
|
|||
MediaOperationTask::ReturnCallbackError(nsresult rv, const char* errorLog)
|
||||
{
|
||||
MM_LOG(("%s , rv=%d", errorLog, rv));
|
||||
NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
|
||||
mOnTracksAvailableCallback.forget()));
|
||||
NS_DispatchToMainThread(do_AddRef(new ReleaseMediaOperationResource(mStream.forget(),
|
||||
mOnTracksAvailableCallback.forget())));
|
||||
nsString log;
|
||||
|
||||
log.AssignASCII(errorLog);
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess;
|
||||
nsRefPtr<MediaMgrError> error = new MediaMgrError(
|
||||
NS_LITERAL_STRING("InternalError"), log);
|
||||
NS_DispatchToMainThread(
|
||||
NS_DispatchToMainThread(do_AddRef(
|
||||
new ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>(onSuccess,
|
||||
mOnFailure,
|
||||
*error,
|
||||
mWindowID));
|
||||
mWindowID)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1067,9 +1067,9 @@ public:
|
|||
MOZ_ASSERT(!mOnSuccess);
|
||||
MOZ_ASSERT(!mOnFailure);
|
||||
|
||||
NS_DispatchToMainThread(runnable);
|
||||
NS_DispatchToMainThread(runnable.forget());
|
||||
// Do after ErrorCallbackRunnable Run()s, as it checks active window list
|
||||
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, mListener));
|
||||
NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, mListener)));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1111,12 +1111,12 @@ public:
|
|||
peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new GetUserMediaStreamRunnable(
|
||||
NS_DispatchToMainThread(do_AddRef(new GetUserMediaStreamRunnable(
|
||||
mOnSuccess, mOnFailure, mWindowID, mListener,
|
||||
(mAudioDevice? mAudioDevice->GetSource() : nullptr),
|
||||
(mVideoDevice? mVideoDevice->GetSource() : nullptr),
|
||||
peerIdentity
|
||||
));
|
||||
)));
|
||||
|
||||
MOZ_ASSERT(!mOnSuccess);
|
||||
MOZ_ASSERT(!mOnFailure);
|
||||
|
@ -1290,7 +1290,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType
|
|||
}
|
||||
|
||||
SourceSet* handoff = result.forget();
|
||||
NS_DispatchToMainThread(NewRunnableFrom([id, handoff]() mutable {
|
||||
NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, handoff]() mutable {
|
||||
ScopedDeletePtr<SourceSet> result(handoff); // grab result
|
||||
nsRefPtr<MediaManager> mgr = MediaManager_GetInstance();
|
||||
if (!mgr) {
|
||||
|
@ -1301,7 +1301,7 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, MediaSourceEnum aVideoType
|
|||
p->Resolve(result.forget());
|
||||
}
|
||||
return NS_OK;
|
||||
}));
|
||||
})));
|
||||
}));
|
||||
return p.forget();
|
||||
}
|
||||
|
@ -2253,7 +2253,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
// must explicitly do this before dispatching the reply, since the reply may kill us with Stop()
|
||||
mBackend = nullptr; // last reference, will invoke Shutdown() again
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(mReply))) {
|
||||
if (NS_FAILED(NS_DispatchToMainThread(mReply.forget()))) {
|
||||
LOG(("Will leak thread: DispatchToMainthread of reply runnable failed in MediaManager shutdown"));
|
||||
}
|
||||
}
|
||||
|
@ -2727,7 +2727,7 @@ GetUserMediaCallbackMediaStreamListener::NotifyFinished(MediaStreamGraph* aGraph
|
|||
{
|
||||
mFinished = true;
|
||||
Invalidate(); // we know it's been activated
|
||||
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, this));
|
||||
NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, this)));
|
||||
}
|
||||
|
||||
// Called from the MediaStreamGraph thread
|
||||
|
|
|
@ -601,6 +601,7 @@ MediaStreamGraphImpl::UpdateStreamOrder()
|
|||
if (CurrentDriver()->AsAudioCallbackDriver()->IsStarted()) {
|
||||
if (mLifecycleState == LIFECYCLE_RUNNING) {
|
||||
SystemClockDriver* driver = new SystemClockDriver(this);
|
||||
mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
|
||||
CurrentDriver()->SwitchAtNextIteration(driver);
|
||||
}
|
||||
}
|
||||
|
@ -3456,6 +3457,7 @@ MediaStreamGraphImpl::ApplyAudioContextOperationImpl(AudioNodeStream* aStream,
|
|||
EnqueueStreamAndPromiseForOperation(aStream, aPromise, aOperation);
|
||||
|
||||
SystemClockDriver* driver = new SystemClockDriver(this);
|
||||
mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
|
||||
CurrentDriver()->SwitchAtNextIteration(driver);
|
||||
} else {
|
||||
// We are closing or suspending an AudioContext, but something else is
|
||||
|
|
|
@ -45,7 +45,19 @@ public:
|
|||
|
||||
// Forward behaviour to wrapped thread pool implementation.
|
||||
NS_FORWARD_SAFE_NSITHREADPOOL(mPool);
|
||||
NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
|
||||
|
||||
// See bug 1155059 - MSVC forces us to not declare Dispatch normally in idl
|
||||
// NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
|
||||
nsresult Dispatch(nsIRunnable *event, uint32_t flags) { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(event, flags); }
|
||||
|
||||
NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override {
|
||||
return Dispatch(event, flags);
|
||||
}
|
||||
|
||||
NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags) override
|
||||
{ return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(Move(event), flags); }
|
||||
|
||||
NS_IMETHOD IsOnCurrentThread(bool *_retval) override { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->IsOnCurrentThread(_retval); }
|
||||
|
||||
// Creates necessary statics. Called once at startup.
|
||||
static void InitStatics();
|
||||
|
|
|
@ -1052,7 +1052,7 @@ GMPParent::EnsureProcessLoaded(base::ProcessId* aID)
|
|||
bool
|
||||
GMPParent::Bridge(GMPServiceParent* aGMPServiceParent)
|
||||
{
|
||||
if (!PGMPContent::Bridge(aGMPServiceParent, this)) {
|
||||
if (NS_FAILED(PGMPContent::Bridge(aGMPServiceParent, this))) {
|
||||
return false;
|
||||
}
|
||||
++mGMPContentChildCount;
|
||||
|
|
|
@ -129,7 +129,18 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId,
|
|||
// We'll handle the bridging asynchronously
|
||||
return true;
|
||||
}
|
||||
return PPluginModule::Bridge(aContentParent, chromeParent);
|
||||
*rv = PPluginModule::Bridge(aContentParent, chromeParent);
|
||||
if (NS_FAILED(*rv)) {
|
||||
#if defined(MOZ_CRASHREPORTER)
|
||||
// We are going to abort due to the failure, lets note the cause
|
||||
// in the report for diagnosing.
|
||||
nsAutoCString error;
|
||||
error.AppendPrintf("%X", *rv);
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BridgePluginError"), error);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
|
|
|
@ -1215,10 +1215,17 @@ Promise::MaybeReportRejected()
|
|||
// Now post an event to do the real reporting async
|
||||
// Since Promises preserve their wrapper, it is essential to nsRefPtr<> the
|
||||
// AsyncErrorReporter, otherwise if the call to DispatchToMainThread fails, it
|
||||
// will leak. See Bug 958684.
|
||||
nsRefPtr<AsyncErrorReporter> r =
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
|
||||
NS_DispatchToMainThread(r);
|
||||
// will leak. See Bug 958684. So... don't use DispatchToMainThread()
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
if (NS_WARN_IF(!mainThread)) {
|
||||
// Would prefer NS_ASSERTION, but that causes failure in xpcshell tests
|
||||
NS_WARNING("!!! Trying to report rejected Promise after MainThread shutdown");
|
||||
}
|
||||
if (mainThread) {
|
||||
nsRefPtr<AsyncErrorReporter> r =
|
||||
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
|
||||
mainThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
|
||||
|
||||
|
@ -1635,7 +1642,7 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
|
|||
if (!runnable->Dispatch(aCx)) {
|
||||
nsRefPtr<WorkerControlRunnable> runnable =
|
||||
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, this);
|
||||
mWorkerPrivate->DispatchControlRunnable(runnable);
|
||||
mWorkerPrivate->DispatchControlRunnable(runnable.forget());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1756,7 +1756,7 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx));
|
||||
if (NS_FAILED(thread->DispatchPrimaryRunnable(friendKey, runnable))) {
|
||||
if (NS_FAILED(thread->DispatchPrimaryRunnable(friendKey, runnable.forget()))) {
|
||||
UnregisterWorker(aCx, aWorkerPrivate);
|
||||
JS_ReportError(aCx, "Could not dispatch to thread!");
|
||||
return false;
|
||||
|
|
|
@ -322,7 +322,10 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
NS_SUCCEEDED(NS_DispatchToMainThread(this));
|
||||
nsCOMPtr<nsIRunnable> that(this);
|
||||
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(this)))) {
|
||||
NS_ASSERTION(false, "Failed to dispatch update back to MainThread in ServiceWorker");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -812,6 +815,8 @@ ServiceWorkerRegistrationWorkerThread::Update()
|
|||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
// XXX: this pattern guarantees we won't know which thread UpdateRunnable
|
||||
// will die on (here or MainThread)
|
||||
nsRefPtr<UpdateRunnable> r = new UpdateRunnable(worker, mScope);
|
||||
r->Dispatch();
|
||||
}
|
||||
|
|
|
@ -1838,7 +1838,14 @@ public:
|
|||
|
||||
protected:
|
||||
NS_IMETHOD
|
||||
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) override
|
||||
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
return Dispatch(runnable.forget(), aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override
|
||||
{
|
||||
// This should only happen on the timer thread.
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
@ -1849,7 +1856,8 @@ protected:
|
|||
// Run the runnable we're given now (should just call DummyCallback()),
|
||||
// otherwise the timer thread will leak it... If we run this after
|
||||
// dispatch running the event can race against resetting the timer.
|
||||
aRunnable->Run();
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
runnable->Run();
|
||||
|
||||
// This can fail if we're racing to terminate or cancel, should be handled
|
||||
// by the terminate or cancel code.
|
||||
|
@ -2872,10 +2880,11 @@ WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx, JS::Handle<JSObject*> a
|
|||
|
||||
template <class Derived>
|
||||
nsresult
|
||||
WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
|
||||
WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable,
|
||||
nsIEventTarget* aSyncLoopTarget)
|
||||
{
|
||||
// May be called on any thread!
|
||||
nsRefPtr<WorkerRunnable> runnable(aRunnable);
|
||||
|
||||
WorkerPrivate* self = ParentAsWorkerPrivate();
|
||||
|
||||
|
@ -2886,7 +2895,7 @@ WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
|
|||
|
||||
if (!self->mThread) {
|
||||
if (ParentStatus() == Pending || self->mStatus == Pending) {
|
||||
mPreStartRunnables.AppendElement(aRunnable);
|
||||
mPreStartRunnables.AppendElement(runnable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2904,9 +2913,9 @@ WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
|
|||
|
||||
nsresult rv;
|
||||
if (aSyncLoopTarget) {
|
||||
rv = aSyncLoopTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
rv = aSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
rv = self->mThread->Dispatch(WorkerThreadFriendKey(), aRunnable);
|
||||
rv = self->mThread->DispatchAnyThread(WorkerThreadFriendKey(), runnable.forget());
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -2956,13 +2965,11 @@ WorkerPrivateParent<Derived>::DisableDebugger()
|
|||
template <class Derived>
|
||||
nsresult
|
||||
WorkerPrivateParent<Derived>::DispatchControlRunnable(
|
||||
WorkerControlRunnable* aWorkerControlRunnable)
|
||||
already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
MOZ_ASSERT(aWorkerControlRunnable);
|
||||
|
||||
nsRefPtr<WorkerControlRunnable> runnable = aWorkerControlRunnable;
|
||||
nsRefPtr<WorkerControlRunnable> runnable(aWorkerControlRunnable);
|
||||
MOZ_ASSERT(runnable);
|
||||
|
||||
WorkerPrivate* self = ParentAsWorkerPrivate();
|
||||
|
||||
|
@ -2996,13 +3003,13 @@ WorkerPrivateParent<Derived>::DispatchControlRunnable(
|
|||
template <class Derived>
|
||||
nsresult
|
||||
WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
|
||||
WorkerRunnable *aDebuggerRunnable)
|
||||
already_AddRefed<WorkerRunnable>&& aDebuggerRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
MOZ_ASSERT(aDebuggerRunnable);
|
||||
nsRefPtr<WorkerRunnable> runnable(aDebuggerRunnable);
|
||||
|
||||
nsRefPtr<WorkerRunnable> runnable = aDebuggerRunnable;
|
||||
MOZ_ASSERT(runnable);
|
||||
|
||||
WorkerPrivate* self = ParentAsWorkerPrivate();
|
||||
|
||||
|
@ -3026,19 +3033,20 @@ WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
|
|||
|
||||
template <class Derived>
|
||||
already_AddRefed<WorkerRunnable>
|
||||
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable)
|
||||
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
MOZ_ASSERT(aRunnable);
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
MOZ_ASSERT(runnable);
|
||||
|
||||
nsRefPtr<WorkerRunnable> workerRunnable =
|
||||
WorkerRunnable::FromRunnable(aRunnable);
|
||||
WorkerRunnable::FromRunnable(runnable);
|
||||
if (workerRunnable) {
|
||||
return workerRunnable.forget();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
|
||||
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
|
||||
if (!cancelable) {
|
||||
MOZ_CRASH("All runnables destined for a worker thread must be cancelable!");
|
||||
}
|
||||
|
@ -5447,7 +5455,7 @@ WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
|
|||
// to run.
|
||||
if (mPreemptingRunnableInfos.Length() == 1 && !NS_HasPendingEvents(mThread)) {
|
||||
nsRefPtr<DummyRunnable> dummyRunnable = new DummyRunnable(this);
|
||||
if (NS_FAILED(Dispatch(dummyRunnable))) {
|
||||
if (NS_FAILED(Dispatch(dummyRunnable.forget()))) {
|
||||
NS_WARNING("RunBeforeNextEvent called after the thread is shutting "
|
||||
"down!");
|
||||
mPreemptingRunnableInfos.Clear();
|
||||
|
@ -7140,7 +7148,7 @@ WorkerPrivate::SetThread(WorkerThread* aThread)
|
|||
if (!mPreStartRunnables.IsEmpty()) {
|
||||
for (uint32_t index = 0; index < mPreStartRunnables.Length(); index++) {
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
mThread->Dispatch(friendKey, mPreStartRunnables[index])));
|
||||
mThread->DispatchAnyThread(friendKey, mPreStartRunnables[index].forget())));
|
||||
}
|
||||
mPreStartRunnables.Clear();
|
||||
}
|
||||
|
@ -7400,9 +7408,19 @@ NS_INTERFACE_MAP_END
|
|||
template <class Derived>
|
||||
NS_IMETHODIMP
|
||||
WorkerPrivateParent<Derived>::
|
||||
EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
EventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event(aRunnable);
|
||||
return Dispatch(event.forget(), aFlags);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
NS_IMETHODIMP
|
||||
WorkerPrivateParent<Derived>::
|
||||
EventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// May be called on any thread!
|
||||
nsCOMPtr<nsIRunnable> event(aRunnable);
|
||||
|
||||
// Workers only support asynchronous dispatch for now.
|
||||
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
|
||||
|
@ -7419,12 +7437,12 @@ EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (aRunnable) {
|
||||
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
|
||||
if (event) {
|
||||
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(event.forget());
|
||||
}
|
||||
|
||||
nsresult rv =
|
||||
mWorkerPrivate->DispatchPrivate(workerRunnable, mNestedEventTarget);
|
||||
mWorkerPrivate->DispatchPrivate(workerRunnable.forget(), mNestedEventTarget);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ private:
|
|||
ErrorResult& aRv);
|
||||
|
||||
nsresult
|
||||
DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget);
|
||||
DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable, nsIEventTarget* aSyncLoopTarget);
|
||||
|
||||
public:
|
||||
virtual JSObject*
|
||||
|
@ -258,19 +258,19 @@ public:
|
|||
}
|
||||
|
||||
nsresult
|
||||
Dispatch(WorkerRunnable* aRunnable)
|
||||
Dispatch(already_AddRefed<WorkerRunnable>&& aRunnable)
|
||||
{
|
||||
return DispatchPrivate(aRunnable, nullptr);
|
||||
return DispatchPrivate(Move(aRunnable), nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable);
|
||||
DispatchControlRunnable(already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable);
|
||||
|
||||
nsresult
|
||||
DispatchDebuggerRunnable(WorkerRunnable* aDebuggerRunnable);
|
||||
DispatchDebuggerRunnable(already_AddRefed<WorkerRunnable>&& aDebuggerRunnable);
|
||||
|
||||
already_AddRefed<WorkerRunnable>
|
||||
MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable);
|
||||
MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
already_AddRefed<nsIEventTarget>
|
||||
GetEventTarget();
|
||||
|
|
|
@ -136,25 +136,27 @@ WorkerRunnable::Dispatch(JSContext* aCx)
|
|||
bool
|
||||
WorkerRunnable::DispatchInternal()
|
||||
{
|
||||
nsRefPtr<WorkerRunnable> runnable(this);
|
||||
|
||||
if (mBehavior == WorkerThreadModifyBusyCount ||
|
||||
mBehavior == WorkerThreadUnchangedBusyCount) {
|
||||
if (IsDebuggerRunnable()) {
|
||||
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(this));
|
||||
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget()));
|
||||
} else {
|
||||
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this));
|
||||
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(runnable.forget()));
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
|
||||
|
||||
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
|
||||
return NS_SUCCEEDED(parent->Dispatch(this));
|
||||
return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
|
||||
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
|
||||
return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -422,7 +424,8 @@ bool
|
|||
WorkerSyncRunnable::DispatchInternal()
|
||||
{
|
||||
if (mSyncLoopTarget) {
|
||||
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
|
||||
nsRefPtr<WorkerSyncRunnable> runnable(this);
|
||||
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
return WorkerRunnable::DispatchInternal();
|
||||
|
@ -482,7 +485,8 @@ StopSyncLoopRunnable::DispatchInternal()
|
|||
{
|
||||
MOZ_ASSERT(mSyncLoopTarget);
|
||||
|
||||
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
|
||||
nsRefPtr<StopSyncLoopRunnable> runnable(this);
|
||||
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -518,18 +522,20 @@ WorkerControlRunnable::Cancel()
|
|||
bool
|
||||
WorkerControlRunnable::DispatchInternal()
|
||||
{
|
||||
nsRefPtr<WorkerControlRunnable> runnable(this);
|
||||
|
||||
if (mBehavior == WorkerThreadUnchangedBusyCount) {
|
||||
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(this));
|
||||
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
|
||||
}
|
||||
|
||||
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
|
||||
return NS_SUCCEEDED(parent->DispatchControlRunnable(this));
|
||||
return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget()));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
MOZ_ASSERT(mainThread);
|
||||
|
||||
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
|
||||
return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -560,8 +566,9 @@ WorkerMainThreadRunnable::Dispatch(JSContext* aCx)
|
|||
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
|
||||
|
||||
mSyncLoopTarget = syncLoop.EventTarget();
|
||||
nsRefPtr<WorkerMainThreadRunnable> runnable(this);
|
||||
|
||||
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL))) {
|
||||
JS_ReportError(aCx, "Failed to dispatch to main thread!");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -139,11 +139,13 @@ WorkerThread::SetWorker(const WorkerThreadFriendKey& /* aKey */,
|
|||
|
||||
nsresult
|
||||
WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
|
||||
nsIRunnable* aRunnable)
|
||||
already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(PR_GetCurrentThread() != mThread);
|
||||
MOZ_ASSERT(aRunnable);
|
||||
MOZ_ASSERT(runnable);
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
|
@ -152,7 +154,7 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
|
|||
}
|
||||
#endif
|
||||
|
||||
nsresult rv = nsThread::Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
nsresult rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -161,8 +163,8 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
|
|||
}
|
||||
|
||||
nsresult
|
||||
WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
|
||||
WorkerRunnable* aWorkerRunnable)
|
||||
WorkerThread::DispatchAnyThread(const WorkerThreadFriendKey& /* aKey */,
|
||||
already_AddRefed<WorkerRunnable>&& aWorkerRunnable)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
|
@ -181,8 +183,9 @@ WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
|
|||
}
|
||||
}
|
||||
#endif
|
||||
nsCOMPtr<nsIRunnable> runnable(aWorkerRunnable);
|
||||
|
||||
nsresult rv = nsThread::Dispatch(aWorkerRunnable, NS_DISPATCH_NORMAL);
|
||||
nsresult rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -197,9 +200,17 @@ WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
|
|||
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThread, nsThread)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
WorkerThread::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
return Dispatch(runnable.forget(), aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// May be called on any thread!
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable); // in case we exit early
|
||||
|
||||
// Workers only support asynchronous dispatch.
|
||||
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
|
||||
|
@ -209,8 +220,8 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
|||
const bool onWorkerThread = PR_GetCurrentThread() == mThread;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aRunnable && !onWorkerThread) {
|
||||
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
|
||||
if (runnable && !onWorkerThread) {
|
||||
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
@ -245,18 +256,14 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
|||
}
|
||||
}
|
||||
|
||||
nsIRunnable* runnableToDispatch;
|
||||
nsRefPtr<WorkerRunnable> workerRunnable;
|
||||
|
||||
if (aRunnable && onWorkerThread) {
|
||||
workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
|
||||
runnableToDispatch = workerRunnable;
|
||||
nsresult rv;
|
||||
if (runnable && onWorkerThread) {
|
||||
nsRefPtr<WorkerRunnable> workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
|
||||
rv = nsThread::Dispatch(workerRunnable.forget(), NS_DISPATCH_NORMAL);
|
||||
} else {
|
||||
runnableToDispatch = aRunnable;
|
||||
rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL);
|
||||
|
||||
if (!onWorkerThread && workerPrivate) {
|
||||
// We need to wake the worker thread if we're not already on the right
|
||||
// thread and the dispatch succeeded.
|
||||
|
|
|
@ -66,11 +66,11 @@ public:
|
|||
|
||||
nsresult
|
||||
DispatchPrimaryRunnable(const WorkerThreadFriendKey& aKey,
|
||||
nsIRunnable* aRunnable);
|
||||
already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
nsresult
|
||||
Dispatch(const WorkerThreadFriendKey& aKey,
|
||||
WorkerRunnable* aWorkerRunnable);
|
||||
DispatchAnyThread(const WorkerThreadFriendKey& aKey,
|
||||
already_AddRefed<WorkerRunnable>&& aWorkerRunnable);
|
||||
|
||||
uint32_t
|
||||
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
|
||||
|
@ -84,7 +84,10 @@ private:
|
|||
// This should only be called by consumers that have an
|
||||
// nsIEventTarget/nsIThread pointer.
|
||||
NS_IMETHOD
|
||||
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) override;
|
||||
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override;
|
||||
|
||||
NS_IMETHOD
|
||||
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
|
|
@ -66,7 +66,6 @@ FontInfoLoadCompleteEvent::Run()
|
|||
|
||||
loader->FinalizeLoader(mFontInfo);
|
||||
|
||||
mFontInfo = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -81,7 +80,6 @@ AsyncFontInfoLoader::Run()
|
|||
|
||||
// post a completion event that transfer the data to the fontlist
|
||||
NS_DispatchToMainThread(mCompleteEvent);
|
||||
mFontInfo = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -140,23 +138,27 @@ gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
|
|||
InitLoader();
|
||||
|
||||
// start async load
|
||||
mState = stateAsyncLoad;
|
||||
nsresult rv = NS_NewNamedThread("Font Loader",
|
||||
getter_AddRefs(mFontLoaderThread),
|
||||
nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
mState = stateAsyncLoad;
|
||||
|
||||
nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
|
||||
|
||||
mFontLoaderThread->Dispatch(loadEvent, NS_DISPATCH_NORMAL);
|
||||
mFontLoaderThread->Dispatch(loadEvent.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo)
|
||||
{
|
||||
// avoid loading data if loader has already been canceled
|
||||
// Avoid loading data if loader has already been canceled.
|
||||
// This should mean that CancelLoader() ran and the Load
|
||||
// thread has already Shutdown(), and likely before processing
|
||||
// the Shutdown event it handled the load event and sent back
|
||||
// our Completion event, thus we end up here.
|
||||
if (mState != stateAsyncLoad) {
|
||||
return;
|
||||
}
|
||||
|
@ -187,8 +189,11 @@ gfxFontInfoLoader::CancelLoader()
|
|||
mTimer = nullptr;
|
||||
}
|
||||
if (mFontLoaderThread) {
|
||||
mFontLoaderThread->Shutdown();
|
||||
mFontLoaderThread = nullptr;
|
||||
// NOTE: Shutdown() runs the event loop, and we can get timer events
|
||||
// ensure that we can't try to do this twice!
|
||||
nsCOMPtr<nsIThread> temp;
|
||||
temp.swap(mFontLoaderThread);
|
||||
temp->Shutdown();
|
||||
}
|
||||
RemoveShutdownObserver();
|
||||
CleanupLoader();
|
||||
|
|
|
@ -179,34 +179,41 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
bool
|
||||
nsresult
|
||||
Bridge(const PrivateIPDLInterface&,
|
||||
MessageChannel* aParentChannel, ProcessId aParentPid,
|
||||
MessageChannel* aChildChannel, ProcessId aChildPid,
|
||||
ProtocolId aProtocol, ProtocolId aChildProtocol)
|
||||
{
|
||||
if (!aParentPid || !aChildPid) {
|
||||
return false;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
TransportDescriptor parentSide, childSide;
|
||||
if (!CreateTransport(aParentPid, &parentSide, &childSide)) {
|
||||
return false;
|
||||
nsresult rv;
|
||||
if (NS_FAILED(rv = CreateTransport(aParentPid, &parentSide, &childSide))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!aParentChannel->Send(new ChannelOpened(parentSide,
|
||||
aChildPid,
|
||||
aProtocol,
|
||||
IPC::Message::PRIORITY_URGENT)) ||
|
||||
!aChildChannel->Send(new ChannelOpened(childSide,
|
||||
aParentPid,
|
||||
aChildProtocol,
|
||||
IPC::Message::PRIORITY_URGENT))) {
|
||||
IPC::Message::PRIORITY_URGENT))) {
|
||||
CloseDescriptor(parentSide);
|
||||
CloseDescriptor(childSide);
|
||||
return false;
|
||||
return NS_ERROR_BRIDGE_OPEN_PARENT;
|
||||
}
|
||||
return true;
|
||||
|
||||
if (!aChildChannel->Send(new ChannelOpened(childSide,
|
||||
aParentPid,
|
||||
aChildProtocol,
|
||||
IPC::Message::PRIORITY_URGENT))) {
|
||||
CloseDescriptor(parentSide);
|
||||
CloseDescriptor(childSide);
|
||||
return NS_ERROR_BRIDGE_OPEN_CHILD;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -224,7 +231,7 @@ Open(const PrivateIPDLInterface&,
|
|||
}
|
||||
|
||||
TransportDescriptor parentSide, childSide;
|
||||
if (!CreateTransport(parentId, &parentSide, &childSide)) {
|
||||
if (NS_FAILED(CreateTransport(parentId, &parentSide, &childSide))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -295,7 +295,7 @@ FatalError(const char* aProtocolName, const char* aMsg,
|
|||
|
||||
struct PrivateIPDLInterface {};
|
||||
|
||||
bool
|
||||
nsresult
|
||||
Bridge(const PrivateIPDLInterface&,
|
||||
MessageChannel*, base::ProcessId, MessageChannel*, base::ProcessId,
|
||||
ProtocolId, ProtocolId);
|
||||
|
|
|
@ -24,8 +24,9 @@ class FileDescriptor;
|
|||
|
||||
typedef IPC::Channel Transport;
|
||||
|
||||
bool CreateTransport(base::ProcessId aProcIdOne,
|
||||
TransportDescriptor* aOne, TransportDescriptor* aTwo);
|
||||
nsresult CreateTransport(base::ProcessId aProcIdOne,
|
||||
TransportDescriptor* aOne,
|
||||
TransportDescriptor* aTwo);
|
||||
|
||||
Transport* OpenDescriptor(const TransportDescriptor& aTd,
|
||||
Transport::Mode aMode);
|
||||
|
|
|
@ -21,9 +21,10 @@ using base::ProcessHandle;
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
bool
|
||||
CreateTransport(base::ProcessId /*unused*/,
|
||||
TransportDescriptor* aOne, TransportDescriptor* aTwo)
|
||||
nsresult
|
||||
CreateTransport(base::ProcessId aProcIdOne,
|
||||
TransportDescriptor* aOne,
|
||||
TransportDescriptor* aTwo)
|
||||
{
|
||||
wstring id = IPC::Channel::GenerateVerifiedChannelID(std::wstring());
|
||||
// Use MODE_SERVER to force creation of the socketpair
|
||||
|
@ -32,7 +33,7 @@ CreateTransport(base::ProcessId /*unused*/,
|
|||
int fd2, dontcare;
|
||||
t.GetClientFileDescriptorMapping(&fd2, &dontcare);
|
||||
if (fd1 < 0 || fd2 < 0) {
|
||||
return false;
|
||||
return NS_ERROR_TRANSPORT_INIT;
|
||||
}
|
||||
|
||||
// The Transport closes these fds when it goes out of scope, so we
|
||||
|
@ -40,12 +41,12 @@ CreateTransport(base::ProcessId /*unused*/,
|
|||
fd1 = dup(fd1);
|
||||
fd2 = dup(fd2);
|
||||
if (fd1 < 0 || fd2 < 0) {
|
||||
return false;
|
||||
return NS_ERROR_DUPLICATE_HANDLE;
|
||||
}
|
||||
|
||||
aOne->mFd = base::FileDescriptor(fd1, true/*close after sending*/);
|
||||
aTwo->mFd = base::FileDescriptor(fd2, true/*close after sending*/);
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Transport*
|
||||
|
|
|
@ -18,16 +18,17 @@ using base::ProcessHandle;
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
bool
|
||||
nsresult
|
||||
CreateTransport(base::ProcessId aProcIdOne,
|
||||
TransportDescriptor* aOne, TransportDescriptor* aTwo)
|
||||
TransportDescriptor* aOne,
|
||||
TransportDescriptor* aTwo)
|
||||
{
|
||||
wstring id = IPC::Channel::GenerateVerifiedChannelID(std::wstring());
|
||||
// Use MODE_SERVER to force creation of the pipe
|
||||
Transport t(id, Transport::MODE_SERVER, nullptr);
|
||||
HANDLE serverPipe = t.GetServerPipeHandle();
|
||||
if (!serverPipe) {
|
||||
return false;
|
||||
return NS_ERROR_TRANSPORT_INIT;
|
||||
}
|
||||
|
||||
// NB: we create the server pipe immediately, instead of just
|
||||
|
@ -39,13 +40,13 @@ CreateTransport(base::ProcessId aProcIdOne,
|
|||
DWORD access = 0;
|
||||
DWORD options = DUPLICATE_SAME_ACCESS;
|
||||
if (!DuplicateHandle(serverPipe, aProcIdOne, &serverDup, access, options)) {
|
||||
return false;
|
||||
return NS_ERROR_DUPLICATE_HANDLE;
|
||||
}
|
||||
|
||||
aOne->mPipeName = aTwo->mPipeName = id;
|
||||
aOne->mServerPipe = serverDup;
|
||||
aTwo->mServerPipe = INVALID_HANDLE_VALUE;
|
||||
return true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Transport*
|
||||
|
|
|
@ -331,6 +331,7 @@ Type.BOOL = Type('bool')
|
|||
Type.INT = Type('int')
|
||||
Type.INT32 = Type('int32_t')
|
||||
Type.INTPTR = Type('intptr_t')
|
||||
Type.NSRESULT = Type('nsresult')
|
||||
Type.UINT32 = Type('uint32_t')
|
||||
Type.UINT32PTR = Type('uint32_t', ptr=1)
|
||||
Type.SIZE = Type('size_t')
|
||||
|
|
|
@ -1680,7 +1680,7 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
|||
'Bridge',
|
||||
params=[ Decl(parentHandleType, parentvar.name),
|
||||
Decl(childHandleType, childvar.name) ],
|
||||
ret=Type.BOOL))
|
||||
ret=Type.NSRESULT))
|
||||
bridgefunc.addstmt(StmtReturn(ExprCall(
|
||||
ExprVar('mozilla::ipc::Bridge'),
|
||||
args=[ _backstagePass(),
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
var asmdiv2 = (function(m) {
|
||||
"use asm"
|
||||
function f(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) / 2)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
return f;
|
||||
})()
|
||||
|
||||
var plaindiv2 = function(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) / 2)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
|
||||
var k2 = 0xf0000000;
|
||||
|
||||
assertEq(asmdiv2(k2), 0x78000000);
|
||||
assertEq(plaindiv2(k2), 0x78000000);
|
||||
|
||||
var asmdiv3 = (function(m) {
|
||||
"use asm"
|
||||
function f(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) / 3)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
return f;
|
||||
})()
|
||||
|
||||
var plaindiv3 = function(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) / 3)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
|
||||
var k3 = 3<<30;
|
||||
|
||||
assertEq(asmdiv3(k3), 1<<30);
|
||||
assertEq(plaindiv3(k3), 1<<30);
|
||||
|
||||
var asmdiv7 = (function(m) {
|
||||
"use asm"
|
||||
function f(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) / 7)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
return f;
|
||||
})()
|
||||
|
||||
var plaindiv7 = function(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) / 7)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
|
||||
var k7 = (1<<29)*7 + 4;
|
||||
|
||||
assertEq(asmdiv7(k7), 1<<29);
|
||||
assertEq(plaindiv7(k7), 1<<29);
|
||||
|
||||
var asmmod3 = (function(m) {
|
||||
"use asm"
|
||||
function f(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) % 3)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
return f;
|
||||
})()
|
||||
|
||||
var plainmod3 = function(x) {
|
||||
x = x|0;
|
||||
var z = 0;
|
||||
z = ((x>>>0) % 3)>>>0;
|
||||
return z|0;
|
||||
}
|
||||
|
||||
var kmod = (3<<30) + 2;
|
||||
|
||||
assertEq(asmmod3(kmod), 2);
|
||||
assertEq(plainmod3(kmod), 2);
|
|
@ -6386,6 +6386,16 @@ class MDiv : public MBinaryArithInstruction
|
|||
}
|
||||
|
||||
bool canBeNegativeDividend() const {
|
||||
// "Dividend" is an ambiguous concept for unsigned truncated
|
||||
// division, because of the truncation procedure:
|
||||
// ((x>>>0)/2)|0, for example, gets transformed in
|
||||
// MDiv::truncate into a node with lhs representing x (not
|
||||
// x>>>0) and rhs representing the constant 2; in other words,
|
||||
// the MIR node corresponds to "cast operands to unsigned and
|
||||
// divide" operation. In this case, is the dividend x or is it
|
||||
// x>>>0? In order to resolve such ambiguities, we disallow
|
||||
// the usage of this method for unsigned division.
|
||||
MOZ_ASSERT(!unsigned_);
|
||||
return canBeNegativeDividend_;
|
||||
}
|
||||
|
||||
|
@ -6469,6 +6479,7 @@ class MMod : public MBinaryArithInstruction
|
|||
|
||||
bool canBeNegativeDividend() const {
|
||||
MOZ_ASSERT(specialization_ == MIRType_Int32);
|
||||
MOZ_ASSERT(!unsigned_);
|
||||
return canBeNegativeDividend_;
|
||||
}
|
||||
|
||||
|
|
|
@ -1574,45 +1574,56 @@ CodeGeneratorShared::addCacheLocations(const CacheLocationList& locs, size_t* nu
|
|||
}
|
||||
|
||||
ReciprocalMulConstants
|
||||
CodeGeneratorShared::computeDivisionConstants(int d) {
|
||||
// In what follows, d is positive and is not a power of 2.
|
||||
MOZ_ASSERT(d > 0 && (d & (d - 1)) != 0);
|
||||
CodeGeneratorShared::computeDivisionConstants(uint32_t d, int maxLog) {
|
||||
MOZ_ASSERT(maxLog >= 2 && maxLog <= 32);
|
||||
// In what follows, 0 < d < 2^maxLog and d is not a power of 2.
|
||||
MOZ_ASSERT(d < (uint64_t(1) << maxLog) && (d & (d - 1)) != 0);
|
||||
|
||||
// Speeding up division by non power-of-2 constants is possible by
|
||||
// calculating, during compilation, a value M such that high-order
|
||||
// bits of M*n correspond to the result of the division. Formally,
|
||||
// we compute values 0 <= M < 2^32 and 0 <= s < 31 such that
|
||||
// (M * n) >> (32 + s) = floor(n/d) if n >= 0
|
||||
// (M * n) >> (32 + s) = ceil(n/d) - 1 if n < 0.
|
||||
// bits of M*n correspond to the result of the division of n by d.
|
||||
// No value of M can serve this purpose for arbitrarily big values
|
||||
// of n but, for optimizing integer division, we're just concerned
|
||||
// with values of n whose absolute value is bounded (by fitting in
|
||||
// an integer type, say). With this in mind, we'll find a constant
|
||||
// M as above that works for -2^maxLog <= n < 2^maxLog; maxLog can
|
||||
// then be 31 for signed division or 32 for unsigned division.
|
||||
//
|
||||
// The original presentation of this technique appears in Hacker's
|
||||
// Delight, a book by Henry S. Warren, Jr.. A proof of correctness
|
||||
// for our version follows.
|
||||
|
||||
// Define p = 32 + s, M = ceil(2^p/d), and assume that s satisfies
|
||||
// M - 2^p/d <= 2^(s+1)/d. (1)
|
||||
// (Observe that s = FloorLog32(d) satisfies this, because in this
|
||||
// case d <= 2^(s+1) and so the RHS of (1) is at least one). Then,
|
||||
// for our version follows; we'll denote maxLog by L in the proof,
|
||||
// for conciseness.
|
||||
//
|
||||
// a) If s <= FloorLog32(d), then M <= 2^32 - 1.
|
||||
// Proof: Indeed, M is monotone in s and, for s = FloorLog32(d),
|
||||
// the inequalities 2^31 > d >= 2^s + 1 readily imply
|
||||
// 2^p / d = 2^p/(d - 1) * (d - 1)/d
|
||||
// <= 2^32 * (1 - 1/d) < 2 * (2^31 - 1) = 2^32 - 2.
|
||||
// Formally, for |d| < 2^L, we'll compute two magic values M and s
|
||||
// in the ranges 0 <= M < 2^(L+1) and 0 <= s <= L such that
|
||||
// (M * n) >> (32 + s) = floor(n/d) if 0 <= n < 2^L
|
||||
// (M * n) >> (32 + s) = ceil(n/d) - 1 if -2^L <= n < 0.
|
||||
//
|
||||
// Define p = 32 + s, M = ceil(2^p/d), and assume that s satisfies
|
||||
// M - 2^p/d <= 2^(p-L)/d. (1)
|
||||
// (Observe that p = CeilLog32(d) + L satisfies this, as the right
|
||||
// side of (1) is at least one in this case). Then,
|
||||
//
|
||||
// a) If p <= CeilLog32(d) + L, then M < 2^(L+1) - 1.
|
||||
// Proof: Indeed, M is monotone in p and, for p equal to the above
|
||||
// value, the bounds 2^L > d >= 2^(p-L-1) + 1 readily imply that
|
||||
// 2^p / d < 2^p/(d - 1) * (d - 1)/d
|
||||
// <= 2^(L+1) * (1 - 1/d) < 2^(L+1) - 2.
|
||||
// The claim follows by applying the ceiling function.
|
||||
//
|
||||
// b) For any 0 <= n < 2^31, floor(Mn/2^p) = floor(n/d).
|
||||
// b) For any 0 <= n < 2^L, floor(Mn/2^p) = floor(n/d).
|
||||
// Proof: Put x = floor(Mn/2^p); it's the unique integer for which
|
||||
// Mn/2^p - 1 < x <= Mn/2^p. (2)
|
||||
// Using M >= 2^p/d on the LHS and (1) on the RHS, we get
|
||||
// n/d - 1 < x <= n/d + n/(2^31 d) < n/d + 1/d.
|
||||
// n/d - 1 < x <= n/d + n/(2^L d) < n/d + 1/d.
|
||||
// Since x is an integer, it's not in the interval (n/d, (n+1)/d),
|
||||
// and so n/d - 1 < x <= n/d, which implies x = floor(n/d).
|
||||
//
|
||||
// c) For any -2^31 <= n < 0, floor(Mn/2^p) + 1 = ceil(n/d).
|
||||
// c) For any -2^L <= n < 0, floor(Mn/2^p) + 1 = ceil(n/d).
|
||||
// Proof: The proof is similar. Equation (2) holds as above. Using
|
||||
// M > 2^p/d (d isn't a power of 2) on the RHS and (1) on the LHS,
|
||||
// n/d + n/(2^31 d) - 1 < x < n/d.
|
||||
// Using n >= -2^31 and summing 1,
|
||||
// n/d + n/(2^L d) - 1 < x < n/d.
|
||||
// Using n >= -2^L and summing 1,
|
||||
// n/d - 1/d < x + 1 < n/d + 1.
|
||||
// Since x + 1 is an integer, this implies n/d <= x + 1 < n/d + 1.
|
||||
// In other words, x + 1 = ceil(n/d).
|
||||
|
@ -1620,27 +1631,30 @@ CodeGeneratorShared::computeDivisionConstants(int d) {
|
|||
// Condition (1) isn't necessary for the existence of M and s with
|
||||
// the properties above. Hacker's Delight provides a slightly less
|
||||
// restrictive condition when d >= 196611, at the cost of a 3-page
|
||||
// proof of correctness.
|
||||
|
||||
// proof of correctness, for the case L = 31.
|
||||
//
|
||||
// Note that, since d*M - 2^p = d - (2^p)%d, (1) can be written as
|
||||
// 2^(s+1) >= d - (2^p)%d.
|
||||
// We now compute the least s with this property...
|
||||
// 2^(p-L) >= d - (2^p)%d.
|
||||
// In order to avoid overflow in the (2^p) % d calculation, we can
|
||||
// compute it as (2^p-1) % d + 1, where 2^p-1 can then be computed
|
||||
// without overflow as UINT64_MAX >> (64-p).
|
||||
|
||||
int32_t shift = 0;
|
||||
while ((int64_t(1) << (shift+1)) + (int64_t(1) << (shift+32)) % d < d)
|
||||
shift++;
|
||||
// We now compute the least p >= 32 with the property above...
|
||||
int32_t p = 32;
|
||||
while ((uint64_t(1) << (p-maxLog)) + (UINT64_MAX >> (64-p)) % d + 1 < d)
|
||||
p++;
|
||||
|
||||
// ...and the corresponding M. This may not fit in a signed 32-bit
|
||||
// integer; we will compute (M - 2^32) * n + (2^32 * n) instead of
|
||||
// M * n if this is the case (cf. item (a) above).
|
||||
// ...and the corresponding M. For either the signed (L=31) or the
|
||||
// unsigned (L=32) case, this value can be too large (cf. item a).
|
||||
// Codegen can still multiply by M by multiplying by (M - 2^L) and
|
||||
// adjusting the value afterwards, if this is the case.
|
||||
ReciprocalMulConstants rmc;
|
||||
rmc.multiplier = int32_t((int64_t(1) << (shift+32))/d + 1);
|
||||
rmc.shiftAmount = shift;
|
||||
rmc.multiplier = (UINT64_MAX >> (64-p))/d + 1;
|
||||
rmc.shiftAmount = p - 32;
|
||||
|
||||
return rmc;
|
||||
}
|
||||
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
|
||||
void
|
||||
|
|
|
@ -45,7 +45,7 @@ struct PatchableBackedgeInfo
|
|||
};
|
||||
|
||||
struct ReciprocalMulConstants {
|
||||
int32_t multiplier;
|
||||
int64_t multiplier;
|
||||
int32_t shiftAmount;
|
||||
};
|
||||
|
||||
|
@ -447,7 +447,7 @@ class CodeGeneratorShared : public LElementVisitor
|
|||
|
||||
void addCache(LInstruction* lir, size_t cacheIndex);
|
||||
size_t addCacheLocations(const CacheLocationList& locs, size_t* numLocs);
|
||||
ReciprocalMulConstants computeDivisionConstants(int d);
|
||||
ReciprocalMulConstants computeDivisionConstants(uint32_t d, int maxLog);
|
||||
|
||||
protected:
|
||||
void addOutOfLineCode(OutOfLineCode* code, const MInstruction* mir);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
_(AsmJSLoadFuncPtr) \
|
||||
_(SimdValueInt32x4) \
|
||||
_(SimdValueFloat32x4) \
|
||||
_(UDivOrMod)
|
||||
_(UDivOrMod) \
|
||||
_(UDivOrModConstant)
|
||||
|
||||
#endif /* jit_x64_LOpcodes_x64_h */
|
||||
|
|
|
@ -1357,6 +1357,9 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
void imull(Register multiplier) {
|
||||
masm.imull_r(multiplier.encoding());
|
||||
}
|
||||
void umull(Register multiplier) {
|
||||
masm.mull_r(multiplier.encoding());
|
||||
}
|
||||
void imull(Imm32 imm, Register dest) {
|
||||
masm.imull_ir(imm.value, dest.encoding(), dest.encoding());
|
||||
}
|
||||
|
|
|
@ -1319,6 +1319,12 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
void mull_r(RegisterID multiplier)
|
||||
{
|
||||
spew("mull %s", GPReg32Name(multiplier));
|
||||
m_formatter.oneByteOp(OP_GROUP3_Ev, multiplier, GROUP3_OP_MUL);
|
||||
}
|
||||
|
||||
void idivl_r(RegisterID divisor)
|
||||
{
|
||||
spew("idivl %s", GPReg32Name(divisor));
|
||||
|
|
|
@ -1005,6 +1005,82 @@ CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod* ins)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitUDivOrModConstant(LUDivOrModConstant *ins) {
|
||||
Register lhs = ToRegister(ins->numerator());
|
||||
Register output = ToRegister(ins->output());
|
||||
uint32_t d = ins->denominator();
|
||||
|
||||
// This emits the division answer into edx or the modulus answer into eax.
|
||||
MOZ_ASSERT(output == eax || output == edx);
|
||||
MOZ_ASSERT(lhs != eax && lhs != edx);
|
||||
bool isDiv = (output == edx);
|
||||
|
||||
if (d == 0) {
|
||||
if (ins->mir()->isTruncated())
|
||||
masm.xorl(output, output);
|
||||
else
|
||||
bailout(ins->snapshot());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The denominator isn't a power of 2 (see LDivPowTwoI and LModPowTwoI).
|
||||
MOZ_ASSERT((d & (d - 1)) != 0);
|
||||
|
||||
ReciprocalMulConstants rmc = computeDivisionConstants(d, /* maxLog = */ 32);
|
||||
|
||||
// We first compute (M * n) >> 32, where M = rmc.multiplier.
|
||||
masm.movl(Imm32(rmc.multiplier), eax);
|
||||
masm.umull(lhs);
|
||||
if (rmc.multiplier > UINT32_MAX) {
|
||||
// M >= 2^32 and shift == 0 is impossible, as d >= 2 implies that
|
||||
// ((M * n) >> (32 + shift)) >= n > floor(n/d) whenever n >= d, contradicting
|
||||
// the proof of correctness in computeDivisionConstants.
|
||||
MOZ_ASSERT(rmc.shiftAmount > 0);
|
||||
MOZ_ASSERT(rmc.multiplier < (int64_t(1) << 33));
|
||||
|
||||
// We actually computed edx = ((uint32_t(M) * n) >> 32) instead. Since
|
||||
// (M * n) >> (32 + shift) is the same as (edx + n) >> shift, we can
|
||||
// correct for the overflow. This case is a bit trickier than the signed
|
||||
// case, though, as the (edx + n) addition itself can overflow; however,
|
||||
// note that (edx + n) >> shift == (((n - edx) >> 1) + edx) >> (shift - 1),
|
||||
// which is overflow-free. See Hacker's Delight, section 10-8 for details.
|
||||
|
||||
// Compute (n - edx) >> 1 into eax.
|
||||
masm.movl(lhs, eax);
|
||||
masm.subl(edx, eax);
|
||||
masm.shrl(Imm32(1), eax);
|
||||
|
||||
// Finish the computation.
|
||||
masm.addl(eax, edx);
|
||||
masm.shrl(Imm32(rmc.shiftAmount - 1), edx);
|
||||
} else {
|
||||
masm.shrl(Imm32(rmc.shiftAmount), edx);
|
||||
}
|
||||
|
||||
// We now have the truncated division value in edx. If we're
|
||||
// computing a modulus or checking whether the division resulted
|
||||
// in an integer, we need to multiply the obtained value by d and
|
||||
// finish the computation/check.
|
||||
if (!isDiv) {
|
||||
masm.imull(Imm32(d), edx, edx);
|
||||
masm.movl(lhs, eax);
|
||||
masm.subl(edx, eax);
|
||||
|
||||
// The final result of the modulus op, just computed above by the
|
||||
// sub instruction, can be a number in the range [2^31, 2^32). If
|
||||
// this is the case and the modulus is not truncated, we must bail
|
||||
// out.
|
||||
if (!ins->mir()->isTruncated())
|
||||
bailoutIf(Assembler::Signed, ins->snapshot());
|
||||
} else if (!ins->mir()->isTruncated()) {
|
||||
masm.imull(Imm32(d), edx, eax);
|
||||
masm.cmpl(lhs, eax);
|
||||
bailoutIf(Assembler::NotEqual, ins->snapshot());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitMulNegativeZeroCheck(MulNegativeZeroCheck* ool)
|
||||
{
|
||||
|
@ -1050,21 +1126,26 @@ CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI* ins)
|
|||
bailoutIf(Assembler::NonZero, ins->snapshot());
|
||||
}
|
||||
|
||||
// Adjust the value so that shifting produces a correctly rounded result
|
||||
// when the numerator is negative. See 10-1 "Signed Division by a Known
|
||||
// Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
|
||||
if (mir->canBeNegativeDividend()) {
|
||||
Register lhsCopy = ToRegister(ins->numeratorCopy());
|
||||
MOZ_ASSERT(lhsCopy != lhs);
|
||||
if (shift > 1)
|
||||
masm.sarl(Imm32(31), lhs);
|
||||
masm.shrl(Imm32(32 - shift), lhs);
|
||||
masm.addl(lhsCopy, lhs);
|
||||
}
|
||||
if (mir->isUnsigned()) {
|
||||
masm.shrl(Imm32(shift), lhs);
|
||||
} else {
|
||||
// Adjust the value so that shifting produces a correctly
|
||||
// rounded result when the numerator is negative. See 10-1
|
||||
// "Signed Division by a Known Power of 2" in Henry
|
||||
// S. Warren, Jr.'s Hacker's Delight.
|
||||
if (mir->canBeNegativeDividend()) {
|
||||
Register lhsCopy = ToRegister(ins->numeratorCopy());
|
||||
MOZ_ASSERT(lhsCopy != lhs);
|
||||
if (shift > 1)
|
||||
masm.sarl(Imm32(31), lhs);
|
||||
masm.shrl(Imm32(32 - shift), lhs);
|
||||
masm.addl(lhsCopy, lhs);
|
||||
}
|
||||
masm.sarl(Imm32(shift), lhs);
|
||||
|
||||
masm.sarl(Imm32(shift), lhs);
|
||||
if (negativeDivisor)
|
||||
masm.negl(lhs);
|
||||
if (negativeDivisor)
|
||||
masm.negl(lhs);
|
||||
}
|
||||
} else if (shift == 0 && negativeDivisor) {
|
||||
// INT32_MIN / -1 overflows.
|
||||
masm.negl(lhs);
|
||||
|
@ -1090,17 +1171,23 @@ CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI* ins) {
|
|||
|
||||
// We will first divide by Abs(d), and negate the answer if d is negative.
|
||||
// If desired, this can be avoided by generalizing computeDivisionConstants.
|
||||
ReciprocalMulConstants rmc = computeDivisionConstants(Abs(d));
|
||||
ReciprocalMulConstants rmc = computeDivisionConstants(Abs(d), /* maxLog = */ 31);
|
||||
|
||||
// As explained in the comments of computeDivisionConstants, we first compute
|
||||
// X >> (32 + shift), where X is either (rmc.multiplier * n) if the multiplier
|
||||
// is non-negative or (rmc.multiplier * n) + (2^32 * n) otherwise. This is the
|
||||
// desired division result if n is non-negative, and is one less than the result
|
||||
// otherwise.
|
||||
// We first compute (M * n) >> 32, where M = rmc.multiplier.
|
||||
masm.movl(Imm32(rmc.multiplier), eax);
|
||||
masm.imull(lhs);
|
||||
if (rmc.multiplier < 0)
|
||||
if (rmc.multiplier > INT32_MAX) {
|
||||
MOZ_ASSERT(rmc.multiplier < (int64_t(1) << 32));
|
||||
|
||||
// We actually computed edx = ((int32_t(M) * n) >> 32) instead. Since
|
||||
// (M * n) >> 32 is the same as (edx + n), we can correct for the overflow.
|
||||
// (edx + n) can't overflow, as n and edx have opposite signs because int32_t(M)
|
||||
// is negative.
|
||||
masm.addl(lhs, edx);
|
||||
}
|
||||
// (M * n) >> (32 + shift) is the truncated division answer if n is non-negative,
|
||||
// as proved in the comments of computeDivisionConstants. We must add 1 later if n is
|
||||
// negative to get the right answer in all cases.
|
||||
masm.sarl(Imm32(rmc.shiftAmount), edx);
|
||||
|
||||
// We'll subtract -1 instead of adding 1, because (n < 0 ? -1 : 0) can be
|
||||
|
@ -1242,7 +1329,7 @@ CodeGeneratorX86Shared::visitModPowTwoI(LModPowTwoI* ins)
|
|||
|
||||
Label negative;
|
||||
|
||||
if (ins->mir()->canBeNegativeDividend()) {
|
||||
if (!ins->mir()->isUnsigned() && ins->mir()->canBeNegativeDividend()) {
|
||||
// Switch based on sign of the lhs.
|
||||
// Positive numbers are just a bitmask
|
||||
masm.branchTest32(Assembler::Signed, lhs, lhs, &negative);
|
||||
|
@ -1250,7 +1337,7 @@ CodeGeneratorX86Shared::visitModPowTwoI(LModPowTwoI* ins)
|
|||
|
||||
masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
|
||||
|
||||
if (ins->mir()->canBeNegativeDividend()) {
|
||||
if (!ins->mir()->isUnsigned() && ins->mir()->canBeNegativeDividend()) {
|
||||
Label done;
|
||||
masm.jump(&done);
|
||||
|
||||
|
|
|
@ -242,6 +242,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||
virtual void visitGuardClass(LGuardClass* guard);
|
||||
virtual void visitEffectiveAddress(LEffectiveAddress* ins);
|
||||
virtual void visitUDivOrMod(LUDivOrMod* ins);
|
||||
virtual void visitUDivOrModConstant(LUDivOrModConstant *ins);
|
||||
virtual void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
|
||||
virtual void visitMemoryBarrier(LMemoryBarrier* ins);
|
||||
|
||||
|
|
|
@ -289,6 +289,7 @@ enum GroupOpcodeID {
|
|||
GROUP3_OP_TEST = 0,
|
||||
GROUP3_OP_NOT = 2,
|
||||
GROUP3_OP_NEG = 3,
|
||||
GROUP3_OP_MUL = 4,
|
||||
GROUP3_OP_IMUL = 5,
|
||||
GROUP3_OP_DIV = 6,
|
||||
GROUP3_OP_IDIV = 7,
|
||||
|
|
|
@ -163,6 +163,37 @@ class LUDivOrMod : public LBinaryMath<1>
|
|||
}
|
||||
};
|
||||
|
||||
class LUDivOrModConstant : public LInstructionHelper<1, 1, 1>
|
||||
{
|
||||
const uint32_t denominator_;
|
||||
|
||||
public:
|
||||
LIR_HEADER(UDivOrModConstant)
|
||||
|
||||
LUDivOrModConstant(const LAllocation &lhs, uint32_t denominator, const LDefinition& temp)
|
||||
: denominator_(denominator)
|
||||
{
|
||||
setOperand(0, lhs);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LAllocation *numerator() {
|
||||
return getOperand(0);
|
||||
}
|
||||
uint32_t denominator() const {
|
||||
return denominator_;
|
||||
}
|
||||
MBinaryArithInstruction *mir() const {
|
||||
MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
|
||||
return static_cast<MBinaryArithInstruction *>(mir_);
|
||||
}
|
||||
bool canBeNegativeDividend() const {
|
||||
if (mir_->isMod())
|
||||
return mir_->toMod()->canBeNegativeDividend();
|
||||
return mir_->toDiv()->canBeNegativeDividend();
|
||||
}
|
||||
};
|
||||
|
||||
class LModPowTwoI : public LInstructionHelper<1,1,0>
|
||||
{
|
||||
const int32_t shift_;
|
||||
|
|
|
@ -274,6 +274,26 @@ LIRGeneratorX86Shared::visitAsmJSNeg(MAsmJSNeg* ins)
|
|||
void
|
||||
LIRGeneratorX86Shared::lowerUDiv(MDiv* div)
|
||||
{
|
||||
if (div->rhs()->isConstant()) {
|
||||
uint32_t rhs = div->rhs()->toConstant()->value().toInt32();
|
||||
int32_t shift = FloorLog2(rhs);
|
||||
|
||||
LAllocation lhs = useRegisterAtStart(div->lhs());
|
||||
if (rhs != 0 && uint32_t(1) << shift == rhs) {
|
||||
LDivPowTwoI* lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift, false);
|
||||
if (div->fallible())
|
||||
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||
defineReuseInput(lir, div, 0);
|
||||
} else {
|
||||
LUDivOrModConstant* lir = new(alloc()) LUDivOrModConstant(useRegister(div->lhs()),
|
||||
rhs, tempFixed(eax));
|
||||
if (div->fallible())
|
||||
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||
defineFixed(lir, div, LAllocation(AnyRegister(edx)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LUDivOrMod* lir = new(alloc()) LUDivOrMod(useRegister(div->lhs()),
|
||||
useRegister(div->rhs()),
|
||||
tempFixed(edx));
|
||||
|
@ -285,6 +305,25 @@ LIRGeneratorX86Shared::lowerUDiv(MDiv* div)
|
|||
void
|
||||
LIRGeneratorX86Shared::lowerUMod(MMod* mod)
|
||||
{
|
||||
if (mod->rhs()->isConstant()) {
|
||||
uint32_t rhs = mod->rhs()->toConstant()->value().toInt32();
|
||||
int32_t shift = FloorLog2(rhs);
|
||||
|
||||
if (rhs != 0 && uint32_t(1) << shift == rhs) {
|
||||
LModPowTwoI* lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
|
||||
if (mod->fallible())
|
||||
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||
defineReuseInput(lir, mod, 0);
|
||||
} else {
|
||||
LUDivOrModConstant* lir = new(alloc()) LUDivOrModConstant(useRegister(mod->lhs()),
|
||||
rhs, tempFixed(edx));
|
||||
if (mod->fallible())
|
||||
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||
defineFixed(lir, mod, LAllocation(AnyRegister(eax)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LUDivOrMod* lir = new(alloc()) LUDivOrMod(useRegister(mod->lhs()),
|
||||
useRegister(mod->rhs()),
|
||||
tempFixed(eax));
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
_(AsmJSLoadFuncPtr) \
|
||||
_(SimdValueInt32x4) \
|
||||
_(SimdValueFloat32x4) \
|
||||
_(UDivOrMod)
|
||||
_(UDivOrMod) \
|
||||
_(UDivOrModConstant)
|
||||
|
||||
#endif /* jit_x86_LOpcodes_x86_h */
|
||||
|
|
|
@ -291,7 +291,7 @@ SandboxFetch(JSContext* cx, JS::HandleObject scope, const CallArgs& args)
|
|||
FetchRequest(global, Constify(request), Constify(options), rv);
|
||||
rv.WouldReportJSException();
|
||||
if (rv.Failed()) {
|
||||
return ThrowMethodFailedWithDetails(cx, rv, "Sandbox", "fetch");
|
||||
return ThrowMethodFailed(cx, rv);
|
||||
}
|
||||
if (!GetOrCreateDOMReflector(cx, scope, response, args.rval())) {
|
||||
return false;
|
||||
|
|
|
@ -1202,13 +1202,9 @@ public:
|
|||
uint32_t flags = imgIContainer::FLAG_SYNC_DECODE;
|
||||
|
||||
nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
|
||||
EventStates state = f->GetContent()->AsElement()->State();
|
||||
DrawResult result =
|
||||
f->DisplayAltFeedback(*aCtx,
|
||||
mVisibleRect,
|
||||
IMAGE_OK(state, true)
|
||||
? nsImageFrame::gIconLoad->mLoadingImage
|
||||
: nsImageFrame::gIconLoad->mBrokenImage,
|
||||
ToReferenceFrame(),
|
||||
flags);
|
||||
|
||||
|
@ -1221,13 +1217,15 @@ public:
|
|||
DrawResult
|
||||
nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
imgIRequest* aRequest,
|
||||
nsPoint aPt,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
// We should definitely have a gIconLoad here.
|
||||
MOZ_ASSERT(gIconLoad, "How did we succeed in Init then?");
|
||||
|
||||
// Whether we draw the broken or loading icon.
|
||||
bool isLoading = IMAGE_OK(GetContent()->AsElement()->State(), true);
|
||||
|
||||
// Calculate the inner area
|
||||
nsRect inner = GetInnerArea() + aPt;
|
||||
|
||||
|
@ -1247,10 +1245,12 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
|
|||
}
|
||||
|
||||
// Paint the border
|
||||
nsRecessedBorder recessedBorder(borderEdgeWidth, PresContext());
|
||||
nsCSSRendering::PaintBorderWithStyleBorder(PresContext(), aRenderingContext,
|
||||
this, inner, inner,
|
||||
recessedBorder, mStyleContext);
|
||||
if (!isLoading || gIconLoad->mPrefShowLoadingPlaceholder) {
|
||||
nsRecessedBorder recessedBorder(borderEdgeWidth, PresContext());
|
||||
nsCSSRendering::PaintBorderWithStyleBorder(PresContext(), aRenderingContext,
|
||||
this, inner, inner,
|
||||
recessedBorder, mStyleContext);
|
||||
}
|
||||
|
||||
// Adjust the inner rect to account for the one pixel recessed border,
|
||||
// and a six pixel padding on each edge
|
||||
|
@ -1271,15 +1271,20 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
|
|||
DrawResult result = DrawResult::NOT_READY;
|
||||
|
||||
// Check if we should display image placeholders
|
||||
if (!gIconLoad->mPrefShowPlaceholders) {
|
||||
if (!gIconLoad->mPrefShowPlaceholders ||
|
||||
(isLoading && !gIconLoad->mPrefShowLoadingPlaceholder)) {
|
||||
result = DrawResult::SUCCESS;
|
||||
} else {
|
||||
nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
|
||||
|
||||
imgIRequest* request = isLoading
|
||||
? nsImageFrame::gIconLoad->mLoadingImage
|
||||
: nsImageFrame::gIconLoad->mBrokenImage;
|
||||
|
||||
// If we weren't previously displaying an icon, register ourselves
|
||||
// as an observer for load and animation updates and flag that we're
|
||||
// doing so now.
|
||||
if (aRequest && !mDisplayingIcon) {
|
||||
if (request && !mDisplayingIcon) {
|
||||
gIconLoad->AddIconObserver(this);
|
||||
mDisplayingIcon = true;
|
||||
}
|
||||
|
@ -1290,11 +1295,11 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
|
|||
|
||||
// If the icon in question is loaded, draw it.
|
||||
uint32_t imageStatus = 0;
|
||||
if (aRequest)
|
||||
aRequest->GetImageStatus(&imageStatus);
|
||||
if (request)
|
||||
request->GetImageStatus(&imageStatus);
|
||||
if (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE) {
|
||||
nsCOMPtr<imgIContainer> imgCon;
|
||||
aRequest->GetImage(getter_AddRefs(imgCon));
|
||||
request->GetImage(getter_AddRefs(imgCon));
|
||||
MOZ_ASSERT(imgCon, "Load complete, but no image container?");
|
||||
nsRect dest(flushRight ? inner.XMost() - size : inner.x,
|
||||
inner.y, size, size);
|
||||
|
@ -2192,6 +2197,7 @@ NS_IMPL_ISUPPORTS(nsImageFrame::IconLoad, nsIObserver,
|
|||
static const char* kIconLoadPrefs[] = {
|
||||
"browser.display.force_inline_alttext",
|
||||
"browser.display.show_image_placeholders",
|
||||
"browser.display.show_loading_image_placeholder",
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
@ -2244,6 +2250,9 @@ void nsImageFrame::IconLoad::GetPrefs()
|
|||
|
||||
mPrefShowPlaceholders =
|
||||
Preferences::GetBool("browser.display.show_image_placeholders", true);
|
||||
|
||||
mPrefShowLoadingPlaceholder =
|
||||
Preferences::GetBool("browser.display.show_loading_image_placeholder", true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -145,7 +145,6 @@ public:
|
|||
|
||||
DrawResult DisplayAltFeedback(nsRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect,
|
||||
imgIRequest* aRequest,
|
||||
nsPoint aPt,
|
||||
uint32_t aFlags);
|
||||
|
||||
|
@ -364,6 +363,7 @@ private:
|
|||
nsRefPtr<imgRequestProxy> mBrokenImage;
|
||||
bool mPrefForceInlineAltText;
|
||||
bool mPrefShowPlaceholders;
|
||||
bool mPrefShowLoadingPlaceholder;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -8897,7 +8897,7 @@ nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
|
|||
const nsCSSValueList* cur = aValue->GetListValue();
|
||||
|
||||
uint8_t sizingBox = NS_STYLE_CLIP_SHAPE_SIZING_NOBOX;
|
||||
nsStyleBasicShape* basicShape = nullptr;
|
||||
nsRefPtr<nsStyleBasicShape> basicShape;
|
||||
for (unsigned i = 0; i < 2; ++i) {
|
||||
if (!cur) {
|
||||
break;
|
||||
|
|
|
@ -50,6 +50,23 @@ addAsyncAnimTest(function *() {
|
|||
"at 300ms");
|
||||
done_div();
|
||||
});
|
||||
|
||||
addAsyncAnimTest(function *() {
|
||||
var [ div, cs ] = new_div("animation: anim 10s 1 linear forwards");
|
||||
var animation = div.getAnimations()[0];
|
||||
advance_clock(300);
|
||||
yield waitForPaints();
|
||||
|
||||
animation.playbackRate = 0;
|
||||
|
||||
yield waitForPaintsFlushed();
|
||||
|
||||
omta_is(div, "transform", { tx: 3 }, RunningOn.MainThread,
|
||||
"animation with zero playback rate should stay in the " +
|
||||
"same position and be running on the main thread");
|
||||
|
||||
done_div();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -62,7 +62,7 @@ GMPGetAPI(const char* aApiName, void* aHostAPI, void** aPluginAPI)
|
|||
*aPluginAPI = new ClearKeySessionManager();
|
||||
}
|
||||
#if defined(ENABLE_WMF)
|
||||
if (!strcmp(aApiName, GMP_API_AUDIO_DECODER) &&
|
||||
else if (!strcmp(aApiName, GMP_API_AUDIO_DECODER) &&
|
||||
wmf::EnsureLibs()) {
|
||||
*aPluginAPI = new AudioDecoder(static_cast<GMPAudioHost*>(aHostAPI));
|
||||
} else if (!strcmp(aApiName, GMP_API_VIDEO_DECODER) &&
|
||||
|
|
|
@ -44,7 +44,7 @@ RunOnThreadInternal(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flag
|
|||
return rv;
|
||||
}
|
||||
if (!on) {
|
||||
return thread->Dispatch(runnable_ref, flags);
|
||||
return thread->Dispatch(runnable_ref.forget(), flags);
|
||||
}
|
||||
}
|
||||
return runnable_ref->Run();
|
||||
|
|
|
@ -202,6 +202,12 @@ public class FxAccountStatusActivity extends LocaleAwareFragmentActivity {
|
|||
boolean enabled = !AppConstants.MOZILLA_OFFICIAL || AppConstants.NIGHTLY_BUILD || AppConstants.DEBUG_BUILD;
|
||||
if (!enabled) {
|
||||
menu.removeItem(R.id.enable_debug_mode);
|
||||
} else {
|
||||
final MenuItem debugModeItem = menu.findItem(R.id.enable_debug_mode);
|
||||
if (debugModeItem != null) {
|
||||
// Update checked state based on internal flag.
|
||||
menu.findItem(R.id.enable_debug_mode).setChecked(FxAccountUtils.LOG_PERSONAL_INFORMATION);
|
||||
}
|
||||
}
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
};
|
||||
|
|
|
@ -208,7 +208,10 @@ pref("browser.display.force_inline_alttext", false); // true = force ALT text fo
|
|||
// 1 = use external leading only when font provides,
|
||||
// 2 = add extra leading both internal leading and external leading are zero
|
||||
pref("browser.display.normal_lineheight_calc_control", 2);
|
||||
pref("browser.display.show_image_placeholders", true); // true = show image placeholders while image is loaded and when image is broken
|
||||
// enable showing image placeholders while image is loading or when image is broken
|
||||
pref("browser.display.show_image_placeholders", true);
|
||||
// if browser.display.show_image_placeholders is true then this controls whether the loading image placeholder and border is shown or not
|
||||
pref("browser.display.show_loading_image_placeholder", false);
|
||||
// min font device pixel size at which to turn on high quality
|
||||
pref("browser.display.auto_quality_min_font_size", 20);
|
||||
pref("browser.anchor_color", "#0000EE");
|
||||
|
|
|
@ -154,13 +154,21 @@ nsSocketTransportService::GetThreadSafely()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::Dispatch(nsIRunnable *event, uint32_t flags)
|
||||
nsSocketTransportService::DispatchFromScript(nsIRunnable *event, uint32_t flags)
|
||||
{
|
||||
SOCKET_LOG(("STS dispatch [%p]\n", event));
|
||||
nsCOMPtr<nsIRunnable> event_ref(event);
|
||||
return Dispatch(event_ref.forget(), flags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event_ref(event);
|
||||
SOCKET_LOG(("STS dispatch [%p]\n", event_ref.get()));
|
||||
|
||||
nsCOMPtr<nsIThread> thread = GetThreadSafely();
|
||||
nsresult rv;
|
||||
rv = thread ? thread->Dispatch(event, flags) : NS_ERROR_NOT_INITIALIZED;
|
||||
rv = thread ? thread->Dispatch(event_ref.forget(), flags) : NS_ERROR_NOT_INITIALIZED;
|
||||
if (rv == NS_ERROR_UNEXPECTED) {
|
||||
// Thread is no longer accepting events. We must have just shut it
|
||||
// down on the main thread. Pretend we never saw it.
|
||||
|
|
|
@ -81,6 +81,10 @@ public:
|
|||
NS_DECL_NSITHREADOBSERVER
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIOBSERVER
|
||||
// missing from NS_DECL_NSIEVENTTARGET because MSVC
|
||||
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
|
||||
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
|
||||
}
|
||||
|
||||
nsSocketTransportService();
|
||||
|
||||
|
|
|
@ -504,8 +504,16 @@ NS_IMPL_ISUPPORTS(nsStreamTransportService,
|
|||
nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStreamTransportService::Dispatch(nsIRunnable *task, uint32_t flags)
|
||||
nsStreamTransportService::DispatchFromScript(nsIRunnable *task, uint32_t flags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event(task);
|
||||
return Dispatch(event.forget(), flags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStreamTransportService::Dispatch(already_AddRefed<nsIRunnable>&& task, uint32_t flags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event(task); // so it gets released on failure paths
|
||||
nsCOMPtr<nsIThreadPool> pool;
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mShutdownLock);
|
||||
|
@ -515,7 +523,7 @@ nsStreamTransportService::Dispatch(nsIRunnable *task, uint32_t flags)
|
|||
pool = mPool;
|
||||
}
|
||||
NS_ENSURE_TRUE(pool, NS_ERROR_NOT_INITIALIZED);
|
||||
return pool->Dispatch(task, flags);
|
||||
return pool->Dispatch(event.forget(), flags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -21,6 +21,10 @@ public:
|
|||
NS_DECL_NSISTREAMTRANSPORTSERVICE
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
NS_DECL_NSIOBSERVER
|
||||
// missing from NS_DECL_NSIEVENTTARGET because MSVC
|
||||
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
|
||||
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
|
||||
}
|
||||
|
||||
nsresult Init();
|
||||
|
||||
|
|
|
@ -254,7 +254,8 @@ nsEffectiveTLDService::GetBaseDomainInternal(nsCString &aHostname,
|
|||
const char *currDomain = aHostname.get();
|
||||
const char *nextDot = strchr(currDomain, '.');
|
||||
const char *end = currDomain + aHostname.Length();
|
||||
const char *eTLD = currDomain;
|
||||
// Default value of *eTLD is currDomain as set in the while loop below
|
||||
const char *eTLD = nullptr;
|
||||
while (1) {
|
||||
// sanity check the string we're about to look up: it should not begin with
|
||||
// a '.'; this would mean the hostname began with a '.' or had an
|
||||
|
|
|
@ -475,9 +475,9 @@ DataChannelConnection::StartDefer()
|
|||
{
|
||||
nsresult rv;
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::START_DEFER,
|
||||
this, (DataChannel *) nullptr));
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::START_DEFER,
|
||||
this, (DataChannel *) nullptr)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -614,9 +614,9 @@ DataChannelConnection::CompleteConnect(TransportFlow *flow, TransportLayer::Stat
|
|||
}
|
||||
}
|
||||
// Note: currently this doesn't actually notify the application
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this));
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -712,7 +712,7 @@ DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length,
|
|||
peer->mSTS->Dispatch(WrapRunnable(
|
||||
nsRefPtr<DataChannelConnection>(peer),
|
||||
&DataChannelConnection::SendPacket, data, length, true),
|
||||
NS_DISPATCH_NORMAL);
|
||||
NS_DISPATCH_NORMAL);
|
||||
res = 0; // cheat! Packets can always be dropped later anyways
|
||||
}
|
||||
return res;
|
||||
|
@ -773,9 +773,9 @@ DataChannelConnection::Listen(unsigned short port)
|
|||
// Notify Connection open
|
||||
// XXX We need to make sure connection sticks around until the message is delivered
|
||||
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this, (DataChannel *) nullptr));
|
||||
this, (DataChannel *) nullptr)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -851,9 +851,9 @@ DataChannelConnection::Connect(const char *addr, unsigned short port)
|
|||
// Notify Connection open
|
||||
// XXX We need to make sure connection sticks around until the message is delivered
|
||||
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this, (DataChannel *) nullptr));
|
||||
this, (DataChannel *) nullptr)));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -1052,9 +1052,9 @@ DataChannelConnection::SendDeferredMessages()
|
|||
channel->mState = OPEN;
|
||||
channel->mReady = true;
|
||||
LOG(("%s: sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, this,
|
||||
channel));
|
||||
channel)));
|
||||
sent = true;
|
||||
} else {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
|
@ -1064,9 +1064,9 @@ DataChannelConnection::SendDeferredMessages()
|
|||
mStreams[channel->mStream] = nullptr;
|
||||
channel->mState = CLOSED;
|
||||
// Don't need to reset; we didn't open it
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
|
||||
channel));
|
||||
channel)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1232,9 +1232,9 @@ DataChannelConnection::HandleOpenRequestMessage(const struct rtcweb_datachannel_
|
|||
|
||||
LOG(("%s: sending ON_CHANNEL_CREATED for %s/%s: %u (state %u)", __FUNCTION__,
|
||||
channel->mLabel.get(), channel->mProtocol.get(), stream, channel->mState));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_CREATED,
|
||||
this, channel));
|
||||
this, channel)));
|
||||
|
||||
LOG(("%s: deferring sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
|
||||
|
||||
|
@ -1462,9 +1462,9 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
|
|||
|
||||
SetEvenOdd();
|
||||
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CONNECTION,
|
||||
this));
|
||||
this)));
|
||||
LOG(("DTLS connect() succeeded! Entering connected mode"));
|
||||
|
||||
// Open any streams pending...
|
||||
|
@ -1479,18 +1479,18 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
|
|||
case SCTP_COMM_LOST:
|
||||
LOG(("Association change: SCTP_COMM_LOST"));
|
||||
// This association is toast, so also close all the channels -- from mainthread!
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_DISCONNECTED,
|
||||
this));
|
||||
this)));
|
||||
break;
|
||||
case SCTP_RESTART:
|
||||
LOG(("Association change: SCTP_RESTART"));
|
||||
break;
|
||||
case SCTP_SHUTDOWN_COMP:
|
||||
LOG(("Association change: SCTP_SHUTDOWN_COMP"));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_DISCONNECTED,
|
||||
this));
|
||||
this)));
|
||||
break;
|
||||
case SCTP_CANT_STR_ASSOC:
|
||||
LOG(("Association change: SCTP_CANT_STR_ASSOC"));
|
||||
|
@ -1753,9 +1753,9 @@ DataChannelConnection::HandleStreamResetEvent(const struct sctp_stream_reset_eve
|
|||
// Mark the stream for reset (the reset is sent below)
|
||||
ResetOutgoingStream(channel->mStream);
|
||||
}
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
|
||||
channel));
|
||||
channel)));
|
||||
mStreams[channel->mStream] = nullptr;
|
||||
|
||||
LOG(("Disconnected DataChannel %p from connection %p",
|
||||
|
@ -1846,9 +1846,9 @@ DataChannelConnection::HandleStreamChangeEvent(const struct sctp_stream_change_e
|
|||
(strchg->strchange_flags & SCTP_STREAM_CHANGE_FAILED)) {
|
||||
/* XXX: Signal to the other end. */
|
||||
channel->mState = CLOSED;
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
|
||||
channel));
|
||||
channel)));
|
||||
// maybe fire onError (bug 843625)
|
||||
} else {
|
||||
stream = FindFreeStream();
|
||||
|
@ -2129,9 +2129,9 @@ DataChannelConnection::OpenFinish(already_AddRefed<DataChannel>&& aChannel)
|
|||
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
|
||||
// We already returned the channel to the app.
|
||||
NS_ERROR("Failed to send open request");
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
|
||||
channel));
|
||||
channel)));
|
||||
}
|
||||
// If we haven't returned the channel yet, it will get destroyed when we exit
|
||||
// this function.
|
||||
|
@ -2149,9 +2149,9 @@ DataChannelConnection::OpenFinish(already_AddRefed<DataChannel>&& aChannel)
|
|||
channel->mReady = true;
|
||||
// FIX? Move into DOMDataChannel? I don't think we can send it yet here
|
||||
LOG(("%s: sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, this,
|
||||
channel));
|
||||
channel)));
|
||||
|
||||
return channel.forget();
|
||||
|
||||
|
@ -2160,9 +2160,9 @@ request_error_cleanup:
|
|||
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
|
||||
// We already returned the channel to the app.
|
||||
NS_ERROR("Failed to request more streams");
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
|
||||
channel));
|
||||
channel)));
|
||||
return channel.forget();
|
||||
}
|
||||
// we'll be destroying the channel, but it never really got set up
|
||||
|
@ -2329,8 +2329,7 @@ DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream *aBlob)
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new ReadBlobRunnable(this, stream, aBlob);
|
||||
mInternalIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
mInternalIOThread->Dispatch(do_AddRef(new ReadBlobRunnable(this, stream, aBlob)), NS_DISPATCH_NORMAL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2577,9 +2576,9 @@ DataChannel::AppReady()
|
|||
mReady = true;
|
||||
if (mState == WAITING_TO_OPEN) {
|
||||
mState = OPEN;
|
||||
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
|
||||
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
|
||||
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, mConnection,
|
||||
this));
|
||||
this)));
|
||||
for (uint32_t i = 0; i < mQueuedMessages.Length(); ++i) {
|
||||
nsCOMPtr<nsIRunnable> runnable = mQueuedMessages[i];
|
||||
MOZ_ASSERT(runnable);
|
||||
|
|
|
@ -494,6 +494,7 @@ class RecursiveMakeBackend(CommonBackend):
|
|||
backend_file.write('GENERATED_FILES += %s\n' % obj.output)
|
||||
if obj.script:
|
||||
backend_file.write("""{output}: {script}{inputs}
|
||||
\t$(REPORT_BUILD)
|
||||
\t$(call py_action,file_generate,{script} {method} {output}{inputs})
|
||||
|
||||
""".format(output=obj.output,
|
||||
|
|
|
@ -377,10 +377,12 @@ class TestRecursiveMakeBackend(BackendTester):
|
|||
expected = [
|
||||
'GENERATED_FILES += bar.c',
|
||||
'bar.c: %s/generate-bar.py' % env.topsrcdir,
|
||||
'$(REPORT_BUILD)',
|
||||
'$(call py_action,file_generate,%s/generate-bar.py baz bar.c)' % env.topsrcdir,
|
||||
'',
|
||||
'GENERATED_FILES += foo.c',
|
||||
'foo.c: %s/generate-foo.py %s/foo-data' % (env.topsrcdir, env.topsrcdir),
|
||||
'$(REPORT_BUILD)',
|
||||
'$(call py_action,file_generate,%s/generate-foo.py main foo.c %s/foo-data)' % (env.topsrcdir, env.topsrcdir),
|
||||
'',
|
||||
'GENERATED_FILES += quux.c',
|
||||
|
|
|
@ -108,7 +108,10 @@ void Finalize(JSFreeOp *fop, JSObject *objSelf)
|
|||
|
||||
// Notify observers. Since we are executed during garbage-collection,
|
||||
// we need to dispatch the notification to the main thread.
|
||||
(void)NS_DispatchToMainThread(event);
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
if (mainThread) {
|
||||
mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
// We may fail at dispatching to the main thread if we arrive too late
|
||||
// during shutdown. In that case, there is not much we can do.
|
||||
}
|
||||
|
|
|
@ -203,8 +203,7 @@
|
|||
<method name="print">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let contentWindow = this.mPPBrowser.contentWindowAsCPOW;
|
||||
PrintUtils.print(contentWindow, this.mPPBrowser);
|
||||
PrintUtils.printWindow(this.mPPBrowser.outerWindowID, this.mPPBrowser);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
|
|
@ -30,18 +30,14 @@
|
|||
* Messages sent:
|
||||
*
|
||||
* Printing:Print
|
||||
* This message is sent to kick off a print job for a particular content
|
||||
* window (which is passed along with the message). We also pass print
|
||||
* settings with this message - though bug 1088070 will have us gather
|
||||
* those settings from the content process instead.
|
||||
* Kick off a print job for a nsIDOMWindow, passing the outer window ID as
|
||||
* windowID.
|
||||
*
|
||||
* Printing:Preview:Enter
|
||||
* This message is sent to put content into print preview mode. We pass
|
||||
* the content window of the browser we're showing the preview of, and
|
||||
* the target of the message is the browser that we'll be showing the
|
||||
* preview in. We also pass print settings in this message, but
|
||||
* bug 1088070 will have us gather those settings from the content process
|
||||
* instead.
|
||||
* preview in.
|
||||
*
|
||||
* Printing:Preview:Exit
|
||||
* This message is sent to take content out of print preview mode.
|
||||
|
@ -95,59 +91,58 @@ var PrintUtils = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Starts printing the contents of aWindow.
|
||||
* Starts the process of printing the contents of a window.
|
||||
*
|
||||
* @param aWindow
|
||||
* An nsIDOMWindow to initiate the printing of. If the chrome window
|
||||
* is not running with remote tabs, this defaults to window.content if
|
||||
* omitted. If running with remote tabs, the caller must pass in the
|
||||
* content window to be printed. This function throws if that invariant
|
||||
* is violated.
|
||||
* @param aBrowser (optional for non-remote browsers)
|
||||
* The remote <xul:browser> that contains aWindow. This argument is
|
||||
* not necessary if aWindow came from a non-remote browser, but is
|
||||
* strictly required otherwise. This function will throw if aWindow
|
||||
* comes from a remote browser and aBrowser is not provided. This
|
||||
* browser must have its type attribute set to "content",
|
||||
* "content-targetable", or "content-primary".
|
||||
* @param aWindowID
|
||||
* The outer window ID of the nsIDOMWindow to print.
|
||||
* @param aBrowser
|
||||
* The <xul:browser> that the nsIDOMWindow for aWindowID belongs to.
|
||||
*/
|
||||
print: function (aWindow, aBrowser)
|
||||
printWindow: function (aWindowID, aBrowser)
|
||||
{
|
||||
if (!aWindow) {
|
||||
// If we're using remote browsers, chances are that window.content will
|
||||
// not be defined.
|
||||
if (this.usingRemoteTabs) {
|
||||
throw new Error("Windows running with remote tabs must explicitly pass " +
|
||||
"a content window to PrintUtils.print.");
|
||||
}
|
||||
// Otherwise, we should have access to window.content.
|
||||
aWindow = window.content;
|
||||
let mm = aBrowser.messageManager;
|
||||
mm.sendAsyncMessage("Printing:Print", {
|
||||
windowID: aWindowID,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* Starts the process of printing the contents of window.content.
|
||||
*
|
||||
*/
|
||||
print: function ()
|
||||
{
|
||||
if (gBrowser) {
|
||||
return this.printWindow(gBrowser.selectedBrowser.outerWindowID,
|
||||
gBrowser.selectedBrowser);
|
||||
}
|
||||
|
||||
if (Components.utils.isCrossProcessWrapper(aWindow)) {
|
||||
if (!aBrowser) {
|
||||
throw new Error("PrintUtils.print expects a remote browser passed as " +
|
||||
"an argument if the content window is a CPOW.");
|
||||
}
|
||||
} else {
|
||||
// For content windows coming from non-remote browsers, the browser can
|
||||
// be resolved as the chromeEventHandler.
|
||||
aBrowser = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
if (this.usingRemoteTabs) {
|
||||
throw new Error("PrintUtils.print cannot be run in windows running with " +
|
||||
"remote tabs. Use PrintUtils.printWindow instead.");
|
||||
}
|
||||
|
||||
if (!aBrowser) {
|
||||
let domWindow = window.content;
|
||||
let ifReq = domWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
|
||||
let browser = ifReq.getInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
if (!browser) {
|
||||
throw new Error("PrintUtils.print could not resolve content window " +
|
||||
"to a browser.");
|
||||
}
|
||||
|
||||
let mm = aBrowser.messageManager;
|
||||
let windowID = ifReq.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.outerWindowID;
|
||||
|
||||
mm.sendAsyncMessage("Printing:Print", null, {
|
||||
contentWindow: aWindow,
|
||||
});
|
||||
let Deprecated = Components.utils.import("resource://gre/modules/Deprecated.jsm", {}).Deprecated;
|
||||
let msg = "PrintUtils.print is now deprecated. Please use PrintUtils.printWindow.";
|
||||
let url = "https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Printing";
|
||||
Deprecated.warning(msg, url);
|
||||
|
||||
this.printWindow(windowID, browser);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -410,9 +405,8 @@ var PrintUtils = {
|
|||
// listener.
|
||||
let ppBrowser = this._listener.getPrintPreviewBrowser();
|
||||
let mm = ppBrowser.messageManager;
|
||||
mm.sendAsyncMessage("Printing:Preview:Enter", null, {
|
||||
contentWindow: this._sourceBrowser.contentWindowAsCPOW ||
|
||||
this._sourceBrowser.contentWindow,
|
||||
mm.sendAsyncMessage("Printing:Preview:Enter", {
|
||||
windowID: this._sourceBrowser.outerWindowID,
|
||||
});
|
||||
|
||||
if (this._webProgressPP.value) {
|
||||
|
|
|
@ -7,6 +7,10 @@ support-files =
|
|||
|
||||
[test_lookup_system_principal.html]
|
||||
[test_classified_annotations.html]
|
||||
tags = trackingprotection
|
||||
[test_allowlisted_annotations.html]
|
||||
tags = trackingprotection
|
||||
[test_privatebrowsing_trackingprotection.html]
|
||||
tags = trackingprotection
|
||||
[test_trackingprotection_bug1157081.html]
|
||||
tags = trackingprotection
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<stringbundle id="viewSourceBundle" src="chrome://global/locale/viewSource.properties"/>
|
||||
|
||||
<command id="cmd_savePage" oncommand="ViewSourceSavePage();"/>
|
||||
<command id="cmd_print" oncommand="PrintUtils.print();"/>
|
||||
<command id="cmd_print" oncommand="PrintUtils.printWindow(gBrowser.outerWindowID, gBrowser);"/>
|
||||
<command id="cmd_printpreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
|
||||
<command id="cmd_pagesetup" oncommand="PrintUtils.showPageSetup();"/>
|
||||
<command id="cmd_close" oncommand="window.close();"/>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<stringbundle id="viewSourceBundle" src="chrome://global/locale/viewSource.properties"/>
|
||||
|
||||
<command id="cmd_savePage" oncommand="ViewSourceSavePage();"/>
|
||||
<command id="cmd_print" oncommand="PrintUtils.print(gBrowser.contentWindowAsCPOW, gBrowser);"/>
|
||||
<command id="cmd_print" oncommand="PrintUtils.printWindow(gBrowser.outerWindowID, gBrowser);"/>
|
||||
<command id="cmd_printpreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
|
||||
<command id="cmd_pagesetup" oncommand="PrintUtils.showPageSetup();"/>
|
||||
<command id="cmd_close" oncommand="window.close();"/>
|
||||
|
|
|
@ -392,7 +392,7 @@ let Printing = {
|
|||
let data = message.data;
|
||||
switch(message.name) {
|
||||
case "Printing:Preview:Enter": {
|
||||
this.enterPrintPreview(objects.contentWindow);
|
||||
this.enterPrintPreview(Services.wm.getOuterWindowWithId(data.windowID));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -412,7 +412,7 @@ let Printing = {
|
|||
}
|
||||
|
||||
case "Printing:Print": {
|
||||
this.print(objects.contentWindow);
|
||||
this.print(Services.wm.getOuterWindowWithId(data.windowID));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -691,3 +691,39 @@ addMessageListener("WebChannelMessageToContent", function (e) {
|
|||
Cu.reportError("WebChannel message failed. No message data.");
|
||||
}
|
||||
});
|
||||
|
||||
let MediaPlaybackListener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
init() {
|
||||
Services.obs.addObserver(this, "media-playback", false);
|
||||
addMessageListener("MediaPlaybackMute", this);
|
||||
addEventListener("unload", () => {
|
||||
MediaPlaybackListener.uninit();
|
||||
});
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "media-playback");
|
||||
removeMessageListener("MediaPlaybackMute", this);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic === "media-playback") {
|
||||
if (subject && subject.top == global.content) {
|
||||
let name = "MediaPlayback:";
|
||||
name += (data === "active") ? "Start" : "Stop";
|
||||
sendAsyncMessage(name);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage(msg) {
|
||||
if (msg.name == "MediaPlaybackMute") {
|
||||
let utils = global.content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
utils.audioMuted = msg.data.type === "mute";
|
||||
}
|
||||
},
|
||||
};
|
||||
MediaPlaybackListener.init();
|
||||
|
|
Двоичный файл не отображается.
|
@ -36,4 +36,10 @@ skip-if = !e10s || !crashreporter
|
|||
support-files =
|
||||
file_redirect.html
|
||||
file_redirect_to.html
|
||||
[browser_bug1170531.js]
|
||||
[browser_bug1170531.js]
|
||||
[browser_mediaPlayback.js]
|
||||
support-files =
|
||||
file_mediaPlayback.html
|
||||
file_mediaPlaybackFrame.html
|
||||
audio.ogg
|
||||
[browser_mute.js]
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback.html";
|
||||
const FRAME = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlaybackFrame.html";
|
||||
|
||||
function wait_for_event(browser, event) {
|
||||
return BrowserTestUtils.waitForEvent(browser, event, false, (event) => {
|
||||
is(event.originalTarget, browser, "Event must be dispatched to correct browser.");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function* test_on_browser(url, browser) {
|
||||
browser.loadURI(url);
|
||||
yield wait_for_event(browser, "DOMMediaPlaybackStarted");
|
||||
yield wait_for_event(browser, "DOMMediaPlaybackStopped");
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
yield new Promise((resolve) => {
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true]]},
|
||||
resolve);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* test_page() {
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: "about:blank",
|
||||
}, test_on_browser.bind(undefined, PAGE));
|
||||
});
|
||||
|
||||
add_task(function* test_frame() {
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: "about:blank",
|
||||
}, test_on_browser.bind(undefined, FRAME));
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
const PAGE = "data:text/html,page";
|
||||
|
||||
function* test_on_browser(browser) {
|
||||
ok(!browser.audioMuted, "Audio should not be muted by default");
|
||||
browser.mute();
|
||||
ok(browser.audioMuted, "Audio should be muted now");
|
||||
browser.unmute();
|
||||
ok(!browser.audioMuted, "Audio should be unmuted now");
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
yield new Promise((resolve) => {
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true]]},
|
||||
resolve);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
yield BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: PAGE,
|
||||
}, test_on_browser);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<script type="text/javascript">
|
||||
var audio = new Audio();
|
||||
audio.oncanplay = function() {
|
||||
audio.oncanplay = null;
|
||||
audio.onplaying = function() {
|
||||
audio.onplaying = null;
|
||||
audio.pause();
|
||||
};
|
||||
audio.play();
|
||||
};
|
||||
audio.src = "audio.ogg";
|
||||
</script>
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<iframe src="file_mediaPlayback.html"></iframe>
|
|
@ -641,7 +641,7 @@
|
|||
<method name="updateBlockedPopups">
|
||||
<body>
|
||||
<![CDATA[
|
||||
var event = document.createEvent("Events");
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("DOMUpdatePageReport", true, true);
|
||||
this.dispatchEvent(event);
|
||||
]]>
|
||||
|
@ -663,6 +663,51 @@
|
|||
onget="return this.blockedPopups;"
|
||||
readonly="true"/>
|
||||
|
||||
<method name="mediaPlaybackStarted">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("DOMMediaPlaybackStarted", true, true);
|
||||
this.dispatchEvent(event);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="mediaPlaybackStopped">
|
||||
<body>
|
||||
<![CDATA[
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("DOMMediaPlaybackStopped", true, true);
|
||||
this.dispatchEvent(event);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<field name="_audioMuted">false</field>
|
||||
<property name="audioMuted"
|
||||
onget="return this._audioMuted;"
|
||||
readonly="true"/>
|
||||
|
||||
<method name="mute">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._audioMuted = true;
|
||||
this.messageManager.sendAsyncMessage("MediaPlaybackMute",
|
||||
{type: "mute"});
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="unmute">
|
||||
<body>
|
||||
<![CDATA[
|
||||
this._audioMuted = false;
|
||||
this.messageManager.sendAsyncMessage("MediaPlaybackMute",
|
||||
{type: "unmute"});
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<property name="securityUI">
|
||||
<getter>
|
||||
<![CDATA[
|
||||
|
@ -813,6 +858,8 @@
|
|||
this.messageManager.addMessageListener("PopupBlocking:UpdateBlockedPopups", this);
|
||||
this.messageManager.addMessageListener("Autoscroll:Start", this);
|
||||
this.messageManager.addMessageListener("Autoscroll:Cancel", this);
|
||||
this.messageManager.addMessageListener("MediaPlayback:Start", this);
|
||||
this.messageManager.addMessageListener("MediaPlayback:Stop", this);
|
||||
}
|
||||
]]>
|
||||
</constructor>
|
||||
|
@ -899,6 +946,12 @@
|
|||
case "Autoscroll:Cancel":
|
||||
this._autoScrollPopup.hidePopup();
|
||||
break;
|
||||
case "MediaPlayback:Start":
|
||||
this.mediaPlaybackStarted();
|
||||
break;
|
||||
case "MediaPlayback:Stop":
|
||||
this.mediaPlaybackStopped();
|
||||
break;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче