Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2013-10-18 12:00:14 +02:00
Родитель e8584439a7 a3284daeb0
Коммит aa20ddde42
324 изменённых файлов: 5150 добавлений и 2408 удалений

Просмотреть файл

@ -129,8 +129,9 @@ pref("app.update.cert.maxErrors", 5);
// the |app.update.url.override| preference should ONLY be used for testing.
// IMPORTANT! metro.js should also be updated for updates to certs.X.issuerName
// Nightly builds have switched over to aus4.mozilla.org, but we don't want anything else to yet.
#ifdef NIGHTLY_BUILD
// Non-release builds (Nightly, Aurora, etc.) have been switched over to aus4.mozilla.org.
// This condition protects us against accidentally using it for release builds.
#ifndef RELEASE_BUILD
pref("app.update.certs.1.issuerName", "CN=DigiCert Secure Server CA,O=DigiCert Inc,C=US");
pref("app.update.certs.1.commonName", "aus4.mozilla.org");
@ -172,7 +173,7 @@ pref("app.update.silent", false);
pref("app.update.staging.enabled", true);
// Update service URL:
#ifdef NIGHTLY_BUILD
#ifndef RELEASE_BUILD
pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
#else
pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
@ -232,6 +233,12 @@ pref("xpinstall.whitelist.add.180", "marketplace.firefox.com");
pref("lightweightThemes.update.enabled", true);
// UI tour experience.
pref("browser.uitour.enabled", true);
pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/themes/");
pref("browser.uitour.pinnedTabUrl", "https://support.mozilla.org/%LOCALE%/kb/pinned-tabs-keep-favorite-websites-open");
pref("browser.uitour.whitelist.add.260", "www.mozilla.org,support.mozilla.org");
pref("keyword.enabled", true);
pref("general.useragent.locale", "@AB_CD@");
@ -659,6 +666,8 @@ pref("plugins.update.notifyUser", false);
pref("plugins.click_to_play", true);
pref("plugins.clickToActivateInfo.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/clicktoplay");
// let all plugins except Flash default to click-to-play
pref("plugin.default.state", 1);
pref("plugin.state.flash", 2);

Просмотреть файл

@ -704,6 +704,9 @@ var gPluginHandler = {
else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
}
else {
url = Services.urlFormatter.formatURLPref("plugins.clickToActivateInfo.url");
}
pluginInfo.detailsLink = url;
centerActions.push(pluginInfo);

Просмотреть файл

@ -778,27 +778,6 @@ var gBrowserInit = {
window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow =
new nsBrowserAccess();
// Manually hook up session and global history for the first browser
// so that we don't have to load global history before bringing up a
// window.
// Wire up session and global history before any possible
// progress notifications for back/forward button updating
gBrowser.webNavigation.sessionHistory = Cc["@mozilla.org/browser/shistory;1"].
createInstance(Ci.nsISHistory);
Services.obs.addObserver(gBrowser.browsers[0], "browser:purge-session-history", false);
// remove the disablehistory attribute so the browser cleans up, as
// though it had done this work itself
gBrowser.browsers[0].removeAttribute("disablehistory");
// enable global history
try {
if (!gMultiProcessBrowser)
gBrowser.docShell.useGlobalHistory = true;
} catch(ex) {
Cu.reportError("Places database may be locked: " + ex);
}
// hook up UI through progress listener
gBrowser.addProgressListener(window.XULBrowserWindow);
gBrowser.addTabsProgressListener(window.TabsProgressListener);

Просмотреть файл

@ -22,6 +22,7 @@
<window id="main-window"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
@ -183,6 +184,22 @@
</hbox>
</panel>
<!-- UI tour experience -->
<panel id="UITourTooltip"
type="arrow"
hidden="true"
consumeoutsideclicks="false"
noautofocus="true"
align="start"
orient="vertical"
role="alert">
<label id="UITourTooltipTitle" flex="1"/>
<description id="UITourTooltipDescription" flex="1"/>
</panel>
<html:div id="UITourHighlightContainer" style="position:relative">
<html:div id="UITourHighlight"></html:div>
</html:div>
<panel id="socialActivatedNotification"
type="arrow"
hidden="true"
@ -1028,7 +1045,7 @@
<splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
<vbox id="appcontent" flex="1">
<tabbrowser id="content" disablehistory="true"
<tabbrowser id="content"
flex="1" contenttooltip="aHTMLTooltip"
tabcontainer="tabbrowser-tabs"
contentcontextmenu="contentAreaContextMenu"

Просмотреть файл

@ -15,6 +15,8 @@ XPCOMUtils.defineLazyModuleGetter(this,
"InsecurePasswordUtils", "resource://gre/modules/InsecurePasswordUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
"resource:///modules/UITour.jsm");
// Creates a new nsIURI object.
function makeURI(uri, originCharset, baseURI) {
@ -49,6 +51,15 @@ if (Services.prefs.getBoolPref("browser.tabs.remote")) {
addEventListener("blur", function(event) {
LoginManagerContent.onUsernameInput(event);
});
addEventListener("mozUITour", function(event) {
if (!Services.prefs.getBoolPref("browser.uitour.enabled"))
return;
let handled = UITour.onPageEvent(event);
if (handled)
addEventListener("pagehide", UITour);
}, false, true);
}
let AboutHomeListener = {

Просмотреть файл

@ -34,7 +34,7 @@
<xul:hbox flex="1" class="browserSidebarContainer">
<xul:vbox flex="1" class="browserContainer">
<xul:stack flex="1" class="browserStack" anonid="browserStack">
<xul:browser anonid="initialBrowser" type="content-primary" message="true" disablehistory="true"
<xul:browser anonid="initialBrowser" type="content-primary" message="true"
xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectpopup"/>
</xul:stack>
</xul:vbox>

Просмотреть файл

@ -472,6 +472,7 @@ BrowserGlue.prototype = {
ShumwayUtils.init();
webrtcUI.init();
AboutHome.init();
SessionStore.init();
if (Services.prefs.getBoolPref("browser.tabs.remote"))
ContentClick.init();
@ -612,7 +613,6 @@ BrowserGlue.prototype = {
}
#endif
SessionStore.init(aWindow);
this._trackSlowStartup();
// Offer to reset a user's profile if it hasn't been used for 60 days.

Просмотреть файл

@ -156,8 +156,8 @@ this.SessionStore = {
SessionStoreInternal.canRestoreLastSession = val;
},
init: function ss_init(aWindow) {
SessionStoreInternal.init(aWindow);
init: function ss_init() {
SessionStoreInternal.init();
},
getBrowserState: function ss_getBrowserState() {
@ -368,15 +368,11 @@ let SessionStoreInternal = {
/**
* Initialize the sessionstore service.
*/
init: function (aWindow) {
init: function () {
if (this._initialized) {
throw new Error("SessionStore.init() must only be called once!");
}
if (!aWindow) {
throw new Error("SessionStore.init() must be called with a valid window.");
}
this._disabledForMultiProcess = Services.prefs.getBoolPref("browser.tabs.remote");
if (this._disabledForMultiProcess) {
this._deferredInitialized.resolve();
@ -390,20 +386,6 @@ let SessionStoreInternal = {
this._initPrefs();
this._initialized = true;
// Wait until nsISessionStartup has finished reading the session data.
gSessionStartup.onceInitialized.then(() => {
// Parse session data and start restoring.
let initialState = this.initSession();
// Start tracking the given (initial) browser window.
if (!aWindow.closed) {
this.onLoad(aWindow, initialState);
}
// Let everyone know we're done.
this._deferredInitialized.resolve();
}, Cu.reportError);
},
initSession: function ssi_initSession() {
@ -489,7 +471,6 @@ let SessionStoreInternal = {
this._prefBranch.setBoolPref("sessionstore.resume_session_once", false);
this._performUpgradeBackup();
this._sessionInitialized = true;
return state;
},
@ -876,7 +857,34 @@ let SessionStoreInternal = {
onOpen: function ssi_onOpen(aWindow) {
let onload = () => {
aWindow.removeEventListener("load", onload);
this.onLoad(aWindow);
if (this._sessionInitialized) {
this.onLoad(aWindow);
return;
}
// We can't call this.onLoad since initialization
// hasn't completed, so we'll wait until it is done.
// Even if additional windows are opened and wait
// for initialization as well, the first opened
// window should execute first, and this.onLoad
// will be called with the initialState.
gSessionStartup.onceInitialized.then(() => {
if (aWindow.closed) {
return;
}
if (this._sessionInitialized) {
this.onLoad(aWindow);
} else {
let initialState = this.initSession();
this._sessionInitialized = true;
this.onLoad(aWindow, initialState);
// Let everyone know we're done.
this._deferredInitialized.resolve();
}
}, Cu.reportError);
};
aWindow.addEventListener("load", onload);
@ -1471,7 +1479,7 @@ let SessionStoreInternal = {
TabStateCache.delete(aTab);
this._setWindowStateBusy(window);
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
this.restoreHistoryPrecursor(window, [aTab], [tabState], 0);
},
duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
@ -1491,7 +1499,7 @@ let SessionStoreInternal = {
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
aWindow.gBrowser.addTab();
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0, 0, 0,
this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0,
true /* Load this tab right away. */);
return newTab;
@ -1571,7 +1579,7 @@ let SessionStoreInternal = {
let tab = tabbrowser.addTab();
// restore tab content
this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1, 0, 0);
this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1);
// restore the tab's position
tabbrowser.moveTabTo(tab, closedTab.pos);
@ -2344,7 +2352,7 @@ let SessionStoreInternal = {
}
this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs,
(overwriteTabs ? (parseInt(winData.selected) || 1) : 0), 0, 0);
(overwriteTabs ? (parseInt(winData.selected) || 1) : 0));
if (aState.scratchpads) {
ScratchpadManager.restoreSession(aState.scratchpads);
@ -2448,40 +2456,17 @@ let SessionStoreInternal = {
* Array of tab data
* @param aSelectTab
* Index of selected tab
* @param aIx
* Index of the next tab to check readyness for
* @param aCount
* Counter for number of times delaying b/c browser or history aren't ready
* @param aRestoreImmediately
* Flag to indicate whether the given set of tabs aTabs should be
* restored/loaded immediately even if restore_on_demand = true
*/
restoreHistoryPrecursor:
function ssi_restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab,
aIx, aCount, aRestoreImmediately = false) {
aRestoreImmediately = false)
{
var tabbrowser = aWindow.gBrowser;
// make sure that all browsers and their histories are available
// - if one's not, resume this check in 100ms (repeat at most 10 times)
for (var t = aIx; t < aTabs.length; t++) {
try {
if (!tabbrowser.getBrowserForTab(aTabs[t]).webNavigation.sessionHistory) {
throw new Error();
}
}
catch (ex) { // in case browser or history aren't ready yet
if (aCount < 10) {
var restoreHistoryFunc = function(self) {
self.restoreHistoryPrecursor(aWindow, aTabs, aTabData, aSelectTab,
aIx, aCount + 1, aRestoreImmediately);
};
aWindow.setTimeout(restoreHistoryFunc, 100, this);
return;
}
}
}
if (!this._isWindowLoaded(aWindow)) {
// from now on, the data will come from the actual window
delete this._statesToRestore[aWindow.__SS_restoreID];
@ -2507,7 +2492,7 @@ let SessionStoreInternal = {
return;
}
// Sets the tabs restoring order.
// Sets the tabs restoring order.
[aTabs, aTabData] =
this._setTabsRestoringOrder(tabbrowser, aTabs, aTabData, aSelectTab);
@ -2515,7 +2500,7 @@ let SessionStoreInternal = {
// and show/hide tabs as necessary. We'll also set the labels, user typed
// value, and attach a copy of the tab's data in case we close it before
// it's been restored.
for (t = 0; t < aTabs.length; t++) {
for (let t = 0; t < aTabs.length; t++) {
let tab = aTabs[t];
let browser = tabbrowser.getBrowserForTab(tab);
let tabData = aTabData[t];
@ -2587,14 +2572,14 @@ let SessionStoreInternal = {
// helper hashes for ensuring unique frame IDs and unique document
// identifiers.
var idMap = { used: {} };
var docIdentMap = {};
let idMap = { used: {} };
let docIdentMap = {};
this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap,
aRestoreImmediately);
},
/**
* Restore history for a window
* Restore history for a list of tabs.
* @param aWindow
* Window reference
* @param aTabs

Просмотреть файл

@ -1537,6 +1537,7 @@ NetworkDetailsView.prototype = {
}));
this._json = new VariablesView($("#response-content-json"),
Heritage.extend(GENERIC_VARIABLES_VIEW_SETTINGS, {
onlyEnumVisible: true,
searchPlaceholder: L10N.getStr("jsonFilterText")
}));
VariablesViewController.attach(this._json);
@ -1874,7 +1875,7 @@ NetworkDetailsView.prototype = {
let sanitizedJSON = aString.replace(jsonpRegex, "");
let callbackPadding = aString.match(jsonpRegex);
// Make sure this is an valid JSON object first. If so, nicely display
// Make sure this is a valid JSON object first. If so, nicely display
// the parsing results in a variables view. Otherwise, simply show
// the contents as plain text.
try {

Просмотреть файл

@ -610,66 +610,23 @@ var Scratchpad = {
deferred.resolve(aError);
}
else {
let reject = aReason => deferred.reject(aReason);
let objectClient = new ObjectClient(this.debuggerClient, aError);
// Because properties on Error objects are lazily added, this roundabout
// way of getting all the properties is required, rather than simply
// using getPrototypeAndProperties. See bug 724768.
let names = ["message", "stack", "fileName", "lineNumber"];
let promises = names.map(aName => {
let deferred = promise.defer();
objectClient.getProperty(aName, aResponse => {
if (aResponse.error) {
deferred.reject(aResponse);
}
else {
deferred.resolve({
name: aName,
descriptor: aResponse.descriptor
});
}
});
return deferred.promise;
});
{
// We also need to use getPrototypeAndProperties to retrieve any
// safeGetterValues in case this is a DOM error.
let deferred = promise.defer();
objectClient.getPrototypeAndProperties(aResponse => {
if (aResponse.error) {
deferred.reject(aResponse);
}
else {
deferred.resolve(aResponse);
}
});
promises.push(deferred.promise);
}
promise.all(promises).then(aProperties => {
let error = {};
let safeGetters;
// Combine all the property descriptor/getter values into one object.
for (let property of aProperties) {
if (property.descriptor) {
error[property.name] = property.descriptor.value;
}
else if (property.safeGetterValues) {
safeGetters = property.safeGetterValues;
}
objectClient.getPrototypeAndProperties(aResponse => {
if (aResponse.error) {
deferred.reject(aResponse);
return;
}
if (safeGetters) {
for (let key of Object.keys(safeGetters)) {
if (!error.hasOwnProperty(key)) {
error[key] = safeGetters[key].getterValue;
}
}
let { ownProperties, safeGetterValues } = aResponse;
let error = Object.create(null);
// Combine all the property descriptor/getter values into one object.
for (let key of Object.keys(safeGetterValues)) {
error[key] = safeGetterValues[key].getterValue;
}
for (let key of Object.keys(ownProperties)) {
error[key] = ownProperties[key].value;
}
// Assemble the best possible stack we can given the properties we have.
@ -693,23 +650,23 @@ var Scratchpad = {
deferred.resolve(error.message + stack);
}
else {
objectClient.getDisplayString(aResult => {
if (aResult.error) {
deferred.reject(aResult);
objectClient.getDisplayString(aResponse => {
if (aResponse.error) {
deferred.reject(aResponse);
}
else if (aResult.displayString.type == "null") {
deferred.resolve(stack);
else if (typeof aResponse.displayString == "string") {
deferred.resolve(aResponse.displayString + stack);
}
else {
deferred.resolve(aResult.displayString + stack);
deferred.resolve(stack);
}
}, reject);
});
}
}, reject);
});
}
return deferred.promise.then(aMessage => {
console.log(aMessage);
console.error(aMessage);
this.writeAsComment("Exception: " + aMessage);
});
},

Просмотреть файл

@ -43,6 +43,7 @@ function testColorUtils() {
let color = new colorUtils.CssColor(authored);
// Check all values.
info("Checking values for " + authored);
is(color.name, name, "color.name === name");
is(color.hex, hex, "color.hex === hex");
is(color.hsl, hsl, "color.hsl === hsl");
@ -291,14 +292,18 @@ function getTestData() {
{authored: "whitesmoke", name: "whitesmoke", hex: "#F5F5F5", hsl: "hsl(0, 0%, 96%)", rgb: "rgb(245, 245, 245)"},
{authored: "yellow", name: "yellow", hex: "#FF0", hsl: "hsl(60, 100%, 50%)", rgb: "rgb(255, 255, 0)"},
{authored: "yellowgreen", name: "yellowgreen", hex: "#9ACD32", hsl: "hsl(79.742, 61%, 50%)", rgb: "rgb(154, 205, 50)"},
{authored: "transparent", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
{authored: "rgba(0, 0, 0, 0)", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
{authored: "hsla(0, 0%, 0%, 0)", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
{authored: "rgba(0, 0, 0, 0)", name: "rgba(0, 0, 0, 0)", hex: "rgba(0, 0, 0, 0)", hsl: "hsla(0, 0%, 0%, 0)", rgb: "rgba(0, 0, 0, 0)"},
{authored: "hsla(0, 0%, 0%, 0)", name: "rgba(0, 0, 0, 0)", hex: "rgba(0, 0, 0, 0)", hsl: "hsla(0, 0%, 0%, 0)", rgb: "rgba(0, 0, 0, 0)"},
{authored: "rgba(50, 60, 70, 0.5)", name: "rgba(50, 60, 70, 0.5)", hex: "rgba(50, 60, 70, 0.5)", hsl: "hsla(210, 17%, 24%, 0.5)", rgb: "rgba(50, 60, 70, 0.5)"},
{authored: "rgba(0, 0, 0, 0.3)", name: "rgba(0, 0, 0, 0.3)", hex: "rgba(0, 0, 0, 0.3)", hsl: "hsla(0, 0%, 0%, 0.3)", rgb: "rgba(0, 0, 0, 0.3)"},
{authored: "rgba(255, 255, 255, 0.6)", name: "rgba(255, 255, 255, 0.6)", hex: "rgba(255, 255, 255, 0.6)", hsl: "hsla(0, 0%, 100%, 0.6)", rgb: "rgba(255, 255, 255, 0.6)"},
{authored: "rgba(127, 89, 45, 1)", name: "#7F592D", hex: "#7F592D", hsl: "hsl(32.195, 48%, 34%)", rgb: "rgb(127, 89, 45)"},
{authored: "hsla(19.304, 56%, 40%, 1)", name: "#9F512C", hex: "#9F512C", hsl: "hsl(19.304, 57%, 40%)", rgb: "rgb(159, 81, 44)"},
{authored: "invalidColor", name: "", hex: "", hsl: "", rgb: ""}
{authored: "currentcolor", name: "currentcolor", hex: "currentcolor", hsl: "currentcolor", rgb: "currentcolor"},
{authored: "inherit", name: "inherit", hex: "inherit", hsl: "inherit", rgb: "inherit"},
{authored: "initial", name: "initial", hex: "initial", hsl: "initial", rgb: "initial"},
{authored: "invalidColor", name: "", hex: "", hsl: "", rgb: ""},
{authored: "transparent", name: "transparent", hex: "transparent", hsl: "transparent", rgb: "transparent"},
{authored: "unset", name: "unset", hex: "unset", hsl: "unset", rgb: "unset"}
];
}

Просмотреть файл

@ -461,7 +461,7 @@ VariablesViewController.prototype = {
scope.expanded = true;
scope.locked = true;
let variable = scope.addItem();
let variable = scope.addItem("", { enumerable: true });
let expanded;
if (aOptions.objectActor) {

Просмотреть файл

@ -449,7 +449,7 @@ pref("app.update.silent", true);
pref("app.update.staging.enabled", true);
// Update service URL:
#ifdef NIGHTLY_BUILD
#ifndef RELEASE_BUILD
pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
#else
pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
@ -522,8 +522,9 @@ pref("app.update.cert.maxErrors", 5);
// the |app.update.url.override| preference should ONLY be used for testing.
// IMPORTANT! firefox.js should also be updated for updates to certs.X.issuerName
// Nightly builds have switched over to aus4.mozilla.org, but we don't want anything else to yet.
#ifdef NIGHTLY_BUILD
// Non-release builds (Nightly, Aurora, etc.) have been switched over to aus4.mozilla.org.
// This condition protects us against accidentally using it for release builds.
#ifndef RELEASE_BUILD
pref("app.update.certs.1.issuerName", "CN=DigiCert Secure Server CA,O=DigiCert Inc,C=US");
pref("app.update.certs.1.commonName", "aus4.mozilla.org");
pref("app.update.certs.2.issuerName", "CN=Thawte SSL CA,O=\"Thawte, Inc.\",C=US");

426
browser/modules/UITour.jsm Normal file
Просмотреть файл

@ -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
js/xpconnect
js/xpconnect/loader
mfbt
js/xpconnect
js/xpconnect/loader
view
caps
xpfe/appshell

Просмотреть файл

@ -86,27 +86,41 @@ dnl ========================================================
MOZ_USE_PTHREADS=
_PTHREAD_LDFLAGS=""
dnl Do not allow a separate objdir build if a srcdir build exists.
dnl Do not allow objdir == srcdir builds.
dnl ==============================================================
_topsrcdir=`cd \`dirname $0\`; pwd`
_objdir=`pwd`
if test "$_topsrcdir" != "$_objdir"
then
# Check for a couple representative files in the source tree
_conflict_files=
for file in $_topsrcdir/Makefile $_topsrcdir/config/autoconf.mk; do
if test -f $file; then
_conflict_files="$_conflict_files $file"
fi
dnl TODO Don't exempt L10N builds once bug 842760 is resolved.
if test "$_topsrcdir" = "$_objdir" -a "${with_l10n_base+set}" != set; then
echo " ***"
echo " * Building directly in the main source directory is not allowed."
echo " *"
echo " * To build, you must run configure from a separate directory"
echo " * (referred to as an object directory)."
echo " *"
echo " * If you are building with a mozconfig, you will need to change your"
echo " * mozconfig to point to a different object directory."
echo " ***"
exit 1
fi
# Check for a couple representative files in the source tree
_conflict_files=
for file in $_topsrcdir/Makefile $_topsrcdir/config/autoconf.mk; do
if test -f $file; then
_conflict_files="$_conflict_files $file"
fi
done
if test "$_conflict_files"; then
echo "***"
echo "* Your source tree contains these files:"
for file in $_conflict_files; do
echo "* $file"
done
if test "$_conflict_files"; then
echo "***"
echo "* Your source tree contains these files:"
for file in $_conflict_files; do
echo "* $file"
done
cat 1>&2 <<-EOF
cat 1>&2 <<-EOF
* This indicates that you previously built in the source tree.
* A source tree build can confuse the separate objdir build.
*
@ -115,9 +129,8 @@ then
* 2. gmake distclean
***
EOF
exit 1
break
fi
exit 1
break
fi
MOZ_BUILD_ROOT=`pwd`

Просмотреть файл

@ -19,6 +19,7 @@
#endif
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "js/RootingAPI.h"
#include "mozilla/Assertions.h"
#include "mozilla/EventForwards.h"
@ -1637,7 +1638,7 @@ public:
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
nsISupports *native, const nsIID* aIID,
JS::Value *vp,
JS::MutableHandle<JS::Value> vp,
// If non-null aHolder will keep the Value alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nullptr,
@ -1649,7 +1650,7 @@ public:
// Same as the WrapNative above, but use this one if aIID is nsISupports' IID.
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
nsISupports *native, JS::Value *vp,
nsISupports *native, JS::MutableHandle<JS::Value> vp,
// If non-null aHolder will keep the Value alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nullptr,
@ -1660,7 +1661,7 @@ public:
}
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
nsISupports *native, nsWrapperCache *cache,
JS::Value *vp,
JS::MutableHandle<JS::Value> vp,
// If non-null aHolder will keep the Value alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nullptr,
@ -2091,7 +2092,7 @@ private:
static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
nsISupports *native, nsWrapperCache *cache,
const nsIID* aIID, JS::Value *vp,
const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
nsIXPConnectJSObjectHolder** aHolder,
bool aAllowWrapping);

Просмотреть файл

@ -5659,14 +5659,14 @@ nsContentUtils::DispatchXULCommand(nsIContent* aTarget,
nsresult
nsContentUtils::WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
nsISupports *native, nsWrapperCache *cache,
const nsIID* aIID, JS::Value *vp,
const nsIID* aIID, JS::MutableHandleValue vp,
nsIXPConnectJSObjectHolder **aHolder,
bool aAllowWrapping)
{
if (!native) {
NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
*vp = JSVAL_NULL;
vp.setNull();
return NS_OK;
}
@ -5685,7 +5685,7 @@ nsContentUtils::WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
nsresult rv = NS_OK;
AutoPushJSContext context(cx);
rv = sXPConnect->WrapNativeToJSVal(context, scope, native, cache, aIID,
aAllowWrapping, vp, aHolder);
aAllowWrapping, vp.address(), aHolder);
return rv;
}
@ -5728,8 +5728,7 @@ nsContentUtils::CreateBlobBuffer(JSContext* aCx,
return NS_ERROR_OUT_OF_MEMORY;
}
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
return nsContentUtils::WrapNative(aCx, scope, blob, aBlob.address(), nullptr,
true);
return nsContentUtils::WrapNative(aCx, scope, blob, aBlob, nullptr, true);
}
void

Просмотреть файл

@ -206,9 +206,11 @@ nsDOMFileReader::GetResult(JSContext* aCx, JS::Value* aResult)
}
nsString tmpResult = mResult;
if (!xpc::StringToJsval(aCx, tmpResult, aResult)) {
JS::Rooted<JS::Value> result(aCx);
if (!xpc::StringToJsval(aCx, tmpResult, &result)) {
return NS_ERROR_FAILURE;
}
*aResult = result;
return NS_OK;
}

Просмотреть файл

@ -5167,7 +5167,7 @@ CustomElementConstructor(JSContext *aCx, unsigned aArgc, JS::Value* aVp)
nsresult rv = document->CreateElem(elemName, nullptr, kNameSpaceID_XHTML,
getter_AddRefs(newElement));
rv = nsContentUtils::WrapNative(aCx, global, newElement, newElement,
args.rval().address());
args.rval());
NS_ENSURE_SUCCESS(rv, false);
return true;
@ -6732,7 +6732,7 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
JS::Rooted<JSObject*> global(cx, GetScopeObject()->GetGlobalJSObject());
JS::Rooted<JS::Value> v(cx);
rv = nsContentUtils::WrapNative(cx, global, this, this, v.address(),
rv = nsContentUtils::WrapNative(cx, global, this, this, &v,
nullptr, /* aAllowWrapping = */ false);
if (rv.Failed())
return nullptr;
@ -11345,7 +11345,7 @@ nsIDocument::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = nsContentUtils::WrapNative(aCx, obj, win,
&NS_GET_IID(nsIDOMWindow),
winVal.address(),
&winVal,
getter_AddRefs(holder),
false);
if (NS_FAILED(rv)) {

Просмотреть файл

@ -832,7 +832,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
JS::Rooted<JS::Value> targetv(ctx);
JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
nsContentUtils::WrapNative(ctx, global, aTarget, targetv.address(),
nsContentUtils::WrapNative(ctx, global, aTarget, &targetv,
nullptr, true);
JS::RootedObject cpows(ctx);
@ -888,7 +888,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
}
JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
nsContentUtils::WrapNative(ctx, global, defaultThisValue,
thisValue.address(), nullptr, true);
&thisValue, nullptr, true);
} else {
// If the listener is a JS object which has receiveMessage function:
if (!JS_GetProperty(ctx, object, "receiveMessage", &funval) ||

Просмотреть файл

@ -49,7 +49,15 @@ void
nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri)
{
if (gDataTable) {
gDataTable->Remove(aUri);
nsCString uriIgnoringRef;
int32_t hashPos = aUri.FindChar('#');
if (hashPos < 0) {
uriIgnoringRef = aUri;
}
else {
uriIgnoringRef = StringHead(aUri, hashPos);
}
gDataTable->Remove(uriIgnoringRef);
if (gDataTable->Count() == 0) {
delete gDataTable;
gDataTable = nullptr;
@ -80,6 +88,27 @@ nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme,
return NS_OK;
}
static DataInfo*
GetDataInfo(const nsACString& aUri)
{
if (!gDataTable) {
return nullptr;
}
DataInfo* res;
nsCString uriIgnoringRef;
int32_t hashPos = aUri.FindChar('#');
if (hashPos < 0) {
uriIgnoringRef = aUri;
}
else {
uriIgnoringRef = StringHead(aUri, hashPos);
}
gDataTable->Get(uriIgnoringRef, &res);
return res;
}
nsIPrincipal*
nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri)
{
@ -87,8 +116,8 @@ nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri)
return nullptr;
}
DataInfo* res;
gDataTable->Get(aUri, &res);
DataInfo* res = GetDataInfo(aUri);
if (!res) {
return nullptr;
}
@ -114,18 +143,6 @@ nsHostObjectProtocolHandler::Traverse(const nsACString& aUri,
aCallback.NoteXPCOMChild(res->mObject);
}
static DataInfo*
GetDataInfo(const nsACString& aUri)
{
if (!gDataTable) {
return nullptr;
}
DataInfo* res;
gDataTable->Get(aUri, &res);
return res;
}
static nsISupports*
GetDataObject(nsIURI* aURI)
{

Просмотреть файл

@ -966,7 +966,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
if (aRv.Failed()) {
return JSVAL_NULL;
}
JS::Value result;
JS::Rooted<JS::Value> result(aCx);
if (!xpc::StringToJsval(aCx, str, &result)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return JSVAL_NULL;
@ -1014,7 +1014,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
JS::Rooted<JS::Value> result(aCx, JSVAL_NULL);
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, result.address(),
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, &result,
nullptr, true);
return result;
}
@ -1026,7 +1026,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx, ErrorResult& aRv)
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
JS::Rooted<JS::Value> result(aCx, JSVAL_NULL);
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, result.address(),
aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, &result,
nullptr, true);
return result;
}
@ -3659,7 +3659,7 @@ nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aRv)
JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
JSAutoCompartment ac(aCx, wrapper);
JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, wrapper));
aRv = nsContentUtils::WrapNative(aCx, global, result, iid, v.address());
aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
return aRv.Failed() ? JSVAL_NULL : v;
}

Двоичные данные
content/base/test/reftest/mixed-bmp-png.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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.");
return NS_ERROR_FAILURE;
int error;
mResampler = speex_resampler_init(mChannels,
aSamplingRate,
kOpusSamplingRate,
SPEEX_RESAMPLER_QUALITY_DEFAULT,
&error);
if (error != RESAMPLER_ERR_SUCCESS) {
return NS_ERROR_FAILURE;
}
}
mSamplingRate = aSamplingRate;
int error = 0;
mEncoder = opus_encoder_create(mSamplingRate, mChannels,
mEncoder = opus_encoder_create(GetOutputSampleRate(), mChannels,
OPUS_APPLICATION_AUDIO, &error);
mInitialized = (error == OPUS_OK);
@ -166,10 +175,16 @@ OpusTrackEncoder::Init(int aChannels, int aSamplingRate)
return error == OPUS_OK ? NS_OK : NS_ERROR_FAILURE;
}
int
OpusTrackEncoder::GetOutputSampleRate()
{
return mResampler ? kOpusSamplingRate : mSamplingRate;
}
int
OpusTrackEncoder::GetPacketDuration()
{
return mSamplingRate * kFrameDurationMs / 1000;
return GetOutputSampleRate() * kFrameDurationMs / 1000;
}
nsresult
@ -282,8 +297,35 @@ OpusTrackEncoder::GetEncodedTrack(nsTArray<uint8_t>* aOutput,
iter.Next();
}
// The ogg time stamping and pre-skip is always timed at 48000.
aOutputDuration = frameCopied * (kOpusSamplingRate / mSamplingRate);
if (mResampler) {
nsAutoTArray<AudioDataValue, 9600> resamplingDest;
// We want to consume all the input data, so we slightly oversize the
// resampled data buffer so we can fit the output data in. We cannot really
// predict the output frame count at each call.
uint32_t outframes = frameCopied * kOpusSamplingRate / mSamplingRate + 1;
uint32_t inframes = frameCopied;
resamplingDest.SetLength(outframes * mChannels);
#if MOZ_SAMPLE_TYPE_S16
short* in = reinterpret_cast<short*>(pcm.Elements());
short* out = reinterpret_cast<short*>(resamplingDest.Elements());
speex_resampler_process_interleaved_int(mResampler, in, &inframes,
out, &outframes);
#else
float* in = reinterpret_cast<float*>(pcm.Elements());
float* out = reinterpret_cast<float*>(resamplingDest.Elements());
speex_resampler_process_interleaved_float(mResampler, in, &inframes,
out, &outframes);
#endif
pcm = resamplingDest;
// This is always at 48000Hz.
aOutputDuration = outframes;
} else {
// The ogg time stamping and pre-skip is always timed at 48000.
aOutputDuration = frameCopied * (kOpusSamplingRate / mSamplingRate);
}
// Remove the raw data which has been pulled to pcm buffer.
// The value of frameCopied should equal to (or smaller than, if eos)
@ -294,6 +336,9 @@ OpusTrackEncoder::GetEncodedTrack(nsTArray<uint8_t>* aOutput,
// encoding.
if (mSourceSegment->GetDuration() == 0 && mEndOfStream) {
mDoneEncoding = true;
if (mResampler) {
speex_resampler_destroy(mResampler);
}
LOG("[Opus] Done encoding.");
}

Просмотреть файл

@ -6,6 +6,8 @@
#ifndef OpusTrackEncoder_h_
#define OpusTrackEncoder_h_
#include <stdint.h>
#include <speex/speex_resampler.h>
#include "TrackEncoder.h"
#include "nsCOMPtr.h"
@ -35,6 +37,12 @@ private:
DATA
} mEncoderState;
/**
* Get the samplerate of the data to be fed to the Opus encoder. This might be
* different from the intput samplerate if resampling occurs.
*/
int GetOutputSampleRate();
/**
* The Opus encoder from libopus.
*/
@ -54,6 +62,12 @@ private:
* in order to align the time of input and output.
*/
int mLookahead;
/**
* If the input sample rate does not divide 48kHz evenly, the input data are
* resampled.
*/
SpeexResamplerState* mResampler;
};
}

Просмотреть файл

@ -231,6 +231,7 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_1(AudioDestinationNode, AudioNode,
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsIDOMEventListener.h"
#include "nsIAudioChannelAgent.h"
#include "AudioChannelCommon.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace dom {
@ -21,6 +22,7 @@ class AudioContext;
class AudioDestinationNode : public AudioNode
, public nsIDOMEventListener
, public nsIAudioChannelAgentCallback
, public nsSupportsWeakReference
{
public:
// This node type knows what MediaStreamGraph to use based on

Просмотреть файл

@ -50,13 +50,13 @@ DelayProcessor::Process(const double *aPerFrameDelays,
MOZ_ASSERT(readPosition >= 0.0, "Why are we reading before the beginning of the buffer?");
// Here is a the reason why readIndex1 and readIndex will never be out
// of bounds. The maximum value for bufferLength is 180 * 48000 (see
// AudioContext::CreateDelay). The maximum value for mCurrentDelay is
// 180.0, so initially readPosition cannot be more than bufferLength +
// a fraction less than 1. Then we take care of that case by
// subtracting bufferLength from it if needed. So, if
// |bufferLength-readPosition<1.0|, readIndex1 will end up being zero.
// If |1.0<=bufferLength-readPosition<2.0|, readIndex1 will be
// of bounds. The maximum value for bufferLength is
// 180 * AudioContext.samplerate (see AudioContext::CreateDelay). The
// maximum value for mCurrentDelay is 180.0, so initially readPosition
// cannot be more than bufferLength + a fraction less than 1. Then we
// take care of that case by subtracting bufferLength from it if needed.
// So, if |bufferLength-readPosition<1.0|, readIndex1 will end up being
// zero. If |1.0<=bufferLength-readPosition<2.0|, readIndex1 will be
// bufferLength-1 and readIndex2 will be 0.
int readIndex1 = int(readPosition);
int readIndex2 = (readIndex1 + 1) % bufferLength;

Двоичные данные
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-44.1k-1ch.ogg Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-44.1k-1ch.wav Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-44.1k-2ch.ogg Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-44.1k-2ch.wav Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-48k-1ch.ogg Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-48k-1ch.wav Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-48k-2ch.ogg Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-48k-2ch.wav Normal file

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-dualchannel44.1.wav Normal file

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-dualchannel48.wav Normal file

Двоичный файл не отображается.

Двоичные данные
content/media/webaudio/test/ting-expected.wav

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
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,27 +347,24 @@ WebappsApplication.prototype = {
this._downloadError = null;
this.initDOMRequestHelper(aWindow, [
"Webapps:OfflineCache",
"Webapps:CheckForUpdate:Return:OK",
"Webapps:CheckForUpdate:Return:KO",
"Webapps:PackageEvent",
"Webapps:Connect:Return:OK",
"Webapps:Connect:Return:KO",
"Webapps:GetConnections:Return:OK"
"Webapps:FireEvent",
"Webapps:GetConnections:Return:OK",
"Webapps:UpdateState"
]);
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
{
messages: ["Webapps:OfflineCache",
"Webapps:PackageEvent",
"Webapps:CheckForUpdate:Return:OK"],
app: {
id: this.id,
manifestURL: this.manifestURL,
installState: this.installState,
downloading: this.downloading
}
});
cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
messages: ["Webapps:FireEvent",
"Webapps:UpdateState"],
app: {
id: this.id,
manifestURL: this.manifestURL,
installState: this.installState,
downloading: this.downloading
}
});
},
get manifest() {
@ -378,8 +375,10 @@ WebappsApplication.prototype = {
},
get updateManifest() {
return this.updateManifest = this._updateManifest ? ObjectWrapper.wrap(this._updateManifest, this._window)
: null;
return this.updateManifest =
this._updateManifest ? ObjectWrapper.wrap(this._updateManifest,
this._window)
: null;
},
set onprogress(aCallback) {
@ -512,18 +511,42 @@ WebappsApplication.prototype = {
uninit: function() {
this._onprogress = null;
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
["Webapps:OfflineCache",
"Webapps:PackageEvent",
"Webapps:CheckForUpdate:Return:OK"]);
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages", [
"Webapps:FireEvent",
"Webapps:PackageEvent"
]);
manifestCache.evict(this.manifestURL, this.innerWindowID);
},
_fireEvent: function(aName, aHandler) {
if (aHandler) {
let event = new this._window.MozApplicationEvent(aName, { application: this });
aHandler.handleEvent(event);
_fireEvent: function(aName) {
let handler = this["_on" + aName];
if (handler) {
let event = new this._window.MozApplicationEvent(aName, {
application: this
});
try {
handler.handleEvent(event);
} catch (ex) {
dump("Event handler expection " + ex + "\n");
}
}
},
_updateState: function(aMsg) {
if (aMsg.app) {
for (let prop in aMsg.app) {
this[prop] = aMsg.app[prop];
}
}
if (aMsg.error) {
this._downloadError = aMsg.error;
}
if (aMsg.manifest) {
this._manifest = aMsg.manifest;
manifestCache.evict(this.manifestURL, this.innerWindowID);
}
},
@ -540,10 +563,11 @@ WebappsApplication.prototype = {
// ondownload* callbacks should be triggered on all app instances
if ((msg.oid != this._id || !req) &&
aMessage.name !== "Webapps:OfflineCache" &&
aMessage.name !== "Webapps:PackageEvent" &&
aMessage.name !== "Webapps:CheckForUpdate:Return:OK")
aMessage.name !== "Webapps:FireEvent" &&
aMessage.name !== "Webapps:UpdateState") {
return;
}
switch (aMessage.name) {
case "Webapps:Launch:Return:KO":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
@ -558,108 +582,36 @@ WebappsApplication.prototype = {
case "Webapps:CheckForUpdate:Return:KO":
Services.DOMRequest.fireError(req, msg.error);
break;
case "Webapps:CheckForUpdate:Return:OK":
if (msg.manifestURL != this.manifestURL)
return;
manifestCache.evict(this.manifestURL, this.innerWindowID);
let hiddenProps = ["manifest", "updateManifest"];
let updatableProps = ["installOrigin", "installTime", "installState",
"lastUpdateCheck", "updateTime", "progress", "downloadAvailable",
"downloading", "readyToApplyDownload", "downloadSize"];
// Props that we don't update: origin, receipts, manifestURL, removable.
updatableProps.forEach(function(prop) {
if (msg.app[prop]) {
this[prop] = msg.app[prop];
}
}, this);
hiddenProps.forEach(function(prop) {
if (msg.app[prop]) {
this["_" + prop] = msg.app[prop];
}
}, this);
if (msg.event == "downloadapplied") {
this._fireEvent("downloadapplied", this._ondownloadapplied);
} else if (msg.event == "downloadavailable") {
this._fireEvent("downloadavailable", this._ondownloadavailable);
case "Webapps:FireEvent":
if (msg.manifestURL != this.manifestURL) {
return;
}
// The parent might ask childs to trigger more than one event in one
// shot, so in order to avoid needless IPC we allow an array for the
// 'eventType' IPC message field.
if (!Array.isArray(msg.eventType)) {
msg.eventType = [msg.eventType];
}
msg.eventType.forEach((aEventType) => {
if ("_on" + aEventType in this) {
this._fireEvent(aEventType);
} else {
dump("Unsupported event type " + aEventType + "\n");
}
});
if (req) {
Services.DOMRequest.fireSuccess(req, this.manifestURL);
}
break;
case "Webapps:OfflineCache":
if (msg.manifest != this.manifestURL)
case "Webapps:UpdateState":
if (msg.manifestURL != this.manifestURL) {
return;
if ("installState" in msg) {
this.installState = msg.installState;
this.progress = msg.progress;
if (this.installState == "installed") {
this._downloadError = null;
this.downloading = false;
this.downloadAvailable = false;
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
this._fireEvent("downloadapplied", this._ondownloadapplied);
} else {
this.downloading = true;
this._fireEvent("downloadprogress", this._onprogress);
}
} else if (msg.error) {
this._downloadError = msg.error;
this.downloading = false;
this._fireEvent("downloaderror", this._ondownloaderror);
}
break;
case "Webapps:PackageEvent":
if (msg.manifestURL != this.manifestURL)
return;
// Set app values according to parent process results.
let app = msg.app;
this.downloading = app.downloading;
this.downloadAvailable = app.downloadAvailable;
this.downloadSize = app.downloadSize || 0;
this.installState = app.installState;
this.progress = app.progress || msg.progress || 0;
this.readyToApplyDownload = app.readyToApplyDownload;
this.updateTime = app.updateTime;
this.origin = app.origin;
switch(msg.type) {
case "error":
case "canceled":
this._downloadError = msg.error;
this._fireEvent("downloaderror", this._ondownloaderror);
break;
case "progress":
this._fireEvent("downloadprogress", this._onprogress);
break;
case "installed":
manifestCache.evict(this.manifestURL, this.innerWindowID);
this._manifest = msg.manifest;
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
this._fireEvent("downloadapplied", this._ondownloadapplied);
break;
case "downloaded":
// We don't update the packaged apps manifests until they
// are installed or until the update is unstaged.
if (msg.manifest) {
manifestCache.evict(this.manifestURL, this.innerWindowID);
this._manifest = msg.manifest;
}
this._fireEvent("downloadsuccess", this._ondownloadsuccess);
break;
case "applied":
manifestCache.evict(this.manifestURL, this.innerWindowID);
this._manifest = msg.manifest;
this._fireEvent("downloadapplied", this._ondownloadapplied);
break;
}
this._updateState(msg);
break;
case "Webapps:ClearBrowserData:Return":
this.removeMessageListeners(aMessage.name);
@ -667,10 +619,10 @@ WebappsApplication.prototype = {
break;
case "Webapps:Connect:Return:OK":
let messagePorts = [];
msg.messagePortIDs.forEach(function(aPortID) {
msg.messagePortIDs.forEach((aPortID) => {
let port = new this._window.MozInterAppMessagePort(aPortID);
messagePorts.push(port);
}, this);
});
req.resolve(messagePorts);
break;
case "Webapps:Connect:Return:KO":
@ -678,13 +630,13 @@ WebappsApplication.prototype = {
break;
case "Webapps:GetConnections:Return:OK":
let connections = [];
msg.connections.forEach(function(aConnection) {
msg.connections.forEach((aConnection) => {
let connection =
new this._window.MozInterAppConnection(aConnection.keyword,
aConnection.pubAppManifestURL,
aConnection.subAppManifestURL);
connections.push(connection);
}, this);
});
req.resolve(connections);
break;
}

Просмотреть файл

@ -43,7 +43,7 @@ function supportSystemMessages() {
}
// Minimum delay between two progress events while downloading, in ms.
const MIN_PROGRESS_EVENT_DELAY = 1000;
const MIN_PROGRESS_EVENT_DELAY = 1500;
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
@ -945,8 +945,6 @@ this.DOMApplicationRegistry = {
addMessageListener: function(aMsgNames, aApp, aMm) {
aMsgNames.forEach(function (aMsgName) {
let man = aApp && aApp.manifestURL;
debug("Adding messageListener for: " + aMsgName + "App: " +
man);
if (!(aMsgName in this.children)) {
this.children[aMsgName] = [];
}
@ -966,8 +964,8 @@ this.DOMApplicationRegistry = {
});
// If it wasn't registered before, let's update its state
if ((aMsgName === 'Webapps:PackageEvent') ||
(aMsgName === 'Webapps:OfflineCache')) {
if ((aMsgName === 'Webapps:FireEvent') ||
(aMsgName === 'Webapps:UpdateState')) {
if (man) {
let app = this.getAppByManifestURL(aApp.manifestURL);
if (app && ((aApp.installState !== app.installState) ||
@ -1124,9 +1122,9 @@ this.DOMApplicationRegistry = {
// Webapps:Install:Return:OK
// Webapps:Uninstall:Return:OK
// Webapps:Uninstall:Broadcast:Return:OK
// Webapps:OfflineCache
// Webapps:FireEvent
// Webapps:checkForUpdate:Return:OK
// Webapps:PackageEvent
// Webapps:UpdateState
broadcastMessage: function broadcastMessage(aMsgName, aContent) {
if (!(aMsgName in this.children)) {
return;
@ -1140,7 +1138,7 @@ this.DOMApplicationRegistry = {
return FileUtils.getDir(DIRECTORY_NAME, ["webapps", aId], true, true);
},
_writeFile: function ss_writeFile(aFile, aData, aCallbak) {
_writeFile: function _writeFile(aFile, aData, aCallback) {
debug("Saving " + aFile.path);
// Initialize the file output stream.
let ostream = FileUtils.openSafeFileOutputStream(aFile);
@ -1153,8 +1151,9 @@ this.DOMApplicationRegistry = {
// Asynchronously copy the data to the file.
let istream = converter.convertToInputStream(aData);
NetUtil.asyncCopy(istream, ostream, function(rc) {
if (aCallbak)
aCallbak();
if (aCallback) {
aCallback();
}
});
},
@ -1216,22 +1215,15 @@ this.DOMApplicationRegistry = {
let app = this.webapps[download.appId];
if (download.cacheUpdate) {
// Cancel hosted app download.
app.isCanceling = true;
try {
download.cacheUpdate.cancel();
} catch (e) {
delete app.isCanceling;
debug (e);
}
} else if (download.channel) {
// Cancel packaged app download.
app.isCanceling = true;
try {
download.channel.cancel(Cr.NS_BINDING_ABORTED);
} catch(e) {
delete app.isCanceling;
}
} catch(e) { }
} else {
return;
}
@ -1241,11 +1233,19 @@ this.DOMApplicationRegistry = {
app.installState = download.previousState;
app.downloading = false;
this._saveApps((function() {
this.broadcastMessage("Webapps:PackageEvent",
{ type: "canceled",
manifestURL: app.manifestURL,
app: app,
error: error });
this.broadcastMessage("Webapps:UpdateState", {
app: {
progress: 0,
installState: download.previousState,
downloading: false
},
error: error,
manifestURL: app.manifestURL,
})
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: app.manifestURL
});
}).bind(this));
AppDownloadManager.remove(aManifestURL);
},
@ -1267,11 +1267,14 @@ this.DOMApplicationRegistry = {
// If the caller is trying to start a download but we have nothing to
// download, send an error.
if (!app.downloadAvailable) {
this.broadcastMessage("Webapps:PackageEvent",
{ type: "canceled",
manifestURL: app.manifestURL,
app: app,
error: "NO_DOWNLOAD_AVAILABLE" });
this.broadcastMessage("Webapps:UpdateState", {
error: "NO_DOWNLOAD_AVAILABLE",
manifestURL: app.manifestURL
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: app.manifestURL
});
return;
}
@ -1303,16 +1306,21 @@ this.DOMApplicationRegistry = {
debug("appcache found");
this.startOfflineCacheDownload(manifest, app, null, isUpdate);
} else {
// hosted app with no appcache, nothing to do, but we fire a
// downloaded event
// Hosted app with no appcache, nothing to do, but we fire a
// downloaded event.
debug("No appcache found, sending 'downloaded' for " + aManifestURL);
app.downloadAvailable = false;
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
{ type: "downloaded",
manifestURL: aManifestURL,
app: app,
manifest: jsonManifest });
DOMApplicationRegistry._saveApps();
DOMApplicationRegistry._saveApps(function() {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: jsonManifest,
manifestURL: aManifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadsuccess",
manifestURL: aManifestURL
});
});
}
}).bind(this));
@ -1321,7 +1329,8 @@ this.DOMApplicationRegistry = {
this._loadJSONAsync(file, (function(aJSON) {
if (!aJSON) {
debug("startDownload: No update manifest found at " + file.path + " " + aManifestURL);
debug("startDownload: No update manifest found at " + file.path + " " +
aManifestURL);
return;
}
@ -1350,11 +1359,14 @@ this.DOMApplicationRegistry = {
app.readyToApplyDownload = true;
app.updateTime = Date.now();
DOMApplicationRegistry._saveApps(function() {
debug("About to fire Webapps:PackageEvent");
DOMApplicationRegistry.broadcastMessage("Webapps:PackageEvent",
{ type: "downloaded",
manifestURL: aManifestURL,
app: app });
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: aManifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadsuccess",
manifestURL: aManifestURL
});
if (app.installState == "pending") {
// We restarted a failed download, apply it automatically.
DOMApplicationRegistry.applyDownload(aManifestURL);
@ -1442,11 +1454,15 @@ this.DOMApplicationRegistry = {
}
this.updateDataStore(this.webapps[id].localId, app.origin,
app.manifestURL, aData);
this.broadcastMessage("Webapps:PackageEvent",
{ type: "applied",
manifestURL: app.manifestURL,
app: app,
manifest: aData });
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: aData,
manifestURL: app.manifestURL
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadapplied",
manifestURL: app.manifestURL
});
}).bind(this));
}).bind(this));
}).bind(this));
@ -1475,6 +1491,14 @@ this.DOMApplicationRegistry = {
aApp.downloading = true;
aApp.progress = 0;
DOMApplicationRegistry._saveApps((function() {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: {
downloading: true,
installState: aApp.installState,
progress: 0
},
manifestURL: aApp.manifestURL
});
let cacheUpdate = aProfileDir
? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
: updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
@ -1598,16 +1622,17 @@ this.DOMApplicationRegistry = {
// event.
app.downloadAvailable = true;
app.downloadSize = manifest.size;
aData.event = "downloadavailable";
aData.app = {
downloadAvailable: true,
downloadSize: manifest.size,
updateManifest: aManifest
}
app.updateManifest = aManifest;
DOMApplicationRegistry._saveApps(function() {
DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
aData);
delete aData.app.updateManifest;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadavailable",
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
}
@ -1662,10 +1687,17 @@ this.DOMApplicationRegistry = {
this.webapps[id] = app;
this._saveApps(function() {
let reg = DOMApplicationRegistry;
aData.app = app;
if (!manifest.appcache_path) {
aData.event = "downloadapplied";
reg.broadcastMessage("Webapps:CheckForUpdate:Return:OK", aData);
reg.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: app.manifest,
manifestURL: app.manifestURL
});
reg.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadapplied",
manifestURL: app.manifestURL,
requestID: aData.requestID
});
} else {
// Check if the appcache is updatable, and send "downloadavailable" or
// "downloadapplied".
@ -1673,14 +1705,24 @@ this.DOMApplicationRegistry = {
observe: function(aSubject, aTopic, aObsData) {
debug("updateHostedApp: updateSvc.checkForUpdate return for " +
app.manifestURL + " - event is " + aTopic);
aData.event =
let eventType =
aTopic == "offline-cache-update-available" ? "downloadavailable"
: "downloadapplied";
aData.app.downloadAvailable = (aData.event == "downloadavailable");
reg._saveApps();
reg.broadcastMessage("Webapps:CheckForUpdate:Return:OK", aData);
app.downloadAvailable = (eventType == "downloadavailable");
reg._saveApps(function() {
reg.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: app.manifest,
manifestURL: app.manifestURL
});
reg.broadcastMessage("Webapps:FireEvent", {
eventType: eventType,
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
}
}
};
debug("updateHostedApp: updateSvc.checkForUpdate for " +
manifest.fullAppcachePath());
updateSvc.checkForUpdate(Services.io.newURI(manifest.fullAppcachePath(), null, null),
@ -1715,8 +1757,8 @@ this.DOMApplicationRegistry = {
let onlyCheckAppCache = false;
#ifdef MOZ_WIDGET_GONK
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
onlyCheckAppCache = (app.basePath == appDir.path);
let appDir = FileUtils.getDir("coreAppsDir", ["webapps"], false);
onlyCheckAppCache = (app.basePath == appDir.path);
#endif
if (onlyCheckAppCache) {
@ -1744,19 +1786,24 @@ this.DOMApplicationRegistry = {
debug("onlyCheckAppCache updateSvc.checkForUpdate return for " +
app.manifestURL + " - event is " + aTopic);
if (aTopic == "offline-cache-update-available") {
aData.event = "downloadavailable";
app.downloadAvailable = true;
aData.app = app;
this._saveApps(function() {
DOMApplicationRegistry.broadcastMessage(
"Webapps:CheckForUpdate:Return:OK", aData);
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "downloadavailable",
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
} else {
aData.error = "NOT_UPDATABLE";
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
}
}
}
};
let helper = new ManifestHelper(manifest);
debug("onlyCheckAppCache - launch updateSvc.checkForUpdate for " +
helper.fullAppcachePath());
@ -1806,15 +1853,21 @@ this.DOMApplicationRegistry = {
if (oldHash != hash) {
updatePackagedApp.call(this, manifest);
} else {
// Like if we got a 304, just send a 'downloadapplied'
// or downloadavailable event.
aData.event = app.downloadAvailable ? "downloadavailable"
: "downloadapplied";
aData.app = {
lastCheckedUpdate: app.lastCheckedUpdate
}
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
this._saveApps();
this._saveApps(function() {
// Like if we got a 304, just send a 'downloadapplied'
// or downloadavailable event.
let eventType = app.downloadAvailable ? "downloadavailable"
: "downloadapplied";
aMm.sendAsyncMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
aMm.sendAsyncMessage("Webapps:FireEvent", {
eventType: eventType,
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
}
} else {
// Update only the appcache if the manifest has not changed
@ -1826,16 +1879,22 @@ this.DOMApplicationRegistry = {
} else if (xhr.status == 304) {
// The manifest has not changed.
if (isPackage) {
// If the app is a packaged app, we just send a 'downloadapplied'
// or downloadavailable event.
app.lastCheckedUpdate = Date.now();
aData.event = app.downloadAvailable ? "downloadavailable"
: "downloadapplied";
aData.app = {
lastCheckedUpdate: app.lastCheckedUpdate
}
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
this._saveApps();
this._saveApps(function() {
// If the app is a packaged app, we just send a 'downloadapplied'
// or downloadavailable event.
let eventType = app.downloadAvailable ? "downloadavailable"
: "downloadapplied";
aMm.sendAsyncMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
aMm.sendAsyncMessage("Webapps:FireEvent", {
eventType: eventType,
manifestURL: app.manifestURL,
requestID: aData.requestID
});
});
} else {
// For hosted apps, even if the manifest has not changed, we check
// for offline cache updates.
@ -2146,21 +2205,25 @@ this.DOMApplicationRegistry = {
if (supportUseCurrentProfile()) {
// Update the permissions for this app.
PermissionsInstaller.installPermissions({ manifest: aManifest,
origin: appObject.origin,
manifestURL: appObject.manifestURL },
true);
PermissionsInstaller.installPermissions({
manifest: aManifest,
origin: appObject.origin,
manifestURL: appObject.manifestURL
}, true);
}
this.updateDataStore(this.webapps[aId].localId, appObject.origin,
appObject.manifestURL, aManifest);
debug("About to fire Webapps:PackageEvent 'installed'");
this.broadcastMessage("Webapps:PackageEvent",
{ type: "installed",
manifestURL: appObject.manifestURL,
app: app,
manifest: aManifest });
this.broadcastMessage("Webapps:UpdateState", {
app: app,
manifest: aManifest,
manifestURL: appObject.manifestURL
});
this.broadcastMessage("Webapps:FireEvent", {
eventType: ["downloadsuccess", "downloadapplied"],
manifestURL: appObject.manifestURL
});
if (installSuccessCallback) {
installSuccessCallback(aManifest, zipFile.path);
}
@ -2426,14 +2489,6 @@ this.DOMApplicationRegistry = {
dir.remove(true);
} catch (e) { }
// We avoid notifying the error to the DOM side if the app download
// was cancelled via cancelDownload, which already sends its own
// notification.
if (app.isCanceling) {
delete app.isCanceling;
return;
}
let download = AppDownloadManager.get(aApp.manifestURL);
app.downloading = false;
@ -2449,20 +2504,31 @@ this.DOMApplicationRegistry = {
delete app.staged;
}
self.broadcastMessage("Webapps:PackageEvent",
{ type: "error",
manifestURL: aApp.manifestURL,
error: aError,
app: app });
self._saveApps();
self._saveApps(function() {
self.broadcastMessage("Webapps:UpdateState", {
app: app,
error: aError,
manifestURL: aApp.manifestURL
});
self.broadcastMessage("Webapps:FireEvent", {
eventType: "downloaderror",
manifestURL: aApp.manifestURL
});
});
AppDownloadManager.remove(aApp.manifestURL);
}
function sendProgressEvent() {
self.broadcastMessage("Webapps:PackageEvent",
{ type: "progress",
manifestURL: aApp.manifestURL,
app: app });
function sendProgressEvent(aProgress) {
self.broadcastMessage("Webapps:UpdateState", {
app: {
progress: aProgress
},
manifestURL: aApp.manifestURL
});
self.broadcastMessage("Webapps:FireEvent", {
eventType: "progress",
manifestURL: aApp.manifestURL
});
}
// aStoreId must be a string of the form
@ -2548,7 +2614,7 @@ this.DOMApplicationRegistry = {
let now = Date.now();
if (now - lastProgressTime > MIN_PROGRESS_EVENT_DELAY) {
debug("onProgress: " + aProgress + "/" + aProgressMax);
sendProgressEvent();
sendProgressEvent(aProgress);
lastProgressTime = now;
self._saveApps();
}
@ -2646,16 +2712,17 @@ this.DOMApplicationRegistry = {
OS.Path.join(dirPath, "update.webapp"));
}
self.broadcastMessage("Webapps:PackageEvent", {
type: "downloaded",
manifestURL: aApp.manifestURL,
app: app });
self.broadcastMessage("Webapps:PackageEvent", {
type: "applied",
manifestURL: aApp.manifestURL,
app: app });
// Save the updated registry, and cleanup the tmp directory.
self._saveApps();
self._saveApps(function() {
self.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: aApp.manifestURL
});
self.broadcastMessage("Webapps:FireEvent", {
manifestURL: aApp.manifestURL,
eventType: ["downloadsuccess", "downloadapplied"]
});
});
let file = FileUtils.getFile("TmpD", ["webapps", id], false);
if (file && file.exists()) {
file.remove(true);
@ -2907,7 +2974,7 @@ this.DOMApplicationRegistry = {
requestChannel.asyncOpen(listener, null);
// send a first progress event to correctly set the DOM object's properties
sendProgressEvent();
sendProgressEvent(0);
};
let checkDownloadSize = function (freeBytes) {
@ -3305,7 +3372,7 @@ let AppcacheObserver = function(aApp) {
this.app = aApp;
this.startStatus = aApp.installState;
this.lastProgressTime = 0;
// send a first progress event to correctly set the DOM object's properties
// Send a first progress event to correctly set the DOM object's properties.
this._sendProgressEvent();
};
@ -3313,10 +3380,14 @@ AppcacheObserver.prototype = {
// nsIOfflineCacheUpdateObserver implementation
_sendProgressEvent: function() {
let app = this.app;
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
{ manifest: app.manifestURL,
installState: app.installState,
progress: app.progress });
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: "progress",
manifestURL: app.manifestURL
});
},
updateStateChanged: function appObs_Update(aUpdate, aState) {
@ -3328,31 +3399,41 @@ AppcacheObserver.prototype = {
var self = this;
let setStatus = function appObs_setStatus(aStatus, aProgress) {
debug("Offlinecache setStatus to " + aStatus + " with progress " +
aProgress + " for " + app.origin);
aProgress + " for " + app.origin);
mustSave = (app.installState != aStatus);
app.installState = aStatus;
app.progress = aProgress;
if (aStatus == "installed") {
app.updateTime = Date.now();
app.downloading = false;
app.downloadAvailable = false;
if (aStatus != "installed") {
self._sendProgressEvent();
return;
}
self._sendProgressEvent();
app.updateTime = Date.now();
app.downloading = false;
app.downloadAvailable = false;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
eventType: ["downloadsuccess", "downloadapplied"],
manifestURL: app.manifestURL
});
}
let setError = function appObs_setError(aError) {
debug("Offlinecache setError to " + aError);
// If we are canceling the download, we already send a DOWNLOAD_CANCELED
// error.
if (!app.isCanceling) {
DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
{ manifest: app.manifestURL,
error: aError });
} else {
delete app.isCanceling;
}
app.downloading = false;
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
manifestURL: app.manifestURL
});
DOMApplicationRegistry.broadcastMessage("Webapps:FireEvent", {
error: aError,
eventType: "downloaderror",
manifestURL: app.manifestURL
});
mustSave = true;
}
@ -3369,9 +3450,9 @@ AppcacheObserver.prototype = {
setStatus("installed", aUpdate.byteProgress);
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
setStatus(this.startStatus, aUpdate.byteProgress);
break;
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
let now = Date.now();
if (now - this.lastProgressTime > MIN_PROGRESS_EVENT_DELAY) {

Просмотреть файл

@ -159,7 +159,7 @@ var steps = [
},
function() {
ok(true, "== TEST == Update packaged app - same package");
updateApp(false, 3, 4);
updateApp(false, 3, 3);
},
function() {
ok(true, "== TEST == Check for Update after getting the same package");

Просмотреть файл

@ -123,7 +123,7 @@ PostMessageReadStructuredClone(JSContext* cx,
JS::Rooted<JS::Value> val(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
val.address(),
&val,
getter_AddRefs(wrapper)))) {
return JSVAL_TO_OBJECT(val);
}

Просмотреть файл

@ -1589,7 +1589,7 @@ Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
if (JSVAL_IS_PRIMITIVE(prop_val) && !JSVAL_IS_NULL(prop_val)) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = nsContentUtils::WrapNative(aCx, aObject, native, prop_val.address(),
rv = nsContentUtils::WrapNative(aCx, aObject, native, &prop_val,
getter_AddRefs(holder), true);
if (NS_FAILED(rv)) {

Просмотреть файл

@ -643,13 +643,13 @@ IdToString(JSContext *cx, jsid id)
static inline nsresult
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
nsWrapperCache *cache, const nsIID* aIID, jsval *vp,
nsWrapperCache *cache, const nsIID* aIID, JS::MutableHandle<JS::Value> vp,
nsIXPConnectJSObjectHolder** aHolder, bool aAllowWrapping)
{
if (!native) {
NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
*vp = JSVAL_NULL;
vp.setNull();
return NS_OK;
}
@ -661,13 +661,13 @@ WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
return nsDOMClassInfo::XPConnect()->WrapNativeToJSVal(cx, scope, native,
cache, aIID,
aAllowWrapping, vp,
aAllowWrapping, vp.address(),
aHolder);
}
static inline nsresult
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
const nsIID* aIID, bool aAllowWrapping, jsval *vp,
const nsIID* aIID, bool aAllowWrapping, JS::MutableHandle<JS::Value> vp,
// If non-null aHolder will keep the jsval alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nullptr)
@ -679,7 +679,7 @@ WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
// Same as the WrapNative above, but use these if aIID is nsISupports' IID.
static inline nsresult
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
bool aAllowWrapping, jsval *vp,
bool aAllowWrapping, JS::MutableHandle<JS::Value> vp,
// If non-null aHolder will keep the jsval alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nullptr)
@ -690,7 +690,8 @@ WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
static inline nsresult
WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
nsWrapperCache *cache, bool aAllowWrapping, jsval *vp,
nsWrapperCache *cache, bool aAllowWrapping,
JS::MutableHandle<JS::Value> vp,
// If non-null aHolder will keep the jsval alive
// while there's a ref to it
nsIXPConnectJSObjectHolder** aHolder = nullptr)
@ -2221,26 +2222,25 @@ BaseStubConstructor(nsIWeakReference* aWeakOwner,
// wrap parameters in the target compartment
// we also pass in the calling window as the first argument
unsigned argc = args.length() + 1;
nsAutoArrayPtr<JS::Value> argv(new JS::Value[argc]);
JS::AutoArrayRooter rooter(cx, 0, argv);
JS::AutoValueVector argv(cx);
argv.resize(argc);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner));
rv = WrapNative(cx, obj, currentWin, &NS_GET_IID(nsIDOMWindow),
true, &argv[0], getter_AddRefs(holder));
true, argv.handleAt(0), getter_AddRefs(holder));
if (!JS_WrapValue(cx, &argv[0]))
return NS_ERROR_FAILURE;
rooter.changeLength(1);
for (size_t i = 1; i < argc; ++i) {
argv[i] = args[i - 1];
if (!JS_WrapValue(cx, &argv[i]))
return NS_ERROR_FAILURE;
rooter.changeLength(i + 1);
}
JS::Rooted<JS::Value> frval(cx);
bool ret = JS_CallFunctionValue(cx, thisObject, funval, argc, argv,
bool ret = JS_CallFunctionValue(cx, thisObject, funval,
argc, argv.begin(),
frval.address());
if (!ret) {
@ -2250,7 +2250,7 @@ BaseStubConstructor(nsIWeakReference* aWeakOwner,
}
}
return WrapNative(cx, obj, native, true, args.rval().address());
return WrapNative(cx, obj, native, true, args.rval());
}
static nsresult
@ -2818,7 +2818,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
JS::Rooted<JS::Value> v(cx);
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
false, v.address(), getter_AddRefs(holder));
false, &v, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
if (install) {
@ -3100,7 +3100,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
JS::Rooted<JS::Value> v(cx);
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
false, v.address(), getter_AddRefs(holder));
false, &v, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
rv = constructor->Install(cx, obj, v);
@ -3202,7 +3202,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JS::Rooted<JS::Value> val(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
false, val.address(), getter_AddRefs(holder));
false, &val, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
rv = constructor->Install(cx, obj, val);
@ -3251,7 +3251,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
scope = aWin->GetGlobalJSObject();
}
rv = WrapNative(cx, scope, native, true, prop_val.address(),
rv = WrapNative(cx, scope, native, true, &prop_val,
getter_AddRefs(holder));
}
@ -3303,7 +3303,7 @@ ContentWindowGetter(JSContext *cx, unsigned argc, jsval *vp)
template<class Interface>
static nsresult
LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
LocationSetterGuts(JSContext *cx, JSObject *obj, JS::MutableHandle<JS::Value> vp)
{
// This function duplicates some of the logic in XPC_WN_HelperSetProperty
obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
@ -3322,7 +3322,7 @@ LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
NS_ENSURE_SUCCESS(rv, rv);
// Grab the value we're being set to before we stomp on |vp|
JS::Rooted<JSString*> val(cx, ::JS_ValueToString(cx, *vp));
JS::Rooted<JSString*> val(cx, ::JS_ValueToString(cx, vp));
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
// Make sure |val| stays alive below
@ -3352,7 +3352,7 @@ static bool
LocationSetter(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, bool strict,
JS::MutableHandle<JS::Value> vp)
{
nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp.address());
nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp);
if (NS_FAILED(rv)) {
xpc::Throw(cx, rv);
return false;
@ -3365,7 +3365,7 @@ static bool
LocationSetterUnwrapper(JSContext *cx, JS::Handle<JSObject*> obj_, JS::Handle<jsid> id,
bool strict, JS::MutableHandle<JS::Value> vp)
{
JS::RootedObject obj(cx, obj_);
JS::Rooted<JSObject*> obj(cx, obj_);
JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj);
if (wrapped) {
@ -3410,7 +3410,7 @@ const InterfaceShimEntry kInterfaceShimMap[] =
{ "nsIDOMXPathResult", "XPathResult" } };
static nsresult
DefineComponentsShim(JSContext *cx, JS::HandleObject global, nsPIDOMWindow *win)
DefineComponentsShim(JSContext *cx, JS::Handle<JSObject*> global, nsPIDOMWindow *win)
{
// Keep track of how often this happens.
Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
@ -3468,7 +3468,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj_, jsid id_, uint32_t flags,
JSObject **objp, bool *_retval)
{
JS::RootedObject obj(cx, obj_);
JS::Rooted<JSObject*> obj(cx, obj_);
JS::RootedId id(cx, id_);
if (!JSID_IS_STRING(id)) {
@ -3565,7 +3565,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
JS::Rooted<JS::Value> v(cx);
rv = WrapNative(cx, scope, location, &NS_GET_IID(nsIDOMLocation), true,
v.address(), getter_AddRefs(holder));
&v, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
bool ok = JS_WrapValue(cx, v.address()) &&
@ -3590,7 +3590,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JS::Rooted<JS::Value> v(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, top, &NS_GET_IID(nsIDOMWindow), true,
v.address(), getter_AddRefs(holder));
&v, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
// Hold on to the top window object as a global property so we
@ -3606,7 +3606,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
// Handle resolving if id refers to a name resolved by DOM worker code.
JS::RootedObject tmp(cx, NULL);
JS::Rooted<JSObject*> tmp(cx, NULL);
if (!ResolveWorkerClasses(cx, obj, id, flags, &tmp)) {
return NS_ERROR_FAILURE;
}
@ -3679,7 +3679,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JS::Rooted<JS::Value> v(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), document, document,
&NS_GET_IID(nsIDOMDocument), v.address(), getter_AddRefs(holder),
&NS_GET_IID(nsIDOMDocument), &v, getter_AddRefs(holder),
false);
NS_ENSURE_SUCCESS(rv, rv);
@ -3986,9 +3986,11 @@ nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
if (array_item) {
JS::Rooted<JS::Value> rval(cx);
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), array_item, cache,
true, vp);
true, &rval);
NS_ENSURE_SUCCESS(rv, rv);
*vp = rval;
rv = NS_SUCCESS_I_DID_SOMETHING;
}
@ -4085,7 +4087,7 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx,
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult tmp = WrapNative(cx, JS::CurrentGlobalOrNull(cx),
static_cast<nsINodeList*>(list), list, false,
collection.address(), getter_AddRefs(holder));
&collection, getter_AddRefs(holder));
if (NS_FAILED(tmp)) {
rv = tmp;
}
@ -4189,7 +4191,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JS::Handle<JSObject*> ob
}
if (result) {
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), result, cache, true, vp.address());
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), result, cache, true, vp);
if (NS_FAILED(rv)) {
xpc::Throw(cx, rv);
@ -4207,7 +4209,7 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle<JSObject*> obj
JS::Handle<jsid> id, unsigned flags,
JS::MutableHandle<JSObject*> objp)
{
JS::RootedValue v(cx);
JS::Rooted<JS::Value> v(cx);
if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
// Define the item() or namedItem() method.
@ -4326,8 +4328,10 @@ nsStringArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_SUCCESS_I_DID_SOMETHING;
}
NS_ENSURE_TRUE(xpc::NonVoidStringToJsval(cx, val, vp),
JS::Rooted<JS::Value> rval(cx);
NS_ENSURE_TRUE(xpc::NonVoidStringToJsval(cx, val, &rval),
NS_ERROR_OUT_OF_MEMORY);
*vp = rval;
return NS_SUCCESS_I_DID_SOMETHING;
}

Просмотреть файл

@ -2385,8 +2385,9 @@ nsDOMWindowUtils::GetIsTestControllingRefreshes(bool *aResult)
return NS_ERROR_DOM_SECURITY_ERR;
}
nsPresContext* pc = GetPresContext();
*aResult =
GetPresContext()->RefreshDriver()->IsTestControllingRefreshesEnabled();
pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false;
return NS_OK;
}

Просмотреть файл

@ -3632,8 +3632,11 @@ nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::Value* aVal)
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
if (content && global) {
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
return nsContentUtils::WrapNative(aCx, global, content, aVal,
getter_AddRefs(wrapper));
JS::Rooted<JS::Value> rval(aCx);
nsresult rv = nsContentUtils::WrapNative(aCx, global, content, &rval,
getter_AddRefs(wrapper));
*aVal = rval;
return rv;
}
return NS_ERROR_FAILURE;
}
@ -6806,9 +6809,9 @@ PostMessageReadStructuredClone(JSContext* cx,
JS::Rooted<JS::Value> val(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
val.address(),
&val,
getter_AddRefs(wrapper)))) {
return JSVAL_TO_OBJECT(val);
return val.toObjectOrNull();
}
}
}

Просмотреть файл

@ -1035,23 +1035,21 @@ nsJSContext::JSObjectFromInterface(nsISupports* aTarget,
// We don't wrap here because we trust the JS engine to wrap the target
// later.
JS::Rooted<JS::Value> v(cx);
nsresult rv = nsContentUtils::WrapNative(cx, aScope, aTarget,
v.address());
nsresult rv = nsContentUtils::WrapNative(cx, aScope, aTarget, &v);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef DEBUG
nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
nsCOMPtr<nsISupports> native =
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
JSVAL_TO_OBJECT(v));
NS_ASSERTION(native == targetSupp, "Native should be the target!");
#endif
JSObject* obj = v.toObjectOrNull();
if (obj) {
JS::ExposeObjectToActiveJS(obj);
}
#ifdef DEBUG
nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
nsCOMPtr<nsISupports> native =
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, obj);
NS_ASSERTION(native == targetSupp, "Native should be the target!");
#endif
*aRet = obj;
return NS_OK;
}
@ -1298,7 +1296,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
#endif
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
JS::Rooted<JS::Value> v(cx);
rv = nsContentUtils::WrapNative(cx, aScope, arg, v.address(),
rv = nsContentUtils::WrapNative(cx, aScope, arg, &v,
getter_AddRefs(wrapper));
if (NS_SUCCEEDED(rv)) {
*thisval = v;
@ -1500,7 +1498,7 @@ nsJSContext::AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv)
JS::Rooted<JSObject*> global(cx, GetWindowProxy());
JS::Rooted<JS::Value> v(cx);
nsresult rv = nsContentUtils::WrapNative(cx, global,
data, iid, v.address(),
data, iid, &v,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -320,13 +320,13 @@ enum {
TOSTRING_NAME_RESERVED_SLOT = 1
};
bool
static bool
InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
{
JS::Rooted<JSObject*> callee(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::Rooted<JSObject*> callee(cx, &args.callee());
JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
if (!obj) {
if (!args.computeThis(cx).isObject()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
"null", "object");
return false;
@ -334,14 +334,14 @@ InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
JS::Value v = js::GetFunctionNativeReserved(callee,
TOSTRING_CLASS_RESERVED_SLOT);
const JSClass* clasp = static_cast<const JSClass*>(JSVAL_TO_PRIVATE(v));
const JSClass* clasp = static_cast<const JSClass*>(v.toPrivate());
v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT);
JSString* jsname = static_cast<JSString*>(JSVAL_TO_STRING(v));
size_t length;
const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length);
if (js::GetObjectJSClass(obj) != clasp) {
if (js::GetObjectJSClass(&args.computeThis(cx).toObject()) != clasp) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
NS_ConvertUTF16toUTF8(name).get(), "toString",
"object");
@ -357,7 +357,7 @@ InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
str.Append('\n');
str.AppendLiteral("}");
return xpc::NonVoidStringToJsval(cx, str, vp);
return xpc::NonVoidStringToJsval(cx, str, args.rval());
}
bool
@ -673,7 +673,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
bool
NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
JS::Handle<JSObject*> aScope,
JS::Value* aRetval,
JS::MutableHandle<JS::Value> aRetval,
xpcObjectHelper& aHelper,
const nsIID* aIID,
bool aAllowNativeWrapper)
@ -684,7 +684,7 @@ NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
nsWrapperCache *cache = aHelper.GetWrapperCache();
if (cache && cache->IsDOMBinding()) {
JS::RootedObject obj(aCx, cache->GetWrapper());
JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper());
if (!obj) {
obj = cache->WrapObject(aCx, aScope);
}
@ -694,7 +694,7 @@ NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
}
if (obj) {
*aRetval = JS::ObjectValue(*obj);
aRetval.setObject(*obj);
return true;
}
}
@ -751,7 +751,7 @@ InstanceClassHasProtoAtDepth(JS::Handle<JSObject*> protoObject, uint32_t protoID
bool
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
xpcObjectHelper& helper, const nsIID* iid,
bool allowNativeWrapper, JS::Value* rval)
bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval)
{
if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid,
allowNativeWrapper)) {
@ -759,7 +759,7 @@ XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
}
#ifdef DEBUG
JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
JSObject* jsobj = rval.toObjectOrNull();
if (jsobj && !js::GetObjectParent(jsobj))
NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
"Why did we recreate this wrapper?");
@ -770,7 +770,7 @@ XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
bool
VariantToJsval(JSContext* aCx, JS::Handle<JSObject*> aScope,
nsIVariant* aVariant, JS::Value* aRetval)
nsIVariant* aVariant, JS::MutableHandle<JS::Value> aRetval)
{
nsresult rv;
if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) {
@ -810,15 +810,14 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
}
JS::Value* argv = JS_ARGV(cx, vp);
if (!argv[0].isObject()) {
if (!args[0].isObject()) {
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
}
nsIJSID* iid;
SelfRef iidRef;
if (NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx, argv[0], &iid, &iidRef.ptr,
&argv[0]))) {
if (NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx, args[0], &iid, &iidRef.ptr,
args[0]))) {
return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
}
MOZ_ASSERT(iid);
@ -1475,7 +1474,7 @@ AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
{
for (uint32_t i = 0; i < names.Length(); ++i) {
JS::Rooted<JS::Value> v(cx);
if (!xpc::NonVoidStringToJsval(cx, names[i], v.address())) {
if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) {
return false;
}
@ -1649,10 +1648,10 @@ private:
};
nsresult
ReparentWrapper(JSContext* aCx, JS::HandleObject aObjArg)
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
{
// aObj is assigned to below, so needs to be re-rooted.
JS::RootedObject aObj(aCx, aObjArg);
JS::Rooted<JSObject*> aObj(aCx, aObjArg);
const DOMClass* domClass = GetDOMClass(aObj);
JS::Rooted<JSObject*> oldParent(aCx, JS_GetParent(aObj));
@ -1756,20 +1755,9 @@ ReparentWrapper(JSContext* aCx, JS::HandleObject aObjArg)
if (ww != aObj) {
MOZ_ASSERT(cache->HasSystemOnlyWrapper());
JS::RootedObject newwrapper(aCx,
xpc::WrapperFactory::WrapSOWObject(aCx, newobj));
if (!newwrapper) {
MOZ_CRASH();
}
// Oops. We don't support transplanting objects with SOWs anymore.
MOZ_CRASH();
// Ok, now we do the special object-plus-wrapper transplant.
ww = xpc::TransplantObjectWithWrapper(aCx, aObj, ww, newobj, newwrapper);
if (!ww) {
MOZ_CRASH();
}
aObj = newobj;
SetSystemOnlyWrapperSlot(aObj, JS::ObjectValue(*ww));
} else {
aObj = xpc::TransplantObject(aCx, aObj, newobj);
if (!aObj) {
@ -1863,7 +1851,7 @@ GlobalObject::GetAsSupports() const
// using new bindings.
nsresult rv = xpc_qsUnwrapArg<nsISupports>(mCx, val, &mGlobalObject,
static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)),
val.address());
&val);
if (NS_FAILED(rv)) {
mGlobalObject = nullptr;
Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS);

Просмотреть файл

@ -35,8 +35,8 @@
class nsPIDOMWindow;
extern nsresult
xpc_qsUnwrapArgImpl(JSContext* cx, jsval v, const nsIID& iid, void** ppArg,
nsISupports** ppArgRef, jsval* vp);
xpc_qsUnwrapArgImpl(JSContext* cx, JS::Handle<JS::Value> v, const nsIID& iid, void** ppArg,
nsISupports** ppArgRef, JS::MutableHandle<JS::Value> vp);
namespace mozilla {
namespace dom {
@ -53,8 +53,8 @@ struct SelfRef
/** Convert a jsval to an XPCOM pointer. */
template <class Interface, class StrongRefType>
inline nsresult
UnwrapArg(JSContext* cx, jsval v, Interface** ppArg,
StrongRefType** ppArgRef, jsval* vp)
UnwrapArg(JSContext* cx, JS::Handle<JS::Value> v, Interface** ppArg,
StrongRefType** ppArgRef, JS::MutableHandle<JS::Value> vp)
{
nsISupports* argRef = *ppArgRef;
nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
@ -792,7 +792,7 @@ WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
bool
NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
JS::Handle<JSObject*> aScope,
JS::Value* aRetval,
JS::MutableHandle<JS::Value> aRetval,
xpcObjectHelper& aHelper,
const nsIID* aIID,
bool aAllowNativeWrapper);
@ -811,7 +811,7 @@ HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
}
qsObjectHelper helper(value, GetWrapperCache(value));
return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval.address(),
return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
helper, nullptr, true);
}
@ -977,12 +977,12 @@ InstanceClassHasProtoAtDepth(JS::Handle<JSObject*> protoObject, uint32_t protoID
bool
XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
xpcObjectHelper& helper, const nsIID* iid,
bool allowNativeWrapper, JS::Value* rval);
bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
// Special-cased wrapping for variants
bool
VariantToJsval(JSContext* aCx, JS::Handle<JSObject*> aScope,
nsIVariant* aVariant, JS::Value* aRetval);
nsIVariant* aVariant, JS::MutableHandle<JS::Value> aRetval);
// Wrap an object "p" which is not using WebIDL bindings yet. This _will_
// actually work on WebIDL binding objects that are wrappercached, but will be
@ -994,10 +994,10 @@ WrapObject(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
nsWrapperCache* cache, const nsIID* iid,
JS::MutableHandle<JS::Value> rval)
{
if (xpc_FastGetCachedWrapper(cache, scope, rval.address()))
if (xpc_FastGetCachedWrapper(cache, scope, rval))
return true;
qsObjectHelper helper(p, cache);
return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval.address());
return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
}
// A specialization of the above for nsIVariant, because that needs to
@ -1010,7 +1010,7 @@ WrapObject<nsIVariant>(JSContext* cx, JS::Handle<JSObject*> scope, nsIVariant* p
{
MOZ_ASSERT(iid);
MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
return VariantToJsval(cx, scope, p, rval.address());
return VariantToJsval(cx, scope, p, rval);
}
// Wrap an object "p" which is not using WebIDL bindings yet. Just like the
@ -1100,8 +1100,8 @@ WrapNativeISupportsParent(JSContext* cx, JS::Handle<JSObject*> scope, T* p,
{
qsObjectHelper helper(ToSupports(p), cache);
JS::Rooted<JS::Value> v(cx);
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, v.address()) ?
JSVAL_TO_OBJECT(v) :
return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
v.toObjectOrNull() :
nullptr;
}
@ -2005,7 +2005,7 @@ const T& NonNullHelper(const OwningNonNull<T>& aArg)
// Reparent the wrapper of aObj to whatever its native now thinks its
// parent should be.
nsresult
ReparentWrapper(JSContext* aCx, JS::HandleObject aObj);
ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
/**
* Used to implement the hasInstance hook of an interface object.

Просмотреть файл

@ -1516,7 +1516,7 @@ class MethodDefiner(PropertyDefiner):
if any(m.isGetter() and m.isIndexed() for m in methods):
self.regular.append({"name": "@@iterator",
"methodInfo": False,
"selfHostedName": "ArrayIterator",
"selfHostedName": "ArrayValues",
"length": 0,
"flags": "JSPROP_ENUMERATE",
"condition": MemberCondition(None, None) })
@ -2409,7 +2409,7 @@ class CastableObjectUnwrapper():
"${type} *objPtr;\n"
"SelfRef objRef;\n"
"JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*${source}));\n"
"nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, val.address());\n"
"nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
"if (NS_FAILED(rv)) {\n"
"${codeOnFailure}\n"
"}\n"
@ -3230,7 +3230,7 @@ for (uint32_t i = 0; i < length; ++i) {
templateBody += (
"JS::Rooted<JS::Value> tmpVal(cx, ${val});\n" +
typePtr + " tmp;\n"
"if (NS_FAILED(UnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), tmpVal.address()))) {\n")
"if (NS_FAILED(UnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
templateBody += CGIndenter(onFailureBadType(failureCode,
descriptor.interface.identifier.name)).define()
templateBody += ("}\n"
@ -4121,9 +4121,9 @@ if (!returnArray) {
if type.isDOMString():
if type.nullable():
return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalRef}.address())" % result), False)
return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False)
else:
return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalRef}.address())" % result), False)
return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False)
if type.isByteString():
if type.nullable():

Просмотреть файл

@ -67,9 +67,9 @@ public:
MOZ_ASSERT(aReq && aAdapterPtr);
}
virtual bool ParseSuccessfulReply(JS::Value* aValue)
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
{
*aValue = JSVAL_VOID;
aValue.setUndefined();
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
@ -113,7 +113,7 @@ public:
return false;
}
aValue->setObject(*JsDevices);
aValue.setObject(*JsDevices);
return true;
}
@ -136,9 +136,9 @@ public:
MOZ_ASSERT(aReq);
}
virtual bool ParseSuccessfulReply(JS::Value* aValue)
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
{
*aValue = JSVAL_VOID;
aValue.setUndefined();
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::Tbool) {
@ -147,7 +147,7 @@ public:
return false;
}
aValue->setBoolean(v.get_bool());
aValue.setBoolean(v.get_bool());
return true;
}

Просмотреть файл

@ -42,9 +42,9 @@ public:
}
bool
ParseSuccessfulReply(JS::Value* aValue)
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
{
*aValue = JSVAL_VOID;
aValue.setUndefined();
const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {

Просмотреть файл

@ -32,7 +32,7 @@ BluetoothReplyRunnable::~BluetoothReplyRunnable()
{}
nsresult
BluetoothReplyRunnable::FireReply(const JS::Value& aVal)
BluetoothReplyRunnable::FireReply(JS::Handle<JS::Value> aVal)
{
nsCOMPtr<nsIDOMRequestService> rs =
do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
@ -62,10 +62,12 @@ BluetoothReplyRunnable::Run()
nsresult rv;
AutoSafeJSContext cx;
JS::Rooted<JS::Value> v(cx, JSVAL_VOID);
if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
rv = FireReply(JSVAL_VOID);
rv = FireReply(v);
} else {
JS::Value v;
if (!ParseSuccessfulReply(&v)) {
rv = FireErrorString();
} else {

Просмотреть файл

@ -37,7 +37,7 @@ public:
protected:
virtual ~BluetoothReplyRunnable();
virtual bool ParseSuccessfulReply(JS::Value* aValue) = 0;
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) = 0;
// This is an autoptr so we don't have to bring the ipdl include into the
// header. We assume we'll only be running this once and it should die on
@ -45,7 +45,7 @@ protected:
nsAutoPtr<BluetoothReply> mReply;
private:
nsresult FireReply(const JS::Value& aVal);
nsresult FireReply(JS::Handle<JS::Value> aVal);
nsresult FireErrorString();
nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
@ -59,9 +59,9 @@ public:
~BluetoothVoidReplyRunnable();
protected:
virtual bool ParseSuccessfulReply(JS::Value* aValue) MOZ_OVERRIDE
virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) MOZ_OVERRIDE
{
*aValue = JSVAL_VOID;
aValue.setUndefined();
return true;
}
};

Просмотреть файл

@ -65,7 +65,7 @@ public:
}
virtual bool
ParseSuccessfulReply(JS::Value* aValue) MOZ_OVERRIDE
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) MOZ_OVERRIDE
{
MOZ_CRASH("This should never be called!");
}

Просмотреть файл

@ -78,6 +78,13 @@ const ContentPanning = {
return;
}
let start = Date.now();
let thread = Services.tm.currentThread;
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
thread.processNextEvent(true);
}
this._delayEvents = false;
switch (evt.type) {
case 'mousedown':
case 'touchstart':
@ -229,6 +236,16 @@ const ContentPanning = {
// We prevent end events to avoid sending a focus event. See bug 889717.
evt.preventDefault();
}
} else if (this.target && click && !this.panning) {
this.notify(this._activationTimer);
this._delayEvents = true;
let start = Date.now();
let thread = Services.tm.currentThread;
while (this._delayEvents && (Date.now() - start) < this._activeDurationMs) {
thread.processNextEvent(true);
}
this._delayEvents = false;
}
this._finishPanning();
@ -467,6 +484,12 @@ const ContentPanning = {
return this._activationDelayMs = delay;
},
get _activeDurationMs() {
let duration = Services.prefs.getIntPref('ui.touch_activation.duration_ms');
delete this._activeDurationMs;
return this._activeDurationMs = duration;
},
_resetActive: function cp_resetActive() {
let elt = this.target || this.pointerDownTarget;
let root = elt.ownerDocument || elt.document;

Просмотреть файл

@ -1368,17 +1368,14 @@ InterfaceToJsval(nsPIDOMWindow* aWindow,
return JSVAL_NULL;
}
JS::RootedObject scopeObj(cx, sgo->GetGlobalJSObject());
JS::Rooted<JSObject*> scopeObj(cx, sgo->GetGlobalJSObject());
NS_ENSURE_TRUE(scopeObj, JSVAL_NULL);
JSAutoCompartment ac(cx, scopeObj);
JS::Rooted<JS::Value> someJsVal(cx);
nsresult rv = nsContentUtils::WrapNative(cx,
scopeObj,
aObject,
aIID,
someJsVal.address());
nsresult rv =
nsContentUtils::WrapNative(cx, scopeObj, aObject, aIID, &someJsVal);
if (NS_FAILED(rv)) {
return JSVAL_NULL;
}
@ -1437,7 +1434,7 @@ JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString)
return JSVAL_NULL;
}
JS::Value result = JSVAL_NULL;
JS::Rooted<JS::Value> result(cx);
if (!xpc::StringToJsval(cx, aString, &result)) {
return JSVAL_NULL;
}

Просмотреть файл

@ -147,11 +147,11 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
break;
case GetFile:
rv = GetFileResult(cx, result.address(), aFileList);
rv = GetFileResult(cx, &result, aFileList);
break;
case GetFiles:
rv = GetFilesResult(cx, result.address(), aFileList);
rv = GetFilesResult(cx, &result, aFileList);
break;
}
@ -208,7 +208,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
nsresult
ArchiveRequest::GetFileResult(JSContext* aCx,
JS::Value* aValue,
JS::MutableHandle<JS::Value> aValue,
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
{
for (uint32_t i = 0; i < aFileList.Length(); ++i) {
@ -230,7 +230,7 @@ ArchiveRequest::GetFileResult(JSContext* aCx,
nsresult
ArchiveRequest::GetFilesResult(JSContext* aCx,
JS::Value* aValue,
JS::MutableHandle<JS::Value> aValue,
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
{
JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, aFileList.Length(), nullptr));
@ -245,13 +245,13 @@ ArchiveRequest::GetFilesResult(JSContext* aCx,
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
nsresult rv = nsContentUtils::WrapNative(aCx, global, file,
&NS_GET_IID(nsIDOMFile),
value.address());
&value);
if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, &value)) {
return NS_ERROR_FAILURE;
}
}
aValue->setObject(*array);
aValue.setObject(*array);
return NS_OK;
}

Просмотреть файл

@ -66,10 +66,10 @@ private:
JS::Value* aValue,
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
nsresult GetFileResult(JSContext* aCx,
JS::Value* aValue,
JS::MutableHandle<JS::Value> aValue,
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
nsresult GetFilesResult(JSContext* aCx,
JS::Value* aValue,
JS::MutableHandle<JS::Value> aValue,
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
protected:

Просмотреть файл

@ -185,10 +185,12 @@ GetFileHelper::GetSuccessResult(JSContext* aCx, JS::Value* aVal)
mFileHandle->CreateFileObject(mLockedFile, mParams->Size());
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
JS::Rooted<JS::Value> rval(aCx);
nsresult rv =
nsContentUtils::WrapNative(aCx, global, domFile,
&NS_GET_IID(nsIDOMFile), aVal);
&NS_GET_IID(nsIDOMFile), &rval);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
*aVal = rval;
return NS_OK;
}

Просмотреть файл

@ -1066,11 +1066,13 @@ ReadTextHelper::GetSuccessResult(JSContext* aCx,
tmpString);
NS_ENSURE_SUCCESS(rv, rv);
if (!xpc::StringToJsval(aCx, tmpString, aVal)) {
JS::Rooted<JS::Value> rval(aCx);
if (!xpc::StringToJsval(aCx, tmpString, &rval)) {
NS_WARNING("Failed to convert string!");
return NS_ERROR_FAILURE;
}
*aVal = rval;
return NS_OK;
}

Просмотреть файл

@ -125,7 +125,7 @@ HelperBase::WrapNative(JSContext* aCx,
NS_ASSERTION(global, "This should never be null!");
nsresult rv =
nsContentUtils::WrapNative(aCx, global, aNative, aResult.address());
nsContentUtils::WrapNative(aCx, global, aNative, aResult);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return NS_OK;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше