mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
5310a97558
@ -129,8 +129,9 @@ pref("app.update.cert.maxErrors", 5);
|
||||
// the |app.update.url.override| preference should ONLY be used for testing.
|
||||
// IMPORTANT! metro.js should also be updated for updates to certs.X.issuerName
|
||||
|
||||
// Nightly builds have switched over to aus4.mozilla.org, but we don't want anything else to yet.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Non-release builds (Nightly, Aurora, etc.) have been switched over to aus4.mozilla.org.
|
||||
// This condition protects us against accidentally using it for release builds.
|
||||
#ifndef RELEASE_BUILD
|
||||
pref("app.update.certs.1.issuerName", "CN=DigiCert Secure Server CA,O=DigiCert Inc,C=US");
|
||||
pref("app.update.certs.1.commonName", "aus4.mozilla.org");
|
||||
|
||||
@ -172,7 +173,7 @@ pref("app.update.silent", false);
|
||||
pref("app.update.staging.enabled", true);
|
||||
|
||||
// Update service URL:
|
||||
#ifdef NIGHTLY_BUILD
|
||||
#ifndef RELEASE_BUILD
|
||||
pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
|
||||
#else
|
||||
pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
|
||||
@ -232,6 +233,12 @@ pref("xpinstall.whitelist.add.180", "marketplace.firefox.com");
|
||||
|
||||
pref("lightweightThemes.update.enabled", true);
|
||||
|
||||
// UI tour experience.
|
||||
pref("browser.uitour.enabled", true);
|
||||
pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
|
||||
pref("browser.uitour.pinnedTabUrl", "https://support.mozilla.org/%LOCALE%/kb/pinned-tabs-keep-favorite-websites-open");
|
||||
pref("browser.uitour.whitelist.add.260", "www.mozilla.org,support.mozilla.org");
|
||||
|
||||
pref("keyword.enabled", true);
|
||||
|
||||
pref("general.useragent.locale", "@AB_CD@");
|
||||
@ -659,6 +666,8 @@ pref("plugins.update.notifyUser", false);
|
||||
|
||||
pref("plugins.click_to_play", true);
|
||||
|
||||
pref("plugins.clickToActivateInfo.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/clicktoplay");
|
||||
|
||||
// let all plugins except Flash default to click-to-play
|
||||
pref("plugin.default.state", 1);
|
||||
pref("plugin.state.flash", 2);
|
||||
|
@ -704,6 +704,9 @@ var gPluginHandler = {
|
||||
else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
|
||||
url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
|
||||
}
|
||||
else {
|
||||
url = Services.urlFormatter.formatURLPref("plugins.clickToActivateInfo.url");
|
||||
}
|
||||
pluginInfo.detailsLink = url;
|
||||
|
||||
centerActions.push(pluginInfo);
|
||||
|
@ -778,27 +778,6 @@ var gBrowserInit = {
|
||||
window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow =
|
||||
new nsBrowserAccess();
|
||||
|
||||
// Manually hook up session and global history for the first browser
|
||||
// so that we don't have to load global history before bringing up a
|
||||
// window.
|
||||
// Wire up session and global history before any possible
|
||||
// progress notifications for back/forward button updating
|
||||
gBrowser.webNavigation.sessionHistory = Cc["@mozilla.org/browser/shistory;1"].
|
||||
createInstance(Ci.nsISHistory);
|
||||
Services.obs.addObserver(gBrowser.browsers[0], "browser:purge-session-history", false);
|
||||
|
||||
// remove the disablehistory attribute so the browser cleans up, as
|
||||
// though it had done this work itself
|
||||
gBrowser.browsers[0].removeAttribute("disablehistory");
|
||||
|
||||
// enable global history
|
||||
try {
|
||||
if (!gMultiProcessBrowser)
|
||||
gBrowser.docShell.useGlobalHistory = true;
|
||||
} catch(ex) {
|
||||
Cu.reportError("Places database may be locked: " + ex);
|
||||
}
|
||||
|
||||
// hook up UI through progress listener
|
||||
gBrowser.addProgressListener(window.XULBrowserWindow);
|
||||
gBrowser.addTabsProgressListener(window.TabsProgressListener);
|
||||
|
@ -22,6 +22,7 @@
|
||||
<window id="main-window"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
|
||||
title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
|
||||
@ -183,6 +184,22 @@
|
||||
</hbox>
|
||||
</panel>
|
||||
|
||||
<!-- UI tour experience -->
|
||||
<panel id="UITourTooltip"
|
||||
type="arrow"
|
||||
hidden="true"
|
||||
consumeoutsideclicks="false"
|
||||
noautofocus="true"
|
||||
align="start"
|
||||
orient="vertical"
|
||||
role="alert">
|
||||
<label id="UITourTooltipTitle" flex="1"/>
|
||||
<description id="UITourTooltipDescription" flex="1"/>
|
||||
</panel>
|
||||
<html:div id="UITourHighlightContainer" style="position:relative">
|
||||
<html:div id="UITourHighlight"></html:div>
|
||||
</html:div>
|
||||
|
||||
<panel id="socialActivatedNotification"
|
||||
type="arrow"
|
||||
hidden="true"
|
||||
@ -1028,7 +1045,7 @@
|
||||
|
||||
<splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
|
||||
<vbox id="appcontent" flex="1">
|
||||
<tabbrowser id="content" disablehistory="true"
|
||||
<tabbrowser id="content"
|
||||
flex="1" contenttooltip="aHTMLTooltip"
|
||||
tabcontainer="tabbrowser-tabs"
|
||||
contentcontextmenu="contentAreaContextMenu"
|
||||
|
@ -15,6 +15,8 @@ XPCOMUtils.defineLazyModuleGetter(this,
|
||||
"InsecurePasswordUtils", "resource://gre/modules/InsecurePasswordUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||
"resource:///modules/UITour.jsm");
|
||||
|
||||
// Creates a new nsIURI object.
|
||||
function makeURI(uri, originCharset, baseURI) {
|
||||
@ -49,6 +51,15 @@ if (Services.prefs.getBoolPref("browser.tabs.remote")) {
|
||||
addEventListener("blur", function(event) {
|
||||
LoginManagerContent.onUsernameInput(event);
|
||||
});
|
||||
|
||||
addEventListener("mozUITour", function(event) {
|
||||
if (!Services.prefs.getBoolPref("browser.uitour.enabled"))
|
||||
return;
|
||||
|
||||
let handled = UITour.onPageEvent(event);
|
||||
if (handled)
|
||||
addEventListener("pagehide", UITour);
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
let AboutHomeListener = {
|
||||
|
@ -34,7 +34,7 @@
|
||||
<xul:hbox flex="1" class="browserSidebarContainer">
|
||||
<xul:vbox flex="1" class="browserContainer">
|
||||
<xul:stack flex="1" class="browserStack" anonid="browserStack">
|
||||
<xul:browser anonid="initialBrowser" type="content-primary" message="true" disablehistory="true"
|
||||
<xul:browser anonid="initialBrowser" type="content-primary" message="true"
|
||||
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectpopup"/>
|
||||
</xul:stack>
|
||||
</xul:vbox>
|
||||
|
@ -472,6 +472,7 @@ BrowserGlue.prototype = {
|
||||
ShumwayUtils.init();
|
||||
webrtcUI.init();
|
||||
AboutHome.init();
|
||||
SessionStore.init();
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.tabs.remote"))
|
||||
ContentClick.init();
|
||||
@ -612,7 +613,6 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
#endif
|
||||
|
||||
SessionStore.init(aWindow);
|
||||
this._trackSlowStartup();
|
||||
|
||||
// Offer to reset a user's profile if it hasn't been used for 60 days.
|
||||
|
@ -156,8 +156,8 @@ this.SessionStore = {
|
||||
SessionStoreInternal.canRestoreLastSession = val;
|
||||
},
|
||||
|
||||
init: function ss_init(aWindow) {
|
||||
SessionStoreInternal.init(aWindow);
|
||||
init: function ss_init() {
|
||||
SessionStoreInternal.init();
|
||||
},
|
||||
|
||||
getBrowserState: function ss_getBrowserState() {
|
||||
@ -368,15 +368,11 @@ let SessionStoreInternal = {
|
||||
/**
|
||||
* Initialize the sessionstore service.
|
||||
*/
|
||||
init: function (aWindow) {
|
||||
init: function () {
|
||||
if (this._initialized) {
|
||||
throw new Error("SessionStore.init() must only be called once!");
|
||||
}
|
||||
|
||||
if (!aWindow) {
|
||||
throw new Error("SessionStore.init() must be called with a valid window.");
|
||||
}
|
||||
|
||||
this._disabledForMultiProcess = Services.prefs.getBoolPref("browser.tabs.remote");
|
||||
if (this._disabledForMultiProcess) {
|
||||
this._deferredInitialized.resolve();
|
||||
@ -390,20 +386,6 @@ let SessionStoreInternal = {
|
||||
|
||||
this._initPrefs();
|
||||
this._initialized = true;
|
||||
|
||||
// Wait until nsISessionStartup has finished reading the session data.
|
||||
gSessionStartup.onceInitialized.then(() => {
|
||||
// Parse session data and start restoring.
|
||||
let initialState = this.initSession();
|
||||
|
||||
// Start tracking the given (initial) browser window.
|
||||
if (!aWindow.closed) {
|
||||
this.onLoad(aWindow, initialState);
|
||||
}
|
||||
|
||||
// Let everyone know we're done.
|
||||
this._deferredInitialized.resolve();
|
||||
}, Cu.reportError);
|
||||
},
|
||||
|
||||
initSession: function ssi_initSession() {
|
||||
@ -489,7 +471,6 @@ let SessionStoreInternal = {
|
||||
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
|
||||
|
||||
this._performUpgradeBackup();
|
||||
this._sessionInitialized = true;
|
||||
|
||||
return state;
|
||||
},
|
||||
@ -876,7 +857,34 @@ let SessionStoreInternal = {
|
||||
onOpen: function ssi_onOpen(aWindow) {
|
||||
let onload = () => {
|
||||
aWindow.removeEventListener("load", onload);
|
||||
this.onLoad(aWindow);
|
||||
|
||||
if (this._sessionInitialized) {
|
||||
this.onLoad(aWindow);
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't call this.onLoad since initialization
|
||||
// hasn't completed, so we'll wait until it is done.
|
||||
// Even if additional windows are opened and wait
|
||||
// for initialization as well, the first opened
|
||||
// window should execute first, and this.onLoad
|
||||
// will be called with the initialState.
|
||||
gSessionStartup.onceInitialized.then(() => {
|
||||
if (aWindow.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._sessionInitialized) {
|
||||
this.onLoad(aWindow);
|
||||
} else {
|
||||
let initialState = this.initSession();
|
||||
this._sessionInitialized = true;
|
||||
this.onLoad(aWindow, initialState);
|
||||
|
||||
// Let everyone know we're done.
|
||||
this._deferredInitialized.resolve();
|
||||
}
|
||||
}, Cu.reportError);
|
||||
};
|
||||
|
||||
aWindow.addEventListener("load", onload);
|
||||
@ -1471,7 +1479,7 @@ let SessionStoreInternal = {
|
||||
|
||||
TabStateCache.delete(aTab);
|
||||
this._setWindowStateBusy(window);
|
||||
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
|
||||
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0);
|
||||
},
|
||||
|
||||
duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
|
||||
@ -1491,7 +1499,7 @@ let SessionStoreInternal = {
|
||||
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
|
||||
aWindow.gBrowser.addTab();
|
||||
|
||||
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0, 0, 0,
|
||||
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0,
|
||||
true /* Load this tab right away. */);
|
||||
|
||||
return newTab;
|
||||
@ -1571,7 +1579,7 @@ let SessionStoreInternal = {
|
||||
let tab = tabbrowser.addTab();
|
||||
|
||||
// restore tab content
|
||||
this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1, 0, 0);
|
||||
this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1);
|
||||
|
||||
// restore the tab's position
|
||||
tabbrowser.moveTabTo(tab, closedTab.pos);
|
||||
@ -2344,7 +2352,7 @@ let SessionStoreInternal = {
|
||||
}
|
||||
|
||||
this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs,
|
||||
(overwriteTabs ? (parseInt(winData.selected) || 1) : 0), 0, 0);
|
||||
(overwriteTabs ? (parseInt(winData.selected) || 1) : 0));
|
||||
|
||||
if (aState.scratchpads) {
|
||||
ScratchpadManager.restoreSession(aState.scratchpads);
|
||||
@ -2448,40 +2456,17 @@ let SessionStoreInternal = {
|
||||
* Array of tab data
|
||||
* @param aSelectTab
|
||||
* Index of selected tab
|
||||
* @param aIx
|
||||
* Index of the next tab to check readyness for
|
||||
* @param aCount
|
||||
* Counter for number of times delaying b/c browser or history aren't ready
|
||||
* @param aRestoreImmediately
|
||||
* Flag to indicate whether the given set of tabs aTabs should be
|
||||
* restored/loaded immediately even if restore_on_demand = true
|
||||
*/
|
||||
restoreHistoryPrecursor:
|
||||
function ssi_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab,
|
||||
aIx, aCount, aRestoreImmediately = false) {
|
||||
aRestoreImmediately = false)
|
||||
{
|
||||
|
||||
var tabbrowser = aWindow.gBrowser;
|
||||
|
||||
// make sure that all browsers and their histories are available
|
||||
// - if one's not, resume this check in 100ms (repeat at most 10 times)
|
||||
for (var t = aIx; t < aTabs.length; t++) {
|
||||
try {
|
||||
if (!tabbrowser.getBrowserForTab(aTabs[t]).webNavigation.sessionHistory) {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
catch (ex) { // in case browser or history aren't ready yet
|
||||
if (aCount < 10) {
|
||||
var restoreHistoryFunc = function(self) {
|
||||
self.restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab,
|
||||
aIx, aCount + 1, aRestoreImmediately);
|
||||
};
|
||||
aWindow.setTimeout(restoreHistoryFunc, 100, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._isWindowLoaded(aWindow)) {
|
||||
// from now on, the data will come from the actual window
|
||||
delete this._statesToRestore[aWindow.__SS_restoreID];
|
||||
@ -2507,7 +2492,7 @@ let SessionStoreInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sets the tabs restoring order.
|
||||
// Sets the tabs restoring order.
|
||||
[aTabs, aTabData] =
|
||||
this._setTabsRestoringOrder(tabbrowser, aTabs, aTabData, aSelectTab);
|
||||
|
||||
@ -2515,7 +2500,7 @@ let SessionStoreInternal = {
|
||||
// and show/hide tabs as necessary. We'll also set the labels, user typed
|
||||
// value, and attach a copy of the tab's data in case we close it before
|
||||
// it's been restored.
|
||||
for (t = 0; t < aTabs.length; t++) {
|
||||
for (let t = 0; t < aTabs.length; t++) {
|
||||
let tab = aTabs[t];
|
||||
let browser = tabbrowser.getBrowserForTab(tab);
|
||||
let tabData = aTabData[t];
|
||||
@ -2587,14 +2572,14 @@ let SessionStoreInternal = {
|
||||
|
||||
// helper hashes for ensuring unique frame IDs and unique document
|
||||
// identifiers.
|
||||
var idMap = { used: {} };
|
||||
var docIdentMap = {};
|
||||
let idMap = { used: {} };
|
||||
let docIdentMap = {};
|
||||
this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap,
|
||||
aRestoreImmediately);
|
||||
},
|
||||
|
||||
/**
|
||||
* Restore history for a window
|
||||
* Restore history for a list of tabs.
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
* @param aTabs
|
||||
|
@ -1537,6 +1537,7 @@ NetworkDetailsView.prototype = {
|
||||
}));
|
||||
this._json = new VariablesView($("#response-content-json"),
|
||||
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
|
||||
onlyEnumVisible: true,
|
||||
searchPlaceholder: L10N.getStr("jsonFilterText")
|
||||
}));
|
||||
VariablesViewController.attach(this._json);
|
||||
@ -1874,7 +1875,7 @@ NetworkDetailsView.prototype = {
|
||||
let sanitizedJSON = aString.replace(jsonpRegex, "");
|
||||
let callbackPadding = aString.match(jsonpRegex);
|
||||
|
||||
// Make sure this is an valid JSON object first. If so, nicely display
|
||||
// Make sure this is a valid JSON object first. If so, nicely display
|
||||
// the parsing results in a variables view. Otherwise, simply show
|
||||
// the contents as plain text.
|
||||
try {
|
||||
|
@ -610,66 +610,23 @@ var Scratchpad = {
|
||||
deferred.resolve(aError);
|
||||
}
|
||||
else {
|
||||
let reject = aReason => deferred.reject(aReason);
|
||||
let objectClient = new ObjectClient(this.debuggerClient, aError);
|
||||
|
||||
// Because properties on Error objects are lazily added, this roundabout
|
||||
// way of getting all the properties is required, rather than simply
|
||||
// using getPrototypeAndProperties. See bug 724768.
|
||||
let names = ["message", "stack", "fileName", "lineNumber"];
|
||||
let promises = names.map(aName => {
|
||||
let deferred = promise.defer();
|
||||
|
||||
objectClient.getProperty(aName, aResponse => {
|
||||
if (aResponse.error) {
|
||||
deferred.reject(aResponse);
|
||||
}
|
||||
else {
|
||||
deferred.resolve({
|
||||
name: aName,
|
||||
descriptor: aResponse.descriptor
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
{
|
||||
// We also need to use getPrototypeAndProperties to retrieve any
|
||||
// safeGetterValues in case this is a DOM error.
|
||||
let deferred = promise.defer();
|
||||
objectClient.getPrototypeAndProperties(aResponse => {
|
||||
if (aResponse.error) {
|
||||
deferred.reject(aResponse);
|
||||
}
|
||||
else {
|
||||
deferred.resolve(aResponse);
|
||||
}
|
||||
});
|
||||
promises.push(deferred.promise);
|
||||
}
|
||||
|
||||
promise.all(promises).then(aProperties => {
|
||||
let error = {};
|
||||
let safeGetters;
|
||||
|
||||
// Combine all the property descriptor/getter values into one object.
|
||||
for (let property of aProperties) {
|
||||
if (property.descriptor) {
|
||||
error[property.name] = property.descriptor.value;
|
||||
}
|
||||
else if (property.safeGetterValues) {
|
||||
safeGetters = property.safeGetterValues;
|
||||
}
|
||||
objectClient.getPrototypeAndProperties(aResponse => {
|
||||
if (aResponse.error) {
|
||||
deferred.reject(aResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (safeGetters) {
|
||||
for (let key of Object.keys(safeGetters)) {
|
||||
if (!error.hasOwnProperty(key)) {
|
||||
error[key] = safeGetters[key].getterValue;
|
||||
}
|
||||
}
|
||||
let { ownProperties, safeGetterValues } = aResponse;
|
||||
let error = Object.create(null);
|
||||
|
||||
// Combine all the property descriptor/getter values into one object.
|
||||
for (let key of Object.keys(safeGetterValues)) {
|
||||
error[key] = safeGetterValues[key].getterValue;
|
||||
}
|
||||
|
||||
for (let key of Object.keys(ownProperties)) {
|
||||
error[key] = ownProperties[key].value;
|
||||
}
|
||||
|
||||
// Assemble the best possible stack we can given the properties we have.
|
||||
@ -693,23 +650,23 @@ var Scratchpad = {
|
||||
deferred.resolve(error.message + stack);
|
||||
}
|
||||
else {
|
||||
objectClient.getDisplayString(aResult => {
|
||||
if (aResult.error) {
|
||||
deferred.reject(aResult);
|
||||
objectClient.getDisplayString(aResponse => {
|
||||
if (aResponse.error) {
|
||||
deferred.reject(aResponse);
|
||||
}
|
||||
else if (aResult.displayString.type == "null") {
|
||||
deferred.resolve(stack);
|
||||
else if (typeof aResponse.displayString == "string") {
|
||||
deferred.resolve(aResponse.displayString + stack);
|
||||
}
|
||||
else {
|
||||
deferred.resolve(aResult.displayString + stack);
|
||||
deferred.resolve(stack);
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise.then(aMessage => {
|
||||
console.log(aMessage);
|
||||
console.error(aMessage);
|
||||
this.writeAsComment("Exception: " + aMessage);
|
||||
});
|
||||
},
|
||||
|
@ -43,6 +43,7 @@ function testColorUtils() {
|
||||
let color = new colorUtils.CssColor(authored);
|
||||
|
||||
// Check all values.
|
||||
info("Checking values for " + authored);
|
||||
is(color.name, name, "color.name === name");
|
||||
is(color.hex, hex, "color.hex === hex");
|
||||
is(color.hsl, hsl, "color.hsl === hsl");
|
||||
@ -291,14 +292,18 @@ function getTestData() {
|
||||
{authored: "whitesmoke", name: "whitesmoke", hex: "#F5F5F5", hsl: "hsl(0, 0%, 96%)", rgb: "rgb(245, 245, 245)"},
|
||||
{authored: "yellow", name: "yellow", hex: "#FF0", hsl: "hsl(60, 100%, 50%)", rgb: "rgb(255, 255, 0)"},
|
||||
{authored: "yellowgreen", name: "yellowgreen", hex: "#9ACD32", hsl: "hsl(79.742, 61%, 50%)", rgb: "rgb(154, 205, 50)"},
|
||||
{authored: "transparent", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
|
||||
{authored: "rgba(0, 0, 0, 0)", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
|
||||
{authored: "hsla(0, 0%, 0%, 0)", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
|
||||
{authored: "rgba(0, 0, 0, 0)", name: "rgba(0, 0, 0, 0)", hex: "rgba(0, 0, 0, 0)", hsl: "hsla(0, 0%, 0%, 0)", rgb: "rgba(0, 0, 0, 0)"},
|
||||
{authored: "hsla(0, 0%, 0%, 0)", name: "rgba(0, 0, 0, 0)", hex: "rgba(0, 0, 0, 0)", hsl: "hsla(0, 0%, 0%, 0)", rgb: "rgba(0, 0, 0, 0)"},
|
||||
{authored: "rgba(50, 60, 70, 0.5)", name: "rgba(50, 60, 70, 0.5)", hex: "rgba(50, 60, 70, 0.5)", hsl: "hsla(210, 17%, 24%, 0.5)", rgb: "rgba(50, 60, 70, 0.5)"},
|
||||
{authored: "rgba(0, 0, 0, 0.3)", name: "rgba(0, 0, 0, 0.3)", hex: "rgba(0, 0, 0, 0.3)", hsl: "hsla(0, 0%, 0%, 0.3)", rgb: "rgba(0, 0, 0, 0.3)"},
|
||||
{authored: "rgba(255, 255, 255, 0.6)", name: "rgba(255, 255, 255, 0.6)", hex: "rgba(255, 255, 255, 0.6)", hsl: "hsla(0, 0%, 100%, 0.6)", rgb: "rgba(255, 255, 255, 0.6)"},
|
||||
{authored: "rgba(127, 89, 45, 1)", name: "#7F592D", hex: "#7F592D", hsl: "hsl(32.195, 48%, 34%)", rgb: "rgb(127, 89, 45)"},
|
||||
{authored: "hsla(19.304, 56%, 40%, 1)", name: "#9F512C", hex: "#9F512C", hsl: "hsl(19.304, 57%, 40%)", rgb: "rgb(159, 81, 44)"},
|
||||
{authored: "invalidColor", name: "", hex: "", hsl: "", rgb: ""}
|
||||
{authored: "currentcolor", name: "currentcolor", hex: "currentcolor", hsl: "currentcolor", rgb: "currentcolor"},
|
||||
{authored: "inherit", name: "inherit", hex: "inherit", hsl: "inherit", rgb: "inherit"},
|
||||
{authored: "initial", name: "initial", hex: "initial", hsl: "initial", rgb: "initial"},
|
||||
{authored: "invalidColor", name: "", hex: "", hsl: "", rgb: ""},
|
||||
{authored: "transparent", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
|
||||
{authored: "unset", name: "unset", hex: "unset", hsl: "unset", rgb: "unset"}
|
||||
];
|
||||
}
|
||||
|
@ -461,7 +461,7 @@ VariablesViewController.prototype = {
|
||||
scope.expanded = true;
|
||||
scope.locked = true;
|
||||
|
||||
let variable = scope.addItem();
|
||||
let variable = scope.addItem("", { enumerable: true });
|
||||
let expanded;
|
||||
|
||||
if (aOptions.objectActor) {
|
||||
|
@ -449,7 +449,7 @@ pref("app.update.silent", true);
|
||||
pref("app.update.staging.enabled", true);
|
||||
|
||||
// Update service URL:
|
||||
#ifdef NIGHTLY_BUILD
|
||||
#ifndef RELEASE_BUILD
|
||||
pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
|
||||
#else
|
||||
pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
|
||||
@ -522,8 +522,9 @@ pref("app.update.cert.maxErrors", 5);
|
||||
// the |app.update.url.override| preference should ONLY be used for testing.
|
||||
// IMPORTANT! firefox.js should also be updated for updates to certs.X.issuerName
|
||||
|
||||
// Nightly builds have switched over to aus4.mozilla.org, but we don't want anything else to yet.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Non-release builds (Nightly, Aurora, etc.) have been switched over to aus4.mozilla.org.
|
||||
// This condition protects us against accidentally using it for release builds.
|
||||
#ifndef RELEASE_BUILD
|
||||
pref("app.update.certs.1.issuerName", "CN=DigiCert Secure Server CA,O=DigiCert Inc,C=US");
|
||||
pref("app.update.certs.1.commonName", "aus4.mozilla.org");
|
||||
pref("app.update.certs.2.issuerName", "CN=Thawte SSL CA,O=\"Thawte, Inc.\",C=US");
|
||||
|
426
browser/modules/UITour.jsm
Normal file
426
browser/modules/UITour.jsm
Normal file
@ -0,0 +1,426 @@
|
||||
// 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/.
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["UITour"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PermissionsUtils",
|
||||
"resource://gre/modules/PermissionsUtils.jsm");
|
||||
|
||||
|
||||
const UITOUR_PERMISSION = "uitour";
|
||||
const PREF_PERM_BRANCH = "browser.uitour.";
|
||||
|
||||
|
||||
this.UITour = {
|
||||
originTabs: new WeakMap(),
|
||||
pinnedTabs: new WeakMap(),
|
||||
urlbarCapture: new WeakMap(),
|
||||
|
||||
highlightEffects: ["wobble", "zoom", "color"],
|
||||
targets: new Map([
|
||||
["backforward", "#unified-back-forward-button"],
|
||||
["appmenu", "#appmenu-button"],
|
||||
["home", "#home-button"],
|
||||
["urlbar", "#urlbar"],
|
||||
["bookmarks", "#bookmarks-menu-button"],
|
||||
["search", "#searchbar"],
|
||||
["searchprovider", function UITour_target_searchprovider(aDocument) {
|
||||
let searchbar = aDocument.getElementById("searchbar");
|
||||
return aDocument.getAnonymousElementByAttribute(searchbar,
|
||||
"anonid",
|
||||
"searchbar-engine-button");
|
||||
}],
|
||||
]),
|
||||
|
||||
onPageEvent: function(aEvent) {
|
||||
let contentDocument = null;
|
||||
if (aEvent.target instanceof Ci.nsIDOMHTMLDocument)
|
||||
contentDocument = aEvent.target;
|
||||
else if (aEvent.target instanceof Ci.nsIDOMHTMLElement)
|
||||
contentDocument = aEvent.target.ownerDocument;
|
||||
else
|
||||
return false;
|
||||
|
||||
// Ignore events if they're not from a trusted origin.
|
||||
if (!this.ensureTrustedOrigin(contentDocument))
|
||||
return false;
|
||||
|
||||
if (typeof aEvent.detail != "object")
|
||||
return false;
|
||||
|
||||
let action = aEvent.detail.action;
|
||||
if (typeof action != "string" || !action)
|
||||
return false;
|
||||
|
||||
let data = aEvent.detail.data;
|
||||
if (typeof data != "object")
|
||||
return false;
|
||||
|
||||
let window = this.getChromeWindow(contentDocument);
|
||||
|
||||
switch (action) {
|
||||
case "showHighlight": {
|
||||
let target = this.getTarget(window, data.target);
|
||||
if (!target)
|
||||
return false;
|
||||
this.showHighlight(target);
|
||||
break;
|
||||
}
|
||||
|
||||
case "hideHighlight": {
|
||||
this.hideHighlight(window);
|
||||
break;
|
||||
}
|
||||
|
||||
case "showInfo": {
|
||||
let target = this.getTarget(window, data.target, true);
|
||||
if (!target)
|
||||
return false;
|
||||
this.showInfo(target, data.title, data.text);
|
||||
break;
|
||||
}
|
||||
|
||||
case "hideInfo": {
|
||||
this.hideInfo(window);
|
||||
break;
|
||||
}
|
||||
|
||||
case "previewTheme": {
|
||||
this.previewTheme(data.theme);
|
||||
break;
|
||||
}
|
||||
|
||||
case "resetTheme": {
|
||||
this.resetTheme();
|
||||
break;
|
||||
}
|
||||
|
||||
case "addPinnedTab": {
|
||||
this.ensurePinnedTab(window, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case "removePinnedTab": {
|
||||
this.removePinnedTab(window);
|
||||
break;
|
||||
}
|
||||
|
||||
case "showMenu": {
|
||||
this.showMenu(window, data.name);
|
||||
break;
|
||||
}
|
||||
|
||||
case "startUrlbarCapture": {
|
||||
if (typeof data.text != "string" || !data.text ||
|
||||
typeof data.url != "string" || !data.url) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let uri = null;
|
||||
try {
|
||||
uri = Services.io.newURI(data.url, null, null);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let secman = Services.scriptSecurityManager;
|
||||
let principal = contentDocument.nodePrincipal;
|
||||
let flags = secman.DISALLOW_INHERIT_PRINCIPAL;
|
||||
try {
|
||||
secman.checkLoadURIWithPrincipal(principal, uri, flags);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.startUrlbarCapture(window, data.text, data.url);
|
||||
break;
|
||||
}
|
||||
|
||||
case "endUrlbarCapture": {
|
||||
this.endUrlbarCapture(window);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let tab = window.gBrowser._getTabForContentWindow(contentDocument.defaultView);
|
||||
if (!this.originTabs.has(window))
|
||||
this.originTabs.set(window, new Set());
|
||||
this.originTabs.get(window).add(tab);
|
||||
|
||||
tab.addEventListener("TabClose", this);
|
||||
window.gBrowser.tabContainer.addEventListener("TabSelect", this);
|
||||
window.addEventListener("SSWindowClosing", this);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "pagehide": {
|
||||
let window = this.getChromeWindow(aEvent.target);
|
||||
this.teardownTour(window);
|
||||
break;
|
||||
}
|
||||
|
||||
case "TabClose": {
|
||||
let window = aEvent.target.ownerDocument.defaultView;
|
||||
this.teardownTour(window);
|
||||
break;
|
||||
}
|
||||
|
||||
case "TabSelect": {
|
||||
let window = aEvent.target.ownerDocument.defaultView;
|
||||
let pinnedTab = this.pinnedTabs.get(window);
|
||||
if (pinnedTab && pinnedTab.tab == window.gBrowser.selectedTab)
|
||||
break;
|
||||
let originTabs = this.originTabs.get(window);
|
||||
if (originTabs && originTabs.has(window.gBrowser.selectedTab))
|
||||
break;
|
||||
|
||||
this.teardownTour(window);
|
||||
break;
|
||||
}
|
||||
|
||||
case "SSWindowClosing": {
|
||||
let window = aEvent.target;
|
||||
this.teardownTour(window, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case "input": {
|
||||
if (aEvent.target.id == "urlbar") {
|
||||
let window = aEvent.target.ownerDocument.defaultView;
|
||||
this.handleUrlbarInput(window);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
teardownTour: function(aWindow, aWindowClosing = false) {
|
||||
aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
|
||||
aWindow.removeEventListener("SSWindowClosing", this);
|
||||
|
||||
let originTabs = this.originTabs.get(aWindow);
|
||||
if (originTabs) {
|
||||
for (let tab of originTabs)
|
||||
tab.removeEventListener("TabClose", this);
|
||||
}
|
||||
this.originTabs.delete(aWindow);
|
||||
|
||||
if (!aWindowClosing) {
|
||||
this.hideHighlight(aWindow);
|
||||
this.hideInfo(aWindow);
|
||||
}
|
||||
|
||||
this.endUrlbarCapture(aWindow);
|
||||
this.removePinnedTab(aWindow);
|
||||
this.resetTheme();
|
||||
},
|
||||
|
||||
getChromeWindow: function(aContentDocument) {
|
||||
return aContentDocument.defaultView
|
||||
.window
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow)
|
||||
.wrappedJSObject;
|
||||
},
|
||||
|
||||
importPermissions: function() {
|
||||
try {
|
||||
PermissionsUtils.importFromPrefs(PREF_PERM_BRANCH, UITOUR_PERMISSION);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
ensureTrustedOrigin: function(aDocument) {
|
||||
if (aDocument.defaultView.top != aDocument.defaultView)
|
||||
return false;
|
||||
|
||||
let uri = aDocument.documentURIObject;
|
||||
|
||||
if (uri.schemeIs("chrome"))
|
||||
return true;
|
||||
|
||||
if (!uri.schemeIs("https"))
|
||||
return false;
|
||||
|
||||
this.importPermissions();
|
||||
let permission = Services.perms.testPermission(uri, UITOUR_PERMISSION);
|
||||
return permission == Services.perms.ALLOW_ACTION;
|
||||
},
|
||||
|
||||
getTarget: function(aWindow, aTargetName, aSticky = false) {
|
||||
if (typeof aTargetName != "string" || !aTargetName)
|
||||
return null;
|
||||
|
||||
if (aTargetName == "pinnedtab")
|
||||
return this.ensurePinnedTab(aWindow, aSticky);
|
||||
|
||||
let targetQuery = this.targets.get(aTargetName);
|
||||
if (!targetQuery)
|
||||
return null;
|
||||
|
||||
if (typeof targetQuery == "function")
|
||||
return targetQuery(aWindow.document);
|
||||
|
||||
return aWindow.document.querySelector(targetQuery);
|
||||
},
|
||||
|
||||
previewTheme: function(aTheme) {
|
||||
let origin = Services.prefs.getCharPref("browser.uitour.themeOrigin");
|
||||
let data = LightweightThemeManager.parseTheme(aTheme, origin);
|
||||
if (data)
|
||||
LightweightThemeManager.previewTheme(data);
|
||||
},
|
||||
|
||||
resetTheme: function() {
|
||||
LightweightThemeManager.resetPreview();
|
||||
},
|
||||
|
||||
ensurePinnedTab: function(aWindow, aSticky = false) {
|
||||
let tabInfo = this.pinnedTabs.get(aWindow);
|
||||
|
||||
if (tabInfo) {
|
||||
tabInfo.sticky = tabInfo.sticky || aSticky;
|
||||
} else {
|
||||
let url = Services.urlFormatter.formatURLPref("browser.uitour.pinnedTabUrl");
|
||||
|
||||
let tab = aWindow.gBrowser.addTab(url);
|
||||
aWindow.gBrowser.pinTab(tab);
|
||||
tab.addEventListener("TabClose", () => {
|
||||
this.pinnedTabs.delete(aWindow);
|
||||
});
|
||||
|
||||
tabInfo = {
|
||||
tab: tab,
|
||||
sticky: aSticky
|
||||
};
|
||||
this.pinnedTabs.set(aWindow, tabInfo);
|
||||
}
|
||||
|
||||
return tabInfo.tab;
|
||||
},
|
||||
|
||||
removePinnedTab: function(aWindow) {
|
||||
let tabInfo = this.pinnedTabs.get(aWindow);
|
||||
if (tabInfo)
|
||||
aWindow.gBrowser.removeTab(tabInfo.tab);
|
||||
},
|
||||
|
||||
showHighlight: function(aTarget) {
|
||||
let highlighter = aTarget.ownerDocument.getElementById("UITourHighlight");
|
||||
|
||||
let randomEffect = Math.floor(Math.random() * this.highlightEffects.length);
|
||||
if (randomEffect == this.highlightEffects.length)
|
||||
randomEffect--; // On the order of 1 in 2^62 chance of this happening.
|
||||
highlighter.setAttribute("active", this.highlightEffects[randomEffect]);
|
||||
|
||||
let targetRect = aTarget.getBoundingClientRect();
|
||||
|
||||
highlighter.style.height = targetRect.height + "px";
|
||||
highlighter.style.width = targetRect.width + "px";
|
||||
|
||||
let highlighterRect = highlighter.getBoundingClientRect();
|
||||
|
||||
let top = targetRect.top + (targetRect.height / 2) - (highlighterRect.height / 2);
|
||||
highlighter.style.top = top + "px";
|
||||
let left = targetRect.left + (targetRect.width / 2) - (highlighterRect.width / 2);
|
||||
highlighter.style.left = left + "px";
|
||||
},
|
||||
|
||||
hideHighlight: function(aWindow) {
|
||||
let tabData = this.pinnedTabs.get(aWindow);
|
||||
if (tabData && !tabData.sticky)
|
||||
this.removePinnedTab(aWindow);
|
||||
|
||||
let highlighter = aWindow.document.getElementById("UITourHighlight");
|
||||
highlighter.removeAttribute("active");
|
||||
},
|
||||
|
||||
showInfo: function(aAnchor, aTitle, aDescription) {
|
||||
aAnchor.focus();
|
||||
|
||||
let document = aAnchor.ownerDocument;
|
||||
let tooltip = document.getElementById("UITourTooltip");
|
||||
let tooltipTitle = document.getElementById("UITourTooltipTitle");
|
||||
let tooltipDesc = document.getElementById("UITourTooltipDescription");
|
||||
|
||||
tooltip.hidePopup();
|
||||
|
||||
tooltipTitle.textContent = aTitle;
|
||||
tooltipDesc.textContent = aDescription;
|
||||
|
||||
let alignment = "bottomcenter topright";
|
||||
let anchorRect = aAnchor.getBoundingClientRect();
|
||||
|
||||
tooltip.hidden = false;
|
||||
tooltip.openPopup(aAnchor, alignment);
|
||||
},
|
||||
|
||||
hideInfo: function(aWindow) {
|
||||
let tooltip = aWindow.document.getElementById("UITourTooltip");
|
||||
tooltip.hidePopup();
|
||||
},
|
||||
|
||||
showMenu: function(aWindow, aMenuName) {
|
||||
function openMenuButton(aId) {
|
||||
let menuBtn = aWindow.document.getElementById(aId);
|
||||
if (menuBtn && menuBtn.boxObject)
|
||||
menuBtn.boxObject.QueryInterface(Ci.nsIMenuBoxObject).openMenu(true);
|
||||
}
|
||||
|
||||
if (aMenuName == "appmenu")
|
||||
openMenuButton("appmenu-button");
|
||||
else if (aMenuName == "bookmarks")
|
||||
openMenuButton("bookmarks-menu-button");
|
||||
},
|
||||
|
||||
startUrlbarCapture: function(aWindow, aExpectedText, aUrl) {
|
||||
let urlbar = aWindow.document.getElementById("urlbar");
|
||||
this.urlbarCapture.set(aWindow, {
|
||||
expected: aExpectedText.toLocaleLowerCase(),
|
||||
url: aUrl
|
||||
});
|
||||
urlbar.addEventListener("input", this);
|
||||
},
|
||||
|
||||
endUrlbarCapture: function(aWindow) {
|
||||
let urlbar = aWindow.document.getElementById("urlbar");
|
||||
urlbar.removeEventListener("input", this);
|
||||
this.urlbarCapture.delete(aWindow);
|
||||
},
|
||||
|
||||
handleUrlbarInput: function(aWindow) {
|
||||
if (!this.urlbarCapture.has(aWindow))
|
||||
return;
|
||||
|
||||
let urlbar = aWindow.document.getElementById("urlbar");
|
||||
|
||||
let {expected, url} = this.urlbarCapture.get(aWindow);
|
||||
|
||||
if (urlbar.value.toLocaleLowerCase().localeCompare(expected) != 0)
|
||||
return;
|
||||
|
||||
urlbar.handleRevert();
|
||||
|
||||
let tab = aWindow.gBrowser.addTab(url, {
|
||||
owner: aWindow.gBrowser.selectedTab,
|
||||
relatedToCurrent: true
|
||||
});
|
||||
aWindow.gBrowser.selectedTab = tab;
|
||||
},
|
||||
};
|
@ -15,6 +15,7 @@ EXTRA_JS_MODULES += [
|
||||
'SitePermissions.jsm',
|
||||
'Social.jsm',
|
||||
'TabCrashReporter.jsm',
|
||||
'UITour.jsm',
|
||||
'offlineAppCache.jsm',
|
||||
'openLocationLastURL.jsm',
|
||||
'webappsUI.jsm',
|
||||
|
@ -1,3 +1,5 @@
|
||||
[DEFAULT]
|
||||
|
||||
[browser_NetworkPrioritizer.js]
|
||||
[browser_UITour.js]
|
||||
support-files = uitour.*
|
212
browser/modules/test/browser_UITour.js
Normal file
212
browser/modules/test/browser_UITour.js
Normal file
@ -0,0 +1,212 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let gTestTab;
|
||||
let gContentAPI;
|
||||
|
||||
Components.utils.import("resource:///modules/UITour.jsm");
|
||||
|
||||
function is_hidden(element) {
|
||||
var style = element.ownerDocument.defaultView.getComputedStyle(element, "");
|
||||
if (style.display == "none")
|
||||
return true;
|
||||
if (style.visibility != "visible")
|
||||
return true;
|
||||
|
||||
// Hiding a parent element will hide all its children
|
||||
if (element.parentNode != element.ownerDocument)
|
||||
return is_hidden(element.parentNode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function is_element_visible(element, msg) {
|
||||
isnot(element, null, "Element should not be null, when checking visibility");
|
||||
ok(!is_hidden(element), msg);
|
||||
}
|
||||
|
||||
function is_element_hidden(element, msg) {
|
||||
isnot(element, null, "Element should not be null, when checking visibility");
|
||||
ok(is_hidden(element), msg);
|
||||
}
|
||||
|
||||
function loadTestPage(callback, untrustedHost = false) {
|
||||
if (gTestTab)
|
||||
gBrowser.removeTab(gTestTab);
|
||||
|
||||
let url = getRootDirectory(gTestPath) + "uitour.html";
|
||||
if (untrustedHost)
|
||||
url = url.replace("chrome://mochitests/content/", "http://example.com/");
|
||||
|
||||
gTestTab = gBrowser.addTab(url);
|
||||
gBrowser.selectedTab = gTestTab;
|
||||
|
||||
gTestTab.linkedBrowser.addEventListener("load", function onLoad() {
|
||||
gTestTab.linkedBrowser.removeEventListener("load", onLoad);
|
||||
|
||||
let contentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView);
|
||||
gContentAPI = contentWindow.Mozilla.UITour;
|
||||
|
||||
waitForFocus(callback, contentWindow);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
Services.prefs.setBoolPref("browser.uitour.enabled", true);
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
delete window.UITour;
|
||||
delete window.gContentAPI;
|
||||
if (gTestTab)
|
||||
gBrowser.removeTab(gTestTab);
|
||||
delete window.gTestTab;
|
||||
Services.prefs.clearUserPref("browser.uitour.enabled", true);
|
||||
});
|
||||
|
||||
function done() {
|
||||
if (gTestTab)
|
||||
gBrowser.removeTab(gTestTab);
|
||||
gTestTab = null;
|
||||
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
is_element_hidden(highlight, "Highlight should be hidden after UITour tab is closed");
|
||||
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
isnot(["hidding","closed"].indexOf(popup.state), -1, "Popup should be closed/hidding after UITour tab is closed");
|
||||
|
||||
is(UITour.pinnedTabs.get(window), null, "Any pinned tab should be closed after UITour tab is closed");
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
|
||||
function nextTest() {
|
||||
if (tests.length == 0) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
let test = tests.shift();
|
||||
|
||||
loadTestPage(function() {
|
||||
test(done);
|
||||
});
|
||||
}
|
||||
nextTest();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
function test_disabled(done) {
|
||||
Services.prefs.setBoolPref("browser.uitour.enabled", false);
|
||||
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
is_element_hidden(highlight, "Highlight should initially be hidden");
|
||||
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
is_element_hidden(highlight, "Highlight should not be shown when feature is disabled");
|
||||
|
||||
Services.prefs.setBoolPref("browser.uitour.enabled", true);
|
||||
done();
|
||||
},
|
||||
function test_untrusted_host(done) {
|
||||
loadTestPage(function() {
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
is_element_hidden(highlight, "Highlight should initially be hidden");
|
||||
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
is_element_hidden(highlight, "Highlight should not be shown on a untrusted domain");
|
||||
|
||||
done();
|
||||
}, true);
|
||||
},
|
||||
function test_highlight(done) {
|
||||
let highlight = document.getElementById("UITourHighlight");
|
||||
is_element_hidden(highlight, "Highlight should initially be hidden");
|
||||
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
is_element_visible(highlight, "Highlight should be shown after showHighlight()");
|
||||
|
||||
gContentAPI.hideHighlight();
|
||||
is_element_hidden(highlight, "Highlight should be hidden after hideHighlight()");
|
||||
|
||||
gContentAPI.showHighlight("urlbar");
|
||||
is_element_visible(highlight, "Highlight should be shown after showHighlight()");
|
||||
gContentAPI.showHighlight("backforward");
|
||||
is_element_visible(highlight, "Highlight should be shown after showHighlight()");
|
||||
|
||||
done();
|
||||
},
|
||||
function test_info_1(done) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
|
||||
is(title.textContent, "test title", "Popup should have correct title");
|
||||
is(desc.textContent, "test text", "Popup should have correct description text");
|
||||
|
||||
popup.addEventListener("popuphidden", function onPopupHidden() {
|
||||
popup.removeEventListener("popuphidden", onPopupHidden);
|
||||
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
done();
|
||||
});
|
||||
|
||||
gContentAPI.showInfo("urlbar", "test title", "test text");
|
||||
|
||||
});
|
||||
gContentAPI.hideInfo();
|
||||
});
|
||||
|
||||
gContentAPI.showInfo("urlbar", "test title", "test text");
|
||||
},
|
||||
function test_info_2(done) {
|
||||
let popup = document.getElementById("UITourTooltip");
|
||||
let title = document.getElementById("UITourTooltipTitle");
|
||||
let desc = document.getElementById("UITourTooltipDescription");
|
||||
popup.addEventListener("popupshown", function onPopupShown() {
|
||||
popup.removeEventListener("popupshown", onPopupShown);
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("urlbar"), "Popup should be anchored to the urlbar");
|
||||
is(title.textContent, "urlbar title", "Popup should have correct title");
|
||||
is(desc.textContent, "urlbar text", "Popup should have correct description text");
|
||||
|
||||
gContentAPI.showInfo("search", "search title", "search text");
|
||||
executeSoon(function() {
|
||||
is(popup.popupBoxObject.anchorNode, document.getElementById("searchbar"), "Popup should be anchored to the searchbar");
|
||||
is(title.textContent, "search title", "Popup should have correct title");
|
||||
is(desc.textContent, "search text", "Popup should have correct description text");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
gContentAPI.showInfo("urlbar", "urlbar title", "urlbar text");
|
||||
},
|
||||
function test_pinnedTab(done) {
|
||||
is(UITour.pinnedTabs.get(window), null, "Should not already have a pinned tab");
|
||||
|
||||
gContentAPI.addPinnedTab();
|
||||
let tabInfo = UITour.pinnedTabs.get(window);
|
||||
isnot(tabInfo, null, "Should have recorded data about a pinned tab after addPinnedTab()");
|
||||
isnot(tabInfo.tab, null, "Should have added a pinned tab after addPinnedTab()");
|
||||
is(tabInfo.tab.pinned, true, "Tab should be marked as pinned");
|
||||
|
||||
let tab = tabInfo.tab;
|
||||
|
||||
gContentAPI.removePinnedTab();
|
||||
isnot(gBrowser.tabs[0], tab, "First tab should not be the pinned tab");
|
||||
let tabInfo = UITour.pinnedTabs.get(window);
|
||||
is(tabInfo, null, "Should not have any data about the removed pinned tab after removePinnedTab()");
|
||||
|
||||
gContentAPI.addPinnedTab();
|
||||
gContentAPI.addPinnedTab();
|
||||
gContentAPI.addPinnedTab();
|
||||
is(gBrowser.tabs[1].pinned, false, "After multiple calls of addPinnedTab, should still only have one pinned tab");
|
||||
|
||||
done();
|
||||
},
|
||||
];
|
15
browser/modules/test/uitour.html
Normal file
15
browser/modules/test/uitour.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>UITour test</title>
|
||||
<script type="application/javascript" src="uitour.js">
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>UITour tests</h1>
|
||||
<p>Because Firefox is...</p>
|
||||
<p>Never gonna let you down</p>
|
||||
<p>Never gonna give you up</p>
|
||||
</body>
|
||||
</html>
|
115
browser/modules/test/uitour.js
Normal file
115
browser/modules/test/uitour.js
Normal file
@ -0,0 +1,115 @@
|
||||
/* 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/. */
|
||||
|
||||
// Copied from the proposed JS library for Bedrock (ie, www.mozilla.org).
|
||||
|
||||
// create namespace
|
||||
if (typeof Mozilla == 'undefined') {
|
||||
var Mozilla = {};
|
||||
}
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
// create namespace
|
||||
if (typeof Mozilla.UITour == 'undefined') {
|
||||
Mozilla.UITour = {};
|
||||
}
|
||||
|
||||
var themeIntervalId = null;
|
||||
function _stopCyclingThemes() {
|
||||
if (themeIntervalId) {
|
||||
clearInterval(themeIntervalId);
|
||||
themeIntervalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _sendEvent(action, data) {
|
||||
var event = new CustomEvent('mozUITour', {
|
||||
bubbles: true,
|
||||
detail: {
|
||||
action: action,
|
||||
data: data || {}
|
||||
}
|
||||
});
|
||||
console.log("Sending mozUITour event: ", event);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY = 10 * 1000;
|
||||
|
||||
Mozilla.UITour.showHighlight = function(target) {
|
||||
_sendEvent('showHighlight', {
|
||||
target: target
|
||||
});
|
||||
};
|
||||
|
||||
Mozilla.UITour.hideHighlight = function() {
|
||||
_sendEvent('hideHighlight');
|
||||
};
|
||||
|
||||
Mozilla.UITour.showInfo = function(target, title, text) {
|
||||
_sendEvent('showInfo', {
|
||||
target: target,
|
||||
title: title,
|
||||
text: text
|
||||
});
|
||||
};
|
||||
|
||||
Mozilla.UITour.hideInfo = function() {
|
||||
_sendEvent('hideInfo');
|
||||
};
|
||||
|
||||
Mozilla.UITour.previewTheme = function(theme) {
|
||||
_stopCyclingThemes();
|
||||
|
||||
_sendEvent('previewTheme', {
|
||||
theme: JSON.stringify(theme)
|
||||
});
|
||||
};
|
||||
|
||||
Mozilla.UITour.resetTheme = function() {
|
||||
_stopCyclingThemes();
|
||||
|
||||
_sendEvent('resetTheme');
|
||||
};
|
||||
|
||||
Mozilla.UITour.cycleThemes = function(themes, delay, callback) {
|
||||
_stopCyclingThemes();
|
||||
|
||||
if (!delay) {
|
||||
delay = Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY;
|
||||
}
|
||||
|
||||
function nextTheme() {
|
||||
var theme = themes.shift();
|
||||
themes.push(theme);
|
||||
|
||||
_sendEvent('previewTheme', {
|
||||
theme: JSON.stringify(theme),
|
||||
state: true
|
||||
});
|
||||
|
||||
callback(theme);
|
||||
}
|
||||
|
||||
themeIntervalId = setInterval(nextTheme, delay);
|
||||
nextTheme();
|
||||
};
|
||||
|
||||
Mozilla.UITour.addPinnedTab = function() {
|
||||
_sendEvent('addPinnedTab');
|
||||
};
|
||||
|
||||
Mozilla.UITour.removePinnedTab = function() {
|
||||
_sendEvent('removePinnedTab');
|
||||
};
|
||||
|
||||
Mozilla.UITour.showMenu = function(name) {
|
||||
_sendEvent('showMenu', {
|
||||
name: name
|
||||
});
|
||||
};
|
||||
})();
|
@ -30,9 +30,8 @@ this.webappsUI = {
|
||||
Services.obs.addObserver(this, "webapps-launch", false);
|
||||
Services.obs.addObserver(this, "webapps-uninstall", false);
|
||||
cpmm.addMessageListener("Webapps:Install:Return:OK", this);
|
||||
cpmm.addMessageListener("Webapps:OfflineCache", this);
|
||||
cpmm.addMessageListener("Webapps:Install:Return:KO", this);
|
||||
cpmm.addMessageListener("Webapps:PackageEvent", this);
|
||||
cpmm.addMessageListener("Webapps:UpdateState", this);
|
||||
},
|
||||
|
||||
uninit: function webappsUI_uninit() {
|
||||
@ -40,9 +39,8 @@ this.webappsUI = {
|
||||
Services.obs.removeObserver(this, "webapps-launch");
|
||||
Services.obs.removeObserver(this, "webapps-uninstall");
|
||||
cpmm.removeMessageListener("Webapps:Install:Return:OK", this);
|
||||
cpmm.removeMessageListener("Webapps:OfflineCache", this);
|
||||
cpmm.removeMessageListener("Webapps:Install:Return:KO", this);
|
||||
cpmm.removeMessageListener("Webapps:PackageEvent", this);
|
||||
cpmm.removeMessageListener("Webapps:UpdateState", this);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
@ -56,10 +54,10 @@ this.webappsUI = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aMessage.name == "Webapps:OfflineCache") {
|
||||
if (aMessage.name == "Webapps:UpdateState") {
|
||||
if (data.error) {
|
||||
this.installations[manifestURL].reject(data.error);
|
||||
} else if (data.installState == "installed") {
|
||||
} else if (data.app.installState == "installed") {
|
||||
this.installations[manifestURL].resolve();
|
||||
}
|
||||
} else if (aMessage.name == "Webapps:Install:Return:OK" &&
|
||||
@ -70,12 +68,6 @@ this.webappsUI = {
|
||||
}
|
||||
} else if (aMessage.name == "Webapps:Install:Return:KO") {
|
||||
this.installations[manifestURL].reject(data.error);
|
||||
} else if (aMessage.name == "Webapps:PackageEvent") {
|
||||
if (data.type == "installed") {
|
||||
this.installations[manifestURL].resolve();
|
||||
} else if (data.type == "error") {
|
||||
this.installations[manifestURL].reject(data.error);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2113,6 +2113,90 @@ toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
/* UI Tour */
|
||||
|
||||
@keyframes uitour-wobble {
|
||||
from {
|
||||
transform: rotate(0deg) translateX(2px) rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg) translateX(2px) rotate(-360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uitour-zoom {
|
||||
from {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
to {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uitour-color {
|
||||
from {
|
||||
border-color: #5B9CD9;
|
||||
}
|
||||
50% {
|
||||
border-color: #FF0000;
|
||||
}
|
||||
to {
|
||||
border-color: #5B9CD9;
|
||||
}
|
||||
}
|
||||
|
||||
html|div#UITourHighlight {
|
||||
display: none;
|
||||
position: absolute;
|
||||
min-height: 32px;
|
||||
min-width: 32px;
|
||||
display: none;
|
||||
border: 2px #5B9CD9 solid;
|
||||
box-shadow: 0 0 2px #5B9CD9, inset 0 0 1px #5B9CD9;
|
||||
border-radius: 20px;
|
||||
z-index: 10000000000;
|
||||
}
|
||||
|
||||
html|div#UITourHighlight[active] {
|
||||
display: block;
|
||||
animation-delay: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
html|div#UITourHighlight[active="wobble"] {
|
||||
animation-name: uitour-wobble;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
html|div#UITourHighlight[active="zoom"] {
|
||||
animation-name: uitour-zoom;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
html|div#UITourHighlight[active="color"] {
|
||||
animation-name: uitour-color;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
#UITourTooltip {
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
#UITourTooltipTitle {
|
||||
font-weight: bold;
|
||||
font-size: 130%;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
#UITourTooltipDescription {
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
/* Social toolbar item */
|
||||
|
||||
#social-provider-button {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
||||
|
@ -3728,6 +3728,88 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* UI Tour */
|
||||
|
||||
@keyframes uitour-wobble {
|
||||
from {
|
||||
transform: rotate(0deg) translateX(2px) rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg) translateX(2px) rotate(-360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uitour-zoom {
|
||||
from {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
to {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uitour-color {
|
||||
from {
|
||||
border-color: #5B9CD9;
|
||||
}
|
||||
50% {
|
||||
border-color: #FF0000;
|
||||
}
|
||||
to {
|
||||
border-color: #5B9CD9;
|
||||
}
|
||||
}
|
||||
|
||||
html|div#UITourHighlight {
|
||||
display: none;
|
||||
position: absolute;
|
||||
min-height: 32px;
|
||||
min-width: 32px;
|
||||
display: none;
|
||||
border: 2px #5B9CD9 solid;
|
||||
box-shadow: 0 0 2px #5B9CD9, inset 0 0 1px #5B9CD9;
|
||||
border-radius: 20px;
|
||||
z-index: 10000000000;
|
||||
}
|
||||
|
||||
html|div#UITourHighlight[active] {
|
||||
display: block;
|
||||
animation-delay: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
html|div#UITourHighlight[active="wobble"] {
|
||||
animation-name: uitour-wobble;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
html|div#UITourHighlight[active="zoom"] {
|
||||
animation-name: uitour-zoom;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
html|div#UITourHighlight[active="color"] {
|
||||
animation-name: uitour-color;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
#UITourTooltip {
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
#UITourTooltipTitle {
|
||||
font-weight: bold;
|
||||
font-size: 130%;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
#UITourTooltipDescription {
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
/* === social toolbar button === */
|
||||
|
||||
#social-toolbar-item > .toolbarbutton-1 {
|
||||
|
@ -2855,6 +2855,87 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
/* UI Tour */
|
||||
|
||||
@keyframes uitour-wobble {
|
||||
from {
|
||||
transform: rotate(0deg) translateX(2px) rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg) translateX(2px) rotate(-360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uitour-zoom {
|
||||
from {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
to {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes uitour-color {
|
||||
from {
|
||||
border-color: #5B9CD9;
|
||||
}
|
||||
50% {
|
||||
border-color: #FF0000;
|
||||
}
|
||||
to {
|
||||
border-color: #5B9CD9;
|
||||
}
|
||||
}
|
||||
|
||||
html|div#UITourHighlight {
|
||||
display: none;
|
||||
position: absolute;
|
||||
min-height: 32px;
|
||||
min-width: 32px;
|
||||
display: none;
|
||||
border: 2px #5B9CD9 solid;
|
||||
box-shadow: 0 0 2px #5B9CD9, inset 0 0 1px #5B9CD9;
|
||||
border-radius: 20px;
|
||||
z-index: 10000000000;
|
||||
}
|
||||
|
||||
html|div#UITourHighlight[active] {
|
||||
display: block;
|
||||
animation-delay: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
html|div#UITourHighlight[active="wobble"] {
|
||||
animation-name: uitour-wobble;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
html|div#UITourHighlight[active="zoom"] {
|
||||
animation-name: uitour-zoom;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
html|div#UITourHighlight[active="color"] {
|
||||
animation-name: uitour-color;
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
#UITourTooltip {
|
||||
}
|
||||
|
||||
#UITourTooltipTitle {
|
||||
font-weight: bold;
|
||||
font-size: 130%;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
#UITourTooltipDescription {
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
/* Social toolbar item */
|
||||
|
||||
#social-provider-button {
|
||||
|
@ -29,9 +29,9 @@ toolkit/library
|
||||
editor
|
||||
parser
|
||||
js/src
|
||||
js/xpconnect
|
||||
js/xpconnect/loader
|
||||
mfbt
|
||||
js/xpconnect
|
||||
js/xpconnect/loader
|
||||
view
|
||||
caps
|
||||
xpfe/appshell
|
||||
|
51
configure.in
51
configure.in
@ -86,27 +86,41 @@ dnl ========================================================
|
||||
MOZ_USE_PTHREADS=
|
||||
_PTHREAD_LDFLAGS=""
|
||||
|
||||
dnl Do not allow a separate objdir build if a srcdir build exists.
|
||||
dnl Do not allow objdir == srcdir builds.
|
||||
dnl ==============================================================
|
||||
_topsrcdir=`cd \`dirname $0\`; pwd`
|
||||
_objdir=`pwd`
|
||||
|
||||
if test "$_topsrcdir" != "$_objdir"
|
||||
then
|
||||
# Check for a couple representative files in the source tree
|
||||
_conflict_files=
|
||||
for file in $_topsrcdir/Makefile $_topsrcdir/config/autoconf.mk; do
|
||||
if test -f $file; then
|
||||
_conflict_files="$_conflict_files $file"
|
||||
fi
|
||||
|
||||
|
||||
dnl TODO Don't exempt L10N builds once bug 842760 is resolved.
|
||||
if test "$_topsrcdir" = "$_objdir" -a "${with_l10n_base+set}" != set; then
|
||||
echo " ***"
|
||||
echo " * Building directly in the main source directory is not allowed."
|
||||
echo " *"
|
||||
echo " * To build, you must run configure from a separate directory"
|
||||
echo " * (referred to as an object directory)."
|
||||
echo " *"
|
||||
echo " * If you are building with a mozconfig, you will need to change your"
|
||||
echo " * mozconfig to point to a different object directory."
|
||||
echo " ***"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for a couple representative files in the source tree
|
||||
_conflict_files=
|
||||
for file in $_topsrcdir/Makefile $_topsrcdir/config/autoconf.mk; do
|
||||
if test -f $file; then
|
||||
_conflict_files="$_conflict_files $file"
|
||||
fi
|
||||
done
|
||||
if test "$_conflict_files"; then
|
||||
echo "***"
|
||||
echo "* Your source tree contains these files:"
|
||||
for file in $_conflict_files; do
|
||||
echo "* $file"
|
||||
done
|
||||
if test "$_conflict_files"; then
|
||||
echo "***"
|
||||
echo "* Your source tree contains these files:"
|
||||
for file in $_conflict_files; do
|
||||
echo "* $file"
|
||||
done
|
||||
cat 1>&2 <<-EOF
|
||||
cat 1>&2 <<-EOF
|
||||
* This indicates that you previously built in the source tree.
|
||||
* A source tree build can confuse the separate objdir build.
|
||||
*
|
||||
@ -115,9 +129,8 @@ then
|
||||
* 2. gmake distclean
|
||||
***
|
||||
EOF
|
||||
exit 1
|
||||
break
|
||||
fi
|
||||
exit 1
|
||||
break
|
||||
fi
|
||||
MOZ_BUILD_ROOT=`pwd`
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#endif
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
@ -1637,7 +1638,7 @@ public:
|
||||
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, const nsIID* aIID,
|
||||
JS::Value *vp,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
// If non-null aHolder will keep the Value alive
|
||||
// while there's a ref to it
|
||||
nsIXPConnectJSObjectHolder** aHolder = nullptr,
|
||||
@ -1649,7 +1650,7 @@ public:
|
||||
|
||||
// Same as the WrapNative above, but use this one if aIID is nsISupports' IID.
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, JS::Value *vp,
|
||||
nsISupports *native, JS::MutableHandle<JS::Value> vp,
|
||||
// If non-null aHolder will keep the Value alive
|
||||
// while there's a ref to it
|
||||
nsIXPConnectJSObjectHolder** aHolder = nullptr,
|
||||
@ -1660,7 +1661,7 @@ public:
|
||||
}
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, nsWrapperCache *cache,
|
||||
JS::Value *vp,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
// If non-null aHolder will keep the Value alive
|
||||
// while there's a ref to it
|
||||
nsIXPConnectJSObjectHolder** aHolder = nullptr,
|
||||
@ -2091,7 +2092,7 @@ private:
|
||||
|
||||
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, nsWrapperCache *cache,
|
||||
const nsIID* aIID, JS::Value *vp,
|
||||
const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
|
||||
nsIXPConnectJSObjectHolder** aHolder,
|
||||
bool aAllowWrapping);
|
||||
|
||||
|
@ -5659,14 +5659,14 @@ nsContentUtils::DispatchXULCommand(nsIContent* aTarget,
|
||||
nsresult
|
||||
nsContentUtils::WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsISupports *native, nsWrapperCache *cache,
|
||||
const nsIID* aIID, JS::Value *vp,
|
||||
const nsIID* aIID, JS::MutableHandleValue vp,
|
||||
nsIXPConnectJSObjectHolder **aHolder,
|
||||
bool aAllowWrapping)
|
||||
{
|
||||
if (!native) {
|
||||
NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
|
||||
|
||||
*vp = JSVAL_NULL;
|
||||
vp.setNull();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -5685,7 +5685,7 @@ nsContentUtils::WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
|
||||
nsresult rv = NS_OK;
|
||||
AutoPushJSContext context(cx);
|
||||
rv = sXPConnect->WrapNativeToJSVal(context, scope, native, cache, aIID,
|
||||
aAllowWrapping, vp, aHolder);
|
||||
aAllowWrapping, vp.address(), aHolder);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -5728,8 +5728,7 @@ nsContentUtils::CreateBlobBuffer(JSContext* aCx,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
return nsContentUtils::WrapNative(aCx, scope, blob, aBlob.address(), nullptr,
|
||||
true);
|
||||
return nsContentUtils::WrapNative(aCx, scope, blob, aBlob, nullptr, true);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -206,9 +206,11 @@ nsDOMFileReader::GetResult(JSContext* aCx, JS::Value* aResult)
|
||||
}
|
||||
|
||||
nsString tmpResult = mResult;
|
||||
if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
|
||||
JS::Rooted<JS::Value> result(aCx);
|
||||
if (!xpc::StringToJsval(aCx, tmpResult, &result)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aResult = result;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5167,7 +5167,7 @@ CustomElementConstructor(JSContext *aCx, unsigned aArgc, JS::Value* aVp)
|
||||
nsresult rv = document->CreateElem(elemName, nullptr, kNameSpaceID_XHTML,
|
||||
getter_AddRefs(newElement));
|
||||
rv = nsContentUtils::WrapNative(aCx, global, newElement, newElement,
|
||||
args.rval().address());
|
||||
args.rval());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
@ -6732,7 +6732,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
|
||||
JS::Rooted<JSObject*> global(cx, GetScopeObject()->GetGlobalJSObject());
|
||||
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
rv = nsContentUtils::WrapNative(cx, global, this, this, v.address(),
|
||||
rv = nsContentUtils::WrapNative(cx, global, this, this, &v,
|
||||
nullptr, /* aAllowWrapping = */ false);
|
||||
if (rv.Failed())
|
||||
return nullptr;
|
||||
@ -11345,7 +11345,7 @@ nsIDocument::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, obj, win,
|
||||
&NS_GET_IID(nsIDOMWindow),
|
||||
winVal.address(),
|
||||
&winVal,
|
||||
getter_AddRefs(holder),
|
||||
false);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -832,7 +832,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
|
||||
JS::Rooted<JS::Value> targetv(ctx);
|
||||
JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
|
||||
nsContentUtils::WrapNative(ctx, global, aTarget, targetv.address(),
|
||||
nsContentUtils::WrapNative(ctx, global, aTarget, &targetv,
|
||||
nullptr, true);
|
||||
|
||||
JS::RootedObject cpows(ctx);
|
||||
@ -888,7 +888,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
}
|
||||
JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
|
||||
nsContentUtils::WrapNative(ctx, global, defaultThisValue,
|
||||
thisValue.address(), nullptr, true);
|
||||
&thisValue, nullptr, true);
|
||||
} else {
|
||||
// If the listener is a JS object which has receiveMessage function:
|
||||
if (!JS_GetProperty(ctx, object, "receiveMessage", &funval) ||
|
||||
|
@ -49,7 +49,15 @@ void
|
||||
nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri)
|
||||
{
|
||||
if (gDataTable) {
|
||||
gDataTable->Remove(aUri);
|
||||
nsCString uriIgnoringRef;
|
||||
int32_t hashPos = aUri.FindChar('#');
|
||||
if (hashPos < 0) {
|
||||
uriIgnoringRef = aUri;
|
||||
}
|
||||
else {
|
||||
uriIgnoringRef = StringHead(aUri, hashPos);
|
||||
}
|
||||
gDataTable->Remove(uriIgnoringRef);
|
||||
if (gDataTable->Count() == 0) {
|
||||
delete gDataTable;
|
||||
gDataTable = nullptr;
|
||||
@ -80,6 +88,27 @@ nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static DataInfo*
|
||||
GetDataInfo(const nsACString& aUri)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
nsCString uriIgnoringRef;
|
||||
int32_t hashPos = aUri.FindChar('#');
|
||||
if (hashPos < 0) {
|
||||
uriIgnoringRef = aUri;
|
||||
}
|
||||
else {
|
||||
uriIgnoringRef = StringHead(aUri, hashPos);
|
||||
}
|
||||
gDataTable->Get(uriIgnoringRef, &res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri)
|
||||
{
|
||||
@ -87,8 +116,8 @@ nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
gDataTable->Get(aUri, &res);
|
||||
DataInfo* res = GetDataInfo(aUri);
|
||||
|
||||
if (!res) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -114,18 +143,6 @@ nsHostObjectProtocolHandler::Traverse(const nsACString& aUri,
|
||||
aCallback.NoteXPCOMChild(res->mObject);
|
||||
}
|
||||
|
||||
static DataInfo*
|
||||
GetDataInfo(const nsACString& aUri)
|
||||
{
|
||||
if (!gDataTable) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataInfo* res;
|
||||
gDataTable->Get(aUri, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static nsISupports*
|
||||
GetDataObject(nsIURI* aURI)
|
||||
{
|
||||
|
@ -966,7 +966,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
|
||||
if (aRv.Failed()) {
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
JS::Value result;
|
||||
JS::Rooted<JS::Value> result(aCx);
|
||||
if (!xpc::StringToJsval(aCx, str, &result)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return JSVAL_NULL;
|
||||
@ -1014,7 +1014,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
|
||||
|
||||
JS::Rooted<JS::Value> result(aCx, JSVAL_NULL);
|
||||
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, result.address(),
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, &result,
|
||||
nullptr, true);
|
||||
return result;
|
||||
}
|
||||
@ -1026,7 +1026,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
|
||||
|
||||
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
JS::Rooted<JS::Value> result(aCx, JSVAL_NULL);
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, result.address(),
|
||||
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, &result,
|
||||
nullptr, true);
|
||||
return result;
|
||||
}
|
||||
@ -3659,7 +3659,7 @@ nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aRv)
|
||||
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
|
||||
JSAutoCompartment ac(aCx, wrapper);
|
||||
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, wrapper));
|
||||
aRv = nsContentUtils::WrapNative(aCx, global, result, iid, v.address());
|
||||
aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
|
||||
return aRv.Failed() ? JSVAL_NULL : v;
|
||||
}
|
||||
|
||||
|
BIN
content/base/test/reftest/mixed-bmp-png.ico
Normal file
BIN
content/base/test/reftest/mixed-bmp-png.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
1
content/base/test/reftest/reftest.list
Normal file
1
content/base/test/reftest/reftest.list
Normal file
@ -0,0 +1 @@
|
||||
== test_bug920877.html test_bug920877-ref.html
|
20
content/base/test/reftest/test_bug920877-ref.html
Normal file
20
content/base/test/reftest/test_bug920877-ref.html
Normal file
@ -0,0 +1,20 @@
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
var img = document.createElement("img");
|
||||
img.id = "img-ori";
|
||||
img.src = "mixed-bmp-png.ico";
|
||||
document.body.appendChild(img);
|
||||
|
||||
img = document.createElement("img");
|
||||
img.id = "img-res32";
|
||||
img.src = "mixed-bmp-png.ico#-moz-resolution=32,32";
|
||||
document.body.appendChild(img);
|
||||
|
||||
img = document.createElement("img");
|
||||
img.id = "img-res48";
|
||||
img.src = "mixed-bmp-png.ico#-moz-resolution=48,48";
|
||||
document.body.appendChild(img);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
38
content/base/test/reftest/test_bug920877.html
Normal file
38
content/base/test/reftest/test_bug920877.html
Normal file
File diff suppressed because one or more lines are too long
@ -114,7 +114,7 @@ HTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate, ErrorResult& aRv)
|
||||
#endif
|
||||
|
||||
mAudioStream = AudioStream::AllocateStream();
|
||||
aRv = mAudioStream->Init(aChannels, aRate, mAudioChannelType);
|
||||
aRv = mAudioStream->Init(aChannels, aRate, mAudioChannelType, AudioStream::HighLatency);
|
||||
if (aRv.Failed()) {
|
||||
mAudioStream->Shutdown();
|
||||
mAudioStream = nullptr;
|
||||
|
@ -3155,7 +3155,7 @@ nsGenericHTMLElement::GetItemValue(JSContext* aCx, JSObject* aScope,
|
||||
|
||||
nsString string;
|
||||
GetItemValueText(string);
|
||||
JS::Value v;
|
||||
JS::Rooted<JS::Value> v(aCx);
|
||||
if (!xpc::NonVoidStringToJsval(aCx, string, &v)) {
|
||||
aError.Throw(NS_ERROR_FAILURE);
|
||||
return JS::UndefinedValue();
|
||||
|
@ -41,6 +41,11 @@ PRLogModuleInfo* gAudioStreamLog = nullptr;
|
||||
static Mutex* gAudioPrefsLock = nullptr;
|
||||
static double gVolumeScale;
|
||||
static uint32_t gCubebLatency;
|
||||
static bool gCubebLatencyPrefSet;
|
||||
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
|
||||
|
||||
StaticMutex AudioStream::mMutex;
|
||||
uint32_t AudioStream::mPreferredSampleRate = 0;
|
||||
|
||||
/**
|
||||
* When MOZ_DUMP_AUDIO is set in the environment (to anything),
|
||||
@ -65,9 +70,10 @@ static int PrefChanged(const char* aPref, void* aClosure)
|
||||
// Arbitrary default stream latency of 100ms. The higher this
|
||||
// value, the longer stream volume changes will take to become
|
||||
// audible.
|
||||
uint32_t value = Preferences::GetUint(aPref, 100);
|
||||
gCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
|
||||
uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
|
||||
MutexAutoLock lock(*gAudioPrefsLock);
|
||||
gCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 20), 1000);
|
||||
gCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -97,6 +103,12 @@ static uint32_t GetCubebLatency()
|
||||
MutexAutoLock lock(*gAudioPrefsLock);
|
||||
return gCubebLatency;
|
||||
}
|
||||
|
||||
static bool CubebLatencyPrefSet()
|
||||
{
|
||||
MutexAutoLock lock(*gAudioPrefsLock);
|
||||
return gCubebLatencyPrefSet;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_CUBEB) && defined(__ANDROID__) && defined(MOZ_B2G)
|
||||
@ -311,7 +323,8 @@ class BufferedAudioStream : public AudioStream
|
||||
~BufferedAudioStream();
|
||||
|
||||
nsresult Init(int32_t aNumChannels, int32_t aRate,
|
||||
const dom::AudioChannelType aAudioChannelType);
|
||||
const dom::AudioChannelType aAudioChannelType,
|
||||
AudioStream::LatencyRequest aLatencyRequest);
|
||||
void Shutdown();
|
||||
nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames);
|
||||
uint32_t Available();
|
||||
@ -431,6 +444,23 @@ int AudioStream::MaxNumberOfChannels()
|
||||
return static_cast<int>(maxNumberOfChannels);
|
||||
}
|
||||
|
||||
int AudioStream::PreferredSampleRate()
|
||||
{
|
||||
StaticMutexAutoLock lock(AudioStream::mMutex);
|
||||
// Get the preferred samplerate for this platform, or fallback to something
|
||||
// sensible if we fail. We cache the value, because this might be accessed
|
||||
// often, and the complexity of the function call below depends on the
|
||||
// backend used.
|
||||
const int fallbackSampleRate = 44100;
|
||||
if (mPreferredSampleRate == 0) {
|
||||
if (cubeb_get_preferred_sample_rate(GetCubebContext(), &mPreferredSampleRate) != CUBEB_OK) {
|
||||
mPreferredSampleRate = fallbackSampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
return mPreferredSampleRate;
|
||||
}
|
||||
|
||||
static void SetUint16LE(uint8_t* aDest, uint16_t aValue)
|
||||
{
|
||||
aDest[0] = aValue & 0xFF;
|
||||
@ -526,7 +556,8 @@ BufferedAudioStream::EnsureTimeStretcherInitialized()
|
||||
|
||||
nsresult
|
||||
BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
|
||||
const dom::AudioChannelType aAudioChannelType)
|
||||
const dom::AudioChannelType aAudioChannelType,
|
||||
AudioStream::LatencyRequest aLatencyRequest)
|
||||
{
|
||||
cubeb* cubebContext = GetCubebContext();
|
||||
|
||||
@ -562,10 +593,22 @@ BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
|
||||
|
||||
mAudioClock.Init();
|
||||
|
||||
// If the latency pref is set, use it. Otherwise, if this stream is intended
|
||||
// for low latency playback, try to get the lowest latency possible.
|
||||
// Otherwise, for normal streams, use 100ms.
|
||||
uint32_t latency;
|
||||
if (aLatencyRequest == AudioStream::LowLatency && !CubebLatencyPrefSet()) {
|
||||
if (cubeb_get_min_latency(cubebContext, params, &latency) != CUBEB_OK) {
|
||||
latency = GetCubebLatency();
|
||||
}
|
||||
} else {
|
||||
latency = GetCubebLatency();
|
||||
}
|
||||
|
||||
{
|
||||
cubeb_stream* stream;
|
||||
if (cubeb_stream_init(cubebContext, &stream, "BufferedAudioStream", params,
|
||||
GetCubebLatency(), DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
|
||||
mCubebStream.own(stream);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "Latency.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
|
||||
namespace soundtouch {
|
||||
class SoundTouch;
|
||||
@ -92,6 +93,10 @@ class AudioClock
|
||||
class AudioStream
|
||||
{
|
||||
public:
|
||||
enum LatencyRequest {
|
||||
HighLatency,
|
||||
LowLatency
|
||||
};
|
||||
AudioStream();
|
||||
|
||||
virtual ~AudioStream();
|
||||
@ -112,11 +117,16 @@ public:
|
||||
// Returns the maximum number of channels supported by the audio hardware.
|
||||
static int MaxNumberOfChannels();
|
||||
|
||||
// Returns the samplerate the systems prefer, because it is the
|
||||
// samplerate the hardware/mixer supports.
|
||||
static int PreferredSampleRate();
|
||||
|
||||
// Initialize the audio stream. aNumChannels is the number of audio
|
||||
// channels (1 for mono, 2 for stereo, etc) and aRate is the sample rate
|
||||
// (22050Hz, 44100Hz, etc).
|
||||
virtual nsresult Init(int32_t aNumChannels, int32_t aRate,
|
||||
const dom::AudioChannelType aAudioStreamType) = 0;
|
||||
const dom::AudioChannelType aAudioStreamType,
|
||||
LatencyRequest aLatencyRequest) = 0;
|
||||
|
||||
// Closes the stream. All future use of the stream is an error.
|
||||
virtual void Shutdown() = 0;
|
||||
@ -178,6 +188,11 @@ public:
|
||||
virtual nsresult SetPreservesPitch(bool aPreservesPitch);
|
||||
|
||||
protected:
|
||||
// This mutex protects the mPreferedSamplerate member below.
|
||||
static StaticMutex mMutex;
|
||||
// Prefered samplerate, in Hz (characteristic of the
|
||||
// hardware/mixer/platform/API used).
|
||||
static uint32_t mPreferredSampleRate;
|
||||
// Input rate in Hz (characteristic of the media being played)
|
||||
int mInRate;
|
||||
// Output rate in Hz (characteristic of the playback rate)
|
||||
|
@ -1059,7 +1059,7 @@ void MediaDecoderStateMachine::AudioLoop()
|
||||
// circumstances, so we take care to drop the decoder monitor while
|
||||
// initializing.
|
||||
nsAutoPtr<AudioStream> audioStream(AudioStream::AllocateStream());
|
||||
audioStream->Init(channels, rate, audioChannelType);
|
||||
audioStream->Init(channels, rate, audioChannelType, AudioStream::HighLatency);
|
||||
audioStream->SetVolume(volume);
|
||||
if (audioStream->SetPreservesPitch(preservesPitch) != NS_OK) {
|
||||
NS_WARNING("Setting the pitch preservation failed at AudioLoop start.");
|
||||
|
@ -768,7 +768,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTim
|
||||
audioOutputStream->mStream = AudioStream::AllocateStream();
|
||||
// XXX for now, allocate stereo output. But we need to fix this to
|
||||
// match the system's ideal channel configuration.
|
||||
audioOutputStream->mStream->Init(2, tracks->GetRate(), AUDIO_CHANNEL_NORMAL);
|
||||
audioOutputStream->mStream->Init(2, tracks->GetRate(), AUDIO_CHANNEL_NORMAL, AudioStream::LowLatency);
|
||||
audioOutputStream->mTrackID = tracks->GetID();
|
||||
}
|
||||
}
|
||||
|
@ -960,7 +960,7 @@ protected:
|
||||
};
|
||||
|
||||
// Returns ideal audio rate for processing
|
||||
inline TrackRate IdealAudioRate() { return 48000; }
|
||||
inline TrackRate IdealAudioRate() { return AudioStream::PreferredSampleRate(); }
|
||||
|
||||
/**
|
||||
* Initially, at least, we will have a singleton MediaStreamGraph per
|
||||
|
@ -119,6 +119,7 @@ OpusTrackEncoder::OpusTrackEncoder()
|
||||
, mEncoder(nullptr)
|
||||
, mSourceSegment(new AudioSegment())
|
||||
, mLookahead(0)
|
||||
, mResampler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@ -147,16 +148,24 @@ OpusTrackEncoder::Init(int aChannels, int aSamplingRate)
|
||||
// The granule position is required to be incremented at a rate of 48KHz, and
|
||||
// it is simply calculated as |granulepos = samples * (48000/source_rate)|,
|
||||
// that is, the source sampling rate must divide 48000 evenly.
|
||||
// If this constraint is not satisfied, we resample the input to 48kHz.
|
||||
if (!((aSamplingRate >= 8000) && (kOpusSamplingRate / aSamplingRate) *
|
||||
aSamplingRate == kOpusSamplingRate)) {
|
||||
LOG("[Opus] Error! The source sample rate should be greater than 8000 and"
|
||||
" divides 48000 evenly.");
|
||||
return NS_ERROR_FAILURE;
|
||||
int error;
|
||||
mResampler = speex_resampler_init(mChannels,
|
||||
aSamplingRate,
|
||||
kOpusSamplingRate,
|
||||
SPEEX_RESAMPLER_QUALITY_DEFAULT,
|
||||
&error);
|
||||
|
||||
if (error != RESAMPLER_ERR_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
mSamplingRate = aSamplingRate;
|
||||
|
||||
int error = 0;
|
||||
mEncoder = opus_encoder_create(mSamplingRate, mChannels,
|
||||
mEncoder = opus_encoder_create(GetOutputSampleRate(), mChannels,
|
||||
OPUS_APPLICATION_AUDIO, &error);
|
||||
|
||||
mInitialized = (error == OPUS_OK);
|
||||
@ -166,10 +175,16 @@ OpusTrackEncoder::Init(int aChannels, int aSamplingRate)
|
||||
return error == OPUS_OK ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int
|
||||
OpusTrackEncoder::GetOutputSampleRate()
|
||||
{
|
||||
return mResampler ? kOpusSamplingRate : mSamplingRate;
|
||||
}
|
||||
|
||||
int
|
||||
OpusTrackEncoder::GetPacketDuration()
|
||||
{
|
||||
return mSamplingRate * kFrameDurationMs / 1000;
|
||||
return GetOutputSampleRate() * kFrameDurationMs / 1000;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -282,8 +297,35 @@ OpusTrackEncoder::GetEncodedTrack(nsTArray<uint8_t>* aOutput,
|
||||
iter.Next();
|
||||
}
|
||||
|
||||
// The ogg time stamping and pre-skip is always timed at 48000.
|
||||
aOutputDuration = frameCopied * (kOpusSamplingRate / mSamplingRate);
|
||||
if (mResampler) {
|
||||
nsAutoTArray<AudioDataValue, 9600> resamplingDest;
|
||||
// We want to consume all the input data, so we slightly oversize the
|
||||
// resampled data buffer so we can fit the output data in. We cannot really
|
||||
// predict the output frame count at each call.
|
||||
uint32_t outframes = frameCopied * kOpusSamplingRate / mSamplingRate + 1;
|
||||
uint32_t inframes = frameCopied;
|
||||
|
||||
resamplingDest.SetLength(outframes * mChannels);
|
||||
|
||||
#if MOZ_SAMPLE_TYPE_S16
|
||||
short* in = reinterpret_cast<short*>(pcm.Elements());
|
||||
short* out = reinterpret_cast<short*>(resamplingDest.Elements());
|
||||
speex_resampler_process_interleaved_int(mResampler, in, &inframes,
|
||||
out, &outframes);
|
||||
#else
|
||||
float* in = reinterpret_cast<float*>(pcm.Elements());
|
||||
float* out = reinterpret_cast<float*>(resamplingDest.Elements());
|
||||
speex_resampler_process_interleaved_float(mResampler, in, &inframes,
|
||||
out, &outframes);
|
||||
#endif
|
||||
|
||||
pcm = resamplingDest;
|
||||
// This is always at 48000Hz.
|
||||
aOutputDuration = outframes;
|
||||
} else {
|
||||
// The ogg time stamping and pre-skip is always timed at 48000.
|
||||
aOutputDuration = frameCopied * (kOpusSamplingRate / mSamplingRate);
|
||||
}
|
||||
|
||||
// Remove the raw data which has been pulled to pcm buffer.
|
||||
// The value of frameCopied should equal to (or smaller than, if eos)
|
||||
@ -294,6 +336,9 @@ OpusTrackEncoder::GetEncodedTrack(nsTArray<uint8_t>* aOutput,
|
||||
// encoding.
|
||||
if (mSourceSegment->GetDuration() == 0 && mEndOfStream) {
|
||||
mDoneEncoding = true;
|
||||
if (mResampler) {
|
||||
speex_resampler_destroy(mResampler);
|
||||
}
|
||||
LOG("[Opus] Done encoding.");
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
#ifndef OpusTrackEncoder_h_
|
||||
#define OpusTrackEncoder_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <speex/speex_resampler.h>
|
||||
#include "TrackEncoder.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
@ -35,6 +37,12 @@ private:
|
||||
DATA
|
||||
} mEncoderState;
|
||||
|
||||
/**
|
||||
* Get the samplerate of the data to be fed to the Opus encoder. This might be
|
||||
* different from the intput samplerate if resampling occurs.
|
||||
*/
|
||||
int GetOutputSampleRate();
|
||||
|
||||
/**
|
||||
* The Opus encoder from libopus.
|
||||
*/
|
||||
@ -54,6 +62,12 @@ private:
|
||||
* in order to align the time of input and output.
|
||||
*/
|
||||
int mLookahead;
|
||||
|
||||
/**
|
||||
* If the input sample rate does not divide 48kHz evenly, the input data are
|
||||
* resampled.
|
||||
*/
|
||||
SpeexResamplerState* mResampler;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -231,6 +231,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_1(AudioDestinationNode, AudioNode,
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIAudioChannelAgent.h"
|
||||
#include "AudioChannelCommon.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -21,6 +22,7 @@ class AudioContext;
|
||||
class AudioDestinationNode : public AudioNode
|
||||
, public nsIDOMEventListener
|
||||
, public nsIAudioChannelAgentCallback
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
// This node type knows what MediaStreamGraph to use based on
|
||||
|
@ -50,13 +50,13 @@ DelayProcessor::Process(const double *aPerFrameDelays,
|
||||
MOZ_ASSERT(readPosition >= 0.0, "Why are we reading before the beginning of the buffer?");
|
||||
|
||||
// Here is a the reason why readIndex1 and readIndex will never be out
|
||||
// of bounds. The maximum value for bufferLength is 180 * 48000 (see
|
||||
// AudioContext::CreateDelay). The maximum value for mCurrentDelay is
|
||||
// 180.0, so initially readPosition cannot be more than bufferLength +
|
||||
// a fraction less than 1. Then we take care of that case by
|
||||
// subtracting bufferLength from it if needed. So, if
|
||||
// |bufferLength-readPosition<1.0|, readIndex1 will end up being zero.
|
||||
// If |1.0<=bufferLength-readPosition<2.0|, readIndex1 will be
|
||||
// of bounds. The maximum value for bufferLength is
|
||||
// 180 * AudioContext.samplerate (see AudioContext::CreateDelay). The
|
||||
// maximum value for mCurrentDelay is 180.0, so initially readPosition
|
||||
// cannot be more than bufferLength + a fraction less than 1. Then we
|
||||
// take care of that case by subtracting bufferLength from it if needed.
|
||||
// So, if |bufferLength-readPosition<1.0|, readIndex1 will end up being
|
||||
// zero. If |1.0<=bufferLength-readPosition<2.0|, readIndex1 will be
|
||||
// bufferLength-1 and readIndex2 will be 0.
|
||||
int readIndex1 = int(readPosition);
|
||||
int readIndex2 = (readIndex1 + 1) % bufferLength;
|
||||
|
Binary file not shown.
@ -12,15 +12,14 @@ support-files =
|
||||
small-shot-expected.wav
|
||||
small-shot-mono-expected.wav
|
||||
small-shot.ogg
|
||||
ting-dualchannel44.1-expected.wav
|
||||
ting-dualchannel44.1.ogg
|
||||
ting-dualchannel48-expected.wav
|
||||
ting-dualchannel48.ogg
|
||||
ting-expected.wav
|
||||
ting-mono-dualchannel44.1-expected.wav
|
||||
ting-mono-dualchannel48-expected.wav
|
||||
ting-mono-expected.wav
|
||||
ting.ogg
|
||||
ting-44.1k-1ch.ogg
|
||||
ting-44.1k-2ch.ogg
|
||||
ting-48k-1ch.ogg
|
||||
ting-48k-2ch.ogg
|
||||
ting-44.1k-1ch.wav
|
||||
ting-44.1k-2ch.wav
|
||||
ting-48k-1ch.wav
|
||||
ting-48k-2ch.wav
|
||||
webaudio.js
|
||||
|
||||
[test_AudioBuffer.html]
|
||||
|
@ -13,7 +13,6 @@ SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
var ac = new AudioContext();
|
||||
ok(ac, "Create a AudioContext object");
|
||||
is(ac.sampleRate, 48000, "Correct sample rate");
|
||||
ok(ac instanceof EventTarget, "AudioContexts must be EventTargets");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
@ -105,63 +105,91 @@ function createWaveFileData(audioBuffer) {
|
||||
</script>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var cx = new AudioContext();
|
||||
|
||||
// fuzzTolerance and fuzzToleranceMobile are used to determine fuzziness
|
||||
// thresholds. They're needed to make sure that we can deal with neglibible
|
||||
// differences in the binary buffer caused as a result of resampling the
|
||||
// audio. fuzzToleranceMobile is typically larger on mobile platforms since
|
||||
// we do fixed-point resampling as opposed to floating-point resampling on
|
||||
// those platforms.
|
||||
var tests = [
|
||||
// A normal ogg file, 44.1khz
|
||||
var files = [
|
||||
// An ogg file, 44.1khz, mono
|
||||
{
|
||||
url: "ting.ogg",
|
||||
url: "ting-44.1k-1ch.ogg",
|
||||
valid: true,
|
||||
expected: "ting-expected.wav",
|
||||
expectedMono: "ting-mono-expected.wav",
|
||||
numberOfChannels: 2,
|
||||
duration: 0.6936,
|
||||
length: 33294,
|
||||
fuzzTolerance: 38,
|
||||
fuzzToleranceMobile: 15906
|
||||
expected: "ting-44.1k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 30592,
|
||||
sampleRate: 44100,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 5,
|
||||
fuzzToleranceMobile: 1284
|
||||
},
|
||||
// An ogg file with two different channels, 44.1khz
|
||||
// An ogg file, 44.1khz, stereo
|
||||
{
|
||||
url: "ting-dualchannel44.1.ogg",
|
||||
url: "ting-44.1k-2ch.ogg",
|
||||
valid: true,
|
||||
expected: "ting-dualchannel44.1-expected.wav",
|
||||
expectedMono: "ting-mono-dualchannel44.1-expected.wav",
|
||||
expected: "ting-44.1k-2ch.wav",
|
||||
numberOfChannels: 2,
|
||||
duration: 0.6932,
|
||||
length: 33274,
|
||||
fuzzTolerance: 39,
|
||||
fuzzToleranceMobile: 16798
|
||||
frames: 30592,
|
||||
sampleRate: 44100,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 6,
|
||||
fuzzToleranceMobile: 2544
|
||||
},
|
||||
// An ogg file with two different channels, 48khz
|
||||
// An ogg file, 48khz, mono
|
||||
{
|
||||
url: "ting-dualchannel48.ogg",
|
||||
url: "ting-48k-1ch.ogg",
|
||||
valid: true,
|
||||
expected: "ting-dualchannel48-expected.wav",
|
||||
expectedMono: "ting-mono-dualchannel48-expected.wav",
|
||||
numberOfChannels: 2,
|
||||
duration: 0.6373,
|
||||
length: 30592,
|
||||
fuzzTolerance: 9,
|
||||
fuzzToleranceMobile: 8000
|
||||
expected: "ting-48k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 7,
|
||||
fuzzToleranceMobile: 7070
|
||||
},
|
||||
// An ogg file which needs to be resampled
|
||||
// An ogg file, 48khz, stereo
|
||||
{
|
||||
url: "small-shot.ogg",
|
||||
url: "ting-48k-2ch.ogg",
|
||||
valid: true,
|
||||
expected: "small-shot-expected.wav",
|
||||
expectedMono: "small-shot-mono-expected.wav",
|
||||
expected: "ting-48k-2ch.wav",
|
||||
numberOfChannels: 2,
|
||||
duration: 0.2760,
|
||||
length: 13248,
|
||||
fuzzTolerance: 76,
|
||||
fuzzToleranceMobile: 14844
|
||||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 12,
|
||||
fuzzToleranceMobile: 13982
|
||||
},
|
||||
// A wave file
|
||||
//{ url: "24bit-44khz.wav", valid: true, expected: "24bit-44khz-expected.wav" },
|
||||
// Make sure decoding a wave file results in the same buffer (for both the
|
||||
// resampling and non-resampling cases)
|
||||
{
|
||||
url: "ting-44.1k-1ch.wav",
|
||||
valid: true,
|
||||
expected: "ting-44.1k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 30592,
|
||||
sampleRate: 44100,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 0,
|
||||
fuzzToleranceMobile: 0
|
||||
},
|
||||
{
|
||||
url: "ting-48k-1ch.wav",
|
||||
valid: true,
|
||||
expected: "ting-48k-1ch.wav",
|
||||
numberOfChannels: 1,
|
||||
frames: 33297,
|
||||
sampleRate: 48000,
|
||||
duration: 0.693,
|
||||
fuzzTolerance: 0,
|
||||
fuzzToleranceMobile: 0
|
||||
},
|
||||
// // A wave file
|
||||
// //{ url: "24bit-44khz.wav", valid: true, expected: "24bit-44khz-expected.wav" },
|
||||
// A non-audio file
|
||||
{ url: "invalid.txt", valid: false },
|
||||
// A webm file with no audio
|
||||
@ -171,24 +199,12 @@ var tests = [
|
||||
url: "audio.ogv",
|
||||
valid: true,
|
||||
expected: "audio-expected.wav",
|
||||
expectedMono: "audio-mono-expected.wav",
|
||||
numberOfChannels: 2,
|
||||
sampleRate: 44100,
|
||||
frames: 47680,
|
||||
duration: 1.0807,
|
||||
length: 51872,
|
||||
fuzzTolerance: 91427,
|
||||
fuzzToleranceMobile: 119684
|
||||
},
|
||||
// Make sure decoding a wave file results in the same buffer
|
||||
{
|
||||
url: "audio-expected.wav",
|
||||
valid: true,
|
||||
expected: "audio-expected.wav",
|
||||
expectedMono: "audio-mono-expected-2.wav",
|
||||
numberOfChannels: 2,
|
||||
duration: 1.0807,
|
||||
length: 51872,
|
||||
fuzzTolerance: 0,
|
||||
fuzzToleranceMobile: 0
|
||||
fuzzTolerance: 106,
|
||||
fuzzToleranceMobile: 3482
|
||||
}
|
||||
];
|
||||
|
||||
@ -198,7 +214,7 @@ function fuzzyMemcmp(buf1, buf2, fuzz) {
|
||||
var difference = 0;
|
||||
is(buf1.length, buf2.length, "same length");
|
||||
for (var i = 0; i < buf1.length; ++i) {
|
||||
if (buf1[i] != buf2[i]) {
|
||||
if (Math.abs(buf1[i] - buf2[i])) {
|
||||
++difference;
|
||||
}
|
||||
}
|
||||
@ -216,17 +232,20 @@ function getFuzzTolerance(test) {
|
||||
}
|
||||
|
||||
function checkAudioBuffer(buffer, test, callback, monoTest) {
|
||||
is(buffer.numberOfChannels, monoTest ? 1 : test.numberOfChannels, "Correct number of channels");
|
||||
ok(Math.abs(buffer.duration - test.duration) < 1e-4, "Correct duration");
|
||||
if (Math.abs(buffer.duration - test.duration) >= 1e-4) {
|
||||
is(buffer.numberOfChannels, test.numberOfChannels, "Correct number of channels");
|
||||
ok(Math.abs(buffer.duration - test.duration) < 1e-3, "Correct duration");
|
||||
if (Math.abs(buffer.duration - test.duration) >= 1e-3) {
|
||||
ok(false, "got: " + buffer.duration + ", expected: " + test.duration);
|
||||
}
|
||||
is(buffer.sampleRate, cx.sampleRate, "Correct sample rate");
|
||||
is(buffer.length, test.length, "Correct length");
|
||||
// Take into account the resampling when checking the size
|
||||
var SRCRate = test.sampleRate / cx.sampleRate;
|
||||
ok(Math.abs(buffer.length * SRCRate - test.frames) < test.frames * 0.01, "Correct length");
|
||||
|
||||
var wave = createWaveFileData(buffer);
|
||||
|
||||
var getExpected = new XMLHttpRequest();
|
||||
getExpected.open("GET", monoTest ? test.expectedMono : test.expected, true);
|
||||
getExpected.open("GET", test.expected, true);
|
||||
getExpected.responseType = "arraybuffer";
|
||||
getExpected.onload = function() {
|
||||
ok(fuzzyMemcmp(wave, new Uint8Array(getExpected.response), getFuzzTolerance(test)), "Received expected decoded data");
|
||||
@ -248,12 +267,7 @@ function runTest(test, callback) {
|
||||
checkAudioBuffer(result, test, function() {
|
||||
result = cx.createBuffer(xhr.response, false);
|
||||
checkAudioBuffer(result, test, function() {
|
||||
if ("expectedMono" in test) {
|
||||
result = cx.createBuffer(xhr.response, true);
|
||||
checkAudioBuffer(result, test, callback, true);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}, false);
|
||||
}, false);
|
||||
}, function onFailure() {
|
||||
@ -267,17 +281,13 @@ function runTest(test, callback) {
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (tests.length) {
|
||||
runTest(tests.shift(), runNextTest);
|
||||
if (files.length) {
|
||||
runTest(files.shift(), runNextTest);
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var cx = new AudioContext();
|
||||
|
||||
// Run some simple tests first
|
||||
function callbackShouldNeverRun() {
|
||||
ok(false, "callback should not fire");
|
||||
@ -298,7 +308,7 @@ expectTypeError(function() {
|
||||
cx.decodeAudioData(new Uint8Array(100), callbackShouldNeverRun, callbackShouldNeverRun);
|
||||
});
|
||||
|
||||
if (cx.sampleRate == 48000) {
|
||||
if (cx.sampleRate >= 44100) {
|
||||
// Now, let's get real!
|
||||
runNextTest();
|
||||
} else {
|
||||
|
BIN
content/media/webaudio/test/ting-44.1k-1ch.ogg
Normal file
BIN
content/media/webaudio/test/ting-44.1k-1ch.ogg
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-44.1k-1ch.wav
Normal file
BIN
content/media/webaudio/test/ting-44.1k-1ch.wav
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-44.1k-2ch.ogg
Normal file
BIN
content/media/webaudio/test/ting-44.1k-2ch.ogg
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-44.1k-2ch.wav
Normal file
BIN
content/media/webaudio/test/ting-44.1k-2ch.wav
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-48k-1ch.ogg
Normal file
BIN
content/media/webaudio/test/ting-48k-1ch.ogg
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-48k-1ch.wav
Normal file
BIN
content/media/webaudio/test/ting-48k-1ch.wav
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-48k-2ch.ogg
Normal file
BIN
content/media/webaudio/test/ting-48k-2ch.ogg
Normal file
Binary file not shown.
BIN
content/media/webaudio/test/ting-48k-2ch.wav
Normal file
BIN
content/media/webaudio/test/ting-48k-2ch.wav
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
content/media/webaudio/test/ting-dualchannel44.1.wav
Normal file
BIN
content/media/webaudio/test/ting-dualchannel44.1.wav
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
content/media/webaudio/test/ting-dualchannel48.wav
Normal file
BIN
content/media/webaudio/test/ting-dualchannel48.wav
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -3,6 +3,8 @@
|
||||
# To: /content/canvas/test/reftest
|
||||
skip-if(xulFennec) include ../../canvas/test/reftest/reftest.list
|
||||
|
||||
include ../../base/test/reftest/reftest.list # bug 920877
|
||||
|
||||
== bug453105.html bug453105-ref.html
|
||||
== optiontext.html optiontext-ref.html
|
||||
== bug456008.xhtml bug456008-ref.html
|
||||
|
@ -166,7 +166,7 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
|
||||
dom::XULElementBinding::GetConstructorObject(cx, global, defineOnGlobal);
|
||||
}
|
||||
|
||||
rv = nsContentUtils::WrapNative(cx, global, aBoundElement, v.address(),
|
||||
rv = nsContentUtils::WrapNative(cx, global, aBoundElement, &v,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -309,7 +309,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(cx, globalObject, aBoundElement, v.address(),
|
||||
nsContentUtils::WrapNative(cx, globalObject, aBoundElement, &v,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -307,7 +307,7 @@ nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
||||
// scope if one doesn't already exist, and potentially wraps it cross-
|
||||
// compartment into our scope (via aAllowWrapping=true).
|
||||
JS::Rooted<JS::Value> targetV(cx, JS::UndefinedValue());
|
||||
rv = nsContentUtils::WrapNative(cx, scopeObject, scriptTarget, targetV.address(), nullptr,
|
||||
rv = nsContentUtils::WrapNative(cx, scopeObject, scriptTarget, &targetV, nullptr,
|
||||
/* aAllowWrapping = */ true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -1385,7 +1385,7 @@ nsXULTemplateBuilder::InitHTMLTemplateRoot()
|
||||
JS::Rooted<JSObject*> scope(jscontext, global->GetGlobalJSObject());
|
||||
JS::Rooted<JS::Value> v(jscontext);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
rv = nsContentUtils::WrapNative(jscontext, scope, mRoot, mRoot, v.address(),
|
||||
rv = nsContentUtils::WrapNative(jscontext, scope, mRoot, mRoot, &v,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -1396,7 +1396,7 @@ nsXULTemplateBuilder::InitHTMLTemplateRoot()
|
||||
JS::Rooted<JS::Value> jsdatabase(jscontext);
|
||||
rv = nsContentUtils::WrapNative(jscontext, scope, mDB,
|
||||
&NS_GET_IID(nsIRDFCompositeDataSource),
|
||||
jsdatabase.address(), getter_AddRefs(wrapper));
|
||||
&jsdatabase, getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool ok;
|
||||
@ -1413,7 +1413,7 @@ nsXULTemplateBuilder::InitHTMLTemplateRoot()
|
||||
rv = nsContentUtils::WrapNative(jscontext, jselement,
|
||||
static_cast<nsIXULTemplateBuilder*>(this),
|
||||
&NS_GET_IID(nsIXULTemplateBuilder),
|
||||
jsbuilder.address(), getter_AddRefs(wrapper));
|
||||
&jsbuilder, getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool ok;
|
||||
|
@ -347,27 +347,24 @@ WebappsApplication.prototype = {
|
||||
this._downloadError = null;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [
|
||||
"Webapps:OfflineCache",
|
||||
"Webapps:CheckForUpdate:Return:OK",
|
||||
"Webapps:CheckForUpdate:Return:KO",
|
||||
"Webapps:PackageEvent",
|
||||
"Webapps:Connect:Return:OK",
|
||||
"Webapps:Connect:Return:KO",
|
||||
"Webapps:GetConnections:Return:OK"
|
||||
"Webapps:FireEvent",
|
||||
"Webapps:GetConnections:Return:OK",
|
||||
"Webapps:UpdateState"
|
||||
]);
|
||||
|
||||
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
|
||||
{
|
||||
messages: ["Webapps:OfflineCache",
|
||||
"Webapps:PackageEvent",
|
||||
"Webapps:CheckForUpdate:Return:OK"],
|
||||
app: {
|
||||
id: this.id,
|
||||
manifestURL: this.manifestURL,
|
||||
installState: this.installState,
|
||||
downloading: this.downloading
|
||||
}
|
||||
});
|
||||
cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
|
||||
messages: ["Webapps:FireEvent",
|
||||
"Webapps:UpdateState"],
|
||||
app: {
|
||||
id: this.id,
|
||||
manifestURL: this.manifestURL,
|
||||
installState: this.installState,
|
||||
downloading: this.downloading
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
get manifest() {
|
||||
@ -378,8 +375,10 @@ WebappsApplication.prototype = {
|
||||
},
|
||||
|
||||
get updateManifest() {
|
||||
return this.updateManifest = this._updateManifest ? ObjectWrapper.wrap(this._updateManifest, this._window)
|
||||
: null;
|
||||
return this.updateManifest =
|
||||
this._updateManifest ? ObjectWrapper.wrap(this._updateManifest,
|
||||
this._window)
|
||||
: null;
|
||||
},
|
||||
|
||||
set onprogress(aCallback) {
|
||||
@ -512,18 +511,42 @@ WebappsApplication.prototype = {
|
||||
|
||||
uninit: function() {
|
||||
this._onprogress = null;
|
||||
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
|
||||
["Webapps:OfflineCache",
|
||||
"Webapps:PackageEvent",
|
||||
"Webapps:CheckForUpdate:Return:OK"]);
|
||||
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [
|
||||
"Webapps:FireEvent",
|
||||
"Webapps:PackageEvent"
|
||||
]);
|
||||
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
},
|
||||
|
||||
_fireEvent: function(aName, aHandler) {
|
||||
if (aHandler) {
|
||||
let event = new this._window.MozApplicationEvent(aName, { application: this });
|
||||
aHandler.handleEvent(event);
|
||||
_fireEvent: function(aName) {
|
||||
let handler = this["_on" + aName];
|
||||
if (handler) {
|
||||
let event = new this._window.MozApplicationEvent(aName, {
|
||||
application: this
|
||||
});
|
||||
try {
|
||||
handler.handleEvent(event);
|
||||
} catch (ex) {
|
||||
dump("Event handler expection " + ex + "\n");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateState: function(aMsg) {
|
||||
if (aMsg.app) {
|
||||
for (let prop in aMsg.app) {
|
||||
this[prop] = aMsg.app[prop];
|
||||
}
|
||||
}
|
||||
|
||||
if (aMsg.error) {
|
||||
this._downloadError = aMsg.error;
|
||||
}
|
||||
|
||||
if (aMsg.manifest) {
|
||||
this._manifest = aMsg.manifest;
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
}
|
||||
},
|
||||
|
||||
@ -540,10 +563,11 @@ WebappsApplication.prototype = {
|
||||
|
||||
// ondownload* callbacks should be triggered on all app instances
|
||||
if ((msg.oid != this._id || !req) &&
|
||||
aMessage.name !== "Webapps:OfflineCache" &&
|
||||
aMessage.name !== "Webapps:PackageEvent" &&
|
||||
aMessage.name !== "Webapps:CheckForUpdate:Return:OK")
|
||||
aMessage.name !== "Webapps:FireEvent" &&
|
||||
aMessage.name !== "Webapps:UpdateState") {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "Webapps:Launch:Return:KO":
|
||||
this.removeMessageListeners(["Webapps:Launch:Return:OK",
|
||||
@ -558,108 +582,36 @@ WebappsApplication.prototype = {
|
||||
case "Webapps:CheckForUpdate:Return:KO":
|
||||
Services.DOMRequest.fireError(req, msg.error);
|
||||
break;
|
||||
case "Webapps:CheckForUpdate:Return:OK":
|
||||
if (msg.manifestURL != this.manifestURL)
|
||||
return;
|
||||
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
|
||||
let hiddenProps = ["manifest", "updateManifest"];
|
||||
let updatableProps = ["installOrigin", "installTime", "installState",
|
||||
"lastUpdateCheck", "updateTime", "progress", "downloadAvailable",
|
||||
"downloading", "readyToApplyDownload", "downloadSize"];
|
||||
// Props that we don't update: origin, receipts, manifestURL, removable.
|
||||
|
||||
updatableProps.forEach(function(prop) {
|
||||
if (msg.app[prop]) {
|
||||
this[prop] = msg.app[prop];
|
||||
}
|
||||
}, this);
|
||||
|
||||
hiddenProps.forEach(function(prop) {
|
||||
if (msg.app[prop]) {
|
||||
this["_" + prop] = msg.app[prop];
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (msg.event == "downloadapplied") {
|
||||
this._fireEvent("downloadapplied", this._ondownloadapplied);
|
||||
} else if (msg.event == "downloadavailable") {
|
||||
this._fireEvent("downloadavailable", this._ondownloadavailable);
|
||||
case "Webapps:FireEvent":
|
||||
if (msg.manifestURL != this.manifestURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The parent might ask childs to trigger more than one event in one
|
||||
// shot, so in order to avoid needless IPC we allow an array for the
|
||||
// 'eventType' IPC message field.
|
||||
if (!Array.isArray(msg.eventType)) {
|
||||
msg.eventType = [msg.eventType];
|
||||
}
|
||||
|
||||
msg.eventType.forEach((aEventType) => {
|
||||
if ("_on" + aEventType in this) {
|
||||
this._fireEvent(aEventType);
|
||||
} else {
|
||||
dump("Unsupported event type " + aEventType + "\n");
|
||||
}
|
||||
});
|
||||
|
||||
if (req) {
|
||||
Services.DOMRequest.fireSuccess(req, this.manifestURL);
|
||||
}
|
||||
break;
|
||||
case "Webapps:OfflineCache":
|
||||
if (msg.manifest != this.manifestURL)
|
||||
case "Webapps:UpdateState":
|
||||
if (msg.manifestURL != this.manifestURL) {
|
||||
return;
|
||||
|
||||
if ("installState" in msg) {
|
||||
this.installState = msg.installState;
|
||||
this.progress = msg.progress;
|
||||
if (this.installState == "installed") {
|
||||
this._downloadError = null;
|
||||
this.downloading = false;
|
||||
this.downloadAvailable = false;
|
||||
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
|
||||
this._fireEvent("downloadapplied", this._ondownloadapplied);
|
||||
} else {
|
||||
this.downloading = true;
|
||||
this._fireEvent("downloadprogress", this._onprogress);
|
||||
}
|
||||
} else if (msg.error) {
|
||||
this._downloadError = msg.error;
|
||||
this.downloading = false;
|
||||
this._fireEvent("downloaderror", this._ondownloaderror);
|
||||
}
|
||||
break;
|
||||
case "Webapps:PackageEvent":
|
||||
if (msg.manifestURL != this.manifestURL)
|
||||
return;
|
||||
|
||||
// Set app values according to parent process results.
|
||||
let app = msg.app;
|
||||
this.downloading = app.downloading;
|
||||
this.downloadAvailable = app.downloadAvailable;
|
||||
this.downloadSize = app.downloadSize || 0;
|
||||
this.installState = app.installState;
|
||||
this.progress = app.progress || msg.progress || 0;
|
||||
this.readyToApplyDownload = app.readyToApplyDownload;
|
||||
this.updateTime = app.updateTime;
|
||||
this.origin = app.origin;
|
||||
|
||||
switch(msg.type) {
|
||||
case "error":
|
||||
case "canceled":
|
||||
this._downloadError = msg.error;
|
||||
this._fireEvent("downloaderror", this._ondownloaderror);
|
||||
break;
|
||||
case "progress":
|
||||
this._fireEvent("downloadprogress", this._onprogress);
|
||||
break;
|
||||
case "installed":
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
this._manifest = msg.manifest;
|
||||
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
|
||||
this._fireEvent("downloadapplied", this._ondownloadapplied);
|
||||
break;
|
||||
case "downloaded":
|
||||
// We don't update the packaged apps manifests until they
|
||||
// are installed or until the update is unstaged.
|
||||
if (msg.manifest) {
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
this._manifest = msg.manifest;
|
||||
}
|
||||
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
|
||||
break;
|
||||
case "applied":
|
||||
manifestCache.evict(this.manifestURL, this.innerWindowID);
|
||||
this._manifest = msg.manifest;
|
||||
this._fireEvent("downloadapplied", this._ondownloadapplied);
|
||||
break;
|
||||
}
|
||||
this._updateState(msg);
|
||||
break;
|
||||
case "Webapps:ClearBrowserData:Return":
|
||||
this.removeMessageListeners(aMessage.name);
|
||||
@ -667,10 +619,10 @@ WebappsApplication.prototype = {
|
||||
break;
|
||||
case "Webapps:Connect:Return:OK":
|
||||
let messagePorts = [];
|
||||
msg.messagePortIDs.forEach(function(aPortID) {
|
||||
msg.messagePortIDs.forEach((aPortID) => {
|
||||
let port = new this._window.MozInterAppMessagePort(aPortID);
|
||||
messagePorts.push(port);
|
||||
}, this);
|
||||
});
|
||||
req.resolve(messagePorts);
|
||||
break;
|
||||
case "Webapps:Connect:Return:KO":
|
||||
@ -678,13 +630,13 @@ WebappsApplication.prototype = {
|
||||
break;
|
||||
case "Webapps:GetConnections:Return:OK":
|
||||
let connections = [];
|
||||
msg.connections.forEach(function(aConnection) {
|
||||
msg.connections.forEach((aConnection) => {
|
||||
let connection =
|
||||
new this._window.MozInterAppConnection(aConnection.keyword,
|
||||
aConnection.pubAppManifestURL,
|
||||
aConnection.subAppManifestURL);
|
||||
connections.push(connection);
|
||||
}, this);
|
||||
});
|
||||
req.resolve(connections);
|
||||
break;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ function supportSystemMessages() {
|
||||
}
|
||||
|
||||
// Minimum delay between two progress events while downloading, in ms.
|
||||
const MIN_PROGRESS_EVENT_DELAY = 1000;
|
||||
const MIN_PROGRESS_EVENT_DELAY = 1500;
|
||||
|
||||
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
|
||||
|
||||
@ -945,8 +945,6 @@ this.DOMApplicationRegistry = {
|
||||
addMessageListener: function(aMsgNames, aApp, aMm) {
|
||||
aMsgNames.forEach(function (aMsgName) {
|
||||
let man = aApp && aApp.manifestURL;
|
||||
debug("Adding messageListener for: " + aMsgName + "App: " +
|
||||
man);
|
||||
if (!(aMsgName in this.children)) {
|
||||
this.children[aMsgName] = [];
|
||||
}
|
||||
@ -966,8 +964,8 @@ this.DOMApplicationRegistry = {
|
||||
});
|
||||
|
||||
// If it wasn't registered before, let's update its state
|
||||
if ((aMsgName === 'Webapps:PackageEvent') ||
|
||||
(aMsgName === 'Webapps:OfflineCache')) {
|
||||
if ((aMsgName === 'Webapps:FireEvent') ||
|
||||
(aMsgName === 'Webapps:UpdateState')) {
|
||||
if (man) {
|
||||
let app = this.getAppByManifestURL(aApp.manifestURL);
|
||||
if (app && ((aApp.installState !== app.installState) ||
|
||||
@ -1124,9 +1122,9 @@ this.DOMApplicationRegistry = {
|
||||
// Webapps:Install:Return:OK
|
||||
// Webapps:Uninstall:Return:OK
|
||||
// Webapps:Uninstall:Broadcast:Return:OK
|
||||
// Webapps:OfflineCache
|
||||
// Webapps:FireEvent
|
||||
// Webapps:checkForUpdate:Return:OK
|
||||
// Webapps:PackageEvent
|
||||
// Webapps:UpdateState
|
||||
broadcastMessage: function broadcastMessage(aMsgName, aContent) {
|
||||
if (!(aMsgName in this.children)) {
|
||||
return;
|
||||
@ -1140,7 +1138,7 @@ this.DOMApplicationRegistry = {
|
||||
return FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true);
|
||||
},
|
||||
|
||||
_writeFile: function ss_writeFile(aFile, aData, aCallbak) {
|
||||
_writeFile: function _writeFile(aFile, aData, aCallback) {
|
||||
debug("Saving " + aFile.path);
|
||||
// Initialize the file output stream.
|
||||
let ostream = FileUtils.openSafeFileOutputStream(aFile);
|
||||
@ -1153,8 +1151,9 @@ this.DOMApplicationRegistry = {
|
||||
// Asynchronously copy the data to the file.
|
||||
let istream = converter.convertToInputStream(aData);
|
||||
NetUtil.asyncCopy(istream, ostream, function(rc) {
|
||||
if (aCallbak)
|
||||
aCallbak();
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@ -1216,22 +1215,15 @@ this.DOMApplicationRegistry = {
|
||||
let app = this.webapps[download.appId];
|
||||
|
||||
if (download.cacheUpdate) {
|
||||
// Cancel hosted app download.
|
||||
app.isCanceling = true;
|
||||
try {
|
||||
download.cacheUpdate.cancel();
|
||||
} catch (e) {
|
||||
delete app.isCanceling;
|
||||
debug (e);
|
||||
}
|
||||
} else if (download.channel) {
|
||||
// Cancel packaged app download.
|
||||
app.isCanceling = true;
|
||||
try {
|
||||
download.channel.cancel(Cr.NS_BINDING_ABORTED);
|
||||
} catch(e) {
|
||||
delete app.isCanceling;
|
||||
}
|
||||
} catch(e) { }
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -1241,11 +1233,19 @@ this.DOMApplicationRegistry = {
|
||||
app.installState = download.previousState;
|
||||
app.downloading = false;
|
||||
this._saveApps((function() {
|
||||
this.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "canceled",
|
||||
manifestURL: app.manifestURL,
|
||||
app: app,
|
||||
error: error });
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: {
|
||||
progress: 0,
|
||||
installState: download.previousState,
|
||||
downloading: false
|
||||
},
|
||||
error: error,
|
||||
manifestURL: app.manifestURL,
|
||||
})
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
}).bind(this));
|
||||
AppDownloadManager.remove(aManifestURL);
|
||||
},
|
||||
@ -1267,11 +1267,14 @@ this.DOMApplicationRegistry = {
|
||||
// If the caller is trying to start a download but we have nothing to
|
||||
// download, send an error.
|
||||
if (!app.downloadAvailable) {
|
||||
this.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "canceled",
|
||||
manifestURL: app.manifestURL,
|
||||
app: app,
|
||||
error: "NO_DOWNLOAD_AVAILABLE" });
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
error: "NO_DOWNLOAD_AVAILABLE",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1303,16 +1306,21 @@ this.DOMApplicationRegistry = {
|
||||
debug("appcache found");
|
||||
this.startOfflineCacheDownload(manifest, app, null, isUpdate);
|
||||
} else {
|
||||
// hosted app with no appcache, nothing to do, but we fire a
|
||||
// downloaded event
|
||||
// Hosted app with no appcache, nothing to do, but we fire a
|
||||
// downloaded event.
|
||||
debug("No appcache found, sending 'downloaded' for " + aManifestURL);
|
||||
app.downloadAvailable = false;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "downloaded",
|
||||
manifestURL: aManifestURL,
|
||||
app: app,
|
||||
manifest: jsonManifest });
|
||||
DOMApplicationRegistry._saveApps();
|
||||
DOMApplicationRegistry._saveApps(function() {
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: jsonManifest,
|
||||
manifestURL: aManifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadsuccess",
|
||||
manifestURL: aManifestURL
|
||||
});
|
||||
});
|
||||
}
|
||||
}).bind(this));
|
||||
|
||||
@ -1321,7 +1329,8 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
this._loadJSONAsync(file, (function(aJSON) {
|
||||
if (!aJSON) {
|
||||
debug("startDownload: No update manifest found at " + file.path + " " + aManifestURL);
|
||||
debug("startDownload: No update manifest found at " + file.path + " " +
|
||||
aManifestURL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1350,11 +1359,14 @@ this.DOMApplicationRegistry = {
|
||||
app.readyToApplyDownload = true;
|
||||
app.updateTime = Date.now();
|
||||
DOMApplicationRegistry._saveApps(function() {
|
||||
debug("About to fire Webapps:PackageEvent");
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "downloaded",
|
||||
manifestURL: aManifestURL,
|
||||
app: app });
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: aManifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadsuccess",
|
||||
manifestURL: aManifestURL
|
||||
});
|
||||
if (app.installState == "pending") {
|
||||
// We restarted a failed download, apply it automatically.
|
||||
DOMApplicationRegistry.applyDownload(aManifestURL);
|
||||
@ -1442,11 +1454,15 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, aData);
|
||||
this.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "applied",
|
||||
manifestURL: app.manifestURL,
|
||||
app: app,
|
||||
manifest: aData });
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: aData,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadapplied",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
}).bind(this));
|
||||
}).bind(this));
|
||||
}).bind(this));
|
||||
@ -1475,6 +1491,14 @@ this.DOMApplicationRegistry = {
|
||||
aApp.downloading = true;
|
||||
aApp.progress = 0;
|
||||
DOMApplicationRegistry._saveApps((function() {
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: {
|
||||
downloading: true,
|
||||
installState: aApp.installState,
|
||||
progress: 0
|
||||
},
|
||||
manifestURL: aApp.manifestURL
|
||||
});
|
||||
let cacheUpdate = aProfileDir
|
||||
? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
|
||||
: updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
|
||||
@ -1598,16 +1622,17 @@ this.DOMApplicationRegistry = {
|
||||
// event.
|
||||
app.downloadAvailable = true;
|
||||
app.downloadSize = manifest.size;
|
||||
aData.event = "downloadavailable";
|
||||
aData.app = {
|
||||
downloadAvailable: true,
|
||||
downloadSize: manifest.size,
|
||||
updateManifest: aManifest
|
||||
}
|
||||
app.updateManifest = aManifest;
|
||||
DOMApplicationRegistry._saveApps(function() {
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
|
||||
aData);
|
||||
delete aData.app.updateManifest;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadavailable",
|
||||
manifestURL: app.manifestURL,
|
||||
requestID: aData.requestID
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -1662,10 +1687,17 @@ this.DOMApplicationRegistry = {
|
||||
this.webapps[id] = app;
|
||||
this._saveApps(function() {
|
||||
let reg = DOMApplicationRegistry;
|
||||
aData.app = app;
|
||||
if (!manifest.appcache_path) {
|
||||
aData.event = "downloadapplied";
|
||||
reg.broadcastMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
reg.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: app.manifest,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
reg.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadapplied",
|
||||
manifestURL: app.manifestURL,
|
||||
requestID: aData.requestID
|
||||
});
|
||||
} else {
|
||||
// Check if the appcache is updatable, and send "downloadavailable" or
|
||||
// "downloadapplied".
|
||||
@ -1673,14 +1705,24 @@ this.DOMApplicationRegistry = {
|
||||
observe: function(aSubject, aTopic, aObsData) {
|
||||
debug("updateHostedApp: updateSvc.checkForUpdate return for " +
|
||||
app.manifestURL + " - event is " + aTopic);
|
||||
aData.event =
|
||||
let eventType =
|
||||
aTopic == "offline-cache-update-available" ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aData.app.downloadAvailable = (aData.event == "downloadavailable");
|
||||
reg._saveApps();
|
||||
reg.broadcastMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
app.downloadAvailable = (eventType == "downloadavailable");
|
||||
reg._saveApps(function() {
|
||||
reg.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: app.manifest,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
reg.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: eventType,
|
||||
manifestURL: app.manifestURL,
|
||||
requestID: aData.requestID
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
debug("updateHostedApp: updateSvc.checkForUpdate for " +
|
||||
manifest.fullAppcachePath());
|
||||
updateSvc.checkForUpdate(Services.io.newURI(manifest.fullAppcachePath(), null, null),
|
||||
@ -1715,8 +1757,8 @@ this.DOMApplicationRegistry = {
|
||||
let onlyCheckAppCache = false;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
|
||||
onlyCheckAppCache = (app.basePath == appDir.path);
|
||||
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
|
||||
onlyCheckAppCache = (app.basePath == appDir.path);
|
||||
#endif
|
||||
|
||||
if (onlyCheckAppCache) {
|
||||
@ -1744,19 +1786,24 @@ this.DOMApplicationRegistry = {
|
||||
debug("onlyCheckAppCache updateSvc.checkForUpdate return for " +
|
||||
app.manifestURL + " - event is " + aTopic);
|
||||
if (aTopic == "offline-cache-update-available") {
|
||||
aData.event = "downloadavailable";
|
||||
app.downloadAvailable = true;
|
||||
aData.app = app;
|
||||
this._saveApps(function() {
|
||||
DOMApplicationRegistry.broadcastMessage(
|
||||
"Webapps:CheckForUpdate:Return:OK", aData);
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloadavailable",
|
||||
manifestURL: app.manifestURL,
|
||||
requestID: aData.requestID
|
||||
});
|
||||
});
|
||||
} else {
|
||||
aData.error = "NOT_UPDATABLE";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let helper = new ManifestHelper(manifest);
|
||||
debug("onlyCheckAppCache - launch updateSvc.checkForUpdate for " +
|
||||
helper.fullAppcachePath());
|
||||
@ -1806,15 +1853,21 @@ this.DOMApplicationRegistry = {
|
||||
if (oldHash != hash) {
|
||||
updatePackagedApp.call(this, manifest);
|
||||
} else {
|
||||
// Like if we got a 304, just send a 'downloadapplied'
|
||||
// or downloadavailable event.
|
||||
aData.event = app.downloadAvailable ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aData.app = {
|
||||
lastCheckedUpdate: app.lastCheckedUpdate
|
||||
}
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
this._saveApps();
|
||||
this._saveApps(function() {
|
||||
// Like if we got a 304, just send a 'downloadapplied'
|
||||
// or downloadavailable event.
|
||||
let eventType = app.downloadAvailable ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
aMm.sendAsyncMessage("Webapps:FireEvent", {
|
||||
eventType: eventType,
|
||||
manifestURL: app.manifestURL,
|
||||
requestID: aData.requestID
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Update only the appcache if the manifest has not changed
|
||||
@ -1826,16 +1879,22 @@ this.DOMApplicationRegistry = {
|
||||
} else if (xhr.status == 304) {
|
||||
// The manifest has not changed.
|
||||
if (isPackage) {
|
||||
// If the app is a packaged app, we just send a 'downloadapplied'
|
||||
// or downloadavailable event.
|
||||
app.lastCheckedUpdate = Date.now();
|
||||
aData.event = app.downloadAvailable ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aData.app = {
|
||||
lastCheckedUpdate: app.lastCheckedUpdate
|
||||
}
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
this._saveApps();
|
||||
this._saveApps(function() {
|
||||
// If the app is a packaged app, we just send a 'downloadapplied'
|
||||
// or downloadavailable event.
|
||||
let eventType = app.downloadAvailable ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
aMm.sendAsyncMessage("Webapps:FireEvent", {
|
||||
eventType: eventType,
|
||||
manifestURL: app.manifestURL,
|
||||
requestID: aData.requestID
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// For hosted apps, even if the manifest has not changed, we check
|
||||
// for offline cache updates.
|
||||
@ -2146,21 +2205,25 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
if (supportUseCurrentProfile()) {
|
||||
// Update the permissions for this app.
|
||||
PermissionsInstaller.installPermissions({ manifest: aManifest,
|
||||
origin: appObject.origin,
|
||||
manifestURL: appObject.manifestURL },
|
||||
true);
|
||||
PermissionsInstaller.installPermissions({
|
||||
manifest: aManifest,
|
||||
origin: appObject.origin,
|
||||
manifestURL: appObject.manifestURL
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[aId].localId, appObject.origin,
|
||||
appObject.manifestURL, aManifest);
|
||||
|
||||
debug("About to fire Webapps:PackageEvent 'installed'");
|
||||
this.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "installed",
|
||||
manifestURL: appObject.manifestURL,
|
||||
app: app,
|
||||
manifest: aManifest });
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: aManifest,
|
||||
manifestURL: appObject.manifestURL
|
||||
});
|
||||
this.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: ["downloadsuccess", "downloadapplied"],
|
||||
manifestURL: appObject.manifestURL
|
||||
});
|
||||
if (installSuccessCallback) {
|
||||
installSuccessCallback(aManifest, zipFile.path);
|
||||
}
|
||||
@ -2426,14 +2489,6 @@ this.DOMApplicationRegistry = {
|
||||
dir.remove(true);
|
||||
} catch (e) { }
|
||||
|
||||
// We avoid notifying the error to the DOM side if the app download
|
||||
// was cancelled via cancelDownload, which already sends its own
|
||||
// notification.
|
||||
if (app.isCanceling) {
|
||||
delete app.isCanceling;
|
||||
return;
|
||||
}
|
||||
|
||||
let download = AppDownloadManager.get(aApp.manifestURL);
|
||||
app.downloading = false;
|
||||
|
||||
@ -2449,20 +2504,31 @@ this.DOMApplicationRegistry = {
|
||||
delete app.staged;
|
||||
}
|
||||
|
||||
self.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "error",
|
||||
manifestURL: aApp.manifestURL,
|
||||
error: aError,
|
||||
app: app });
|
||||
self._saveApps();
|
||||
self._saveApps(function() {
|
||||
self.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
error: aError,
|
||||
manifestURL: aApp.manifestURL
|
||||
});
|
||||
self.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "downloaderror",
|
||||
manifestURL: aApp.manifestURL
|
||||
});
|
||||
});
|
||||
AppDownloadManager.remove(aApp.manifestURL);
|
||||
}
|
||||
|
||||
function sendProgressEvent() {
|
||||
self.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "progress",
|
||||
manifestURL: aApp.manifestURL,
|
||||
app: app });
|
||||
function sendProgressEvent(aProgress) {
|
||||
self.broadcastMessage("Webapps:UpdateState", {
|
||||
app: {
|
||||
progress: aProgress
|
||||
},
|
||||
manifestURL: aApp.manifestURL
|
||||
});
|
||||
self.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "progress",
|
||||
manifestURL: aApp.manifestURL
|
||||
});
|
||||
}
|
||||
|
||||
// aStoreId must be a string of the form
|
||||
@ -2548,7 +2614,7 @@ this.DOMApplicationRegistry = {
|
||||
let now = Date.now();
|
||||
if (now - lastProgressTime > MIN_PROGRESS_EVENT_DELAY) {
|
||||
debug("onProgress: " + aProgress + "/" + aProgressMax);
|
||||
sendProgressEvent();
|
||||
sendProgressEvent(aProgress);
|
||||
lastProgressTime = now;
|
||||
self._saveApps();
|
||||
}
|
||||
@ -2646,16 +2712,17 @@ this.DOMApplicationRegistry = {
|
||||
OS.Path.join(dirPath, "update.webapp"));
|
||||
}
|
||||
|
||||
self.broadcastMessage("Webapps:PackageEvent", {
|
||||
type: "downloaded",
|
||||
manifestURL: aApp.manifestURL,
|
||||
app: app });
|
||||
self.broadcastMessage("Webapps:PackageEvent", {
|
||||
type: "applied",
|
||||
manifestURL: aApp.manifestURL,
|
||||
app: app });
|
||||
// Save the updated registry, and cleanup the tmp directory.
|
||||
self._saveApps();
|
||||
self._saveApps(function() {
|
||||
self.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: aApp.manifestURL
|
||||
});
|
||||
self.broadcastMessage("Webapps:FireEvent", {
|
||||
manifestURL: aApp.manifestURL,
|
||||
eventType: ["downloadsuccess", "downloadapplied"]
|
||||
});
|
||||
});
|
||||
let file = FileUtils.getFile("TmpD", ["webapps", id], false);
|
||||
if (file && file.exists()) {
|
||||
file.remove(true);
|
||||
@ -2907,7 +2974,7 @@ this.DOMApplicationRegistry = {
|
||||
requestChannel.asyncOpen(listener, null);
|
||||
|
||||
// send a first progress event to correctly set the DOM object's properties
|
||||
sendProgressEvent();
|
||||
sendProgressEvent(0);
|
||||
};
|
||||
|
||||
let checkDownloadSize = function (freeBytes) {
|
||||
@ -3305,7 +3372,7 @@ let AppcacheObserver = function(aApp) {
|
||||
this.app = aApp;
|
||||
this.startStatus = aApp.installState;
|
||||
this.lastProgressTime = 0;
|
||||
// send a first progress event to correctly set the DOM object's properties
|
||||
// Send a first progress event to correctly set the DOM object's properties.
|
||||
this._sendProgressEvent();
|
||||
};
|
||||
|
||||
@ -3313,10 +3380,14 @@ AppcacheObserver.prototype = {
|
||||
// nsIOfflineCacheUpdateObserver implementation
|
||||
_sendProgressEvent: function() {
|
||||
let app = this.app;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
|
||||
{ manifest: app.manifestURL,
|
||||
installState: app.installState,
|
||||
progress: app.progress });
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: "progress",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
},
|
||||
|
||||
updateStateChanged: function appObs_Update(aUpdate, aState) {
|
||||
@ -3328,31 +3399,41 @@ AppcacheObserver.prototype = {
|
||||
var self = this;
|
||||
let setStatus = function appObs_setStatus(aStatus, aProgress) {
|
||||
debug("Offlinecache setStatus to " + aStatus + " with progress " +
|
||||
aProgress + " for " + app.origin);
|
||||
aProgress + " for " + app.origin);
|
||||
mustSave = (app.installState != aStatus);
|
||||
|
||||
app.installState = aStatus;
|
||||
app.progress = aProgress;
|
||||
if (aStatus == "installed") {
|
||||
app.updateTime = Date.now();
|
||||
app.downloading = false;
|
||||
app.downloadAvailable = false;
|
||||
if (aStatus != "installed") {
|
||||
self._sendProgressEvent();
|
||||
return;
|
||||
}
|
||||
self._sendProgressEvent();
|
||||
|
||||
app.updateTime = Date.now();
|
||||
app.downloading = false;
|
||||
app.downloadAvailable = false;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
eventType: ["downloadsuccess", "downloadapplied"],
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
}
|
||||
|
||||
let setError = function appObs_setError(aError) {
|
||||
debug("Offlinecache setError to " + aError);
|
||||
// If we are canceling the download, we already send a DOWNLOAD_CANCELED
|
||||
// error.
|
||||
if (!app.isCanceling) {
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
|
||||
{ manifest: app.manifestURL,
|
||||
error: aError });
|
||||
} else {
|
||||
delete app.isCanceling;
|
||||
}
|
||||
|
||||
app.downloading = false;
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
|
||||
error: aError,
|
||||
eventType: "downloaderror",
|
||||
manifestURL: app.manifestURL
|
||||
});
|
||||
mustSave = true;
|
||||
}
|
||||
|
||||
@ -3369,9 +3450,9 @@ AppcacheObserver.prototype = {
|
||||
setStatus("installed", aUpdate.byteProgress);
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
|
||||
setStatus(this.startStatus, aUpdate.byteProgress);
|
||||
break;
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
|
||||
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
|
||||
let now = Date.now();
|
||||
if (now - this.lastProgressTime > MIN_PROGRESS_EVENT_DELAY) {
|
||||
|
@ -159,7 +159,7 @@ var steps = [
|
||||
},
|
||||
function() {
|
||||
ok(true, "== TEST == Update packaged app - same package");
|
||||
updateApp(false, 3, 4);
|
||||
updateApp(false, 3, 3);
|
||||
},
|
||||
function() {
|
||||
ok(true, "== TEST == Check for Update after getting the same package");
|
||||
|
@ -123,7 +123,7 @@ PostMessageReadStructuredClone(JSContext* cx,
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
|
||||
val.address(),
|
||||
&val,
|
||||
getter_AddRefs(wrapper)))) {
|
||||
return JSVAL_TO_OBJECT(val);
|
||||
}
|
||||
|
@ -1589,7 +1589,7 @@ Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
rv = nsContentUtils::WrapNative(aCx, aObject, native, prop_val.address(),
|
||||
rv = nsContentUtils::WrapNative(aCx, aObject, native, &prop_val,
|
||||
getter_AddRefs(holder), true);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -643,13 +643,13 @@ IdToString(JSContext *cx, jsid id)
|
||||
|
||||
static inline nsresult
|
||||
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
nsWrapperCache *cache, const nsIID* aIID, jsval *vp,
|
||||
nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
|
||||
nsIXPConnectJSObjectHolder** aHolder, bool aAllowWrapping)
|
||||
{
|
||||
if (!native) {
|
||||
NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
|
||||
|
||||
*vp = JSVAL_NULL;
|
||||
vp.setNull();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -661,13 +661,13 @@ WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
|
||||
return nsDOMClassInfo::XPConnect()->WrapNativeToJSVal(cx, scope, native,
|
||||
cache, aIID,
|
||||
aAllowWrapping, vp,
|
||||
aAllowWrapping, vp.address(),
|
||||
aHolder);
|
||||
}
|
||||
|
||||
static inline nsresult
|
||||
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
const nsIID* aIID, bool aAllowWrapping, jsval *vp,
|
||||
const nsIID* aIID, bool aAllowWrapping, JS::MutableHandle<JS::Value> vp,
|
||||
// If non-null aHolder will keep the jsval alive
|
||||
// while there's a ref to it
|
||||
nsIXPConnectJSObjectHolder** aHolder = nullptr)
|
||||
@ -679,7 +679,7 @@ WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
// Same as the WrapNative above, but use these if aIID is nsISupports' IID.
|
||||
static inline nsresult
|
||||
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
bool aAllowWrapping, jsval *vp,
|
||||
bool aAllowWrapping, JS::MutableHandle<JS::Value> vp,
|
||||
// If non-null aHolder will keep the jsval alive
|
||||
// while there's a ref to it
|
||||
nsIXPConnectJSObjectHolder** aHolder = nullptr)
|
||||
@ -690,7 +690,8 @@ WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
|
||||
static inline nsresult
|
||||
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
|
||||
nsWrapperCache *cache, bool aAllowWrapping, jsval *vp,
|
||||
nsWrapperCache *cache, bool aAllowWrapping,
|
||||
JS::MutableHandle<JS::Value> vp,
|
||||
// If non-null aHolder will keep the jsval alive
|
||||
// while there's a ref to it
|
||||
nsIXPConnectJSObjectHolder** aHolder = nullptr)
|
||||
@ -2221,26 +2222,25 @@ BaseStubConstructor(nsIWeakReference* aWeakOwner,
|
||||
// wrap parameters in the target compartment
|
||||
// we also pass in the calling window as the first argument
|
||||
unsigned argc = args.length() + 1;
|
||||
nsAutoArrayPtr<JS::Value> argv(new JS::Value[argc]);
|
||||
JS::AutoArrayRooter rooter(cx, 0, argv);
|
||||
JS::AutoValueVector argv(cx);
|
||||
argv.resize(argc);
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner));
|
||||
rv = WrapNative(cx, obj, currentWin, &NS_GET_IID(nsIDOMWindow),
|
||||
true, &argv[0], getter_AddRefs(holder));
|
||||
true, argv.handleAt(0), getter_AddRefs(holder));
|
||||
if (!JS_WrapValue(cx, &argv[0]))
|
||||
return NS_ERROR_FAILURE;
|
||||
rooter.changeLength(1);
|
||||
|
||||
for (size_t i = 1; i < argc; ++i) {
|
||||
argv[i] = args[i - 1];
|
||||
if (!JS_WrapValue(cx, &argv[i]))
|
||||
return NS_ERROR_FAILURE;
|
||||
rooter.changeLength(i + 1);
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> frval(cx);
|
||||
bool ret = JS_CallFunctionValue(cx, thisObject, funval, argc, argv,
|
||||
bool ret = JS_CallFunctionValue(cx, thisObject, funval,
|
||||
argc, argv.begin(),
|
||||
frval.address());
|
||||
|
||||
if (!ret) {
|
||||
@ -2250,7 +2250,7 @@ BaseStubConstructor(nsIWeakReference* aWeakOwner,
|
||||
}
|
||||
}
|
||||
|
||||
return WrapNative(cx, obj, native, true, args.rval().address());
|
||||
return WrapNative(cx, obj, native, true, args.rval());
|
||||
}
|
||||
|
||||
static nsresult
|
||||
@ -2818,7 +2818,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
|
||||
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
|
||||
false, v.address(), getter_AddRefs(holder));
|
||||
false, &v, getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (install) {
|
||||
@ -3100,7 +3100,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
|
||||
false, v.address(), getter_AddRefs(holder));
|
||||
false, &v, getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = constructor->Install(cx, obj, v);
|
||||
@ -3202,7 +3202,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
|
||||
false, val.address(), getter_AddRefs(holder));
|
||||
false, &val, getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = constructor->Install(cx, obj, val);
|
||||
@ -3251,7 +3251,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
|
||||
scope = aWin->GetGlobalJSObject();
|
||||
}
|
||||
|
||||
rv = WrapNative(cx, scope, native, true, prop_val.address(),
|
||||
rv = WrapNative(cx, scope, native, true, &prop_val,
|
||||
getter_AddRefs(holder));
|
||||
}
|
||||
|
||||
@ -3303,7 +3303,7 @@ ContentWindowGetter(JSContext *cx, unsigned argc, jsval *vp)
|
||||
|
||||
template<class Interface>
|
||||
static nsresult
|
||||
LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
|
||||
LocationSetterGuts(JSContext *cx, JSObject *obj, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
// This function duplicates some of the logic in XPC_WN_HelperSetProperty
|
||||
obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
|
||||
@ -3322,7 +3322,7 @@ LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Grab the value we're being set to before we stomp on |vp|
|
||||
JS::Rooted<JSString*> val(cx, ::JS_ValueToString(cx, *vp));
|
||||
JS::Rooted<JSString*> val(cx, ::JS_ValueToString(cx, vp));
|
||||
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Make sure |val| stays alive below
|
||||
@ -3352,7 +3352,7 @@ static bool
|
||||
LocationSetter(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
|
||||
JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp.address());
|
||||
nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
return false;
|
||||
@ -3365,7 +3365,7 @@ static bool
|
||||
LocationSetterUnwrapper(JSContext *cx, JS::Handle<JSObject*> obj_, JS::Handle<jsid> id,
|
||||
bool strict, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
JS::RootedObject obj(cx, obj_);
|
||||
JS::Rooted<JSObject*> obj(cx, obj_);
|
||||
|
||||
JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj);
|
||||
if (wrapped) {
|
||||
@ -3410,7 +3410,7 @@ const InterfaceShimEntry kInterfaceShimMap[] =
|
||||
{ "nsIDOMXPathResult", "XPathResult" } };
|
||||
|
||||
static nsresult
|
||||
DefineComponentsShim(JSContext *cx, JS::HandleObject global, nsPIDOMWindow *win)
|
||||
DefineComponentsShim(JSContext *cx, JS::Handle<JSObject*> global, nsPIDOMWindow *win)
|
||||
{
|
||||
// Keep track of how often this happens.
|
||||
Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
|
||||
@ -3468,7 +3468,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JSObject *obj_, jsid id_, uint32_t flags,
|
||||
JSObject **objp, bool *_retval)
|
||||
{
|
||||
JS::RootedObject obj(cx, obj_);
|
||||
JS::Rooted<JSObject*> obj(cx, obj_);
|
||||
JS::RootedId id(cx, id_);
|
||||
|
||||
if (!JSID_IS_STRING(id)) {
|
||||
@ -3565,7 +3565,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
rv = WrapNative(cx, scope, location, &NS_GET_IID(nsIDOMLocation), true,
|
||||
v.address(), getter_AddRefs(holder));
|
||||
&v, getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool ok = JS_WrapValue(cx, v.address()) &&
|
||||
@ -3590,7 +3590,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
rv = WrapNative(cx, obj, top, &NS_GET_IID(nsIDOMWindow), true,
|
||||
v.address(), getter_AddRefs(holder));
|
||||
&v, getter_AddRefs(holder));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Hold on to the top window object as a global property so we
|
||||
@ -3606,7 +3606,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
}
|
||||
|
||||
// Handle resolving if id refers to a name resolved by DOM worker code.
|
||||
JS::RootedObject tmp(cx, NULL);
|
||||
JS::Rooted<JSObject*> tmp(cx, NULL);
|
||||
if (!ResolveWorkerClasses(cx, obj, id, flags, &tmp)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -3679,7 +3679,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), document, document,
|
||||
&NS_GET_IID(nsIDOMDocument), v.address(), getter_AddRefs(holder),
|
||||
&NS_GET_IID(nsIDOMDocument), &v, getter_AddRefs(holder),
|
||||
false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -3986,9 +3986,11 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (array_item) {
|
||||
JS::Rooted<JS::Value> rval(cx);
|
||||
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), array_item, cache,
|
||||
true, vp);
|
||||
true, &rval);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*vp = rval;
|
||||
|
||||
rv = NS_SUCCESS_I_DID_SOMETHING;
|
||||
}
|
||||
@ -4085,7 +4087,7 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx,
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
||||
nsresult tmp = WrapNative(cx, JS::CurrentGlobalOrNull(cx),
|
||||
static_cast<nsINodeList*>(list), list, false,
|
||||
collection.address(), getter_AddRefs(holder));
|
||||
&collection, getter_AddRefs(holder));
|
||||
if (NS_FAILED(tmp)) {
|
||||
rv = tmp;
|
||||
}
|
||||
@ -4189,7 +4191,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JS::Handle<JSObject*> ob
|
||||
}
|
||||
|
||||
if (result) {
|
||||
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), result, cache, true, vp.address());
|
||||
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), result, cache, true, vp);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(cx, rv);
|
||||
|
||||
@ -4207,7 +4209,7 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle<JSObject*> obj
|
||||
JS::Handle<jsid> id, unsigned flags,
|
||||
JS::MutableHandle<JSObject*> objp)
|
||||
{
|
||||
JS::RootedValue v(cx);
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
|
||||
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
|
||||
// Define the item() or namedItem() method.
|
||||
@ -4326,8 +4328,10 @@ nsStringArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
|
||||
return NS_SUCCESS_I_DID_SOMETHING;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(xpc::NonVoidStringToJsval(cx, val, vp),
|
||||
JS::Rooted<JS::Value> rval(cx);
|
||||
NS_ENSURE_TRUE(xpc::NonVoidStringToJsval(cx, val, &rval),
|
||||
NS_ERROR_OUT_OF_MEMORY);
|
||||
*vp = rval;
|
||||
return NS_SUCCESS_I_DID_SOMETHING;
|
||||
}
|
||||
|
||||
|
@ -2385,8 +2385,9 @@ nsDOMWindowUtils::GetIsTestControllingRefreshes(bool *aResult)
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsPresContext* pc = GetPresContext();
|
||||
*aResult =
|
||||
GetPresContext()->RefreshDriver()->IsTestControllingRefreshesEnabled();
|
||||
pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -3632,8 +3632,11 @@ nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::Value* aVal)
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
if (content && global) {
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
return nsContentUtils::WrapNative(aCx, global, content, aVal,
|
||||
getter_AddRefs(wrapper));
|
||||
JS::Rooted<JS::Value> rval(aCx);
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, global, content, &rval,
|
||||
getter_AddRefs(wrapper));
|
||||
*aVal = rval;
|
||||
return rv;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -6806,9 +6809,9 @@ PostMessageReadStructuredClone(JSContext* cx,
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
|
||||
val.address(),
|
||||
&val,
|
||||
getter_AddRefs(wrapper)))) {
|
||||
return JSVAL_TO_OBJECT(val);
|
||||
return val.toObjectOrNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1035,23 +1035,21 @@ nsJSContext::JSObjectFromInterface(nsISupports* aTarget,
|
||||
// We don't wrap here because we trust the JS engine to wrap the target
|
||||
// later.
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, aScope, aTarget,
|
||||
v.address());
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, aScope, aTarget, &v);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
|
||||
nsCOMPtr<nsISupports> native =
|
||||
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
|
||||
JSVAL_TO_OBJECT(v));
|
||||
NS_ASSERTION(native == targetSupp, "Native should be the target!");
|
||||
#endif
|
||||
|
||||
JSObject* obj = v.toObjectOrNull();
|
||||
if (obj) {
|
||||
JS::ExposeObjectToActiveJS(obj);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
|
||||
nsCOMPtr<nsISupports> native =
|
||||
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, obj);
|
||||
NS_ASSERTION(native == targetSupp, "Native should be the target!");
|
||||
#endif
|
||||
|
||||
*aRet = obj;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1298,7 +1296,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
|
||||
#endif
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
rv = nsContentUtils::WrapNative(cx, aScope, arg, v.address(),
|
||||
rv = nsContentUtils::WrapNative(cx, aScope, arg, &v,
|
||||
getter_AddRefs(wrapper));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*thisval = v;
|
||||
@ -1500,7 +1498,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
|
||||
JS::Rooted<JSObject*> global(cx, GetWindowProxy());
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
nsresult rv = nsContentUtils::WrapNative(cx, global,
|
||||
data, iid, v.address(),
|
||||
data, iid, &v,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -320,13 +320,13 @@ enum {
|
||||
TOSTRING_NAME_RESERVED_SLOT = 1
|
||||
};
|
||||
|
||||
bool
|
||||
static bool
|
||||
InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
|
||||
{
|
||||
JS::Rooted<JSObject*> callee(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
JS::Rooted<JSObject*> callee(cx, &args.callee());
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
|
||||
if (!obj) {
|
||||
if (!args.computeThis(cx).isObject()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
|
||||
"null", "object");
|
||||
return false;
|
||||
@ -334,14 +334,14 @@ InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
|
||||
|
||||
JS::Value v = js::GetFunctionNativeReserved(callee,
|
||||
TOSTRING_CLASS_RESERVED_SLOT);
|
||||
const JSClass* clasp = static_cast<const JSClass*>(JSVAL_TO_PRIVATE(v));
|
||||
const JSClass* clasp = static_cast<const JSClass*>(v.toPrivate());
|
||||
|
||||
v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT);
|
||||
JSString* jsname = static_cast<JSString*>(JSVAL_TO_STRING(v));
|
||||
size_t length;
|
||||
const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length);
|
||||
|
||||
if (js::GetObjectJSClass(obj) != clasp) {
|
||||
if (js::GetObjectJSClass(&args.computeThis(cx).toObject()) != clasp) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
|
||||
NS_ConvertUTF16toUTF8(name).get(), "toString",
|
||||
"object");
|
||||
@ -357,7 +357,7 @@ InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
|
||||
str.Append('\n');
|
||||
str.AppendLiteral("}");
|
||||
|
||||
return xpc::NonVoidStringToJsval(cx, str, vp);
|
||||
return xpc::NonVoidStringToJsval(cx, str, args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -673,7 +673,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
|
||||
bool
|
||||
NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope,
|
||||
JS::Value* aRetval,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
xpcObjectHelper& aHelper,
|
||||
const nsIID* aIID,
|
||||
bool aAllowNativeWrapper)
|
||||
@ -684,7 +684,7 @@ NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
|
||||
nsWrapperCache *cache = aHelper.GetWrapperCache();
|
||||
|
||||
if (cache && cache->IsDOMBinding()) {
|
||||
JS::RootedObject obj(aCx, cache->GetWrapper());
|
||||
JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
|
||||
if (!obj) {
|
||||
obj = cache->WrapObject(aCx, aScope);
|
||||
}
|
||||
@ -694,7 +694,7 @@ NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
|
||||
}
|
||||
|
||||
if (obj) {
|
||||
*aRetval = JS::ObjectValue(*obj);
|
||||
aRetval.setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -751,7 +751,7 @@ InstanceClassHasProtoAtDepth(JS::Handle<JSObject*> protoObject, uint32_t protoID
|
||||
bool
|
||||
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
xpcObjectHelper& helper, const nsIID* iid,
|
||||
bool allowNativeWrapper, JS::Value* rval)
|
||||
bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
|
||||
{
|
||||
if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
|
||||
allowNativeWrapper)) {
|
||||
@ -759,7 +759,7 @@ XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
|
||||
JSObject* jsobj = rval.toObjectOrNull();
|
||||
if (jsobj && !js::GetObjectParent(jsobj))
|
||||
NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
|
||||
"Why did we recreate this wrapper?");
|
||||
@ -770,7 +770,7 @@ XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
|
||||
bool
|
||||
VariantToJsval(JSContext* aCx, JS::Handle<JSObject*> aScope,
|
||||
nsIVariant* aVariant, JS::Value* aRetval)
|
||||
nsIVariant* aVariant, JS::MutableHandle<JS::Value> aRetval)
|
||||
{
|
||||
nsresult rv;
|
||||
if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
|
||||
@ -810,15 +810,14 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
}
|
||||
|
||||
JS::Value* argv = JS_ARGV(cx, vp);
|
||||
if (!argv[0].isObject()) {
|
||||
if (!args[0].isObject()) {
|
||||
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
||||
}
|
||||
|
||||
nsIJSID* iid;
|
||||
SelfRef iidRef;
|
||||
if (NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx, argv[0], &iid, &iidRef.ptr,
|
||||
&argv[0]))) {
|
||||
if (NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx, args[0], &iid, &iidRef.ptr,
|
||||
args[0]))) {
|
||||
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
||||
}
|
||||
MOZ_ASSERT(iid);
|
||||
@ -1475,7 +1474,7 @@ AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
{
|
||||
for (uint32_t i = 0; i < names.Length(); ++i) {
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
|
||||
if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1649,10 +1648,10 @@ private:
|
||||
};
|
||||
|
||||
nsresult
|
||||
ReparentWrapper(JSContext* aCx, JS::HandleObject aObjArg)
|
||||
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
|
||||
{
|
||||
// aObj is assigned to below, so needs to be re-rooted.
|
||||
JS::RootedObject aObj(aCx, aObjArg);
|
||||
JS::Rooted<JSObject*> aObj(aCx, aObjArg);
|
||||
const DOMClass* domClass = GetDOMClass(aObj);
|
||||
|
||||
JS::Rooted<JSObject*> oldParent(aCx, JS_GetParent(aObj));
|
||||
@ -1756,20 +1755,9 @@ ReparentWrapper(JSContext* aCx, JS::HandleObject aObjArg)
|
||||
if (ww != aObj) {
|
||||
MOZ_ASSERT(cache->HasSystemOnlyWrapper());
|
||||
|
||||
JS::RootedObject newwrapper(aCx,
|
||||
xpc::WrapperFactory::WrapSOWObject(aCx, newobj));
|
||||
if (!newwrapper) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
// Oops. We don't support transplanting objects with SOWs anymore.
|
||||
MOZ_CRASH();
|
||||
|
||||
// Ok, now we do the special object-plus-wrapper transplant.
|
||||
ww = xpc::TransplantObjectWithWrapper(aCx, aObj, ww, newobj, newwrapper);
|
||||
if (!ww) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
aObj = newobj;
|
||||
SetSystemOnlyWrapperSlot(aObj, JS::ObjectValue(*ww));
|
||||
} else {
|
||||
aObj = xpc::TransplantObject(aCx, aObj, newobj);
|
||||
if (!aObj) {
|
||||
@ -1863,7 +1851,7 @@ GlobalObject::GetAsSupports() const
|
||||
// using new bindings.
|
||||
nsresult rv = xpc_qsUnwrapArg<nsISupports>(mCx, val, &mGlobalObject,
|
||||
static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)),
|
||||
val.address());
|
||||
&val);
|
||||
if (NS_FAILED(rv)) {
|
||||
mGlobalObject = nullptr;
|
||||
Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
||||
|
@ -35,8 +35,8 @@
|
||||
class nsPIDOMWindow;
|
||||
|
||||
extern nsresult
|
||||
xpc_qsUnwrapArgImpl(JSContext* cx, jsval v, const nsIID& iid, void** ppArg,
|
||||
nsISupports** ppArgRef, jsval* vp);
|
||||
xpc_qsUnwrapArgImpl(JSContext* cx, JS::Handle<JS::Value> v, const nsIID& iid, void** ppArg,
|
||||
nsISupports** ppArgRef, JS::MutableHandle<JS::Value> vp);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -53,8 +53,8 @@ struct SelfRef
|
||||
/** Convert a jsval to an XPCOM pointer. */
|
||||
template <class Interface, class StrongRefType>
|
||||
inline nsresult
|
||||
UnwrapArg(JSContext* cx, jsval v, Interface** ppArg,
|
||||
StrongRefType** ppArgRef, jsval* vp)
|
||||
UnwrapArg(JSContext* cx, JS::Handle<JS::Value> v, Interface** ppArg,
|
||||
StrongRefType** ppArgRef, JS::MutableHandle<JS::Value> vp)
|
||||
{
|
||||
nsISupports* argRef = *ppArgRef;
|
||||
nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
|
||||
@ -792,7 +792,7 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
bool
|
||||
NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope,
|
||||
JS::Value* aRetval,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
xpcObjectHelper& aHelper,
|
||||
const nsIID* aIID,
|
||||
bool aAllowNativeWrapper);
|
||||
@ -811,7 +811,7 @@ HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
}
|
||||
|
||||
qsObjectHelper helper(value, GetWrapperCache(value));
|
||||
return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval.address(),
|
||||
return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
|
||||
helper, nullptr, true);
|
||||
}
|
||||
|
||||
@ -977,12 +977,12 @@ InstanceClassHasProtoAtDepth(JS::Handle<JSObject*> protoObject, uint32_t protoID
|
||||
bool
|
||||
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
|
||||
xpcObjectHelper& helper, const nsIID* iid,
|
||||
bool allowNativeWrapper, JS::Value* rval);
|
||||
bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
|
||||
|
||||
// Special-cased wrapping for variants
|
||||
bool
|
||||
VariantToJsval(JSContext* aCx, JS::Handle<JSObject*> aScope,
|
||||
nsIVariant* aVariant, JS::Value* aRetval);
|
||||
nsIVariant* aVariant, JS::MutableHandle<JS::Value> aRetval);
|
||||
|
||||
// Wrap an object "p" which is not using WebIDL bindings yet. This _will_
|
||||
// actually work on WebIDL binding objects that are wrappercached, but will be
|
||||
@ -994,10 +994,10 @@ WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
|
||||
nsWrapperCache* cache, const nsIID* iid,
|
||||
JS::MutableHandle<JS::Value> rval)
|
||||
{
|
||||
if (xpc_FastGetCachedWrapper(cache, scope, rval.address()))
|
||||
if (xpc_FastGetCachedWrapper(cache, scope, rval))
|
||||
return true;
|
||||
qsObjectHelper helper(p, cache);
|
||||
return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval.address());
|
||||
return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
|
||||
}
|
||||
|
||||
// A specialization of the above for nsIVariant, because that needs to
|
||||
@ -1010,7 +1010,7 @@ WrapObject<nsIVariant>(JSContext* cx, JS::Handle<JSObject*> scope, nsIVariant* p
|
||||
{
|
||||
MOZ_ASSERT(iid);
|
||||
MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
|
||||
return VariantToJsval(cx, scope, p, rval.address());
|
||||
return VariantToJsval(cx, scope, p, rval);
|
||||
}
|
||||
|
||||
// Wrap an object "p" which is not using WebIDL bindings yet. Just like the
|
||||
@ -1100,8 +1100,8 @@ WrapNativeISupportsParent(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
|
||||
{
|
||||
qsObjectHelper helper(ToSupports(p), cache);
|
||||
JS::Rooted<JS::Value> v(cx);
|
||||
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, v.address()) ?
|
||||
JSVAL_TO_OBJECT(v) :
|
||||
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
|
||||
v.toObjectOrNull() :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
@ -2005,7 +2005,7 @@ const T& NonNullHelper(const OwningNonNull<T>& aArg)
|
||||
// Reparent the wrapper of aObj to whatever its native now thinks its
|
||||
// parent should be.
|
||||
nsresult
|
||||
ReparentWrapper(JSContext* aCx, JS::HandleObject aObj);
|
||||
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
|
||||
|
||||
/**
|
||||
* Used to implement the hasInstance hook of an interface object.
|
||||
|
@ -1516,7 +1516,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
if any(m.isGetter() and m.isIndexed() for m in methods):
|
||||
self.regular.append({"name": "@@iterator",
|
||||
"methodInfo": False,
|
||||
"selfHostedName": "ArrayIterator",
|
||||
"selfHostedName": "ArrayValues",
|
||||
"length": 0,
|
||||
"flags": "JSPROP_ENUMERATE",
|
||||
"condition": MemberCondition(None, None) })
|
||||
@ -2409,7 +2409,7 @@ class CastableObjectUnwrapper():
|
||||
"${type} *objPtr;\n"
|
||||
"SelfRef objRef;\n"
|
||||
"JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*${source}));\n"
|
||||
"nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, val.address());\n"
|
||||
"nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
|
||||
"if (NS_FAILED(rv)) {\n"
|
||||
"${codeOnFailure}\n"
|
||||
"}\n"
|
||||
@ -3230,7 +3230,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
||||
templateBody += (
|
||||
"JS::Rooted<JS::Value> tmpVal(cx, ${val});\n" +
|
||||
typePtr + " tmp;\n"
|
||||
"if (NS_FAILED(UnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), tmpVal.address()))) {\n")
|
||||
"if (NS_FAILED(UnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
|
||||
templateBody += CGIndenter(onFailureBadType(failureCode,
|
||||
descriptor.interface.identifier.name)).define()
|
||||
templateBody += ("}\n"
|
||||
@ -4121,9 +4121,9 @@ if (!returnArray) {
|
||||
|
||||
if type.isDOMString():
|
||||
if type.nullable():
|
||||
return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalRef}.address())" % result), False)
|
||||
return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
|
||||
else:
|
||||
return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalRef}.address())" % result), False)
|
||||
return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
|
||||
|
||||
if type.isByteString():
|
||||
if type.nullable():
|
||||
|
@ -67,9 +67,9 @@ public:
|
||||
MOZ_ASSERT(aReq && aAdapterPtr);
|
||||
}
|
||||
|
||||
virtual bool ParseSuccessfulReply(JS::Value* aValue)
|
||||
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
*aValue = JSVAL_VOID;
|
||||
aValue.setUndefined();
|
||||
|
||||
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
||||
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
|
||||
@ -113,7 +113,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
aValue->setObject(*JsDevices);
|
||||
aValue.setObject(*JsDevices);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -136,9 +136,9 @@ public:
|
||||
MOZ_ASSERT(aReq);
|
||||
}
|
||||
|
||||
virtual bool ParseSuccessfulReply(JS::Value* aValue)
|
||||
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
*aValue = JSVAL_VOID;
|
||||
aValue.setUndefined();
|
||||
|
||||
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
||||
if (v.type() != BluetoothValue::Tbool) {
|
||||
@ -147,7 +147,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
aValue->setBoolean(v.get_bool());
|
||||
aValue.setBoolean(v.get_bool());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -42,9 +42,9 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
ParseSuccessfulReply(JS::Value* aValue)
|
||||
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
*aValue = JSVAL_VOID;
|
||||
aValue.setUndefined();
|
||||
|
||||
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
|
||||
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
|
||||
|
@ -32,7 +32,7 @@ BluetoothReplyRunnable::~BluetoothReplyRunnable()
|
||||
{}
|
||||
|
||||
nsresult
|
||||
BluetoothReplyRunnable::FireReply(const JS::Value& aVal)
|
||||
BluetoothReplyRunnable::FireReply(JS::Handle<JS::Value> aVal)
|
||||
{
|
||||
nsCOMPtr<nsIDOMRequestService> rs =
|
||||
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
|
||||
@ -62,10 +62,12 @@ BluetoothReplyRunnable::Run()
|
||||
|
||||
nsresult rv;
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
JS::Rooted<JS::Value> v(cx, JSVAL_VOID);
|
||||
|
||||
if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
|
||||
rv = FireReply(JSVAL_VOID);
|
||||
rv = FireReply(v);
|
||||
} else {
|
||||
JS::Value v;
|
||||
if (!ParseSuccessfulReply(&v)) {
|
||||
rv = FireErrorString();
|
||||
} else {
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
protected:
|
||||
virtual ~BluetoothReplyRunnable();
|
||||
|
||||
virtual bool ParseSuccessfulReply(JS::Value* aValue) = 0;
|
||||
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) = 0;
|
||||
|
||||
// This is an autoptr so we don't have to bring the ipdl include into the
|
||||
// header. We assume we'll only be running this once and it should die on
|
||||
@ -45,7 +45,7 @@ protected:
|
||||
nsAutoPtr<BluetoothReply> mReply;
|
||||
|
||||
private:
|
||||
nsresult FireReply(const JS::Value& aVal);
|
||||
nsresult FireReply(JS::Handle<JS::Value> aVal);
|
||||
nsresult FireErrorString();
|
||||
|
||||
nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
|
||||
@ -59,9 +59,9 @@ public:
|
||||
~BluetoothVoidReplyRunnable();
|
||||
|
||||
protected:
|
||||
virtual bool ParseSuccessfulReply(JS::Value* aValue) MOZ_OVERRIDE
|
||||
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) MOZ_OVERRIDE
|
||||
{
|
||||
*aValue = JSVAL_VOID;
|
||||
aValue.setUndefined();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
}
|
||||
|
||||
virtual bool
|
||||
ParseSuccessfulReply(JS::Value* aValue) MOZ_OVERRIDE
|
||||
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
@ -78,6 +78,13 @@ const ContentPanning = {
|
||||
return;
|
||||
}
|
||||
|
||||
let start = Date.now();
|
||||
let thread = Services.tm.currentThread;
|
||||
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
this._delayEvents = false;
|
||||
|
||||
switch (evt.type) {
|
||||
case 'mousedown':
|
||||
case 'touchstart':
|
||||
@ -229,6 +236,16 @@ const ContentPanning = {
|
||||
// We prevent end events to avoid sending a focus event. See bug 889717.
|
||||
evt.preventDefault();
|
||||
}
|
||||
} else if (this.target && click && !this.panning) {
|
||||
this.notify(this._activationTimer);
|
||||
|
||||
this._delayEvents = true;
|
||||
let start = Date.now();
|
||||
let thread = Services.tm.currentThread;
|
||||
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
this._delayEvents = false;
|
||||
}
|
||||
|
||||
this._finishPanning();
|
||||
@ -467,6 +484,12 @@ const ContentPanning = {
|
||||
return this._activationDelayMs = delay;
|
||||
},
|
||||
|
||||
get _activeDurationMs() {
|
||||
let duration = Services.prefs.getIntPref('ui.touch_activation.duration_ms');
|
||||
delete this._activeDurationMs;
|
||||
return this._activeDurationMs = duration;
|
||||
},
|
||||
|
||||
_resetActive: function cp_resetActive() {
|
||||
let elt = this.target || this.pointerDownTarget;
|
||||
let root = elt.ownerDocument || elt.document;
|
||||
|
@ -1368,17 +1368,14 @@ InterfaceToJsval(nsPIDOMWindow* aWindow,
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
|
||||
JS::RootedObject scopeObj(cx, sgo->GetGlobalJSObject());
|
||||
JS::Rooted<JSObject*> scopeObj(cx, sgo->GetGlobalJSObject());
|
||||
NS_ENSURE_TRUE(scopeObj, JSVAL_NULL);
|
||||
JSAutoCompartment ac(cx, scopeObj);
|
||||
|
||||
|
||||
JS::Rooted<JS::Value> someJsVal(cx);
|
||||
nsresult rv = nsContentUtils::WrapNative(cx,
|
||||
scopeObj,
|
||||
aObject,
|
||||
aIID,
|
||||
someJsVal.address());
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(cx, scopeObj, aObject, aIID, &someJsVal);
|
||||
if (NS_FAILED(rv)) {
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
@ -1437,7 +1434,7 @@ JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString)
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
|
||||
JS::Value result = JSVAL_NULL;
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
if (!xpc::StringToJsval(cx, aString, &result)) {
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
|
@ -147,11 +147,11 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
||||
break;
|
||||
|
||||
case GetFile:
|
||||
rv = GetFileResult(cx, result.address(), aFileList);
|
||||
rv = GetFileResult(cx, &result, aFileList);
|
||||
break;
|
||||
|
||||
case GetFiles:
|
||||
rv = GetFilesResult(cx, result.address(), aFileList);
|
||||
rv = GetFilesResult(cx, &result, aFileList);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -208,7 +208,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFileResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
|
||||
{
|
||||
for (uint32_t i = 0; i < aFileList.Length(); ++i) {
|
||||
@ -230,7 +230,7 @@ ArchiveRequest::GetFileResult(JSContext* aCx,
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFilesResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
|
||||
{
|
||||
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length(), nullptr));
|
||||
@ -245,13 +245,13 @@ ArchiveRequest::GetFilesResult(JSContext* aCx,
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, global, file,
|
||||
&NS_GET_IID(nsIDOMFile),
|
||||
value.address());
|
||||
&value);
|
||||
if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, &value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
aValue->setObject(*array);
|
||||
aValue.setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -66,10 +66,10 @@ private:
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
|
||||
nsresult GetFileResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
|
||||
nsresult GetFilesResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
JS::MutableHandle<JS::Value> aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
|
||||
|
||||
protected:
|
||||
|
@ -185,10 +185,12 @@ GetFileHelper::GetSuccessResult(JSContext* aCx, JS::Value* aVal)
|
||||
mFileHandle->CreateFileObject(mLockedFile, mParams->Size());
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
JS::Rooted<JS::Value> rval(aCx);
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, global, domFile,
|
||||
&NS_GET_IID(nsIDOMFile), aVal);
|
||||
&NS_GET_IID(nsIDOMFile), &rval);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
|
||||
*aVal = rval;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1066,11 +1066,13 @@ ReadTextHelper::GetSuccessResult(JSContext* aCx,
|
||||
tmpString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!xpc::StringToJsval(aCx, tmpString, aVal)) {
|
||||
JS::Rooted<JS::Value> rval(aCx);
|
||||
if (!xpc::StringToJsval(aCx, tmpString, &rval)) {
|
||||
NS_WARNING("Failed to convert string!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*aVal = rval;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ HelperBase::WrapNative(JSContext* aCx,
|
||||
NS_ASSERTION(global, "This should never be null!");
|
||||
|
||||
nsresult rv =
|
||||
nsContentUtils::WrapNative(aCx, global, aNative, aResult.address());
|
||||
nsContentUtils::WrapNative(aCx, global, aNative, aResult);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
return NS_OK;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user