mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Merge m-i to a CLOSED TREE m-c
This commit is contained in:
commit
61ea412a96
@ -159,11 +159,10 @@ SocialUI = {
|
||||
}
|
||||
break;
|
||||
case "social:profile-changed":
|
||||
// make sure anything that happens here only affects the provider for
|
||||
// which the profile is changing, and that anything we call actually
|
||||
// needs to change based on profile data.
|
||||
if (this._matchesCurrentProvider(data)) {
|
||||
SocialToolbar.updateProvider();
|
||||
SocialMarks.update();
|
||||
SocialChatBar.update();
|
||||
}
|
||||
break;
|
||||
case "social:frameworker-error":
|
||||
@ -216,20 +215,13 @@ SocialUI = {
|
||||
// enabled == true means we at least have a defaultProvider
|
||||
let provider = Social.provider || Social.defaultProvider;
|
||||
// We only need to update the command itself - all our menu items use it.
|
||||
let label;
|
||||
if (Social.providers.length == 1) {
|
||||
label = gNavigatorBundle.getFormattedString(Social.provider
|
||||
? "social.turnOff.label"
|
||||
: "social.turnOn.label",
|
||||
[provider.name]);
|
||||
} else {
|
||||
label = gNavigatorBundle.getString(Social.provider
|
||||
? "social.turnOffAll.label"
|
||||
: "social.turnOnAll.label");
|
||||
}
|
||||
let accesskey = gNavigatorBundle.getString(Social.provider
|
||||
? "social.turnOff.accesskey"
|
||||
: "social.turnOn.accesskey");
|
||||
let label = gNavigatorBundle.getFormattedString(Social.provider ?
|
||||
"social.turnOff.label" :
|
||||
"social.turnOn.label",
|
||||
[provider.name]);
|
||||
let accesskey = gNavigatorBundle.getString(Social.provider ?
|
||||
"social.turnOff.accesskey" :
|
||||
"social.turnOn.accesskey");
|
||||
toggleCommand.setAttribute("label", label);
|
||||
toggleCommand.setAttribute("accesskey", accesskey);
|
||||
}
|
||||
@ -876,19 +868,17 @@ SocialToolbar = {
|
||||
toggleNotificationsCommand.setAttribute("hidden", !socialEnabled);
|
||||
|
||||
let parent = document.getElementById("social-notification-panel");
|
||||
while (parent.hasChildNodes()) {
|
||||
let frame = parent.firstChild;
|
||||
SharedFrame.forgetGroup(frame.id);
|
||||
parent.removeChild(frame);
|
||||
}
|
||||
|
||||
let tbi = document.getElementById("social-provider-button");
|
||||
if (tbi) {
|
||||
// buttons after social-provider-button are ambient icons, remove the
|
||||
// button and the attached shared frame.
|
||||
// buttons after social-provider-button are ambient icons
|
||||
while (tbi.nextSibling) {
|
||||
let tb = tbi.nextSibling;
|
||||
let nid = tb.getAttribute("notificationFrameId");
|
||||
let frame = document.getElementById(nid);
|
||||
if (frame) {
|
||||
SharedFrame.forgetGroup(frame.id);
|
||||
parent.removeChild(frame);
|
||||
}
|
||||
tbi.parentNode.removeChild(tb);
|
||||
tbi.parentNode.removeChild(tbi.nextSibling);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1119,25 +1119,18 @@ var gBrowserInit = {
|
||||
// If the user manually opens the download manager before the timeout, the
|
||||
// downloads will start right away, and getting the service again won't hurt.
|
||||
setTimeout(function() {
|
||||
try {
|
||||
let DownloadsCommon =
|
||||
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
|
||||
if (DownloadsCommon.useJSTransfer) {
|
||||
// Open the data link without initalizing nsIDownloadManager.
|
||||
DownloadsCommon.initializeAllDataLinks();
|
||||
let DownloadsTaskbar =
|
||||
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {}).DownloadsTaskbar;
|
||||
DownloadsTaskbar.registerIndicator(window);
|
||||
} else {
|
||||
// Initalizing nsIDownloadManager will trigger the data link.
|
||||
Services.downloads;
|
||||
let DownloadTaskbarProgress =
|
||||
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
|
||||
DownloadTaskbarProgress.onBrowserWindowLoad(window);
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
let DownloadsCommon =
|
||||
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
|
||||
if (DownloadsCommon.useJSTransfer) {
|
||||
// Open the data link without initalizing nsIDownloadManager.
|
||||
DownloadsCommon.initializeAllDataLinks();
|
||||
} else {
|
||||
// Initalizing nsIDownloadManager will trigger the data link.
|
||||
Services.downloads;
|
||||
}
|
||||
let DownloadTaskbarProgress =
|
||||
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
|
||||
DownloadTaskbarProgress.onBrowserWindowLoad(window);
|
||||
}, 10000);
|
||||
|
||||
// The object handling the downloads indicator is also initialized here in the
|
||||
|
@ -7,7 +7,6 @@ function test() {
|
||||
|
||||
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||
runSocialTestWithProvider(gProviders, function (finishcb) {
|
||||
Social.enabled = true;
|
||||
runSocialTests(tests, undefined, undefined, function() {
|
||||
Services.prefs.clearUserPref("social.allowMultipleWorkers");
|
||||
finishcb();
|
||||
|
@ -2,36 +2,18 @@
|
||||
* 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/. */
|
||||
|
||||
let manifests = [{ // normal provider
|
||||
name: "provider example.com",
|
||||
let manifest = { // normal provider
|
||||
name: "provider 1",
|
||||
origin: "https://example.com",
|
||||
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
|
||||
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
|
||||
}, { // used for testing install
|
||||
name: "provider test1",
|
||||
origin: "https://test1.example.com",
|
||||
statusURL: "https://test1.example.com/browser/browser/base/content/test/social/social_panel.html",
|
||||
iconURL: "https://test1.example.com/browser/browser/base/content/test/moz.png",
|
||||
}];
|
||||
};
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// required to test status button in combination with the toolbaritem
|
||||
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||
|
||||
// Preset the currentSet so the statusbutton is in the toolbar on addition. We
|
||||
// bypass the SocialStatus class here since it requires the manifest already
|
||||
// be installed.
|
||||
let tbh = SocialStatus._toolbarHelper;
|
||||
tbh.setPersistentPosition(tbh.idFromOrgin(manifests[1].origin));
|
||||
|
||||
runSocialTestWithProvider(manifests, function (finishcb) {
|
||||
runSocialTests(tests, undefined, undefined, function() {
|
||||
Services.prefs.clearUserPref("social.allowMultipleWorkers");
|
||||
SocialStatus.removePosition(manifests[1].origin);
|
||||
finishcb();
|
||||
});
|
||||
runSocialTestWithProvider(manifest, function (finishcb) {
|
||||
runSocialTests(tests, undefined, undefined, finishcb);
|
||||
});
|
||||
}
|
||||
|
||||
@ -55,7 +37,7 @@ var tests = {
|
||||
},
|
||||
testProfileSet: function(next) {
|
||||
let statusIcon = document.getElementById("social-provider-button").style.listStyleImage;
|
||||
is(statusIcon, "url(\"" + manifests[0].iconURL + "\")", "manifest iconURL is showing");
|
||||
is(statusIcon, "url(\"" + manifest.iconURL + "\")", "manifest iconURL is showing");
|
||||
let profile = {
|
||||
portrait: "https://example.com/portrait.jpg",
|
||||
userName: "trickster",
|
||||
@ -185,32 +167,14 @@ var tests = {
|
||||
}, "statusIcon was never found");
|
||||
},
|
||||
testProfileUnset: function(next) {
|
||||
let panel = document.getElementById("social-notification-panel");
|
||||
// load the status button for provider 2
|
||||
let provider = Social._getProviderFromOrigin(manifests[1].origin);
|
||||
let id = SocialStatus._toolbarHelper.idFromOrgin(provider.origin);
|
||||
let btn = document.getElementById(id)
|
||||
ok(btn, "got a status button");
|
||||
// cheat a little, we want the iframe for the status button to be created,
|
||||
// not testing the statusbutton itself here.
|
||||
SocialStatus._attachNotificatonPanel(btn, provider);
|
||||
|
||||
let numIcons = Object.keys(Social.provider.ambientNotificationIcons).length;
|
||||
let ambientIcons = document.querySelectorAll("#social-toolbar-item > toolbarbutton[type='badged']");
|
||||
is(numIcons, ambientIcons.length, "all ambient icons exist");
|
||||
is(panel.childNodes.length, ambientIcons.length + 1, "frames all exist");
|
||||
|
||||
// we need to wait until after social:profile-changed has completed
|
||||
waitForNotification("social:profile-changed", function() {
|
||||
// let the notifications finish first
|
||||
executeSoon(function() {
|
||||
let icons = document.querySelectorAll("#social-toolbar-item > toolbarbutton[type='badged']");
|
||||
is(icons.length, 0, "ambient icons have been removed");
|
||||
is(panel.childNodes.length, 1, "frame still exists");
|
||||
next();
|
||||
});
|
||||
});
|
||||
Social.provider.updateUserProfile({});
|
||||
// check dom values
|
||||
let ambientIcons = document.querySelectorAll("#social-toolbar-item > box");
|
||||
for (let ambientIcon of ambientIcons) {
|
||||
ok(ambientIcon.collapsed, "ambient icon (" + ambientIcon.id + ") is collapsed");
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
testMenuitemsExist: function(next) {
|
||||
let toggleSidebarMenuitems = document.getElementsByClassName("social-toggle-sidebar-menuitem");
|
||||
@ -230,5 +194,5 @@ var tests = {
|
||||
is(cmd.getAttribute("checked"), enabled ? "true" : "false");
|
||||
Services.prefs.clearUserPref("social.toast-notifications.enabled");
|
||||
next();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -298,14 +298,6 @@ function checkSocialUI(win) {
|
||||
is(numGoodTests, numTests, "The Social UI tests succeeded.")
|
||||
}
|
||||
|
||||
function waitForNotification(topic, cb) {
|
||||
function observer(subject, topic, data) {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
cb();
|
||||
}
|
||||
Services.obs.addObserver(observer, topic, false);
|
||||
}
|
||||
|
||||
// blocklist testing
|
||||
function updateBlocklist(aCallback) {
|
||||
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
|
||||
|
@ -1,180 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Handles the download progress indicator in the taskbar.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"DownloadsTaskbar",
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
"resource:///modules/RecentWindow.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gWinTaskbar", function () {
|
||||
if (!("@mozilla.org/windows-taskbar;1" in Cc)) {
|
||||
return null;
|
||||
}
|
||||
let winTaskbar = Cc["@mozilla.org/windows-taskbar;1"]
|
||||
.getService(Ci.nsIWinTaskbar);
|
||||
return winTaskbar.available && winTaskbar;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gMacTaskbarProgress", function () {
|
||||
return ("@mozilla.org/widget/macdocksupport;1" in Cc) &&
|
||||
Cc["@mozilla.org/widget/macdocksupport;1"]
|
||||
.getService(Ci.nsITaskbarProgress);
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsTaskbar
|
||||
|
||||
/**
|
||||
* Handles the download progress indicator in the taskbar.
|
||||
*/
|
||||
this.DownloadsTaskbar = {
|
||||
/**
|
||||
* Underlying DownloadSummary providing the aggregate download information, or
|
||||
* null if the indicator has never been initialized.
|
||||
*/
|
||||
_summary: null,
|
||||
|
||||
/**
|
||||
* nsITaskbarProgress object to which download information is dispatched.
|
||||
* This can be null if the indicator has never been initialized or if the
|
||||
* indicator is currently hidden on Windows.
|
||||
*/
|
||||
_taskbarProgress: null,
|
||||
|
||||
/**
|
||||
* This method is called after a new browser window is opened, and ensures
|
||||
* that the download progress indicator is displayed in the taskbar.
|
||||
*
|
||||
* On Windows, the indicator is attached to the first browser window that
|
||||
* calls this method. When the window is closed, the indicator is moved to
|
||||
* another browser window, if available, in no particular order. When there
|
||||
* are no browser windows visible, the indicator is hidden.
|
||||
*
|
||||
* On Mac OS X, the indicator is initialized globally when this method is
|
||||
* called for the first time. Subsequent calls have no effect.
|
||||
*
|
||||
* @param aBrowserWindow
|
||||
* nsIDOMWindow object of the newly opened browser window to which the
|
||||
* indicator may be attached.
|
||||
*/
|
||||
registerIndicator: function (aBrowserWindow)
|
||||
{
|
||||
if (!this._taskbarProgress) {
|
||||
if (gMacTaskbarProgress) {
|
||||
// On Mac OS X, we have to register the global indicator only once.
|
||||
this._taskbarProgress = gMacTaskbarProgress;
|
||||
// Free the XPCOM reference on shutdown, to prevent detecting a leak.
|
||||
Services.obs.addObserver(() => {
|
||||
this._taskbarProgress = null;
|
||||
gMacTaskbarProgress = null;
|
||||
}, "quit-application-granted", false);
|
||||
} else if (gWinTaskbar) {
|
||||
// On Windows, the indicator is currently hidden because we have no
|
||||
// previous browser window, thus we should attach the indicator now.
|
||||
this._attachIndicator(aBrowserWindow);
|
||||
} else {
|
||||
// The taskbar indicator is not available on this platform.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the DownloadSummary object will be created asynchronously.
|
||||
if (!this._summary) {
|
||||
Downloads.getSummary(Downloads.ALL).then(summary => {
|
||||
// In case the method is re-entered, we simply ignore redundant
|
||||
// invocations of the callback, instead of keeping separate state.
|
||||
if (this._summary) {
|
||||
return;
|
||||
}
|
||||
this._summary = summary;
|
||||
this._summary.addView(this);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* On Windows, attaches the taskbar indicator to the specified browser window.
|
||||
*/
|
||||
_attachIndicator: function (aWindow)
|
||||
{
|
||||
// Activate the indicator on the specified window.
|
||||
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIXULWindow).docShell;
|
||||
this._taskbarProgress = gWinTaskbar.getTaskbarProgress(docShell);
|
||||
|
||||
// If the DownloadSummary object has already been created, we should update
|
||||
// the state of the new indicator, otherwise it will be updated as soon as
|
||||
// the DownloadSummary view is registered.
|
||||
if (this._summary) {
|
||||
this.onSummaryChanged();
|
||||
}
|
||||
|
||||
aWindow.addEventListener("unload", () => {
|
||||
// Locate another browser window, excluding the one being closed.
|
||||
let browserWindow = RecentWindow.getMostRecentBrowserWindow();
|
||||
if (browserWindow) {
|
||||
// Move the progress indicator to the other browser window.
|
||||
this._attachIndicator(browserWindow);
|
||||
} else {
|
||||
// The last browser window has been closed. We remove the reference to
|
||||
// the taskbar progress object so that the indicator will be registered
|
||||
// again on the next browser window that is opened.
|
||||
this._taskbarProgress = null;
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadSummary view
|
||||
|
||||
onSummaryChanged: function ()
|
||||
{
|
||||
// If the last browser window has been closed, we have no indicator anymore.
|
||||
if (!this._taskbarProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._summary.allHaveStopped || this._summary.progressTotalBytes == 0) {
|
||||
this._taskbarProgress.setProgressState(
|
||||
Ci.nsITaskbarProgress.STATE_NO_PROGRESS, 0, 0);
|
||||
} else {
|
||||
// For a brief moment before completion, some download components may
|
||||
// report more transferred bytes than the total number of bytes. Thus,
|
||||
// ensure that we never break the expectations of the progress indicator.
|
||||
let progressCurrentBytes = Math.min(this._summary.progressTotalBytes,
|
||||
this._summary.progressCurrentBytes);
|
||||
this._taskbarProgress.setProgressState(
|
||||
Ci.nsITaskbarProgress.STATE_NORMAL,
|
||||
progressCurrentBytes,
|
||||
this._summary.progressTotalBytes);
|
||||
}
|
||||
},
|
||||
};
|
@ -13,6 +13,5 @@ EXTRA_COMPONENTS += [
|
||||
EXTRA_JS_MODULES += [
|
||||
'DownloadsCommon.jsm',
|
||||
'DownloadsLogger.jsm',
|
||||
'DownloadsTaskbar.jsm',
|
||||
]
|
||||
|
||||
|
@ -428,8 +428,6 @@ social.turnOff.accesskey=T
|
||||
# LOCALIZATION NOTE (social.turnOn.label): %S is the name of the social provider
|
||||
social.turnOn.label=Turn on %S
|
||||
social.turnOn.accesskey=T
|
||||
social.turnOffAll.label=Turn off all Services
|
||||
social.turnOnAll.label=Turn on all Services
|
||||
|
||||
# LOCALIZATION NOTE (social.markpageMenu.label): %S is the name of the social provider
|
||||
social.markpageMenu.label=Save Page to %S
|
||||
|
@ -34,8 +34,9 @@ function prefObserver(subject, topic, data) {
|
||||
if (enable && !Social.provider) {
|
||||
// this will result in setting Social.provider
|
||||
SocialService.getOrderedProviderList(function(providers) {
|
||||
Social.enabled = true;
|
||||
Social._updateProviderCache(providers);
|
||||
Social.enabled = true;
|
||||
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
||||
});
|
||||
} else if (!enable && Social.provider) {
|
||||
Social.provider = null;
|
||||
@ -167,7 +168,7 @@ this.Social = {
|
||||
// Retrieve the current set of providers, and set the current provider.
|
||||
SocialService.getOrderedProviderList(function (providers) {
|
||||
Social._updateProviderCache(providers);
|
||||
Social._updateWorkerState(SocialService.enabled);
|
||||
Social._updateWorkerState(true);
|
||||
});
|
||||
}
|
||||
|
||||
@ -180,16 +181,10 @@ this.Social = {
|
||||
Services.obs.notifyObservers(null, "social:" + topic, origin);
|
||||
return;
|
||||
}
|
||||
if (topic == "provider-enabled") {
|
||||
Social._updateProviderCache(providers);
|
||||
Social._updateWorkerState(Social.enabled);
|
||||
Services.obs.notifyObservers(null, "social:" + topic, origin);
|
||||
return;
|
||||
}
|
||||
if (topic == "provider-disabled") {
|
||||
// a provider was removed from the list of providers, that does not
|
||||
// affect worker state for other providers
|
||||
if (topic == "provider-enabled" || topic == "provider-disabled") {
|
||||
Social._updateProviderCache(providers);
|
||||
Social._updateWorkerState(true);
|
||||
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
||||
Services.obs.notifyObservers(null, "social:" + topic, origin);
|
||||
return;
|
||||
}
|
||||
@ -199,6 +194,7 @@ this.Social = {
|
||||
Social._updateProviderCache(providers);
|
||||
let provider = Social._getProviderFromOrigin(origin);
|
||||
provider.reload();
|
||||
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -214,7 +210,6 @@ this.Social = {
|
||||
// Called to update our cache of providers and set the current provider
|
||||
_updateProviderCache: function (providers) {
|
||||
this.providers = providers;
|
||||
Services.obs.notifyObservers(null, "social:providers-changed", null);
|
||||
|
||||
// If social is currently disabled there's nothing else to do other than
|
||||
// to notify about the lack of a provider.
|
||||
|
@ -4,4 +4,4 @@
|
||||
# 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/.
|
||||
|
||||
DIRS += ['chrome', 'unit']
|
||||
DIRS += ['chrome']
|
||||
|
@ -1,9 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DIRS += ['social']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['social/xpcshell.ini']
|
@ -1,11 +0,0 @@
|
||||
# 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/.
|
||||
|
||||
XPCSHELL_RESOURCES = \
|
||||
xpcshell.ini \
|
||||
head.js \
|
||||
blocklist.xml \
|
||||
test_social.js \
|
||||
test_socialDisabledStartup.js \
|
||||
$(NULL)
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<emItems>
|
||||
<emItem blockID="s1" id="bad.com@services.mozilla.org"></emItem>
|
||||
</emItems>
|
||||
</blocklist>
|
@ -1,146 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var Social, SocialService;
|
||||
|
||||
let manifests = [
|
||||
{
|
||||
name: "provider 1",
|
||||
origin: "https://example1.com",
|
||||
sidebarURL: "https://example1.com/sidebar/",
|
||||
},
|
||||
{
|
||||
name: "provider 2",
|
||||
origin: "https://example2.com",
|
||||
sidebarURL: "https://example1.com/sidebar/",
|
||||
}
|
||||
];
|
||||
|
||||
const MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
|
||||
|
||||
// SocialProvider class relies on blocklisting being enabled. To enable
|
||||
// blocklisting, we have to setup an app and initialize the blocklist (see
|
||||
// initApp below).
|
||||
const gProfD = do_get_profile();
|
||||
|
||||
const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
|
||||
const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
|
||||
|
||||
function createAppInfo(id, name, version, platformVersion) {
|
||||
gAppInfo = {
|
||||
// nsIXULAppInfo
|
||||
vendor: "Mozilla",
|
||||
name: name,
|
||||
ID: id,
|
||||
version: version,
|
||||
appBuildID: "2007010101",
|
||||
platformVersion: platformVersion ? platformVersion : "1.0",
|
||||
platformBuildID: "2007010101",
|
||||
|
||||
// nsIXULRuntime
|
||||
inSafeMode: false,
|
||||
logConsoleErrors: true,
|
||||
OS: "XPCShell",
|
||||
XPCOMABI: "noarch-spidermonkey",
|
||||
invalidateCachesOnRestart: function invalidateCachesOnRestart() {
|
||||
// Do nothing
|
||||
},
|
||||
|
||||
// nsICrashReporter
|
||||
annotations: {},
|
||||
|
||||
annotateCrashReport: function(key, data) {
|
||||
this.annotations[key] = data;
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULAppInfo,
|
||||
Ci.nsIXULRuntime,
|
||||
Ci.nsICrashReporter,
|
||||
Ci.nsISupports])
|
||||
};
|
||||
|
||||
var XULAppInfoFactory = {
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
return gAppInfo.QueryInterface(iid);
|
||||
}
|
||||
};
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
|
||||
XULAPPINFO_CONTRACTID, XULAppInfoFactory);
|
||||
}
|
||||
|
||||
function initApp() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
|
||||
// prepare a blocklist file for the blocklist service
|
||||
var blocklistFile = gProfD.clone();
|
||||
blocklistFile.append("blocklist.xml");
|
||||
if (blocklistFile.exists())
|
||||
blocklistFile.remove(false);
|
||||
var source = do_get_file("blocklist.xml");
|
||||
source.copyTo(gProfD, "blocklist.xml");
|
||||
}
|
||||
|
||||
function setManifestPref(manifest) {
|
||||
let string = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
string.data = JSON.stringify(manifest);
|
||||
Services.prefs.setComplexValue("social.manifest." + manifest.origin, Ci.nsISupportsString, string);
|
||||
}
|
||||
|
||||
function do_wait_observer(topic, cb) {
|
||||
function observer(subject, topic, data) {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
cb();
|
||||
}
|
||||
Services.obs.addObserver(observer, topic, false);
|
||||
}
|
||||
|
||||
function do_initialize_social(enabledOnStartup, cb) {
|
||||
initApp();
|
||||
|
||||
manifests.forEach(function (manifest) {
|
||||
setManifestPref(manifest);
|
||||
});
|
||||
// Set both providers active and flag the first one as "current"
|
||||
let activeVal = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
let active = {};
|
||||
for (let m of manifests)
|
||||
active[m.origin] = 1;
|
||||
activeVal.data = JSON.stringify(active);
|
||||
Services.prefs.setComplexValue("social.activeProviders",
|
||||
Ci.nsISupportsString, activeVal);
|
||||
Services.prefs.setCharPref("social.provider.current", manifests[0].origin);
|
||||
Services.prefs.setBoolPref("social.enabled", enabledOnStartup);
|
||||
|
||||
do_register_cleanup(function() {
|
||||
manifests.forEach(function (manifest) {
|
||||
Services.prefs.clearUserPref("social.manifest." + manifest.origin);
|
||||
});
|
||||
Services.prefs.clearUserPref("social.enabled");
|
||||
Services.prefs.clearUserPref("social.provider.current");
|
||||
Services.prefs.clearUserPref("social.activeProviders");
|
||||
});
|
||||
|
||||
// expecting 2 providers installed
|
||||
do_wait_observer("social:providers-changed", function() {
|
||||
do_check_eq(Social.providers.length, 2, "2 providers installed");
|
||||
cb();
|
||||
});
|
||||
|
||||
// import and initialize everything
|
||||
SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
|
||||
do_check_eq(SocialService.enabled, enabledOnStartup, "service is doing its thing");
|
||||
do_check_true(SocialService.hasEnabledProviders, "Service has enabled providers");
|
||||
Social = Cu.import("resource:///modules/Social.jsm", {}).Social;
|
||||
do_check_false(Social.initialized, "Social is not initialized");
|
||||
Social.init();
|
||||
do_check_true(Social.initialized, "Social is initialized");
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
@ -1,34 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
// we are testing worker startup specifically
|
||||
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.clearUserPref("social.allowMultipleWorkers");
|
||||
});
|
||||
do_test_pending();
|
||||
add_test(testStartupEnabled);
|
||||
add_test(testDisableAfterStartup);
|
||||
do_initialize_social(true, run_next_test);
|
||||
}
|
||||
|
||||
function testStartupEnabled() {
|
||||
// wait on startup before continuing
|
||||
do_check_eq(Social.providers.length, 2, "two social providers enabled");
|
||||
do_check_true(Social.providers[0].enabled, "provider is enabled");
|
||||
do_check_true(Social.providers[1].enabled, "provider is enabled");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function testDisableAfterStartup() {
|
||||
do_wait_observer("social:provider-set", function() {
|
||||
do_check_eq(Social.enabled, false, "Social is disabled");
|
||||
do_check_false(Social.providers[0].enabled, "provider is enabled");
|
||||
do_check_false(Social.providers[1].enabled, "provider is enabled");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
Social.enabled = false;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
function run_test() {
|
||||
// we are testing worker startup specifically
|
||||
Services.prefs.setBoolPref("social.allowMultipleWorkers", true);
|
||||
do_register_cleanup(function() {
|
||||
Services.prefs.clearUserPref("social.allowMultipleWorkers");
|
||||
});
|
||||
do_test_pending();
|
||||
add_test(testStartupDisabled);
|
||||
add_test(testEnableAfterStartup);
|
||||
do_initialize_social(false, run_next_test);
|
||||
}
|
||||
|
||||
function testStartupDisabled() {
|
||||
// wait on startup before continuing
|
||||
do_check_eq(Social.providers.length, 2, "two social providers available");
|
||||
do_check_false(Social.providers[0].enabled, "provider is enabled");
|
||||
do_check_false(Social.providers[1].enabled, "provider is enabled");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function testEnableAfterStartup() {
|
||||
do_wait_observer("social:provider-set", function() {
|
||||
do_check_true(Social.enabled, "Social is enabled");
|
||||
do_check_eq(Social.providers.length, 2, "two social providers available");
|
||||
do_check_true(Social.providers[0].enabled, "provider is enabled");
|
||||
do_check_true(Social.providers[1].enabled, "provider is enabled");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
Social.enabled = true;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
|
||||
[test_social.js]
|
||||
|
||||
[test_socialDisabledStartup.js]
|
@ -716,9 +716,9 @@ nsScriptLoader::ProcessOffThreadRequest(void **aOffThreadToken)
|
||||
{
|
||||
nsCOMPtr<nsScriptLoadRequest> request = mOffThreadScriptRequest;
|
||||
mOffThreadScriptRequest = nullptr;
|
||||
nsresult rv = ProcessRequest(request, aOffThreadToken);
|
||||
mDocument->UnblockOnload(false);
|
||||
|
||||
return ProcessRequest(request, aOffThreadToken);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -47,6 +47,38 @@ HasOpaqueAncestorLayer(Layer* aLayer)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rectangle of content painted opaquely by aLayer. Very consertative;
|
||||
* bails by returning an empty rect in any tricky situations.
|
||||
*/
|
||||
static nsIntRect
|
||||
GetOpaqueRect(Layer* aLayer)
|
||||
{
|
||||
nsIntRect result;
|
||||
// Just bail if there's anything difficult to handle.
|
||||
if (!aLayer->GetEffectiveTransform().IsIdentity() ||
|
||||
aLayer->GetEffectiveOpacity() != 1.0f ||
|
||||
aLayer->GetMaskLayer()) {
|
||||
return result;
|
||||
}
|
||||
if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
|
||||
result = aLayer->GetEffectiveVisibleRegion().GetLargestRectangle();
|
||||
} else {
|
||||
// Drill down into RefLayers because that's what we particularly care about;
|
||||
// layer construction for aLayer will not have known about the opaqueness
|
||||
// of any RefLayer subtrees.
|
||||
RefLayer* refLayer = aLayer->AsRefLayer();
|
||||
if (refLayer && refLayer->GetFirstChild()) {
|
||||
result = GetOpaqueRect(refLayer->GetFirstChild());
|
||||
}
|
||||
}
|
||||
const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
|
||||
if (clipRect) {
|
||||
result.IntersectRect(result, *clipRect);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class ContainerT> void
|
||||
ContainerRender(ContainerT* aContainer,
|
||||
const nsIntPoint& aOffset,
|
||||
@ -143,6 +175,23 @@ ContainerRender(ContainerT* aContainer,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 1 < children.Length() &&
|
||||
layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) {
|
||||
LayerComposite* nextLayer = static_cast<LayerComposite*>(children.ElementAt(i + 1)->ImplData());
|
||||
nsIntRect nextLayerOpaqueRect;
|
||||
if (nextLayer && nextLayer->GetLayer()) {
|
||||
nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer());
|
||||
}
|
||||
if (!nextLayerOpaqueRect.IsEmpty()) {
|
||||
nsIntRegion visibleRegion;
|
||||
visibleRegion.Sub(layerToRender->GetShadowVisibleRegion(), nextLayerOpaqueRect);
|
||||
layerToRender->SetShadowVisibleRegion(visibleRegion);
|
||||
if (visibleRegion.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsIntRect clipRect = layerToRender->GetLayer()->
|
||||
CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
|
||||
if (clipRect.IsEmpty()) {
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "nsCanvasFrame.h"
|
||||
#include "StickyScrollContainer.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "gfxPlatform.h"
|
||||
#include "AnimationCommon.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsIFrame.h"
|
||||
@ -16,7 +15,6 @@
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "RestyleManager.h"
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "mozilla/css/Declaration.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "gfxFontConstants.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
@ -11,8 +11,6 @@
|
||||
#ifndef mozilla_css_StyleRule_h__
|
||||
#define mozilla_css_StyleRule_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/css/Rule.h"
|
||||
@ -21,7 +19,6 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsCSSPseudoClasses.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
class nsIAtom;
|
||||
class nsCSSStyleSheet;
|
||||
|
@ -12,9 +12,7 @@
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsStyleAnimation.h"
|
||||
#include "nsSMILKeySpline.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include <math.h>
|
||||
|
||||
|
@ -8,15 +8,12 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "AnimationCommon.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsCSSKeyframesRule;
|
||||
class nsStyleContext;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsCSSPropertySet.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "imgRequestProxy.h"
|
||||
|
||||
struct nsRuleData;
|
||||
class nsCSSExpandedDataBlock;
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "nsCSSKeywords.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStaticNameTable.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
// required to make the symbol external, so that TestCSSPropertyLookup.cpp can link with it
|
||||
extern const char* const kCSSRawKeywords[];
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsCSSPseudoClasses.h"
|
||||
|
@ -19,8 +19,10 @@
|
||||
#include "mozilla/LookAndFeel.h" // for system colors
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStaticNameTable.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "nsStyleStruct.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
|
@ -12,9 +12,8 @@
|
||||
#define nsCSSProps_h___
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsCSSProperty.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsStyleStructFwd.h"
|
||||
#include "nsCSSKeywords.h"
|
||||
|
||||
// Flags for ParseVariant method
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsCSSPseudoClasses.h"
|
||||
#include "nsStaticAtom.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsString.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef nsCSSPseudoClasses_h___
|
||||
#define nsCSSPseudoClasses_h___
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
class nsIAtom;
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include <algorithm>
|
||||
#include "nsCRT.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "pldhash.h"
|
||||
#include "nsICSSPseudoComparator.h"
|
||||
@ -28,9 +27,7 @@
|
||||
#include "mozilla/css/GroupRule.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsEventStateManager.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsRuleWalker.h"
|
||||
@ -44,17 +41,11 @@
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIMediaList.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "prlog.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsNthIndexCache.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "nsCSSStyleSheet.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsRuleWalker.h"
|
||||
#include "nsEventStates.h"
|
||||
|
||||
@ -28,6 +27,8 @@ struct nsCSSSelectorList;
|
||||
struct RuleCascadeData;
|
||||
struct TreeMatchContext;
|
||||
class nsCSSKeyframesRule;
|
||||
class nsCSSPageRule;
|
||||
class nsCSSFontFeatureValuesRule;
|
||||
|
||||
/**
|
||||
* The CSS style rule processor provides a mechanism for sibling style
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "nsIDOMCSSSupportsRule.h"
|
||||
#include "nsIDOMMozCSSKeyframeRule.h"
|
||||
#include "nsIDOMMozCSSKeyframesRule.h"
|
||||
#include "nsIDOMCSSStyleDeclaration.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSProperty.h"
|
||||
#include "nsCSSValue.h"
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "nsCSSScanner.h"
|
||||
#include "nsStyleUtil.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "mozilla/css/ErrorReporter.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "gfxFontConstants.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "imgRequestProxy.h"
|
||||
|
||||
namespace css = mozilla::css;
|
||||
|
||||
|
@ -29,8 +29,6 @@ class nsIDocument;
|
||||
class nsIPrincipal;
|
||||
class nsPresContext;
|
||||
class nsIURI;
|
||||
template <class T>
|
||||
class nsPtrHashKey;
|
||||
|
||||
// Deletes a linked list iteratively to avoid blowing up the stack (bug 456196).
|
||||
#define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_) \
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "prtime.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
#include "nsUTF8Utils.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -15,8 +15,10 @@
|
||||
#include "nsCSSProperty.h"
|
||||
#include "nsDOMCSSDeclaration.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -28,8 +30,37 @@ class Element;
|
||||
class nsIFrame;
|
||||
class nsIPresShell;
|
||||
class nsDOMCSSValueList;
|
||||
class nsMargin;
|
||||
class nsROCSSPrimitiveValue;
|
||||
class nsStyleContext;
|
||||
class nsStyleBackground;
|
||||
class nsStyleBorder;
|
||||
class nsStyleContent;
|
||||
class nsStyleColumn;
|
||||
class nsStyleColor;
|
||||
class nsStyleCoord;
|
||||
class nsStyleCorners;
|
||||
class nsStyleDisplay;
|
||||
class nsStyleFilter;
|
||||
class nsStyleFont;
|
||||
class nsStyleGradient;
|
||||
class nsStyleImage;
|
||||
class nsStyleList;
|
||||
class nsStyleMargin;
|
||||
class nsStyleOutline;
|
||||
class nsStylePadding;
|
||||
class nsStylePosition;
|
||||
class nsStyleQuotes;
|
||||
class nsStyleSides;
|
||||
class nsStyleSVG;
|
||||
class nsStyleSVGReset;
|
||||
class nsStyleTable;
|
||||
class nsStyleText;
|
||||
class nsStyleTextReset;
|
||||
class nsStyleTimingFunction;
|
||||
class nsStyleUIReset;
|
||||
class nsStyleVisibility;
|
||||
class nsStyleXUL;
|
||||
class nsTimingFunction;
|
||||
class gfx3DMatrix;
|
||||
|
||||
class nsComputedDOMStyle MOZ_FINAL : public nsDOMCSSDeclaration
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
namespace css = mozilla::css;
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIDocument;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define nsDOMCSSRect_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIDOMRect.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsCrossSiteListenerProxy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsChannelPolicy.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
|
||||
|
@ -17,12 +17,10 @@
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsCSSRules.h"
|
||||
|
||||
class nsISupports;
|
||||
class nsPresContext;
|
||||
class nsIPrincipal;
|
||||
|
||||
class nsFontFaceLoader;
|
||||
class nsCSSFontFaceRule;
|
||||
|
||||
// nsUserFontSet - defines the loading mechanism for downloadable fonts
|
||||
class nsUserFontSet : public gfxUserFontSet
|
||||
|
@ -12,8 +12,6 @@
|
||||
#include "mozilla/css/StyleRule.h"
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsRuleWalker.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
@ -13,9 +13,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
|
||||
struct MiscContainer;
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "RestyleManager.h"
|
||||
|
||||
|
@ -17,12 +17,12 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIStyleRule.h"
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "pldhash.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsMappedAttributes;
|
||||
|
||||
class nsHTMLStyleSheet MOZ_FINAL : public nsIStyleRuleProcessor
|
||||
|
@ -11,7 +11,9 @@
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsCSSValue.h"
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#endif
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define nsRuleData_h_
|
||||
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleStructFwd.h"
|
||||
|
||||
class nsPresContext;
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef nsStyleAnimation_h_
|
||||
#define nsStyleAnimation_h_
|
||||
|
||||
#include "nsAString.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsCRTGlue.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsCSSProperty.h"
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsHTMLCSSStyleSheet.h"
|
||||
#include "nsHTMLStyleSheet.h"
|
||||
#include "nsCSSRules.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "gfxFontFeatures.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsCSSFontFaceRule;
|
||||
class nsCSSKeyframesRule;
|
||||
class nsCSSFontFeatureValuesRule;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsRuleNode.h"
|
||||
#include "nsCSSKeywords.h"
|
||||
#include "nsStyleAnimation.h"
|
||||
#include "gfxMatrix.h"
|
||||
|
||||
namespace css = mozilla::css;
|
||||
|
||||
|
@ -11,10 +11,8 @@
|
||||
#define nsStyleTransformMatrix_h_
|
||||
|
||||
#include "nsCSSValue.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfx3DMatrix.h"
|
||||
|
||||
struct nsCSSValueList;
|
||||
class nsStyleContext;
|
||||
class nsPresContext;
|
||||
struct nsRect;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsRuleNode.h"
|
||||
#include "nsROCSSPrimitiveValue.h"
|
||||
|
@ -7,15 +7,16 @@
|
||||
|
||||
#include "nsCoord.h"
|
||||
#include "nsCSSProperty.h"
|
||||
#include "gfxFontFeatures.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsSubstring.h"
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
class nsCSSValue;
|
||||
class nsStringComparator;
|
||||
class nsStyleCoord;
|
||||
class nsIContent;
|
||||
class nsIPrincipal;
|
||||
class nsIURI;
|
||||
struct gfxFontFeature;
|
||||
struct gfxAlternateValue;
|
||||
class nsCSSValueList;
|
||||
template <class E> class nsTArray;
|
||||
|
||||
|
@ -15,17 +15,13 @@
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "nsIStyleRule.h"
|
||||
#include "nsRuleWalker.h"
|
||||
#include "nsRuleData.h"
|
||||
#include "gfxColor.h"
|
||||
#include "nsCSSPropertySet.h"
|
||||
#include "nsStyleAnimation.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsGUIEvent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "Layers.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
|
||||
#include "primpl.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
/*
|
||||
* AddThreadToCVWaitQueueInternal --
|
||||
@ -150,6 +152,10 @@ md_UnlockAndPostNotifies(
|
||||
thred->md.prev = thred->md.next = NULL;
|
||||
|
||||
rv = ReleaseSemaphore(thred->md.blocked_sema, 1, NULL);
|
||||
if (!rv) {
|
||||
fprintf(stderr, "ReleaseSemaphore failed, handle: %x, last error: %x\n",
|
||||
(void*)thred->md.blocked_sema, GetLastError());
|
||||
}
|
||||
PR_ASSERT(rv != 0);
|
||||
thred = next;
|
||||
}
|
||||
@ -246,6 +252,10 @@ void _PR_MD_WAIT_CV(_MDCVar *cv, _MDLock *lock, PRIntervalTime timeout )
|
||||
|
||||
/* Wait for notification or timeout; don't really care which */
|
||||
rv = WaitForSingleObject(thred->md.blocked_sema, msecs);
|
||||
if (rv == WAIT_FAILED) {
|
||||
fprintf(stderr, "WaitForSingleObject failed, handle: %x, last error: %x\n",
|
||||
(void*)thred->md.blocked_sema, GetLastError());
|
||||
}
|
||||
|
||||
EnterCriticalSection(&(lock->mutex));
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include "primpl.h"
|
||||
#include <process.h> /* for _beginthreadex() */
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
/*
|
||||
@ -217,6 +219,10 @@ _PR_MD_CLEAN_THREAD(PRThread *thread)
|
||||
|
||||
if (thread->md.handle) {
|
||||
rv = CloseHandle(thread->md.handle);
|
||||
if (!rv) {
|
||||
fprintf(stderr, "CloseHandle failed, handle: %x, last error: %x\n",
|
||||
(void*)thread->md.handle, GetLastError());
|
||||
}
|
||||
PR_ASSERT(rv);
|
||||
thread->md.handle = 0;
|
||||
}
|
||||
|
@ -131,7 +131,11 @@
|
||||
"content/html/document/test/test_bug446483.html": "",
|
||||
"content/html/document/test/test_bug741266.html": "",
|
||||
"content/media/test/test_autoplay_contentEditable.html": "x86 only",
|
||||
"content/media/test/test_playback_rate.html": "bug 845162",
|
||||
"content/media/test/test_seek.html": "bug 845162",
|
||||
"content/media/test/test_played.html": "bug 751539",
|
||||
"content/media/test/test_buffered.html": "",
|
||||
"content/media/test/test_bug465498.html": "",
|
||||
"content/media/test/test_bug448534.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug495145.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug495300.html": "x86 only bug 914439",
|
||||
|
@ -13,9 +13,6 @@
|
||||
*
|
||||
* DownloadCombinedList
|
||||
* Provides a unified, unordered list combining public and private downloads.
|
||||
*
|
||||
* DownloadSummary
|
||||
* Provides an aggregated view on the contents of a DownloadList.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
@ -23,7 +20,6 @@
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"DownloadList",
|
||||
"DownloadCombinedList",
|
||||
"DownloadSummary",
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -336,185 +332,3 @@ DownloadCombinedList.prototype = {
|
||||
this._notifyAllViews("onDownloadRemoved", aDownload);
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadSummary
|
||||
|
||||
/**
|
||||
* Provides an aggregated view on the contents of a DownloadList.
|
||||
*/
|
||||
function DownloadSummary() {
|
||||
this._downloads = [];
|
||||
this._views = new Set();
|
||||
}
|
||||
|
||||
DownloadSummary.prototype = {
|
||||
/**
|
||||
* Array of Download objects that are currently part of the summary.
|
||||
*/
|
||||
_downloads: null,
|
||||
|
||||
/**
|
||||
* Underlying DownloadList whose contents should be summarized.
|
||||
*/
|
||||
_list: null,
|
||||
|
||||
/**
|
||||
* This method may be called once to bind this object to a DownloadList.
|
||||
*
|
||||
* Views on the summarized data can be registered before this object is bound
|
||||
* to an actual list. This allows the summary to be used without requiring
|
||||
* the initialization of the DownloadList first.
|
||||
*
|
||||
* @param aList
|
||||
* Underlying DownloadList whose contents should be summarized.
|
||||
*/
|
||||
bindToList: function (aList)
|
||||
{
|
||||
if (this._list) {
|
||||
throw new Error("bindToList may be called only once.");
|
||||
}
|
||||
|
||||
aList.addView(this);
|
||||
|
||||
// Set the list reference only after addView has returned, so that we don't
|
||||
// send a notification to our views for each download that is added.
|
||||
this._list = aList;
|
||||
this._onListChanged();
|
||||
},
|
||||
|
||||
/**
|
||||
* Set of currently registered views.
|
||||
*/
|
||||
_views: null,
|
||||
|
||||
/**
|
||||
* Adds a view that will be notified of changes to the summary. The newly
|
||||
* added view will receive an initial onSummaryChanged notification.
|
||||
*
|
||||
* @param aView
|
||||
* The view object to add. The following methods may be defined:
|
||||
* {
|
||||
* onSummaryChanged: function () {
|
||||
* // Called after any property of the summary has changed.
|
||||
* },
|
||||
* }
|
||||
*/
|
||||
addView: function (aView)
|
||||
{
|
||||
this._views.add(aView);
|
||||
|
||||
if ("onSummaryChanged" in aView) {
|
||||
try {
|
||||
aView.onSummaryChanged();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a view that was previously added using addView. The removed view
|
||||
* will not receive any more notifications after this method returns.
|
||||
*
|
||||
* @param aView
|
||||
* The view object to remove.
|
||||
*/
|
||||
removeView: function (aView)
|
||||
{
|
||||
this._views.delete(aView);
|
||||
},
|
||||
|
||||
/**
|
||||
* Indicates whether all the downloads are currently stopped.
|
||||
*/
|
||||
allHaveStopped: true,
|
||||
|
||||
/**
|
||||
* Indicates the total number of bytes to be transferred before completing all
|
||||
* the downloads that are currently in progress.
|
||||
*
|
||||
* For downloads that do not have a known final size, the number of bytes
|
||||
* currently transferred is reported as part of this property.
|
||||
*
|
||||
* This is zero if no downloads are currently in progress.
|
||||
*/
|
||||
progressTotalBytes: 0,
|
||||
|
||||
/**
|
||||
* Number of bytes currently transferred as part of all the downloads that are
|
||||
* currently in progress.
|
||||
*
|
||||
* This is zero if no downloads are currently in progress.
|
||||
*/
|
||||
progressCurrentBytes: 0,
|
||||
|
||||
/**
|
||||
* This function is called when any change in the list of downloads occurs,
|
||||
* and will recalculate the summary and notify the views in case the
|
||||
* aggregated properties are different.
|
||||
*/
|
||||
_onListChanged: function () {
|
||||
let allHaveStopped = true;
|
||||
let progressTotalBytes = 0;
|
||||
let progressCurrentBytes = 0;
|
||||
|
||||
// Recalculate the aggregated state. See the description of the individual
|
||||
// properties for an explanation of the summarization logic.
|
||||
for (let download of this._downloads) {
|
||||
if (!download.stopped) {
|
||||
allHaveStopped = false;
|
||||
progressTotalBytes += download.hasProgress ? download.totalBytes
|
||||
: download.currentBytes;
|
||||
progressCurrentBytes += download.currentBytes;
|
||||
}
|
||||
}
|
||||
|
||||
// Exit now if the properties did not change.
|
||||
if (this.allHaveStopped == allHaveStopped &&
|
||||
this.progressTotalBytes == progressTotalBytes &&
|
||||
this.progressCurrentBytes == progressCurrentBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.allHaveStopped = allHaveStopped;
|
||||
this.progressTotalBytes = progressTotalBytes;
|
||||
this.progressCurrentBytes = progressCurrentBytes;
|
||||
|
||||
// Notify all the views that our properties changed.
|
||||
for (let view of this._views) {
|
||||
try {
|
||||
if ("onSummaryChanged" in view) {
|
||||
view.onSummaryChanged();
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadList view
|
||||
|
||||
onDownloadAdded: function (aDownload)
|
||||
{
|
||||
this._downloads.push(aDownload);
|
||||
if (this._list) {
|
||||
this._onListChanged();
|
||||
}
|
||||
},
|
||||
|
||||
onDownloadChanged: function (aDownload)
|
||||
{
|
||||
this._onListChanged();
|
||||
},
|
||||
|
||||
onDownloadRemoved: function (aDownload)
|
||||
{
|
||||
let index = this._downloads.indexOf(aDownload);
|
||||
if (index != -1) {
|
||||
this._downloads.splice(index, 1);
|
||||
}
|
||||
this._onListChanged();
|
||||
},
|
||||
};
|
||||
|
@ -31,8 +31,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration",
|
||||
"resource://gre/modules/DownloadIntegration.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadList",
|
||||
"resource://gre/modules/DownloadList.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadSummary",
|
||||
"resource://gre/modules/DownloadList.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
|
||||
"resource://gre/modules/DownloadUIHelper.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
@ -164,87 +162,44 @@ this.Downloads = {
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
getList: function (aType)
|
||||
{
|
||||
if (!this._promiseListsInitialized) {
|
||||
this._promiseListsInitialized = Task.spawn(function () {
|
||||
let publicList = new DownloadList();
|
||||
let privateList = new DownloadList();
|
||||
let combinedList = new DownloadCombinedList(publicList, privateList);
|
||||
|
||||
try {
|
||||
yield DownloadIntegration.addListObservers(publicList, false);
|
||||
yield DownloadIntegration.addListObservers(privateList, true);
|
||||
yield DownloadIntegration.initializePublicDownloadList(publicList);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
||||
let publicSummary = yield this.getSummary(Downloads.PUBLIC);
|
||||
let privateSummary = yield this.getSummary(Downloads.PRIVATE);
|
||||
let combinedSummary = yield this.getSummary(Downloads.ALL);
|
||||
|
||||
publicSummary.bindToList(publicList);
|
||||
privateSummary.bindToList(privateList);
|
||||
combinedSummary.bindToList(combinedList);
|
||||
|
||||
this._lists[Downloads.PUBLIC] = publicList;
|
||||
this._lists[Downloads.PRIVATE] = privateList;
|
||||
this._lists[Downloads.ALL] = combinedList;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return this._promiseListsInitialized.then(() => this._lists[aType]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Promise resolved when the initialization of the download lists has
|
||||
* completed, or null if initialization has never been requested.
|
||||
*/
|
||||
_promiseListsInitialized: null,
|
||||
|
||||
/**
|
||||
* After initialization, this object is populated with one key for each type
|
||||
* of download list that can be returned (Downloads.PUBLIC, Downloads.PRIVATE,
|
||||
* or Downloads.ALL). The values are the DownloadList objects.
|
||||
*/
|
||||
_lists: {},
|
||||
|
||||
/**
|
||||
* Retrieves the specified type of DownloadSummary object. There is one
|
||||
* download summary for each type, and this method always retrieves a
|
||||
* reference to the same download summary when called with the same argument.
|
||||
*
|
||||
* Calling this function does not cause the list of public downloads to be
|
||||
* reloaded from the previous session. The summary will behave as if no
|
||||
* downloads are present until the getList method is called.
|
||||
*
|
||||
* @param aType
|
||||
* This can be Downloads.PUBLIC, Downloads.PRIVATE, or Downloads.ALL.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The requested DownloadList or DownloadCombinedList object.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
getSummary: function (aType)
|
||||
{
|
||||
if (aType != Downloads.PUBLIC && aType != Downloads.PRIVATE &&
|
||||
aType != Downloads.ALL) {
|
||||
throw new Error("Invalid aType argument.");
|
||||
}
|
||||
|
||||
if (!(aType in this._summaries)) {
|
||||
this._summaries[aType] = new DownloadSummary();
|
||||
if (!(aType in this._listPromises)) {
|
||||
this._listPromises[aType] = Task.spawn(function () {
|
||||
let list;
|
||||
if (aType == Downloads.ALL) {
|
||||
list = new DownloadCombinedList(
|
||||
(yield this.getList(Downloads.PUBLIC)),
|
||||
(yield this.getList(Downloads.PRIVATE)));
|
||||
} else {
|
||||
list = new DownloadList();
|
||||
try {
|
||||
yield DownloadIntegration.addListObservers(
|
||||
list, aType == Downloads.PRIVATE);
|
||||
if (aType == Downloads.PUBLIC) {
|
||||
yield DownloadIntegration.initializePublicDownloadList(list);
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
throw new Task.Result(list);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return Promise.resolve(this._summaries[aType]);
|
||||
return this._listPromises[aType];
|
||||
},
|
||||
|
||||
/**
|
||||
* This object is populated by the getSummary method with one key for each
|
||||
* type of object that can be returned (Downloads.PUBLIC, Downloads.PRIVATE,
|
||||
* or Downloads.ALL). The values are the DownloadSummary objects.
|
||||
* This object is populated by the getList method with one key for each type
|
||||
* of object that can be returned (Downloads.PUBLIC, Downloads.PRIVATE, or
|
||||
* Downloads.ALL). The values are the promises returned by the method.
|
||||
*/
|
||||
_summaries: {},
|
||||
_listPromises: {},
|
||||
|
||||
/**
|
||||
* Returns the system downloads directory asynchronously.
|
||||
|
@ -35,6 +35,36 @@ function promiseStartDownload(aSourceUrl) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a download to reach half of its progress, in case it has not
|
||||
* reached the expected progress already.
|
||||
*
|
||||
* @param aDownload
|
||||
* The Download object to wait upon.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the download has reached half of its progress.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function promiseDownloadMidway(aDownload) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// Wait for the download to reach half of its progress.
|
||||
let onchange = function () {
|
||||
if (!aDownload.stopped && !aDownload.canceled && aDownload.progress == 50) {
|
||||
aDownload.onchange = null;
|
||||
deferred.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Register for the notification, but also call the function directly in
|
||||
// case the download already reached the expected progress.
|
||||
aDownload.onchange = onchange;
|
||||
onchange();
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a download to finish, in case it has not finished already.
|
||||
*
|
||||
|
@ -463,36 +463,6 @@ function promiseStartExternalHelperAppServiceDownload(aSourceUrl) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a download to reach half of its progress, in case it has not
|
||||
* reached the expected progress already.
|
||||
*
|
||||
* @param aDownload
|
||||
* The Download object to wait upon.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the download has reached half of its progress.
|
||||
* @rejects Never.
|
||||
*/
|
||||
function promiseDownloadMidway(aDownload) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
// Wait for the download to reach half of its progress.
|
||||
let onchange = function () {
|
||||
if (!aDownload.stopped && !aDownload.canceled && aDownload.progress == 50) {
|
||||
aDownload.onchange = null;
|
||||
deferred.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
// Register for the notification, but also call the function directly in
|
||||
// case the download already reached the expected progress.
|
||||
aDownload.onchange = onchange;
|
||||
onchange();
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new public or private DownloadList object.
|
||||
*
|
||||
@ -505,13 +475,19 @@ function promiseDownloadMidway(aDownload) {
|
||||
*/
|
||||
function promiseNewList(aIsPrivate)
|
||||
{
|
||||
// We need to clear all the internal state for the list and summary objects,
|
||||
// since all the objects are interdependent internally.
|
||||
Downloads._promiseListsInitialized = null;
|
||||
Downloads._lists = {};
|
||||
Downloads._summaries = {};
|
||||
let type = aIsPrivate ? Downloads.PRIVATE : Downloads.PUBLIC;
|
||||
|
||||
return Downloads.getList(aIsPrivate ? Downloads.PRIVATE : Downloads.PUBLIC);
|
||||
// Force the creation of a new list.
|
||||
if (type in Downloads._listPromises) {
|
||||
delete Downloads._listPromises[type];
|
||||
}
|
||||
|
||||
// Invalidate the combined list, if any.
|
||||
if (Downloads.ALL in Downloads._listPromises) {
|
||||
delete Downloads._listPromises[Downloads.ALL];
|
||||
}
|
||||
|
||||
return Downloads.getList(type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,7 +278,7 @@ add_task(function test_mix_notifications()
|
||||
mustInterruptResponses();
|
||||
|
||||
let publicList = yield promiseNewList();
|
||||
let privateList = yield Downloads.getList(Downloads.PRIVATE);
|
||||
let privateList = yield promiseNewList(true);
|
||||
let download1 = yield promiseNewDownload(httpUrl("interruptible.txt"));
|
||||
let download2 = yield promiseNewDownload(httpUrl("interruptible.txt"));
|
||||
let promiseAttempt1 = download1.start();
|
||||
|
@ -137,7 +137,7 @@ add_task(function test_remove()
|
||||
add_task(function test_DownloadCombinedList_add_remove_getAll()
|
||||
{
|
||||
let publicList = yield promiseNewList();
|
||||
let privateList = yield Downloads.getList(Downloads.PRIVATE);
|
||||
let privateList = yield promiseNewList(true);
|
||||
let combinedList = yield Downloads.getList(Downloads.ALL);
|
||||
|
||||
let publicDownload = yield promiseNewDownload();
|
||||
@ -448,120 +448,3 @@ add_task(function test_removeFinished()
|
||||
let downloads = yield list.getAll()
|
||||
do_check_eq(downloads.length, 1);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the global DownloadSummary objects for the public, private, and
|
||||
* combined download lists.
|
||||
*/
|
||||
add_task(function test_DownloadSummary()
|
||||
{
|
||||
mustInterruptResponses();
|
||||
|
||||
let publicList = yield promiseNewList();
|
||||
let privateList = yield Downloads.getList(Downloads.PRIVATE);
|
||||
|
||||
let publicSummary = yield Downloads.getSummary(Downloads.PUBLIC);
|
||||
let privateSummary = yield Downloads.getSummary(Downloads.PRIVATE);
|
||||
let combinedSummary = yield Downloads.getSummary(Downloads.ALL);
|
||||
|
||||
// Add a public download that has succeeded.
|
||||
let succeededPublicDownload = yield promiseNewDownload();
|
||||
yield succeededPublicDownload.start();
|
||||
publicList.add(succeededPublicDownload);
|
||||
|
||||
// Add a public download that has been canceled midway.
|
||||
let canceledPublicDownload =
|
||||
yield promiseNewDownload(httpUrl("interruptible.txt"));
|
||||
canceledPublicDownload.start();
|
||||
yield promiseDownloadMidway(canceledPublicDownload);
|
||||
yield canceledPublicDownload.cancel();
|
||||
publicList.add(canceledPublicDownload);
|
||||
|
||||
// Add a public download that is in progress.
|
||||
let inProgressPublicDownload =
|
||||
yield promiseNewDownload(httpUrl("interruptible.txt"));
|
||||
inProgressPublicDownload.start();
|
||||
yield promiseDownloadMidway(inProgressPublicDownload);
|
||||
publicList.add(inProgressPublicDownload);
|
||||
|
||||
// Add a private download that is in progress.
|
||||
let inProgressPrivateDownload = yield Downloads.createDownload({
|
||||
source: { url: httpUrl("interruptible.txt"), isPrivate: true },
|
||||
target: getTempFile(TEST_TARGET_FILE_NAME).path,
|
||||
});
|
||||
inProgressPrivateDownload.start();
|
||||
yield promiseDownloadMidway(inProgressPrivateDownload);
|
||||
privateList.add(inProgressPrivateDownload);
|
||||
|
||||
// Verify that the summary includes the total number of bytes and the
|
||||
// currently transferred bytes only for the downloads that are not stopped.
|
||||
// For simplicity, we assume that after a download is added to the list, its
|
||||
// current state is immediately propagated to the summary object, which is
|
||||
// true in the current implementation, though it is not guaranteed as all the
|
||||
// download operations may happen asynchronously.
|
||||
do_check_false(publicSummary.allHaveStopped);
|
||||
do_check_eq(publicSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
|
||||
do_check_eq(publicSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
|
||||
|
||||
do_check_false(privateSummary.allHaveStopped);
|
||||
do_check_eq(privateSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
|
||||
do_check_eq(privateSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
|
||||
|
||||
do_check_false(combinedSummary.allHaveStopped);
|
||||
do_check_eq(combinedSummary.progressTotalBytes, TEST_DATA_SHORT.length * 4);
|
||||
do_check_eq(combinedSummary.progressCurrentBytes, TEST_DATA_SHORT.length * 2);
|
||||
|
||||
yield inProgressPublicDownload.cancel();
|
||||
|
||||
// Stopping the download should have excluded it from the summary.
|
||||
do_check_true(publicSummary.allHaveStopped);
|
||||
do_check_eq(publicSummary.progressTotalBytes, 0);
|
||||
do_check_eq(publicSummary.progressCurrentBytes, 0);
|
||||
|
||||
do_check_false(privateSummary.allHaveStopped);
|
||||
do_check_eq(privateSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
|
||||
do_check_eq(privateSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
|
||||
|
||||
do_check_false(combinedSummary.allHaveStopped);
|
||||
do_check_eq(combinedSummary.progressTotalBytes, TEST_DATA_SHORT.length * 2);
|
||||
do_check_eq(combinedSummary.progressCurrentBytes, TEST_DATA_SHORT.length);
|
||||
|
||||
yield inProgressPrivateDownload.cancel();
|
||||
|
||||
// All the downloads should be stopped now.
|
||||
do_check_true(publicSummary.allHaveStopped);
|
||||
do_check_eq(publicSummary.progressTotalBytes, 0);
|
||||
do_check_eq(publicSummary.progressCurrentBytes, 0);
|
||||
|
||||
do_check_true(privateSummary.allHaveStopped);
|
||||
do_check_eq(privateSummary.progressTotalBytes, 0);
|
||||
do_check_eq(privateSummary.progressCurrentBytes, 0);
|
||||
|
||||
do_check_true(combinedSummary.allHaveStopped);
|
||||
do_check_eq(combinedSummary.progressTotalBytes, 0);
|
||||
do_check_eq(combinedSummary.progressCurrentBytes, 0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that views receive the summary change notification. This is tested on
|
||||
* the combined summary when adding a public download, as we assume that if we
|
||||
* pass the test in this case we will also pass it in the others.
|
||||
*/
|
||||
add_task(function test_DownloadSummary_notifications()
|
||||
{
|
||||
let list = yield promiseNewList();
|
||||
let summary = yield Downloads.getSummary(Downloads.ALL);
|
||||
|
||||
let download = yield promiseNewDownload();
|
||||
list.add(download);
|
||||
|
||||
// Check that we receive change notifications.
|
||||
let receivedOnSummaryChanged = false;
|
||||
summary.addView({
|
||||
onSummaryChanged: function () {
|
||||
receivedOnSummaryChanged = true;
|
||||
},
|
||||
});
|
||||
yield download.start();
|
||||
do_check_true(receivedOnSummaryChanged);
|
||||
});
|
||||
|
@ -118,26 +118,6 @@ add_task(function test_getList()
|
||||
do_check_neq(publicListOne, privateListOne);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that the getSummary function returns the same summary when called
|
||||
* multiple times with the same argument, but returns different summaries when
|
||||
* called with different arguments. More detailed tests are implemented
|
||||
* separately for the DownloadSummary object in the DownloadList module.
|
||||
*/
|
||||
add_task(function test_getSummary()
|
||||
{
|
||||
let publicSummaryOne = yield Downloads.getSummary(Downloads.PUBLIC);
|
||||
let privateSummaryOne = yield Downloads.getSummary(Downloads.PRIVATE);
|
||||
|
||||
let publicSummaryTwo = yield Downloads.getSummary(Downloads.PUBLIC);
|
||||
let privateSummaryTwo = yield Downloads.getSummary(Downloads.PRIVATE);
|
||||
|
||||
do_check_eq(publicSummaryOne, publicSummaryTwo);
|
||||
do_check_eq(privateSummaryOne, privateSummaryTwo);
|
||||
|
||||
do_check_neq(publicSummaryOne, privateSummaryOne);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that the getSystemDownloadsDirectory returns a valid nsFile
|
||||
* download directory object.
|
||||
|
@ -66,11 +66,6 @@ function injectController(doc, topic, data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we always handle window.close on social content, even if they are not
|
||||
// "enabled". "enabled" is about the worker state and a provider may
|
||||
// still be in e.g. the share panel without having their worker enabled.
|
||||
handleWindowClose(window);
|
||||
|
||||
SocialService.getProvider(doc.nodePrincipal.origin, function(provider) {
|
||||
if (provider && provider.enabled) {
|
||||
attachToWindow(provider, window);
|
||||
@ -219,9 +214,7 @@ function attachToWindow(provider, targetWindow) {
|
||||
schedule(function () { port.close(); });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleWindowClose(targetWindow) {
|
||||
// We allow window.close() to close the panel, so add an event handler for
|
||||
// this, then cancel the event (so the window itself doesn't die) and
|
||||
// close the panel instead.
|
||||
|
@ -40,12 +40,16 @@ var PREF_EM_CHECK_COMPATIBILITY;
|
||||
|
||||
const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
|
||||
const SHUTDOWN_EVENT = "profile-before-change";
|
||||
|
||||
const VALID_TYPES_REGEXP = /^[\w\-]+$/;
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
|
||||
"resource://gre/modules/AddonRepository.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "CertUtils", function certUtilsLazyGetter() {
|
||||
let certUtils = {};
|
||||
@ -453,8 +457,6 @@ var AddonManagerInternal = {
|
||||
|
||||
this.recordTimestamp("AMI_startup_begin");
|
||||
|
||||
Services.obs.addObserver(this, SHUTDOWN_EVENT, false);
|
||||
|
||||
let appChanged = undefined;
|
||||
|
||||
let oldAppVersion = null;
|
||||
@ -547,6 +549,10 @@ var AddonManagerInternal = {
|
||||
}
|
||||
}
|
||||
|
||||
// Register our shutdown handler with the AsyncShutdown manager
|
||||
AsyncShutdown.profileBeforeChange.addBlocker("AddonManager: shutting down providers",
|
||||
this.shutdown.bind(this));
|
||||
|
||||
// Once we start calling providers we must allow all normal methods to work.
|
||||
gStarted = true;
|
||||
|
||||
@ -678,13 +684,58 @@ var AddonManagerInternal = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls a method on all registered providers, if the provider implements
|
||||
* the method. The called method is expected to return a promise, and
|
||||
* callProvidersAsync returns a promise that resolves when every provider
|
||||
* method has either resolved or rejected. Rejection reasons are logged
|
||||
* but otherwise ignored. Return values are ignored. Any parameters after the
|
||||
* method parameter are passed to the provider's method.
|
||||
*
|
||||
* @param aMethod
|
||||
* The method name to call
|
||||
* @see callProvider
|
||||
*/
|
||||
callProvidersAsync: function AMI_callProviders(aMethod, ...aArgs) {
|
||||
if (!aMethod || typeof aMethod != "string")
|
||||
throw Components.Exception("aMethod must be a non-empty string",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
let allProviders = [];
|
||||
|
||||
let providers = this.providers.slice(0);
|
||||
for (let provider of providers) {
|
||||
try {
|
||||
if (aMethod in provider) {
|
||||
// Resolve a new promise with the result of the method, to handle both
|
||||
// methods that return values (or nothing) and methods that return promises.
|
||||
let providerResult = provider[aMethod].apply(provider, aArgs);
|
||||
let nextPromise = Promise.resolve(providerResult);
|
||||
// Log and swallow the errors from methods that do return promises.
|
||||
nextPromise = nextPromise.then(
|
||||
null,
|
||||
e => ERROR("Exception calling provider " + aMethod, e));
|
||||
allProviders.push(nextPromise);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
ERROR("Exception calling provider " + aMethod, e);
|
||||
}
|
||||
}
|
||||
// Because we use promise.then to catch and log all errors above, Promise.all()
|
||||
// will never exit early because of a rejection.
|
||||
return Promise.all(allProviders);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shuts down the addon manager and all registered providers, this must clean
|
||||
* up everything in order for automated tests to fake restarts.
|
||||
* @return Promise{null} that resolves when all providers and dependent modules
|
||||
* have finished shutting down
|
||||
*/
|
||||
shutdown: function AMI_shutdown() {
|
||||
LOG("shutdown");
|
||||
Services.obs.removeObserver(this, SHUTDOWN_EVENT);
|
||||
// Clean up listeners
|
||||
Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this);
|
||||
Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this);
|
||||
Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this);
|
||||
@ -692,19 +743,32 @@ var AddonManagerInternal = {
|
||||
Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this);
|
||||
Services.prefs.removeObserver(PREF_EM_HOTFIX_ID, this);
|
||||
|
||||
// Always clean up listeners, but only shutdown providers if they've been
|
||||
// started.
|
||||
if (gStarted)
|
||||
this.callProviders("shutdown");
|
||||
// Only shut down providers if they've been started. Shut down
|
||||
// AddonRepository after providers (if any).
|
||||
let shuttingDown = null;
|
||||
if (gStarted) {
|
||||
shuttingDown = this.callProvidersAsync("shutdown")
|
||||
.then(null,
|
||||
err => ERROR("Failure during async provider shutdown", err))
|
||||
.then(() => AddonRepository.shutdown());
|
||||
}
|
||||
else {
|
||||
shuttingDown = AddonRepository.shutdown();
|
||||
}
|
||||
|
||||
this.managerListeners.splice(0, this.managerListeners.length);
|
||||
this.installListeners.splice(0, this.installListeners.length);
|
||||
this.addonListeners.splice(0, this.addonListeners.length);
|
||||
this.typeListeners.splice(0, this.typeListeners.length);
|
||||
for (let type in this.startupChanges)
|
||||
delete this.startupChanges[type];
|
||||
gStarted = false;
|
||||
gStartupComplete = false;
|
||||
shuttingDown.then(val => LOG("Async provider shutdown done"),
|
||||
err => ERROR("Failure during AddonRepository shutdown", err))
|
||||
.then(() => {
|
||||
this.managerListeners.splice(0, this.managerListeners.length);
|
||||
this.installListeners.splice(0, this.installListeners.length);
|
||||
this.addonListeners.splice(0, this.addonListeners.length);
|
||||
this.typeListeners.splice(0, this.typeListeners.length);
|
||||
for (let type in this.startupChanges)
|
||||
delete this.startupChanges[type];
|
||||
gStarted = false;
|
||||
gStartupComplete = false;
|
||||
});
|
||||
return shuttingDown;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -713,11 +777,6 @@ var AddonManagerInternal = {
|
||||
* @see nsIObserver
|
||||
*/
|
||||
observe: function AMI_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == SHUTDOWN_EVENT) {
|
||||
this.shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aData) {
|
||||
case PREF_EM_CHECK_COMPATIBILITY: {
|
||||
let oldValue = gCheckCompatibility;
|
||||
@ -910,7 +969,6 @@ var AddonManagerInternal = {
|
||||
|
||||
if (this.updateEnabled) {
|
||||
let scope = {};
|
||||
Components.utils.import("resource://gre/modules/AddonRepository.jsm", scope);
|
||||
Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope);
|
||||
scope.LightweightThemeManager.updateCurrentTheme();
|
||||
|
||||
@ -921,7 +979,7 @@ var AddonManagerInternal = {
|
||||
|
||||
// Repopulate repository cache first, to ensure compatibility overrides
|
||||
// are up to date before checking for addon updates.
|
||||
scope.AddonRepository.backgroundUpdateCheck(
|
||||
AddonRepository.backgroundUpdateCheck(
|
||||
ids, function BUC_backgroundUpdateCheckCallback() {
|
||||
AddonManagerInternal.updateAddonRepositoryData(
|
||||
function BUC_updateAddonCallback() {
|
||||
@ -1144,7 +1202,7 @@ var AddonManagerInternal = {
|
||||
* An optional array of extra InstallListeners to also call
|
||||
* @return false if any of the listeners returned false, true otherwise
|
||||
*/
|
||||
callInstallListeners: function AMI_callInstallListeners(aMethod,
|
||||
callInstallListeners: function AMI_callInstallListeners(aMethod,
|
||||
aExtraListeners, ...aArgs) {
|
||||
if (!gStarted)
|
||||
throw Components.Exception("AddonManager is not initialized",
|
||||
@ -1248,7 +1306,7 @@ var AddonManagerInternal = {
|
||||
|
||||
this.callProviders("updateAddonAppDisabledStates");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Notifies all providers that the repository has updated its data for
|
||||
* installed add-ons.
|
||||
@ -1632,7 +1690,7 @@ var AddonManagerInternal = {
|
||||
if (!aListener || typeof aListener != "object")
|
||||
throw Components.Exception("aListener must be a InstallListener object",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
||||
if (!this.installListeners.some(function addInstallListener_matchListener(i) {
|
||||
return i == aListener; }))
|
||||
this.installListeners.push(aListener);
|
||||
@ -1763,7 +1821,7 @@ var AddonManagerInternal = {
|
||||
|
||||
new AsyncObjectCaller(aIDs, null, {
|
||||
nextObject: function getAddonsByIDs_nextObject(aCaller, aID) {
|
||||
AddonManagerInternal.getAddonByID(aID,
|
||||
AddonManagerInternal.getAddonByID(aID,
|
||||
function getAddonsByIDs_getAddonByID(aAddon) {
|
||||
addons.push(aAddon);
|
||||
aCaller.callNext();
|
||||
@ -2444,7 +2502,7 @@ this.AddonManager = {
|
||||
if (!aAddon || typeof aAddon != "object")
|
||||
throw Components.Exception("aAddon must be specified",
|
||||
Cr.NS_ERROR_INVALID_ARG);
|
||||
|
||||
|
||||
if (!("applyBackgroundUpdates" in aAddon))
|
||||
return false;
|
||||
if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE)
|
||||
|
@ -23,6 +23,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "DeferredSave",
|
||||
"resource://gre/modules/DeferredSave.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository_SQLiteMigrator",
|
||||
"resource://gre/modules/AddonRepository_SQLiteMigrator.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "AddonRepository" ];
|
||||
|
||||
@ -525,34 +527,17 @@ this.AddonRepository = {
|
||||
// Maximum number of results to return
|
||||
_maxResults: null,
|
||||
|
||||
/**
|
||||
* Initialize AddonRepository.
|
||||
*/
|
||||
initialize: function AddonRepo_initialize() {
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Observe xpcom-shutdown notification, so we can shutdown cleanly.
|
||||
*/
|
||||
observe: function AddonRepo_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "xpcom-shutdown") {
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
this.shutdown();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shut down AddonRepository
|
||||
* return: promise{integer} resolves with the result of flushing
|
||||
* the AddonRepository database
|
||||
*/
|
||||
shutdown: function AddonRepo_shutdown() {
|
||||
this.cancelSearch();
|
||||
|
||||
this._addons = null;
|
||||
this._pendingCallbacks = null;
|
||||
AddonDatabase.shutdown(function shutdown_databaseShutdown() {
|
||||
Services.obs.notifyObservers(null, "addon-repository-shutdown", null);
|
||||
});
|
||||
return AddonDatabase.shutdown(false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1514,7 +1499,6 @@ this.AddonRepository = {
|
||||
}
|
||||
|
||||
};
|
||||
AddonRepository.initialize();
|
||||
|
||||
var AddonDatabase = {
|
||||
// true if the database connection has been opened
|
||||
@ -1644,13 +1628,11 @@ var AddonDatabase = {
|
||||
* An optional boolean to skip flushing data to disk. Useful
|
||||
* when the database is going to be deleted afterwards.
|
||||
*/
|
||||
shutdown: function AD_shutdown(aCallback, aSkipFlush) {
|
||||
shutdown: function AD_shutdown(aSkipFlush) {
|
||||
this.databaseOk = true;
|
||||
aCallback = aCallback || function() {};
|
||||
|
||||
if (!this.initialized) {
|
||||
aCallback();
|
||||
return;
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
this.initialized = false;
|
||||
@ -1660,9 +1642,9 @@ var AddonDatabase = {
|
||||
});
|
||||
|
||||
if (aSkipFlush) {
|
||||
aCallback();
|
||||
return Promise.resolve(0);
|
||||
} else {
|
||||
this.Writer.flush().then(aCallback, aCallback);
|
||||
return this.Writer.flush();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1676,13 +1658,14 @@ var AddonDatabase = {
|
||||
delete: function AD_delete(aCallback) {
|
||||
this.DB = BLANK_DB();
|
||||
|
||||
this.Writer.flush().then(null, () => {}).then(() => {
|
||||
this.shutdown(() => {
|
||||
let promise = OS.File.remove(this.jsonFile.path, {});
|
||||
if (aCallback)
|
||||
promise.then(aCallback, aCallback);
|
||||
}, true);
|
||||
});
|
||||
this.Writer.flush()
|
||||
.then(null, () => {})
|
||||
// shutdown(true) never rejects
|
||||
.then(() => this.shutdown(true))
|
||||
.then(() => OS.File.remove(this.jsonFile.path, {}))
|
||||
.then(null, error => ERROR("Unable to delete Addon Repository file " +
|
||||
this.jsonFile.path, error))
|
||||
.then(aCallback);
|
||||
},
|
||||
|
||||
toJSON: function AD_toJSON() {
|
||||
|
@ -1685,6 +1685,8 @@ var XPIProvider = {
|
||||
this.installs = [];
|
||||
this.installLocations = [];
|
||||
this.installLocationsByName = {};
|
||||
// Hook for tests to detect when saving database at shutdown time fails
|
||||
this._shutdownError = null;
|
||||
|
||||
AddonManagerPrivate.recordTimestamp("XPI_startup_begin");
|
||||
|
||||
@ -1873,6 +1875,9 @@ var XPIProvider = {
|
||||
|
||||
/**
|
||||
* Shuts down the database and releases all references.
|
||||
* Return: Promise{integer} resolves / rejects with the result of
|
||||
* flushing the XPI Database if it was loaded,
|
||||
* 0 otherwise.
|
||||
*/
|
||||
shutdown: function XPI_shutdown() {
|
||||
LOG("shutdown");
|
||||
@ -1903,10 +1908,19 @@ var XPIProvider = {
|
||||
delete this._uriMappings;
|
||||
|
||||
if (gLazyObjectsLoaded) {
|
||||
XPIDatabase.shutdown(function shutdownCallback(saveError) {
|
||||
LOG("Notifying XPI shutdown observers");
|
||||
Services.obs.notifyObservers(null, "xpi-provider-shutdown", saveError);
|
||||
});
|
||||
let done = XPIDatabase.shutdown();
|
||||
done.then(
|
||||
ret => {
|
||||
LOG("Notifying XPI shutdown observers");
|
||||
Services.obs.notifyObservers(null, "xpi-provider-shutdown", null);
|
||||
},
|
||||
err => {
|
||||
LOG("Notifying XPI shutdown observers");
|
||||
this._shutdownError = err;
|
||||
Services.obs.notifyObservers(null, "xpi-provider-shutdown", err);
|
||||
}
|
||||
);
|
||||
return done;
|
||||
}
|
||||
else {
|
||||
LOG("Notifying XPI shutdown observers");
|
||||
@ -3190,6 +3204,9 @@ var XPIProvider = {
|
||||
// active state of add-ons but didn't commit them properly (normally due
|
||||
// to the application crashing)
|
||||
let hasPendingChanges = Prefs.getBoolPref(PREF_PENDING_OPERATIONS);
|
||||
if (hasPendingChanges) {
|
||||
updateReasons.push("hasPendingChanges");
|
||||
}
|
||||
|
||||
// If the schema appears to have changed then we should update the database
|
||||
if (DB_SCHEMA != Prefs.getIntPref(PREF_DB_SCHEMA, 0)) {
|
||||
@ -3249,9 +3266,6 @@ var XPIProvider = {
|
||||
let extensionListChanged = false;
|
||||
// If the database needs to be updated then open it and then update it
|
||||
// from the filesystem
|
||||
if (hasPendingChanges) {
|
||||
updateReasons.push("hasPendingChanges");
|
||||
}
|
||||
if (updateReasons.length > 0) {
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_load_reasons", updateReasons);
|
||||
XPIDatabase.syncLoadDB(false);
|
||||
|
@ -978,8 +978,11 @@ this.XPIDatabase = {
|
||||
|
||||
/**
|
||||
* Shuts down the database connection and releases all cached objects.
|
||||
* Return: Promise{integer} resolves / rejects with the result of the DB
|
||||
* flush after the database is flushed and
|
||||
* all cleanup is done
|
||||
*/
|
||||
shutdown: function XPIDB_shutdown(aCallback) {
|
||||
shutdown: function XPIDB_shutdown() {
|
||||
LOG("shutdown");
|
||||
if (this.initialized) {
|
||||
// If our last database I/O had an error, try one last time to save.
|
||||
@ -997,21 +1000,17 @@ this.XPIDatabase = {
|
||||
"XPIDB_saves_late", this._deferredSave.dirty ? 1 : 0);
|
||||
}
|
||||
|
||||
// Make sure any pending writes of the DB are complete, and we
|
||||
// finish cleaning up, and then call back
|
||||
this.flush()
|
||||
.then(null, error => {
|
||||
// Return a promise that any pending writes of the DB are complete and we
|
||||
// are finished cleaning up
|
||||
let flushPromise = this.flush();
|
||||
flushPromise.then(null, error => {
|
||||
ERROR("Flush of XPI database failed", error);
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_shutdownFlush_failed", 1);
|
||||
return 0;
|
||||
})
|
||||
.then(count => {
|
||||
// If our last attempt to read or write the DB failed, force a new
|
||||
// extensions.ini to be written to disk on the next startup
|
||||
let lastSaveFailed = this.lastError;
|
||||
if (lastSaveFailed)
|
||||
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true);
|
||||
|
||||
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true);
|
||||
})
|
||||
.then(count => {
|
||||
// Clear out the cached addons data loaded from JSON
|
||||
delete this.addonDB;
|
||||
delete this._dbPromise;
|
||||
@ -1019,15 +1018,10 @@ this.XPIDatabase = {
|
||||
delete this._deferredSave;
|
||||
// re-enable the schema version setter
|
||||
delete this._schemaVersionSet;
|
||||
|
||||
if (aCallback)
|
||||
aCallback(lastSaveFailed);
|
||||
});
|
||||
return flushPromise;
|
||||
}
|
||||
else {
|
||||
if (aCallback)
|
||||
aCallback(null);
|
||||
}
|
||||
return Promise.resolve(0);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1382,6 +1376,13 @@ this.XPIDatabase = {
|
||||
* Synchronously calculates and updates all the active flags in the database.
|
||||
*/
|
||||
updateActiveAddons: function XPIDB_updateActiveAddons() {
|
||||
if (!this.addonDB) {
|
||||
WARN("updateActiveAddons called when DB isn't loaded");
|
||||
// force the DB to load
|
||||
AddonManagerPrivate.recordSimpleMeasure("XPIDB_lateOpen_updateActive",
|
||||
XPIProvider.runPhase);
|
||||
this.syncLoadDB(true);
|
||||
}
|
||||
LOG("Updating add-on states");
|
||||
for (let [, addon] of this.addonDB) {
|
||||
let newActive = (addon.visible && !addon.userDisabled &&
|
||||
|
@ -400,29 +400,16 @@ function shutdownManager() {
|
||||
if (!gInternalManager)
|
||||
return;
|
||||
|
||||
let xpiShutdown = false;
|
||||
Services.obs.addObserver({
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
xpiShutdown = true;
|
||||
gXPISaveError = aData;
|
||||
Services.obs.removeObserver(this, "xpi-provider-shutdown");
|
||||
}
|
||||
}, "xpi-provider-shutdown", false);
|
||||
|
||||
let repositoryShutdown = false;
|
||||
Services.obs.addObserver({
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
repositoryShutdown = true;
|
||||
Services.obs.removeObserver(this, "addon-repository-shutdown");
|
||||
}
|
||||
}, "addon-repository-shutdown", false);
|
||||
let shutdownDone = false;
|
||||
|
||||
Services.obs.notifyObservers(null, "quit-application-granted", null);
|
||||
let scope = Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||
scope.AddonManagerInternal.shutdown();
|
||||
gInternalManager = null;
|
||||
scope.AddonManagerInternal.shutdown()
|
||||
.then(
|
||||
() => shutdownDone = true,
|
||||
err => shutdownDone = true);
|
||||
|
||||
AddonRepository.shutdown();
|
||||
gInternalManager = null;
|
||||
|
||||
// Load the add-ons list as it was after application shutdown
|
||||
loadAddonsList();
|
||||
@ -433,13 +420,16 @@ function shutdownManager() {
|
||||
let thr = Services.tm.mainThread;
|
||||
|
||||
// Wait until we observe the shutdown notifications
|
||||
while (!repositoryShutdown || !xpiShutdown) {
|
||||
while (!shutdownDone) {
|
||||
thr.processNextEvent(true);
|
||||
}
|
||||
|
||||
// Force the XPIProvider provider to reload to better
|
||||
// simulate real-world usage.
|
||||
scope = Components.utils.import("resource://gre/modules/XPIProvider.jsm");
|
||||
// This would be cleaner if I could get it as the rejection reason from
|
||||
// the AddonManagerInternal.shutdown() promise
|
||||
gXPISaveError = scope.XPIProvider._shutdownError;
|
||||
AddonManagerPrivate.unregisterProvider(scope.XPIProvider);
|
||||
Components.utils.unload("resource://gre/modules/XPIProvider.jsm");
|
||||
}
|
||||
|
@ -78,40 +78,6 @@ function run_test() {
|
||||
db.schemaVersion = 1;
|
||||
db.close();
|
||||
|
||||
Services.obs.addObserver({
|
||||
observe: function () {
|
||||
Services.obs.removeObserver(this, "addon-repository-shutdown");
|
||||
// Check the DB schema has changed once AddonRepository has freed it.
|
||||
db = AM_Cc["@mozilla.org/storage/service;1"].
|
||||
getService(AM_Ci.mozIStorageService).
|
||||
openDatabase(dbfile);
|
||||
do_check_eq(db.schemaVersion, EXPECTED_SCHEMA_VERSION);
|
||||
do_check_true(db.indexExists("developer_idx"));
|
||||
do_check_true(db.indexExists("screenshot_idx"));
|
||||
do_check_true(db.indexExists("compatibility_override_idx"));
|
||||
do_check_true(db.tableExists("compatibility_override"));
|
||||
do_check_true(db.indexExists("icon_idx"));
|
||||
do_check_true(db.tableExists("icon"));
|
||||
|
||||
// Check the trigger is working
|
||||
db.executeSimpleSQL("INSERT INTO addon (id, type, name) VALUES('test_addon', 'extension', 'Test Addon')");
|
||||
let internalID = db.lastInsertRowID;
|
||||
db.executeSimpleSQL("INSERT INTO compatibility_override (addon_internal_id, num, type) VALUES('" + internalID + "', '1', 'incompatible')");
|
||||
|
||||
let stmt = db.createStatement("SELECT COUNT(*) AS count FROM compatibility_override");
|
||||
stmt.executeStep();
|
||||
do_check_eq(stmt.row.count, 1);
|
||||
stmt.reset();
|
||||
|
||||
db.executeSimpleSQL("DELETE FROM addon");
|
||||
stmt.executeStep();
|
||||
do_check_eq(stmt.row.count, 0);
|
||||
stmt.finalize();
|
||||
|
||||
db.close();
|
||||
do_test_finished();
|
||||
}
|
||||
}, "addon-repository-shutdown", null);
|
||||
|
||||
Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", true);
|
||||
AddonRepository.getCachedAddonByID("test1@tests.mozilla.org", function (aAddon) {
|
||||
@ -123,6 +89,39 @@ function run_test() {
|
||||
do_check_true(aAddon.screenshots[0].thumbnailHeight === null);
|
||||
do_check_eq(aAddon.iconURL, undefined);
|
||||
do_check_eq(JSON.stringify(aAddon.icons), "{}");
|
||||
AddonRepository.shutdown();
|
||||
AddonRepository.shutdown().then(
|
||||
function checkAfterRepoShutdown() {
|
||||
// Check the DB schema has changed once AddonRepository has freed it.
|
||||
db = AM_Cc["@mozilla.org/storage/service;1"].
|
||||
getService(AM_Ci.mozIStorageService).
|
||||
openDatabase(dbfile);
|
||||
do_check_eq(db.schemaVersion, EXPECTED_SCHEMA_VERSION);
|
||||
do_check_true(db.indexExists("developer_idx"));
|
||||
do_check_true(db.indexExists("screenshot_idx"));
|
||||
do_check_true(db.indexExists("compatibility_override_idx"));
|
||||
do_check_true(db.tableExists("compatibility_override"));
|
||||
do_check_true(db.indexExists("icon_idx"));
|
||||
do_check_true(db.tableExists("icon"));
|
||||
|
||||
// Check the trigger is working
|
||||
db.executeSimpleSQL("INSERT INTO addon (id, type, name) VALUES('test_addon', 'extension', 'Test Addon')");
|
||||
let internalID = db.lastInsertRowID;
|
||||
db.executeSimpleSQL("INSERT INTO compatibility_override (addon_internal_id, num, type) VALUES('" + internalID + "', '1', 'incompatible')");
|
||||
|
||||
let stmt = db.createStatement("SELECT COUNT(*) AS count FROM compatibility_override");
|
||||
stmt.executeStep();
|
||||
do_check_eq(stmt.row.count, 1);
|
||||
stmt.reset();
|
||||
|
||||
db.executeSimpleSQL("DELETE FROM addon");
|
||||
stmt.executeStep();
|
||||
do_check_eq(stmt.row.count, 0);
|
||||
stmt.finalize();
|
||||
|
||||
db.close();
|
||||
do_test_finished();
|
||||
},
|
||||
do_report_unexpected_exception
|
||||
);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user