зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound
This commit is contained in:
Коммит
aa20ddde42
|
@ -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);
|
||||
|
||||
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];
|
||||
|
@ -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);
|
||||
return;
|
||||
}
|
||||
|
||||
promise.all(promises).then(aProperties => {
|
||||
let error = {};
|
||||
let safeGetters;
|
||||
let { ownProperties, safeGetterValues } = aResponse;
|
||||
let error = Object.create(null);
|
||||
|
||||
// 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;
|
||||
}
|
||||
for (let key of Object.keys(safeGetterValues)) {
|
||||
error[key] = safeGetterValues[key].getterValue;
|
||||
}
|
||||
|
||||
if (safeGetters) {
|
||||
for (let key of Object.keys(safeGetters)) {
|
||||
if (!error.hasOwnProperty(key)) {
|
||||
error[key] = safeGetters[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");
|
||||
|
|
|
@ -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.*
|
|
@ -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();
|
||||
},
|
||||
];
|
|
@ -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>
|
|
@ -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
|
||||
mfbt
|
||||
js/xpconnect
|
||||
js/xpconnect/loader
|
||||
mfbt
|
||||
view
|
||||
caps
|
||||
xpfe/appshell
|
||||
|
|
31
configure.in
31
configure.in
|
@ -86,21 +86,35 @@ 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
|
||||
|
||||
|
||||
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
|
||||
done
|
||||
if test "$_conflict_files"; then
|
||||
echo "***"
|
||||
echo "* Your source tree contains these files:"
|
||||
for file in $_conflict_files; do
|
||||
|
@ -117,7 +131,6 @@ then
|
|||
EOF
|
||||
exit 1
|
||||
break
|
||||
fi
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 17 KiB |
|
@ -0,0 +1 @@
|
|||
== test_bug920877.html test_bug920877-ref.html
|
|
@ -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>
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -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.");
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
Двоичные данные
content/media/webaudio/test/audio-expected.wav
Двоичные данные
content/media/webaudio/test/audio-expected.wav
Двоичный файл не отображается.
|
@ -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 {
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-dualchannel44.1-expected.wav
Двоичные данные
content/media/webaudio/test/ting-dualchannel44.1-expected.wav
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-dualchannel44.1.ogg
Двоичные данные
content/media/webaudio/test/ting-dualchannel44.1.ogg
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-dualchannel48-expected.wav
Двоичные данные
content/media/webaudio/test/ting-dualchannel48-expected.wav
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-dualchannel48.ogg
Двоичные данные
content/media/webaudio/test/ting-dualchannel48.ogg
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-expected.wav
Двоичные данные
content/media/webaudio/test/ting-expected.wav
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-mono-dualchannel48-expected.wav
Двоичные данные
content/media/webaudio/test/ting-mono-dualchannel48-expected.wav
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting-mono-expected.wav
Двоичные данные
content/media/webaudio/test/ting-mono-expected.wav
Двоичный файл не отображается.
Двоичные данные
content/media/webaudio/test/ting.ogg
Двоичные данные
content/media/webaudio/test/ting.ogg
Двоичный файл не отображается.
|
@ -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,20 +347,17 @@ 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"],
|
||||
cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
|
||||
messages: ["Webapps:FireEvent",
|
||||
"Webapps:UpdateState"],
|
||||
app: {
|
||||
id: this.id,
|
||||
manifestURL: this.manifestURL,
|
||||
|
@ -378,7 +375,9 @@ WebappsApplication.prototype = {
|
|||
},
|
||||
|
||||
get updateManifest() {
|
||||
return this.updateManifest = this._updateManifest ? ObjectWrapper.wrap(this._updateManifest, this._window)
|
||||
return this.updateManifest =
|
||||
this._updateManifest ? ObjectWrapper.wrap(this._updateManifest,
|
||||
this._window)
|
||||
: null;
|
||||
},
|
||||
|
||||
|
@ -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)
|
||||
case "Webapps:FireEvent":
|
||||
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];
|
||||
// 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];
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (msg.event == "downloadapplied") {
|
||||
this._fireEvent("downloadapplied", this._ondownloadapplied);
|
||||
} else if (msg.event == "downloadavailable") {
|
||||
this._fireEvent("downloadavailable", this._ondownloadavailable);
|
||||
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",
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: {
|
||||
progress: 0,
|
||||
installState: download.previousState,
|
||||
downloading: false
|
||||
},
|
||||
error: error,
|
||||
manifestURL: app.manifestURL,
|
||||
app: app,
|
||||
error: error });
|
||||
})
|
||||
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,
|
||||
DOMApplicationRegistry._saveApps(function() {
|
||||
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: jsonManifest });
|
||||
DOMApplicationRegistry._saveApps();
|
||||
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,
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: aData });
|
||||
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),
|
||||
|
@ -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 {
|
||||
this._saveApps(function() {
|
||||
// Like if we got a 304, just send a 'downloadapplied'
|
||||
// or downloadavailable event.
|
||||
aData.event = app.downloadAvailable ? "downloadavailable"
|
||||
let eventType = app.downloadAvailable ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aData.app = {
|
||||
lastCheckedUpdate: app.lastCheckedUpdate
|
||||
}
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
this._saveApps();
|
||||
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) {
|
||||
app.lastCheckedUpdate = Date.now();
|
||||
this._saveApps(function() {
|
||||
// If the app is a packaged app, we just send a 'downloadapplied'
|
||||
// or downloadavailable event.
|
||||
app.lastCheckedUpdate = Date.now();
|
||||
aData.event = app.downloadAvailable ? "downloadavailable"
|
||||
let eventType = app.downloadAvailable ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aData.app = {
|
||||
lastCheckedUpdate: app.lastCheckedUpdate
|
||||
}
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
this._saveApps();
|
||||
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,
|
||||
PermissionsInstaller.installPermissions({
|
||||
manifest: aManifest,
|
||||
origin: appObject.origin,
|
||||
manifestURL: appObject.manifestURL },
|
||||
true);
|
||||
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,
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: aManifest });
|
||||
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,
|
||||
self._saveApps(function() {
|
||||
self.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
error: aError,
|
||||
app: app });
|
||||
self._saveApps();
|
||||
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) {
|
||||
|
@ -3330,29 +3401,39 @@ AppcacheObserver.prototype = {
|
|||
debug("Offlinecache setStatus to " + aStatus + " with progress " +
|
||||
aProgress + " for " + app.origin);
|
||||
mustSave = (app.installState != aStatus);
|
||||
|
||||
app.installState = aStatus;
|
||||
app.progress = aProgress;
|
||||
if (aStatus == "installed") {
|
||||
if (aStatus != "installed") {
|
||||
self._sendProgressEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
app.updateTime = Date.now();
|
||||
app.downloading = false;
|
||||
app.downloadAvailable = false;
|
||||
}
|
||||
self._sendProgressEvent();
|
||||
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,
|
||||
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) {
|
||||
// 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;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче