merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2013-08-12 11:37:21 +02:00
Родитель ec5b5b31a1 b9e01e20d4
Коммит 33286db4be
144 изменённых файлов: 3163 добавлений и 3284 удалений

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

@ -1,4 +1,4 @@
{
"revision": "0e3e30e489ff38cceb8b9cf9ee5caea5fb072457",
"revision": "cc6b6bcc278e02d1e23c78cc41fcc21c074a82db",
"repo_path": "/integration/gaia-central"
}

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

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1375219877000">
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1376092730000">
<emItems>
<emItem blockID="i350" id="sqlmoz@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
@ -55,8 +55,8 @@
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i6" id="{3f963a5b-e555-4543-90e2-c3908898db71}">
<versionRange minVersion=" " maxVersion="8.5">
<emItem blockID="i440" id="{2d069a16-fca1-4e81-81ea-5d5086dcbd0c}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i392" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
@ -84,10 +84,18 @@
<versionRange minVersion="3.4.1" maxVersion="3.4.1.194" severity="1">
</versionRange>
</emItem>
<emItem blockID="i433" id="{c95a4e8e-816d-4655-8c79-d736da1adb6d}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
<versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1">
</versionRange>
</emItem>
<emItem blockID="i430" id="1chtw@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i78" id="socialnetworktools@mozilla.doslash.org">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -127,6 +135,10 @@
<versionRange minVersion=" " maxVersion="1.0.0.5">
</versionRange>
</emItem>
<emItem blockID="i436" id="/(\{7aeae561-714b-45f6-ace3-4a8aed6e227b\})|(\{01e86e69-a2f8-48a0-b068-83869bdba3d0\})|(\{77f5fe49-12e3-4cf5-abb4-d993a0164d9e\})/">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i97" id="support3_en@adobe122.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -158,6 +170,10 @@
<versionRange minVersion="1.1b1" maxVersion="1.1b1">
</versionRange>
</emItem>
<emItem blockID="i438" id="{02edb56b-9b33-435b-b7df-b2843273a694}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i111" os="WINNT" id="{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}">
<versionRange minVersion="0" maxVersion="15.0.5" severity="1">
</versionRange>
@ -204,6 +220,10 @@
<versionRange minVersion="4.2" maxVersion="4.2" severity="3">
</versionRange>
</emItem>
<emItem blockID="i306" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE10}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i63" id="youtube@youtuber.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -409,7 +429,7 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i262" id="{167d9323-f7cc-48f5-948a-6f012831a69f}">
<emItem blockID="i432" id="lugcla21@gmail.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
@ -417,10 +437,18 @@
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i435" id="pluggets@gmail.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i67" id="youtube2@youtube2.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i6" id="{3f963a5b-e555-4543-90e2-c3908898db71}">
<versionRange minVersion=" " maxVersion="8.5">
</versionRange>
</emItem>
<emItem blockID="i56" id="flash@adobe.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -514,6 +542,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i431" id="chinaescapeone@facebook.com">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i312" id="extension21804@extension21804.com">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
@ -530,6 +562,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i262" id="{167d9323-f7cc-48f5-948a-6f012831a69f}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i61" id="youtube@youtube3.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -548,6 +584,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i439" id="{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i346" id="{a6e67e6f-8615-4fe0-a599-34a73fc3fba5}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
@ -572,8 +612,8 @@
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i306" id="{ADFA33FD-16F5-4355-8504-DF4D664CFE10}">
<versionRange minVersion="0" maxVersion="*" severity="1">
<emItem blockID="i437" id="{4933189D-C7F7-4C6E-834B-A29F087BFD23}">
<versionRange minVersion="0" maxVersion="*" severity="3">
</versionRange>
</emItem>
<emItem blockID="i165" id="{EEF73632-A085-4fd3-A778-ECD82C8CB297}">
@ -595,6 +635,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i434" id="afurladvisor@anchorfree.com">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i90" id="videoplugin@player.com">
<versionRange minVersion="0" maxVersion="*">
</versionRange>
@ -603,6 +647,10 @@
<versionRange minVersion="0" maxVersion="*">
</versionRange>
</emItem>
<emItem blockID="i441" id="{49c53dce-afa0-49a1-a08b-2eb8e8444128}">
<versionRange minVersion="0" maxVersion="*" severity="1">
</versionRange>
</emItem>
<emItem blockID="i282" id="{33e0daa6-3af3-d8b5-6752-10e949c61516}">
<versionRange minVersion="0" maxVersion="1.1.999" severity="1">
</versionRange>

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = [ "DocumentUtils" ];
const Cu = Components.utils;

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["SessionMigration"];
const Cu = Components.utils;

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["SessionStorage"];
const Cu = Components.utils;

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["SessionStore"];
const Cu = Components.utils;
@ -304,10 +306,6 @@ let SessionStoreInternal = {
// states for all currently opened windows
_windows: {},
// internal states for all open windows (data we need to associate,
// but not write to disk)
_internalWindows: {},
// states for all recently closed windows
_closedWindows: [],
@ -719,9 +717,6 @@ let SessionStoreInternal = {
// and create its data object
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
// and create its internal data object
this._internalWindows[aWindow.__SSi] = { hosts: {} }
let isPrivateWindow = false;
if (PrivateBrowsingUtils.isWindowPrivate(aWindow))
this._windows[aWindow.__SSi].isPrivate = isPrivateWindow = true;
@ -875,12 +870,12 @@ let SessionStoreInternal = {
* Window reference
*/
onOpen: function ssi_onOpen(aWindow) {
var _this = this;
aWindow.addEventListener("load", function(aEvent) {
aEvent.currentTarget.removeEventListener("load", arguments.callee, false);
_this.onLoad(aEvent.currentTarget);
}, false);
return;
let onload = () => {
aWindow.removeEventListener("load", onload);
this.onLoad(aWindow);
};
aWindow.addEventListener("load", onload);
},
/**
@ -935,9 +930,7 @@ let SessionStoreInternal = {
winData.title = aWindow.content.document.title || tabbrowser.selectedTab.label;
winData.title = this._replaceLoadingTitle(winData.title, tabbrowser,
tabbrowser.selectedTab);
let windows = {};
windows[aWindow.__SSi] = winData;
this._updateCookies(windows);
this._updateCookies([winData]);
}
#ifndef XP_MACOSX
@ -959,7 +952,6 @@ let SessionStoreInternal = {
// clear this window from the list
delete this._windows[aWindow.__SSi];
delete this._internalWindows[aWindow.__SSi];
// save the state without this window to disk
this.saveStateDelayed();
@ -1055,20 +1047,17 @@ let SessionStoreInternal = {
delete aTab.linkedBrowser.__SS_data;
delete aTab.linkedBrowser.__SS_tabStillLoading;
delete aTab.linkedBrowser.__SS_formDataSaved;
delete aTab.linkedBrowser.__SS_hostSchemeData;
if (aTab.linkedBrowser.__SS_restoreState)
this._resetTabRestoringState(aTab);
});
}, this);
openWindows[aWindow.__SSi] = true;
});
// also clear all data about closed tabs and windows
for (let ix in this._windows) {
if (ix in openWindows) {
this._windows[ix]._closedTabs = [];
}
else {
} else {
delete this._windows[ix];
delete this._internalWindows[ix];
}
}
// also clear all data about closed windows
@ -1079,9 +1068,6 @@ let SessionStoreInternal = {
win.setTimeout(function() { _this.saveState(true); }, 0);
else if (this._loadState == STATE_RUNNING)
this.saveState(true);
// Delete the private browsing backed up state, if any
if ("_stateBackup" in this)
delete this._stateBackup;
this._clearRestoringWindows();
},
@ -1225,7 +1211,6 @@ let SessionStoreInternal = {
delete browser.__SS_data;
delete browser.__SS_tabStillLoading;
delete browser.__SS_formDataSaved;
delete browser.__SS_hostSchemeData;
// If this tab was in the middle of restoring or still needs to be restored,
// we need to reset that state. If the tab was restoring, we will attempt to
@ -1981,11 +1966,10 @@ let SessionStoreInternal = {
tabData.index = history.index + 1;
}
else if (history && history.count > 0) {
browser.__SS_hostSchemeData = [];
try {
for (var j = 0; j < history.count; j++) {
let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false),
includePrivateData, aTab.pinned, browser.__SS_hostSchemeData);
includePrivateData, aTab.pinned);
tabData.entries.push(entry);
}
// If we make it through the for loop, then we're ok and we should clear
@ -2077,23 +2061,12 @@ let SessionStoreInternal = {
* always return privacy sensitive data (use with care)
* @param aIsPinned
* the tab is pinned and should be treated differently for privacy
* @param aHostSchemeData
* an array of objects with host & scheme keys
* @returns object
*/
_serializeHistoryEntry:
function ssi_serializeHistoryEntry(aEntry, aIncludePrivateData, aIsPinned, aHostSchemeData) {
function ssi_serializeHistoryEntry(aEntry, aIncludePrivateData, aIsPinned) {
var entry = { url: aEntry.URI.spec };
try {
// throwing is expensive, we know that about: pages will throw
if (entry.url.indexOf("about:") != 0)
aHostSchemeData.push({ host: aEntry.URI.host, scheme: aEntry.URI.scheme });
}
catch (ex) {
// We just won't attempt to get cookies for this entry.
}
if (aEntry.title && aEntry.title != entry.url) {
entry.title = aEntry.title;
}
@ -2204,7 +2177,7 @@ let SessionStoreInternal = {
}
children.push(this._serializeHistoryEntry(child, aIncludePrivateData,
aIsPinned, aHostSchemeData));
aIsPinned));
}
}
@ -2425,8 +2398,8 @@ let SessionStoreInternal = {
/**
* Serialize cookie data
* @param aWindows
* JS object containing window data references
* { id: winData, etc. }
* An array of window data objects
* { tabs: [ ... ], etc. }
*/
_updateCookies: function ssi_updateCookies(aWindows) {
function addCookieToHash(aHash, aHost, aPath, aName, aCookie) {
@ -2444,12 +2417,18 @@ let SessionStoreInternal = {
// MAX_EXPIRY should be 2^63-1, but JavaScript can't handle that precision
var MAX_EXPIRY = Math.pow(2, 62);
for (let [id, window] in Iterator(aWindows)) {
for (let window of aWindows) {
window.cookies = [];
let internalWindow = this._internalWindows[id];
if (!internalWindow.hosts)
return;
for (var [host, isPinned] in Iterator(internalWindow.hosts)) {
// Collect all hosts for the current window.
let hosts = {};
window.tabs.forEach(function(tab) {
tab.entries.forEach(function(entry) {
this._extractHostsForCookiesFromEntry(entry, hosts, true, tab.pinned);
}, this);
}, this);
for (var [host, isPinned] in Iterator(hosts)) {
let list;
try {
list = Services.cookies.getCookiesFromHost(host);
@ -2542,20 +2521,24 @@ let SessionStoreInternal = {
DirtyWindows.clear();
}
// collect the data for all windows
var total = [], windows = {}, ids = [];
// An array that at the end will hold all current window data.
var total = [];
// The ids of all windows contained in 'total' in the same order.
var ids = [];
// The number of window that are _not_ popups.
var nonPopupCount = 0;
var ix;
// collect the data for all windows
for (ix in this._windows) {
if (this._windows[ix]._restoring) // window data is still in _statesToRestore
continue;
total.push(this._windows[ix]);
ids.push(ix);
windows[ix] = this._windows[ix];
if (!this._windows[ix].isPopup)
nonPopupCount++;
}
this._updateCookies(windows);
this._updateCookies(total);
// collect the data for all windows yet to be restored
for (ix in this._statesToRestore) {
@ -2627,12 +2610,10 @@ let SessionStoreInternal = {
this._collectWindowData(aWindow);
}
var winData = this._windows[aWindow.__SSi];
let windows = {};
windows[aWindow.__SSi] = winData;
let windows = [this._windows[aWindow.__SSi]];
this._updateCookies(windows);
return { windows: [winData] };
return { windows: windows };
},
_collectWindowData: function ssi_collectWindowData(aWindow) {
@ -2643,22 +2624,10 @@ let SessionStoreInternal = {
let tabs = tabbrowser.tabs;
let winData = this._windows[aWindow.__SSi];
let tabsData = winData.tabs = [];
let hosts = this._internalWindows[aWindow.__SSi].hosts = {};
// update the internal state data for this window
for (let tab of tabs) {
tabsData.push(this._collectTabData(tab));
// Since we are only ever called for open
// windows during a session, we can call into
// _extractHostsForCookiesFromHostScheme directly using data
// that is attached to each browser.
let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || [];
for (let j = 0; j < hostSchemeData.length; j++) {
this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host,
hostSchemeData[j].scheme,
hosts, true, tab.pinned);
}
}
winData.selected = tabbrowser.mTabBox.selectedIndex + 1;

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["XPathGenerator"];
this.XPathGenerator = {

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
/**
* Session Storage and Restoration
*

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

@ -2,6 +2,8 @@
* 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/. */
"use strict";
/**
* Session Storage and Restoration
*

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

@ -37,8 +37,9 @@ var ContextCommands = {
cut: function cc_cut() {
let target = ContextMenuUI.popupState.target;
if (!target)
if (!target) {
return;
}
if (target.localName === "browser") {
// content
@ -49,7 +50,7 @@ var ContextCommands = {
}
} else {
// chrome
target.editor.cut();
CommandUpdater.doCommand("cmd_cut");
}
target.focus();
@ -58,8 +59,9 @@ var ContextCommands = {
copy: function cc_copy() {
let target = ContextMenuUI.popupState.target;
if (!target)
if (!target) {
return;
}
if (target.localName == "browser") {
// content
@ -72,7 +74,7 @@ var ContextCommands = {
this.clipboard.copyString(ContextMenuUI.popupState.string, this.docRef);
} else {
// chrome
target.editor.copy();
CommandUpdater.doCommand("cmd_copy");
}
target.focus();
@ -80,6 +82,11 @@ var ContextCommands = {
paste: function cc_paste() {
let target = ContextMenuUI.popupState.target;
if (!target) {
return;
}
if (target.localName == "browser") {
// content
let x = ContextMenuUI.popupState.x;
@ -89,7 +96,7 @@ var ContextCommands = {
SelectionHelperUI.closeEditSession();
} else {
// chrome
target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
CommandUpdater.doCommand("cmd_paste");
target.focus();
}
},

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

@ -260,10 +260,6 @@
if (selectionStart != selectionEnd) {
json.types.push("cut");
json.types.push("copy");
json.string = aTextbox.value.slice(selectionStart, selectionEnd);
} else if (aTextbox.value) {
json.types.push("copy-all");
json.string = aTextbox.value;
}
if (selectionStart > 0 || selectionEnd < aTextbox.textLength)

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

@ -800,7 +800,7 @@
<content>
<html:div anonid="anon-tile" class="tile-content" xbl:inherits="customImage">
<html:div class="tile-start-container" xbl:inherits="customImage">
<html:div class="tile-icon-box"><xul:image anonid="anon-tile-icon" xbl:inherits="src=iconURI"/></html:div>
<html:div class="tile-icon-box" anonid="anon-tile-icon-box"><xul:image anonid="anon-tile-icon" xbl:inherits="src=iconURI"/></html:div>
</html:div>
<html:div anonid="anon-tile-label" class="tile-desc" xbl:inherits="xbl:text=label"/>
</html:div>
@ -817,6 +817,7 @@
<property name="_textbox" onget="return document.getAnonymousElementByAttribute(this, 'class', 'tile-desc');"/>
<property name="_top" onget="return document.getAnonymousElementByAttribute(this, 'class', 'tile-start-container');"/>
<property name="_icon" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'anon-tile-icon');"/>
<property name="_iconBox" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'anon-tile-icon-box');"/>
<property name="_label" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'anon-tile-label');"/>
<property name="iconSrc"
onset="this._icon.src = val; this.setAttribute('iconURI', val);"
@ -876,9 +877,21 @@
if (val) {
this.setAttribute("customColor", val);
this._contentBox.style.backgroundColor = val;
// overridden in tiles.css for non-thumbnail types
this._label.style.backgroundColor = val.replace(/rgb\(([^\)]+)\)/, 'rgba($1, 0.8)');
// Small icons get a border+background-color treatment.
// See tiles.css for large icon overrides
this._iconBox.style.borderColor = val.replace(/rgb\(([^\)]+)\)/, 'rgba($1, 0.6)');
this._iconBox.style.backgroundColor = this.hasAttribute("tintColor") ?
this.getAttribute("tintColor") : "#fff";
} else {
this.removeAttribute("customColor");
this._contentBox.style.removeProperty("background-color");
this._label.style.removeProperty("background-color");
this._iconBox.style.removeProperty("border-color");
this._iconBox.style.removeProperty("background-color");
}
]]></setter>
</property>

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

@ -157,7 +157,7 @@
<![CDATA[
// Grab the actual input field's value, not our value, which could include moz-action:
let inputVal = this.inputField.value;
let selectedVal = inputVal.substring(this.selectionStart, this.electionEnd);
let selectedVal = inputVal.substring(this.selectionStart, this.selectionEnd);
// If the selection doesn't start at the beginning or doesn't span the full domain or
// the URL bar is modified, nothing else to do here.
@ -485,14 +485,17 @@
<binding id="urlbar-autocomplete">
<content orient="horizontal">
<xul:vbox id="results-vbox" flex="1">
<xul:label class="meta-section-title" value="&autocompleteResultsHeader.label;"/>
<richgrid id="results-richgrid" rows="3" deferlayout="true" anonid="results" seltype="single" flex="1"/>
<xul:vbox id="results-vbox" anonid="results-container" flex="1">
<xul:label class="meta-section-title"
value="&autocompleteResultsHeader.label;"/>
<richgrid id="results-richgrid" anonid="results" rows="3" flex="1"
seltype="single" deferlayout="true"/>
</xul:vbox>
<xul:vbox id="searches-vbox" flex="1">
<xul:label class="meta-section-title" value="&autocompleteSearchesHeader.label;"/>
<richgrid id="searches-richgrid" rows="3" deferlayout="true" anonid="searches" seltype="single" flex="1"/>
<xul:label anonid="searches-header" class="meta-section-title"/>
<richgrid id="searches-richgrid" anonid="searches" rows="3" flex="1"
seltype="single" deferlayout="true"/>
</xul:vbox>
</content>
@ -590,7 +593,11 @@
<!-- Updating grid content -->
<field name="_grid">null</field>
<field name="_results" readonly="true">document.getAnonymousElementByAttribute(this, 'anonid', 'results');</field>
<field name="_resultsContainer" readonly="true">document.getAnonymousElementByAttribute(this, 'anonid', 'results-container');</field>
<field name="_searchesHeader" readonly="true">document.getAnonymousElementByAttribute(this, 'anonid', 'searches-header');</field>
<field name="_searches" readonly="true">document.getAnonymousElementByAttribute(this, 'anonid', 'searches');</field>
<property name="_otherGrid" readonly="true">
@ -620,7 +627,7 @@
return;
this.updateResults();
this.updateSearchEngineSubtitles();
this.updateSearchEngineHeader();
]]>
</body>
</method>
@ -636,6 +643,13 @@
if (!this.input)
return;
let haveNoResults = (this.matchCount == 0);
this._resultsContainer.hidden = haveNoResults;
if (haveNoResults) {
return;
}
let controller = this.input.controller;
let lastMatch = this.matchCount - 1;
let iterCount = Math.max(this._results.itemCount, this.matchCount);
@ -706,20 +720,17 @@
</body>
</method>
<method name="updateSearchEngineSubtitles">
<method name="updateSearchEngineHeader">
<body>
<![CDATA[
if (!this._isGridBound(this._searches))
return;
let searchString = this.input.controller.searchString;
let label = Strings.browser.formatStringFromName("opensearch.search", [searchString], 1);
let label = Strings.browser.formatStringFromName(
"opensearch.search.header", [searchString], 1);
for (let i = 0, len = this._searches.itemCount; i < len; i++) {
let item = this._searches.getItemAtIndex(i);
item.setAttribute("label", label);
item.refresh && item.refresh();
}
this._searchesHeader.value = label;
]]>
</body>
</method>

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

@ -109,7 +109,7 @@ HistoryView.prototype = Util.extend(Object.create(View.prototype), {
_setContextActions: function bv__setContextActions(aItem) {
let uri = aItem.getAttribute("value");
aItem.setAttribute("data-contextactions", "delete," + (this._pinHelper.isPinned(uri) ? "unpin" : "pin"));
if (aItem.refresh) aItem.refresh();
if ("refresh" in aItem) aItem.refresh();
},
_sendNeedsRefresh: function bv__sendNeedsRefresh(){
@ -273,6 +273,8 @@ HistoryView.prototype = Util.extend(Object.create(View.prototype), {
let currIcon = item.getAttribute("iconURI");
if (currIcon != aValue) {
item.setAttribute("iconURI", aValue);
if("refresh" in item)
item.refresh();
}
}
}

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

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function test() {
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);

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

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function test() {
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);

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

@ -6,6 +6,8 @@
* TestEchoReceiver - receives json data, reserializes it and send it back.
*/
"use strict";
var TestEchoReceiver = {
init: function init() {
addMessageListener("Test:EchoRequest", this);

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

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Misc. constants
const kInfoHeader = "PERF-TEST | ";
const kDeclareId = "DECLARE ";

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

@ -134,6 +134,37 @@ gTests.push({
}
});
function getClipboardCondition(aExpected) {
return () => aExpected == SpecialPowers.getClipboardData("text/unicode");
}
gTests.push({
desc: "bug 894715 - URLs selected by touch are copied with trimming",
run: function () {
gWindow = window;
yield showNavBar();
let edit = document.getElementById("urlbar-edit");
edit.value = "http://www.wikipedia.org/";
sendElementTap(window, edit);
edit.select();
let panel = ContextMenuUI._menuPopup._panel;
let promise = waitForEvent(panel, "popupshown")
sendContextMenuClickToElement(window, edit);
ok((yield promise), "show context menu");
let copy = document.getElementById("context-copy");
ok(!copy.hidden, "copy menu item is visible")
let condition = getClipboardCondition("http://www.wikipedia.org/");
let promise = waitForCondition(condition);
sendElementTap(window, copy);
ok((yield promise), "copy text onto clipboard")
}
})
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");

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

@ -1,3 +1,5 @@
"use strict";
load('Util.js');
function run_test() {

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

@ -13,7 +13,6 @@
<!ENTITY closetab.label "Close Tab">
<!ENTITY autocompleteResultsHeader.label "Your Results">
<!ENTITY autocompleteSearchesHeader.label "Internet Searches">
<!ENTITY appbarErrorConsole.label "Open error console">
<!ENTITY appbarJSShell.label "Open JavaScript shell">

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

@ -128,8 +128,9 @@ indexedDBQuota.wantsTo=%S wants to store a lot of data on your device for offlin
tabs.emptyTabTitle=New Tab
# Open Search
# LOCALIZATION NOTE (opensearch.search): %S is the word or phrase typed by the user
opensearch.search=Search: %S
# LOCALIZATION NOTE (opensearch.search.header): %S is the word or phrase
# typed by the user in the urlbar to search
opensearch.search.header=Search for “%S” on:
# Check for Updates in the About Panel - button labels and accesskeys
# LOCALIZATION NOTE - all of the following update buttons labels will only be

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

@ -58,6 +58,13 @@ View.prototype = {
let successAction = function(foreground, background) {
aItem.style.color = foreground; //color text
aItem.setAttribute("customColor", background);
let matteColor = 0xffffff; // white
let alpha = 0.04; // the tint weight
let [,r,g,b] = background.match(/rgb\((\d+),(\d+),(\d+)/);
// get the rgb value that represents this color at given opacity over a white matte
let tintColor = ColorUtils.addRgbColors(matteColor, ColorUtils.createDecimalColorWord(r,g,b,alpha));
aItem.setAttribute("tintColor", ColorUtils.convertDecimalToRgbColor(tintColor));
if (aItem.refresh) {
aItem.refresh();
}

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

@ -449,7 +449,7 @@ documenttab[selected] .documenttab-selection {
}
.circularprogressindicator-progressRing {
margin: 0 @toolbar_horizontal_spacing@;
margin: -2px 18px;
pointer-events:none;
position: absolute;
}

Двоичные данные
browser/metro/theme/images/progresscircle.png

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

До

Ширина:  |  Высота:  |  Размер: 363 B

После

Ширина:  |  Высота:  |  Размер: 363 B

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

@ -577,7 +577,6 @@ arrowbox {
.meta-section-title {
font-size: @metro_font_large@;
font-weight: 100;
display: none;
cursor: default;
}
@ -591,9 +590,9 @@ arrowbox {
padding: 0;
}
#start-container[viewstate="snapped"] .meta-section-title.narrow-title,
#start-container:not([viewstate="snapped"]) .meta-section-title.wide-title {
display: block;
#start-container:not([viewstate="snapped"]) .meta-section-title.narrow-title,
#start-container[viewstate="snapped"] .meta-section-title.wide-title {
display: none;
}
.meta-section:not([expanded]) > .meta-section-title.narrow-title:-moz-locale-dir(ltr):after {

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

@ -62,7 +62,9 @@ richgriditem {
.tile-content {
display: block;
position: absolute;
background-color: #fff;
/* background-color colors the tile-edge,
and will normally be overridden with a favicon-based color */
background-color: #ccc;
background-origin: padding-box;
/* content positioning within the grid "cell"
gives us the gutters/spacing between tiles */
@ -77,9 +79,9 @@ richgriditem {
top: 0;
bottom: 0;
right: 0;
left: 20px;
background: hsla(0,2%,98%,.95);
left: 10px;
padding: 8px;
background-color: #fff;
}
richgriditem:not([tiletype="thumbnail"]) .tile-start-container {
@ -87,36 +89,61 @@ richgriditem:not([tiletype="thumbnail"]) .tile-start-container {
}
.tile-icon-box {
display: inline-block;
padding: 4px;
background: #fff;
position: absolute;
top: 50%;
margin-top: -17px;
padding: 8px;
/* default color, may be overriden by a favicon-based color */
background-color: white;
border: 1px solid #ccc;
border-radius: 1px;
opacity: 1.0;
}
.tile-icon-box > image {
display: block;
width: 16px;
height: 16px;
list-style-image: url("chrome://browser/skin/images/identity-icons-generic.png");
}
/* for larger favicons (which includes the fallback icon) */
richgriditem:not([iconURI]) .tile-icon-box,
richgriditem[iconURI=""] .tile-icon-box,
richgriditem[iconsize="large"] .tile-icon-box {
background-color: transparent!important;
border-color: transparent!important;
padding: 4px;
}
richgriditem[iconsize="large"] .tile-icon-box > image,
.tile-icon-box > image[src=""] {
width: 24px;
height: 24px;
list-style-image: url("chrome://browser/skin/images/identity-icons-generic.png");
}
.tile-desc {
display: block;
position: absolute;
bottom: 0;
top: 6px;
left: 52px; /* label goes to the right of the favicon */
right: 0;
left: 20px; /* the colored bar in the default tile is the background color peeking through */
z-index: 1;
padding: 4px 8px;
padding: 1em 6px 6px 12px;
color: #333;
margin: 0;
-moz-margin-start: 0;
display: block;
font-size: 20px;
font-size: 16px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
richgriditem:not([tiletype="thumbnail"]) .tile-desc {
background-color: transparent!important;
}
richgriditem.collapsed {
height: 0!important;
overflow: hidden;
@ -147,9 +174,11 @@ richgriditem[tiletype="thumbnail"] {
}
richgriditem[tiletype="thumbnail"] .tile-desc {
background: transparent;
margin: 0px;
margin: 0;
top: auto;
bottom: 0;
left: 0;
padding: 4px 8px 4px 56px;
}
richgriditem[tiletype="thumbnail"] > .tile-content > .tile-desc {
@ -157,20 +186,24 @@ richgriditem[tiletype="thumbnail"] > .tile-content > .tile-desc {
color: inherit;
}
/* put the image in place of the icon if there is an image background */
/* thumbnail tiles use a screenshot thumbnail as the background */
richgriditem[tiletype="thumbnail"] > .tile-content > .tile-start-container {
background-size: cover;
background-position: top left;
background-repeat: no-repeat;
position: absolute;
top: 0;
bottom: 32px; /* TODO: should be some em value? */;
bottom: 0;
right: 0;
left: 0;
background-color: hsla(0,2%,98%,.95);
}
richgriditem[tiletype="thumbnail"] .tile-icon-box {
visibility: collapse;
top: auto;
left: 10px;
bottom: 6px;
margin-top: 0;
z-index: 1;
box-shadow: 0px 0px 2px 2px rgba(0, 0, 0, 0.05), 0px 2px 0px rgba(0, 0, 0, 0.1);
}
/* selected tile indicator */
@ -262,25 +295,7 @@ richgriditem[bending] > .tile-content {
}
.tile-desc {
top: 0;
left: 44px; /* label goes to the right of the favicon */
right: 0;
padding: 8px;
}
.tile-start-container {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 6px;
background: #fff;
padding: 8px;
}
.tile-icon-box {
padding: 2px;
background: #fff;
opacity: 1.0;
padding: 0.5em 4px 4px 4px;
}
.tile-content {

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

@ -54,27 +54,61 @@ class nsEventTargetChainItem
private:
nsEventTargetChainItem(EventTarget* aTarget,
nsEventTargetChainItem* aChild = nullptr);
public:
nsEventTargetChainItem()
: mChild(nullptr), mParent(nullptr), mFlags(0), mItemFlags(0)
{
}
static nsEventTargetChainItem* Create(nsTArray<nsEventTargetChainItem>& aPool,
EventTarget* aTarget,
// This is the ETCI recycle pool, which is used to avoid some malloc/free
// churn. It's implemented as a linked list.
static nsEventTargetChainItem* sEtciRecyclePool;
static uint32_t sNumRecycledEtcis;
static const uint32_t kMaxNumRecycledEtcis = 128;
public:
static nsEventTargetChainItem* Create(EventTarget* aTarget,
nsEventTargetChainItem* aChild = nullptr)
{
return new (aPool.AppendElement()) nsEventTargetChainItem(aTarget, aChild);
// Allocate from the ETCI recycle pool if possible.
void* place = nullptr;
if (sNumRecycledEtcis > 0) {
MOZ_ASSERT(sEtciRecyclePool);
place = sEtciRecyclePool;
sEtciRecyclePool = sEtciRecyclePool->mNext;
--sNumRecycledEtcis;
} else {
place = malloc(sizeof(nsEventTargetChainItem));
}
return place
? ::new (place) nsEventTargetChainItem(aTarget, aChild)
: nullptr;
}
static void Destroy(nsEventTargetChainItem* aItem)
{
// nsEventTargetChainItem objects are deleted when the pool goes out of
// the scope.
if (aItem->mChild) {
aItem->mChild->mParent = nullptr;
aItem->mChild = nullptr;
// ::Destroy deletes ancestor chain.
nsEventTargetChainItem* item = aItem;
if (item->mChild) {
item->mChild->mParent = nullptr;
item->mChild = nullptr;
}
// Put destroyed ETCIs into the recycle pool if it's not already full.
while (item) {
nsEventTargetChainItem* parent = item->mParent;
item->~nsEventTargetChainItem();
if (sNumRecycledEtcis < kMaxNumRecycledEtcis) {
item->mNext = sEtciRecyclePool;
sEtciRecyclePool = item;
++sNumRecycledEtcis;
} else {
free(item);
}
item = parent;
}
}
static void ShutdownRecyclePool()
{
while (sEtciRecyclePool) {
nsEventTargetChainItem* tmp = sEtciRecyclePool;
sEtciRecyclePool = sEtciRecyclePool->mNext;
free(tmp);
}
}
@ -199,9 +233,21 @@ public:
nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor,
nsCxPusher* aPusher);
static uint32_t MaxEtciCount() { return sMaxEtciCount; }
static void ResetMaxEtciCount()
{
MOZ_ASSERT(!sCurrentEtciCount, "Wrong time to call ResetMaxEtciCount()!");
sMaxEtciCount = 0;
}
nsCOMPtr<EventTarget> mTarget;
nsEventTargetChainItem* mChild;
nsEventTargetChainItem* mParent;
union {
nsEventTargetChainItem* mParent;
// This is used only when recycling ETCIs.
nsEventTargetChainItem* mNext;
};
uint16_t mFlags;
uint16_t mItemFlags;
nsCOMPtr<nsISupports> mItemData;
@ -209,8 +255,14 @@ public:
nsCOMPtr<EventTarget> mNewTarget;
// Cache mTarget's event listener manager.
nsRefPtr<nsEventListenerManager> mManager;
static uint32_t sMaxEtciCount;
static uint32_t sCurrentEtciCount;
};
nsEventTargetChainItem* nsEventTargetChainItem::sEtciRecyclePool = nullptr;
uint32_t nsEventTargetChainItem::sNumRecycledEtcis = 0;
nsEventTargetChainItem::nsEventTargetChainItem(EventTarget* aTarget,
nsEventTargetChainItem* aChild)
: mTarget(aTarget), mChild(aChild), mParent(nullptr), mFlags(0), mItemFlags(0)
@ -353,9 +405,13 @@ nsEventTargetChainItem::HandleEventTargetChain(
return NS_OK;
}
void NS_ShutdownEventTargetChainItemRecyclePool()
{
nsEventTargetChainItem::ShutdownRecyclePool();
}
nsEventTargetChainItem*
EventTargetChainItemForChromeTarget(nsTArray<nsEventTargetChainItem>& aPool,
nsINode* aNode,
EventTargetChainItemForChromeTarget(nsINode* aNode,
nsEventTargetChainItem* aChild = nullptr)
{
if (!aNode->IsInDoc()) {
@ -366,9 +422,9 @@ EventTargetChainItemForChromeTarget(nsTArray<nsEventTargetChainItem>& aPool,
NS_ENSURE_TRUE(piTarget, nullptr);
nsEventTargetChainItem* etci =
nsEventTargetChainItem::Create(aPool,
piTarget->GetTargetForEventTargetChain(),
nsEventTargetChainItem::Create(piTarget->GetTargetForEventTargetChain(),
aChild);
NS_ENSURE_TRUE(etci, nullptr);
if (!etci->IsValid()) {
nsEventTargetChainItem::Destroy(etci);
return nullptr;
@ -466,12 +522,10 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
// event dispatching is finished.
nsRefPtr<nsPresContext> kungFuDeathGrip(aPresContext);
// Try to limit malloc/free churn by using an array as a pool.
nsTArray<nsEventTargetChainItem> pool(128);
// Create the event target chain item for the event target.
nsEventTargetChainItem* targetEtci =
nsEventTargetChainItem::Create(pool, target->GetTargetForEventTargetChain());
nsEventTargetChainItem::Create(target->GetTargetForEventTargetChain());
NS_ENSURE_TRUE(targetEtci, NS_ERROR_OUT_OF_MEMORY);
if (!targetEtci->IsValid()) {
nsEventTargetChainItem::Destroy(targetEtci);
return NS_ERROR_FAILURE;
@ -517,7 +571,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
if (!preVisitor.mCanHandle && preVisitor.mAutomaticChromeDispatch && content) {
// Event target couldn't handle the event. Try to propagate to chrome.
nsEventTargetChainItem::Destroy(targetEtci);
targetEtci = EventTargetChainItemForChromeTarget(pool, content);
targetEtci = EventTargetChainItemForChromeTarget(content);
NS_ENSURE_STATE(targetEtci);
targetEtci->PreHandleEvent(preVisitor);
}
@ -530,7 +584,11 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
while (preVisitor.mParentTarget) {
EventTarget* parentTarget = preVisitor.mParentTarget;
nsEventTargetChainItem* parentEtci =
nsEventTargetChainItem::Create(pool, preVisitor.mParentTarget, topEtci);
nsEventTargetChainItem::Create(preVisitor.mParentTarget, topEtci);
if (!parentEtci) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
if (!parentEtci->IsValid()) {
rv = NS_ERROR_FAILURE;
break;
@ -555,8 +613,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
// propagate to chrome.
nsCOMPtr<nsINode> disabledTarget = do_QueryInterface(parentTarget);
if (disabledTarget) {
parentEtci = EventTargetChainItemForChromeTarget(pool,
disabledTarget,
parentEtci = EventTargetChainItemForChromeTarget(disabledTarget,
topEtci);
if (parentEtci) {
parentEtci->PreHandleEvent(preVisitor);

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

@ -8,6 +8,9 @@ let Cc = Components.classes;
let Ci = Components.interfaces;
let Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
this.EXPORTED_SYMBOLS = ["SettingsDB", "SETTINGSDB_NAME", "SETTINGSSTORE_NAME"];
const DEBUG = false;
@ -80,17 +83,17 @@ SettingsDB.prototype = {
let value = cursor.value;
if (value.settingName in settings) {
if (DEBUG) debug("Upgrade " +settings[value.settingName]);
value.defaultValue = settings[value.settingName];
value.defaultValue = this.prepareValue(settings[value.settingName]);
delete settings[value.settingName];
if ("settingValue" in value) {
value.userValue = value.settingValue;
value.userValue = this.prepareValue(value.settingValue);
delete value.settingValue;
}
cursor.update(value);
} else if ("userValue" in value || "settingValue" in value) {
value.defaultValue = undefined;
if (aOldVersion == 1 && value.settingValue) {
value.userValue = value.settingValue;
value.userValue = this.prepareValue(value.settingValue);
delete value.settingValue;
}
cursor.update(value);
@ -100,11 +103,99 @@ SettingsDB.prototype = {
cursor.continue();
} else {
for (let name in settings) {
if (DEBUG) debug("Set new:" + name +", " + settings[name]);
objectStore.add({ settingName: name, defaultValue: settings[name], userValue: undefined });
let value = this.prepareValue(settings[name]);
if (DEBUG) debug("Set new:" + name +", " + value);
objectStore.add({ settingName: name, defaultValue: value, userValue: undefined });
}
}
};
}.bind(this);
},
// If the value is a data: uri, convert it to a Blob.
convertDataURIToBlob: function(aValue) {
/* base64 to ArrayBuffer decoding, from
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding
*/
function b64ToUint6 (nChr) {
return nChr > 64 && nChr < 91 ?
nChr - 65
: nChr > 96 && nChr < 123 ?
nChr - 71
: nChr > 47 && nChr < 58 ?
nChr + 4
: nChr === 43 ?
62
: nChr === 47 ?
63
:
0;
}
function base64DecToArr(sBase64, nBlocksSize) {
let sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""),
nInLen = sB64Enc.length,
nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize
: nInLen * 3 + 1 >> 2,
taBytes = new Uint8Array(nOutLen);
for (let nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
if (nMod4 === 3 || nInLen - nInIdx === 1) {
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
}
nUint24 = 0;
}
}
return taBytes;
}
// Check if we have a data: uri, and if it's base64 encoded.
// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...
if (typeof aValue == "string" && aValue.startsWith("data:")) {
try {
let uri = Services.io.newURI(aValue, null, null);
// XXX: that would be nice to reuse the c++ bits of the data:
// protocol handler instead.
let mimeType = "application/octet-stream";
let mimeDelim = aValue.indexOf(";");
if (mimeDelim !== -1) {
mimeType = aValue.substring(5, mimeDelim);
}
let start = aValue.indexOf(",") + 1;
let isBase64 = ((aValue.indexOf("base64") + 7) == start);
let payload = aValue.substring(start);
return new Blob([isBase64 ? base64DecToArr(payload) : payload],
{ type: mimeType });
} catch(e) {
dump(e);
}
}
return aValue
},
// Makes sure any property that is a data: uri gets converted to a Blob.
prepareValue: function(aObject) {
let kind = ObjectWrapper.getObjectKind(aObject);
if (kind == "array") {
let res = [];
aObject.forEach(function(aObj) {
res.push(this.prepareValue(aObj));
}, this);
return res;
} else if (kind == "file" || kind == "blob" || kind == "date") {
return aObject;
} else if (kind == "primitive") {
return this.convertDataURIToBlob(aObject);
}
// Fall-through, we now have a dictionary object.
for (let prop in aObject) {
aObject[prop] = this.prepareValue(aObject[prop]);
}
return aObject;
},
init: function init(aGlobal) {

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

@ -17,7 +17,7 @@ Cu.import("resource://gre/modules/SettingsQueue.jsm");
Cu.import("resource://gre/modules/SettingsDB.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm")
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
@ -189,8 +189,10 @@ SettingsLock.prototype = {
// parse(stringify(obj)) because that breaks things like Blobs, Files and
// Dates, so we use stringify's replacer and parse's reviver parameters to
// preserve binaries.
let manager = this._settingsManager;
let binaries = Object.create(null);
let stringified = JSON.stringify(aObject, function(key, value) {
value = manager._settingsDB.prepareValue(value);
let kind = ObjectWrapper.getObjectKind(value);
if (kind == "file" || kind == "blob" || kind == "date") {
let uuid = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)

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

@ -165,7 +165,7 @@ SettingsServiceLock.prototype = {
this._requests.enqueue({ callback: aCallback,
intent: "set",
name: aName,
value: aValue,
value: this._settingsService._settingsDB.prepareValue(aValue),
message: aMessage });
this.createTransactionAndProcess();
},

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

@ -16,6 +16,7 @@ MOCHITEST_FILES = \
test_settings_events.html \
test_settings_onsettingchange.html \
test_settings_blobs.html \
test_settings_data_uris.html \
test_settings_navigator_object.html \
$(NULL)

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

@ -0,0 +1,154 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=806374
-->
<head>
<title>Test for Bug 806374 Settings API</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=821630">Mozilla Bug 821630</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.7">
"use strict";
if (SpecialPowers.isMainProcess()) {
SpecialPowers.Cu.import("resource://gre/modules/SettingsChangeNotifier.jsm");
}
SpecialPowers.addPermission("settings-read", true, document);
SpecialPowers.addPermission("settings-write", true, document);
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
return function(s) {
if (s) {
ok(false, "in on Failure! - " + s);
} else {
ok(false, "in on Failure!");
}
}
}
let mozSettings = window.navigator.mozSettings;
let req;
// A simple data URI that will be converted to a blob.
let dataURI = "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;";
function checkBlob(blob) {
try {
let url = URL.createObjectURL(blob);
ok(true, "Valid blob");
} catch (e) {
ok(false, "Valid blob");
}
}
let steps = [
function() {
let lock = mozSettings.createLock();
req = lock.clear();
req.onsuccess = next;
req.onerror = onFailure("Deleting database");
},
function() {
function obs(e) {
checkBlob(e.settingValue);
mozSettings.removeObserver("test1", obs);
next();
}
mozSettings.addObserver("test1", obs);
next();
},
function() {
// next is called by the observer above
let req = mozSettings.createLock().set({"test1": dataURI});
req.onerror = onFailure("Saving blob");
},
function() {
let req = mozSettings.createLock().get("test1");
req.onsuccess = function(event) {
checkBlob(event.target.result["test1"]);
next();
};
req.onerror = onFailure("Getting blob");
},
function() {
let req = mozSettings.createLock().set({"test2": [1, 2, dataURI, 4]});
req.onsuccess = next;
req.onerror = onFailure("Saving array");
},
function() {
let req = mozSettings.createLock().get("test2");
req.onsuccess = function(event) {
let val = event.target.result["test2"];
ok(Array.isArray(val), "Result is an array");
ok(val[0] == 1 && val[1] == 2 && val[3] == 4, "Primitives are preserved");
checkBlob(val[2]);
next();
};
req.onerror = onFailure("Getting array");
},
function() {
let req = mozSettings.createLock().set({"test3": {foo: "bar", baz: {number: 1, arr: [dataURI]}}});
req.onsuccess = next();
req.onerror = onFailure("Saving object");
},
function() {
let req = mozSettings.createLock().get("test3");
req.onsuccess = function(event) {
let val = event.target.result["test3"];
ok(typeof(val) == "object", "Result is an object");
ok("foo" in val && typeof(val.foo) == "string", "String property preserved");
ok("baz" in val && typeof(val.baz) == "object", "Object property preserved");
let baz = val.baz;
ok("number" in baz && baz.number == 1, "Primite inside object preserved");
ok("arr" in baz && Array.isArray(baz.arr), "Array inside object is preserved");
checkBlob(baz.arr[0]);
next();
};
req.onerror = onFailure("Getting object");
},
function() {
let req = mozSettings.createLock().clear();
req.onsuccess = function() {
next();
};
req.onerror = onFailure("Deleting database");
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
try {
let step = steps.shift();
if (step) {
step();
}
} catch(ex) {
ok(false, "Caught exception", ex);
}
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(next);
</script>
</pre>
</body>
</html>

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

@ -692,6 +692,8 @@ function RadioInterface(options) {
displayName: null
};
this.operatorInfo = {};
// Read the 'ril.radio.disabled' setting in order to start with a known
// value at boot time.
let lock = gSettingsService.createLock();
@ -746,6 +748,19 @@ RadioInterface.prototype = {
dump("-*- RadioInterface[" + this.clientId + "]: " + s + "\n");
},
/**
* A utility function to copy objects. The srcInfo may contain
* 'rilMessageType', should ignore it.
*/
updateInfo: function updateInfo(srcInfo, destInfo) {
for (let key in srcInfo) {
if (key === 'rilMessageType') {
continue;
}
destInfo[key] = srcInfo[key];
}
},
/**
* Process a message from the content process.
*/
@ -1143,18 +1158,15 @@ RadioInterface.prototype = {
// Batch the *InfoChanged messages together
if (voiceMessage) {
voiceMessage.batch = true;
this.updateVoiceConnection(voiceMessage);
this.updateVoiceConnection(voiceMessage, true);
}
if (dataMessage) {
dataMessage.batch = true;
this.updateDataConnection(dataMessage);
this.updateDataConnection(dataMessage, true);
}
if (operatorMessage) {
operatorMessage.batch = true;
this.handleOperatorChange(operatorMessage);
this.handleOperatorChange(operatorMessage, true);
}
let voice = this.rilContext.voice;
@ -1204,13 +1216,13 @@ RadioInterface.prototype = {
},
/**
* Sends the RIL:VoiceInfoChanged message when the voice
* connection's state has changed.
* Handle data connection changes.
*
* @param newInfo The new voice connection information. When newInfo.batch is true,
* the RIL:VoiceInfoChanged message will not be sent.
* @param newInfo The new voice connection information.
* @param batch When batch is true, the RIL:VoiceInfoChanged message will
* not be sent.
*/
updateVoiceConnection: function updateVoiceConnection(newInfo) {
updateVoiceConnection: function updateVoiceConnection(newInfo, batch) {
let voiceInfo = this.rilContext.voice;
voiceInfo.state = newInfo.state;
voiceInfo.connected = newInfo.connected;
@ -1220,23 +1232,30 @@ RadioInterface.prototype = {
// Make sure we also reset the operator and signal strength information
// if we drop off the network.
if (newInfo.regState !== RIL.NETWORK_CREG_STATE_REGISTERED_HOME &&
newInfo.regState !== RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING) {
if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
voiceInfo.cell = null;
voiceInfo.network = null;
voiceInfo.signalStrength = null;
voiceInfo.relSignalStrength = null;
} else {
voiceInfo.cell = newInfo.cell;
voiceInfo.network = this.operatorInfo;
}
if (!newInfo.batch) {
if (!batch) {
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
this.clientId, voiceInfo);
}
},
updateDataConnection: function updateDataConnection(newInfo) {
/**
* Handle the data connection's state has changed.
*
* @param newInfo The new data connection information.
* @param batch When batch is true, the RIL:DataInfoChanged message will
* not be sent.
*/
updateDataConnection: function updateDataConnection(newInfo, batch) {
let dataInfo = this.rilContext.data;
dataInfo.state = newInfo.state;
dataInfo.roaming = newInfo.roaming;
@ -1253,17 +1272,17 @@ RadioInterface.prototype = {
// Make sure we also reset the operator and signal strength information
// if we drop off the network.
if (newInfo.regState !== RIL.NETWORK_CREG_STATE_REGISTERED_HOME &&
newInfo.regState !== RIL.NETWORK_CREG_STATE_REGISTERED_ROAMING) {
if (newInfo.state !== RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
dataInfo.cell = null;
dataInfo.network = null;
dataInfo.signalStrength = null;
dataInfo.relSignalStrength = null;
} else {
dataInfo.cell = newInfo.cell;
dataInfo.network = this.operatorInfo;
}
if (!newInfo.batch) {
if (!batch) {
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
this.clientId, dataInfo);
}
@ -1371,11 +1390,21 @@ RadioInterface.prototype = {
destNetwork.mcc != srcNetwork.mcc;
},
handleOperatorChange: function handleOperatorChange(message) {
/**
* Handle operator information changes.
*
* @param message The new operator information.
* @param batch When batch is true, the RIL:VoiceInfoChanged and
* RIL:DataInfoChanged message will not be sent.
*/
handleOperatorChange: function handleOperatorChange(message, batch) {
let operatorInfo = this.operatorInfo;
let voice = this.rilContext.voice;
let data = this.rilContext.data;
if (this.networkChanged(message, voice.network)) {
if (this.networkChanged(message, operatorInfo)) {
this.updateInfo(message, operatorInfo);
// Update lastKnownNetwork
if (message.mcc && message.mnc) {
try {
@ -1384,16 +1413,14 @@ RadioInterface.prototype = {
} catch (e) {}
}
voice.network = message;
if (!message.batch) {
// If the voice is unregistered, no need to send RIL:VoiceInfoChanged.
if (voice.network && !batch) {
gMessageManager.sendMobileConnectionMessage("RIL:VoiceInfoChanged",
this.clientId, voice);
}
}
if (this.networkChanged(message, data.network)) {
data.network = message;
if (!message.batch) {
// If the data is unregistered, no need to send RIL:DataInfoChanged.
if (data.network && !batch) {
gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged",
this.clientId, data);
}

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

@ -118,6 +118,8 @@ using namespace mozilla::system;
#include "nsDocument.h"
#include "mozilla/dom/HTMLVideoElement.h"
extern void NS_ShutdownEventTargetChainItemRecyclePool();
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
@ -374,6 +376,8 @@ nsLayoutStatics::Shutdown()
nsRegion::ShutdownStatic();
NS_ShutdownEventTargetChainItemRecyclePool();
HTMLInputElement::DestroyUploadLastDir();
nsLayoutUtils::Shutdown();

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

@ -8,6 +8,23 @@
</head>
<body>
Login Manager test: simple form fill
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
/** Test for Login Manager: form fill, multiple forms. **/
function startTest() {
is($_(1, "uname").value, "testuser", "Checking for filled username");
is($_(1, "pword").value, "testpass", "Checking for filled password");
SimpleTest.finish();
}
window.onload = startTest;
</script>
<p id="display"></p>
<div id="content" style="display: none">
@ -23,25 +40,7 @@ Login Manager test: simple form fill
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
commonInit();
/** Test for Login Manager: form fill, multiple forms. **/
// Make sure that all forms in a document are processed.
function startTest() {
is($_(1, "uname").value, "testuser", "Checking for filled username");
is($_(1, "pword").value, "testpass", "Checking for filled password");
SimpleTest.finish();
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<pre id="test"></pre>
</body>
</html>

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

@ -8,6 +8,16 @@
</head>
<body>
Login Manager test: simple form fill with autofillForms disabled
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
// Assume that the pref starts out true, so set to false
SpecialPowers.setBoolPref("signon.autofillForms", false);
</script>
<p id="display"></p>
<div id="content" style="display: block">
@ -28,18 +38,6 @@ Login Manager test: simple form fill with autofillForms disabled
/** Test for Login Manager: simple form fill with autofillForms disabled **/
commonInit();
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var pwmgr = Components.classes["@mozilla.org/login-manager;1"].
getService(Components.interfaces.nsILoginManager);
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);
prefs = prefs.getBranch("signon.");
// Assume that the pref starts out true, so set to false
prefs.setBoolPref("autofillForms", false);
function startTest(){
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Ensure the form is empty at start
@ -55,14 +53,12 @@ function startTest(){
is($_(1, "pword").value, "testpass", "Checking for filled password");
// Reset pref (since we assumed it was true to start)
prefs.setBoolPref("autofillForms", true);
SpecialPowers.setBoolPref("signon.autofillForms", true);
SimpleTest.finish();
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -9,86 +9,14 @@
</head>
<body>
Login Manager test: multiple login autocomplete
<p id="display"></p>
<!-- we presumably can't hide the content for this test. -->
<div id="content">
<!-- form1 tests multiple matching logins -->
<form id="form1" action="http://autocomplete:8888/formtest.js" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- other forms test single logins, with autocomplete=off set -->
<form id="form2" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<form id="form3" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form4" action="http://autocomplete2" onsubmit="return false;" autocomplete="off">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form5" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<!-- control -->
<form id="form6" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- This form will be manipulated to insert a different username field. -->
<form id="form7" action="http://autocomplete3" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- test for no autofill after onblur with blank username -->
<form id="form8" action="http://autocomplete4" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- test autocomplete dropdown -->
<form id="form9" action="http://autocomplete5" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: multiple login autocomplete. **/
<script>
commonInit();
var uname = $_(1, "uname");
var pword = $_(1, "pword");
const shiftModifier = Components.interfaces.nsIDOMEvent.SHIFT_MASK;
SimpleTest.waitForExplicitFinish();
// Get the pwmgr service
var pwmgr = SpecialPowers.wrap(Components).classes["@mozilla.org/login-manager;1"]
.getService(Components.interfaces.nsILoginManager);
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
ok(pwmgr != null, "nsLoginManager service");
// Create some logins just for this form, since we'll be deleting them.
@ -164,6 +92,82 @@ try {
ok(false, "addLogin threw: " + e);
}
</script>
<p id="display"></p>
<!-- we presumably can't hide the content for this test. -->
<div id="content">
<!-- form1 tests multiple matching logins -->
<form id="form1" action="http://autocomplete:8888/formtest.js" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- other forms test single logins, with autocomplete=off set -->
<form id="form2" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<form id="form3" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form4" action="http://autocomplete2" onsubmit="return false;" autocomplete="off">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<form id="form5" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname" autocomplete="off">
<input type="password" name="pword" autocomplete="off">
<button type="submit">Submit</button>
</form>
<!-- control -->
<form id="form6" action="http://autocomplete2" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- This form will be manipulated to insert a different username field. -->
<form id="form7" action="http://autocomplete3" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- test for no autofill after onblur with blank username -->
<form id="form8" action="http://autocomplete4" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
<!-- test autocomplete dropdown -->
<form id="form9" action="http://autocomplete5" onsubmit="return false;">
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
</form>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: multiple login autocomplete. **/
var uname = $_(1, "uname");
var pword = $_(1, "pword");
const shiftModifier = Components.interfaces.nsIDOMEvent.SHIFT_MASK;
// Restore the form to the default state.
function restoreForm() {
@ -812,8 +816,6 @@ function startTest() {
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,6 +8,39 @@
</head>
<body>
Login Manager test: html5 input types (email, tel, url, etc.)
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
const Ci = SpecialPowers.Ci;
const Cc = SpecialPowers.Cc;
pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
login1 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login3 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login4 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login1.init("http://mochi.test:8888", "http://bug600551-1", null,
"testuser@example.com", "testpass1", "", "");
login2.init("http://mochi.test:8888", "http://bug600551-2", null,
"555-555-5555", "testpass2", "", "");
login3.init("http://mochi.test:8888", "http://bug600551-3", null,
"http://mozilla.org", "testpass3", "", "");
login4.init("http://mochi.test:8888", "http://bug600551-4", null,
"123456789", "testpass4", "", "");
pwmgr.addLogin(login1);
pwmgr.addLogin(login2);
pwmgr.addLogin(login3);
pwmgr.addLogin(login4);
</script>
<p id="display"></p>
<div id="content" style="display: none">
@ -99,38 +132,6 @@ Login Manager test: html5 input types (email, tel, url, etc.)
/* Test for Login Manager: 600551
(Password manager not working with input type=email)
*/
commonInit();
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Ci = Components.interfaces;
const Cc = Components.classes;
pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
login1 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login3 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login4 = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login1.init("http://mochi.test:8888", "http://bug600551-1", null,
"testuser@example.com", "testpass1", "", "");
login2.init("http://mochi.test:8888", "http://bug600551-2", null,
"555-555-5555", "testpass2", "", "");
login3.init("http://mochi.test:8888", "http://bug600551-3", null,
"http://mozilla.org", "testpass3", "", "");
login4.init("http://mochi.test:8888", "http://bug600551-4", null,
"123456789", "testpass4", "", "");
pwmgr.addLogin(login1);
pwmgr.addLogin(login2);
pwmgr.addLogin(login3);
pwmgr.addLogin(login4);
function startTest() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
@ -166,9 +167,6 @@ function startTest() {
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,6 +8,17 @@
</head>
<body>
Login Manager test: simple form with autocomplete off and notifying observers & normal form
<script>
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
commonInit();
SimpleTest.waitForExplicitFinish();
</script>
<p id="display"></p>
<div id="content" style="display: block">
@ -20,7 +31,7 @@ Login Manager test: simple form with autocomplete off and notifying observers &
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form2" action="formtest.js">
<p>This is form 2.</p>
<input type="text" name="uname">
@ -36,15 +47,6 @@ Login Manager test: simple form with autocomplete off and notifying observers &
<script class="testbody" type="text/javascript">
/** Test for Login Manager: simple form with autocomplete off and notifying observers & normal form **/
commonInit();
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var TestObserver = {
receivedNotification1 : false,
receivedNotification2 : false,
@ -99,8 +101,6 @@ function startTest(){
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,6 +8,21 @@
</head>
<body>
Login Manager test: simple form with autofillForms disabled and notifying observers
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// Assume that the pref starts out true, so set to false
SpecialPowers.setBoolPref("signon.autofillForms", false);
</script>
<p id="display"></p>
<div id="content" style="display: block">
@ -28,20 +43,6 @@ Login Manager test: simple form with autofillForms disabled and notifying observ
/** Test for Login Manager: simple form with autofillForms disabled and notifying observers **/
commonInit();
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var prefs = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService);
prefs = prefs.getBranch("signon.");
// Assume that the pref starts out true, so set to false
prefs.setBoolPref("autofillForms", false);
var TestObserver = {
receivedNotificationFoundForm : false,
receivedNotificationFoundLogins : false,
@ -92,7 +93,7 @@ function startTest(){
"Checking selectedLogin is found login");
// Reset pref (since we assumed it was true to start)
prefs.setBoolPref("autofillForms", true);
SpecialPowers.setBoolPref("signon.autofillForms", true);
// Remove the observer
os.removeObserver(TestObserver, "passwordmgr-found-form");
@ -102,8 +103,6 @@ function startTest(){
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,66 +8,13 @@
</head>
<body>
Login Manager test: notifying observers of passwordmgr-found-logins
<p id="display"></p>
<div id="content" style="display: block">
<form id="form1" action="formtest.js">
<p>This is form 1.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form2" action="formtest.js">
<p>This is form 2.</p>
<input type="text" name="uname" value="existing">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form3" action="formtest.js">
<p>This is form 3.</p>
<input type="text" name="uname">
<input type="password" name="pword" value="existing">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form4" action="formtest.js" autocomplete="off">
<p>This is form 4.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form5" action="http://www.example.com">
<p>This is form 5.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: notifying observers of passwordmgr-found-logins **/
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -110,6 +57,63 @@ for (var formID of ["form1", "form2", "form3", "form4", "form5"])
var os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.addObserver(TestObserver, "passwordmgr-found-logins", false);
</script>
<p id="display"></p>
<div id="content" style="display: block">
<form id="form1" action="formtest.js">
<p>This is form 1.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form2" action="formtest.js">
<p>This is form 2.</p>
<input type="text" name="uname" value="existing">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form3" action="formtest.js">
<p>This is form 3.</p>
<input type="text" name="uname">
<input type="password" name="pword" value="existing">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form4" action="formtest.js" autocomplete="off">
<p>This is form 4.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
<form id="form5" action="http://www.example.com">
<p>This is form 5.</p>
<input type="text" name="uname">
<input type="password" name="pword">
<button type="submit">Submit</button>
<button type="reset"> Reset </button>
</form>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: notifying observers of passwordmgr-found-logins **/
function startTest(){
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
@ -181,8 +185,6 @@ function startTest(){
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,6 +8,39 @@
</head>
<body>
Login Manager test: forms and logins without a username.
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo);
ok(nsLoginInfo != null, "nsLoginInfo constructor");
// pwlogin1 uses a unique formSubmitURL, to check forms where no other logins
// will apply. pwlogin2 uses the normal formSubmitURL, so that we can test
// forms with a mix of username and non-username logins that might apply.
//
// Note: pwlogin2 is deleted at the end of the test.
pwlogin1 = new nsLoginInfo();
pwlogin2 = new nsLoginInfo();
pwlogin1.init("http://mochi.test:8888", "http://mochi.test:1111", null,
"", "1234", "uname", "pword");
pwlogin2.init("http://mochi.test:8888", "http://mochi.test:8888", null,
"", "1234", "uname", "pword");
try {
pwmgr.addLogin(pwlogin1);
pwmgr.addLogin(pwlogin2);
} catch (e) {
ok(false, "addLogin threw: " + e);
}
</script>
<p id="display"></p>
<div id="content" style="display: none">
@ -154,8 +187,6 @@ password-only, the other is username+password)
<script class="testbody" type="text/javascript">
/** Test for Login Manager: password-only logins **/
commonInit();
function startTest() {
checkForm(1, "1234");
@ -181,48 +212,7 @@ function startTest() {
SimpleTest.finish();
}
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Get the pwmgr service
var Cc_pwmgr = Components.classes["@mozilla.org/login-manager;1"];
ok(Cc_pwmgr != null, "Access Cc[@mozilla.org/login-manager;1]");
var Ci_pwmgr = Components.interfaces.nsILoginManager;
ok(Ci_pwmgr != null, "Access Ci.nsILoginManager");
var pwmgr = Cc_pwmgr.getService(Ci_pwmgr);
ok(pwmgr != null, "pwmgr getService()");
var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Components.interfaces.nsILoginInfo);
ok(nsLoginInfo != null, "nsLoginInfo constructor");
// pwlogin1 uses a unique formSubmitURL, to check forms where no other logins
// will apply. pwlogin2 uses the normal formSubmitURL, so that we can test
// forms with a mix of username and non-username logins that might apply.
//
// Note: pwlogin2 is deleted at the end of the test.
pwlogin1 = new nsLoginInfo();
pwlogin2 = new nsLoginInfo();
pwlogin1.init("http://mochi.test:8888", "http://mochi.test:1111", null,
"", "1234", "uname", "pword");
pwlogin2.init("http://mochi.test:8888", "http://mochi.test:8888", null,
"", "1234", "uname", "pword");
try {
pwmgr.addLogin(pwlogin1);
pwmgr.addLogin(pwlogin2);
} catch (e) {
ok(false, "addLogin threw: " + e);
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,9 +8,17 @@
</head>
<body>
Login Manager test: 227640
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
</script>
<p id="display"></p>
<div id="content" style="display: none">
<!-- no autocomplete for password field -->
<form id="form1" onsubmit="return checkSubmit(1)" method="get">
<input type="text" name="uname" value="">
@ -147,7 +155,6 @@ Login Manager test: 227640
/** Test for Login Manager: 227640 (password is saved even when the
password field has autocomplete="off") **/
commonInit();
// This test ensures that pwmgr does not save a username or password when
// autocomplete=off is present.
@ -230,24 +237,7 @@ function countLogins() {
return logins.length;
}
// Get the pwmgr service
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var Cc_pwmgr = Components.classes["@mozilla.org/login-manager;1"];
ok(Cc_pwmgr != null, "Access Cc[@mozilla.org/login-manager;1]");
var Ci_pwmgr = Components.interfaces.nsILoginManager;
ok(Ci_pwmgr != null, "Access Ci.nsILoginManager");
var pwmgr = Cc_pwmgr.getService(Ci_pwmgr);
ok(pwmgr != null, "pwmgr getService()");
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -8,6 +8,28 @@
</head>
<body>
Login Manager test: form with JS submit action
<script>
SimpleTest.waitForExplicitFinish();
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
var jslogin = SpecialPowers.Cc["@mozilla.org/login-manager/loginInfo;1"]
.createInstance(SpecialPowers.Ci.nsILoginInfo);
jslogin.init("http://mochi.test:8888", "javascript:", null,
"jsuser", "jspass123", "uname", "pword");
pwmgr.addLogin(jslogin);
/** Test for Login Manager: JS action URL **/
function startTest() {
checkForm(1, "jsuser", "jspass123");
pwmgr.removeLogin(jslogin);
SimpleTest.finish();
}
window.onload = startTest;
</script>
<p id="display"></p>
<div id="content" style="display: none">
@ -23,51 +45,7 @@ Login Manager test: form with JS submit action
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Login Manager: JS action URL **/
function startTest() {
checkForm(1, "jsuser", "jspass123");
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
pwmgr.removeLogin(jslogin);
SimpleTest.finish();
}
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Get the pwmgr service
var Cc_pwmgr = Components.classes["@mozilla.org/login-manager;1"];
ok(Cc_pwmgr != null, "Access Cc[@mozilla.org/login-manager;1]");
var Ci_pwmgr = Components.interfaces.nsILoginManager;
ok(Ci_pwmgr != null, "Access Ci.nsILoginManager");
var pwmgr = Cc_pwmgr.getService(Ci_pwmgr);
ok(pwmgr != null, "pwmgr getService()");
var jslogin = Components.classes["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Components.interfaces.nsILoginInfo);
ok(jslogin != null, "create a login");
jslogin.init("http://mochi.test:8888", "javascript:", null,
"jsuser", "jspass123", "uname", "pword");
try {
pwmgr.addLogin(jslogin);
} catch (e) {
ok(false, "addLogin threw: " + e);
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<pre id="test"></pre>
</body>
</html>

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

@ -8,6 +8,45 @@
</head>
<body>
Login Manager test: 444968
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
const Ci = SpecialPowers.Ci;
const Cc = SpecialPowers.Cc;
pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
login1A = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login1B = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2A = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2B = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2C = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login1A.init("http://mochi.test:8888", "http://bug444968-1", null,
"testuser1A", "testpass1A", "", "");
login1B.init("http://mochi.test:8888", "http://bug444968-1", null,
"", "testpass1B", "", "");
login2A.init("http://mochi.test:8888", "http://bug444968-2", null,
"testuser2A", "testpass2A", "", "");
login2B.init("http://mochi.test:8888", "http://bug444968-2", null,
"", "testpass2B", "", "");
login2C.init("http://mochi.test:8888", "http://bug444968-2", null,
"testuser2C", "testpass2C", "", "");
pwmgr.addLogin(login1A);
pwmgr.addLogin(login1B);
pwmgr.addLogin(login2A);
pwmgr.addLogin(login2B);
pwmgr.addLogin(login2C);
</script>
<p id="display"></p>
<div id="content" style="display: none">
<!-- first 3 forms have matching user+pass and pass-only logins -->
@ -69,47 +108,7 @@ Login Manager test: 444968
/* Test for Login Manager: 444968 (password-only forms should prefer a
* password-only login when present )
*/
commonInit();
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
const Ci = Components.interfaces;
const Cc = Components.classes;
pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
login1A = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login1B = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2A = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2B = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login2C = Cc["@mozilla.org/login-manager/loginInfo;1"].
createInstance(Ci.nsILoginInfo);
login1A.init("http://mochi.test:8888", "http://bug444968-1", null,
"testuser1A", "testpass1A", "", "");
login1B.init("http://mochi.test:8888", "http://bug444968-1", null,
"", "testpass1B", "", "");
login2A.init("http://mochi.test:8888", "http://bug444968-2", null,
"testuser2A", "testpass2A", "", "");
login2B.init("http://mochi.test:8888", "http://bug444968-2", null,
"", "testpass2B", "", "");
login2C.init("http://mochi.test:8888", "http://bug444968-2", null,
"testuser2C", "testpass2C", "", "");
pwmgr.addLogin(login1A);
pwmgr.addLogin(login1B);
pwmgr.addLogin(login2A);
pwmgr.addLogin(login2B);
pwmgr.addLogin(login2C);
function startTest() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
checkForm(1, "testuser1A", "testpass1A");
checkForm(2, "testpass1B");
checkForm(3, "testuser1A", "testpass1A");
@ -124,14 +123,11 @@ function startTest() {
pwmgr.removeLogin(login2A);
pwmgr.removeLogin(login2B);
pwmgr.removeLogin(login2C);
SimpleTest.finish();
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -9,6 +9,32 @@
</head>
<body>
Login Manager test: master password.
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
.getService(SpecialPowers.Ci.nsILoginManager);
var pwcrypt = SpecialPowers.Cc["@mozilla.org/login-manager/crypto/SDR;1"]
.getService(Ci.nsILoginManagerCrypto);
var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo);
var exampleCom = "http://example.com/tests/toolkit/components/passwordmgr/test/";
var exampleOrg = "http://example.org/tests/toolkit/components/passwordmgr/test/";
var login1 = new nsLoginInfo();
var login2 = new nsLoginInfo();
login1.init("http://example.com", "http://example.com", null,
"user1", "pass1", "uname", "pword");
login2.init("http://example.org", "http://example.org", null,
"user2", "pass2", "uname", "pword");
pwmgr.addLogin(login1);
pwmgr.addLogin(login2);
</script>
<p id="display"></p>
<div id="content" style="display: none">
@ -18,9 +44,9 @@ Login Manager test: master password.
<pre id="test">
<script class="testbody" type="text/javascript">
commonInit();
var testNum = 1;
var iframe1 = document.getElementById("iframe1");
var iframe2 = document.getElementById("iframe2");
/*
* handleDialog
@ -79,8 +105,12 @@ function handleDialog(doc, testNum) {
ok(true, "handleDialog done");
didDialog = true;
if (testNum == 4)
if (testNum == 3)
SimpleTest.executeSoon(checkTest3);
else if (testNum == 4)
checkTest4A();
else if (testNum == 5)
SimpleTest.executeSoon(checkTest4C);
}
@ -119,12 +149,6 @@ function startTest1() {
// --- Test 3 ---
// Load a single iframe to trigger a MP
testNum++;
// Note that because DOMContentLoaded is dispatched synchronously, the
// document's load event is blocked until after the MP entry (because
// pwmgr's listener doesn't return until after it processes the form,
// which is blocked waiting on a MP entry).
iframe1.onload = checkTest3;
iframe1.src = exampleCom + "subtst_master_pass.html";
startCallbackTimer();
}
@ -147,7 +171,6 @@ function checkTest3() {
// --- Test 4 ---
// first part of loading 2 MP-triggering iframes
testNum++;
iframe1.onload = checkTest4C;
iframe1.src = exampleOrg + "subtst_master_pass.html";
// start the callback, but we'll not enter the MP, just call checkTest4A
startCallbackTimer();
@ -170,7 +193,9 @@ function checkTest4A() {
// Load another iframe with a login form
// This should detect that there's already a pending MP prompt, and not
// put up a second one. The load event will fire.
// put up a second one. The load event will fire (note that when pwmgr is
// driven from DOMContentLoaded, if that blocks due to prompting for a MP,
// the load even will also be blocked until the prompt is dismissed).
iframe2.onload = checkTest4B;
iframe2.src = exampleCom + "subtst_master_pass.html";
}
@ -196,7 +221,6 @@ function checkTest4B() {
}
function checkTest4C() {
// iframe1 finally loads after the MP entry.
ok(true, "checkTest4C starting");
ok(didDialog, "handleDialog was invoked");
@ -232,41 +256,7 @@ function finishTest() {
SimpleTest.finish();
}
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// Get the pwmgr service
var pwmgr = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
ok(pwmgr != null, "pwmgr getService()");
var pwcrypt = Cc["@mozilla.org/login-manager/crypto/SDR;1"].
getService(Ci.nsILoginManagerCrypto);
ok(pwcrypt != null, "pwcrypt getService()");
var nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo);
ok(nsLoginInfo != null, "nsLoginInfo constructor");
var exampleCom = "http://example.com/tests/toolkit/components/passwordmgr/test/";
var exampleOrg = "http://example.org/tests/toolkit/components/passwordmgr/test/";
var login1 = new nsLoginInfo();
var login2 = new nsLoginInfo();
login1.init("http://example.com", "http://example.com", null,
"user1", "pass1", "uname", "pword");
login2.init("http://example.org", "http://example.org", null,
"user2", "pass2", "uname", "pword");
pwmgr.addLogin(login1);
pwmgr.addLogin(login2);
var iframe1 = document.getElementById("iframe1");
var iframe2 = document.getElementById("iframe2");
window.onload = startTest1;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -11,8 +11,6 @@ Login Manager test: master password cleanup
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="iframe1"></iframe>
<iframe id="iframe2"></iframe>
</div>
<pre id="test">

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

@ -12,8 +12,10 @@ Test limiting number of forms filled.
<p id="display"></p>
<div id="content" style="display: none"></div>
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var FORMS_TO_CREATE = 39;
function createForm(id) {
@ -34,7 +36,6 @@ theDiv.innerHTML = formsHtml;
<pre id="test">
<script class="testbody" type="text/javascript">
commonInit();
/** Test for Login Manager: form fill, multiple forms. **/
function startTest() {
@ -52,10 +53,7 @@ function startTest() {
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

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

@ -12,8 +12,10 @@ Test limiting number of forms filled.
<p id="display"></p>
<div id="content" style="display: none"></div>
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var FORMS_TO_CREATE = 40;
function createForm(id) {
@ -34,7 +36,6 @@ theDiv.innerHTML = formsHtml;
<pre id="test">
<script class="testbody" type="text/javascript">
commonInit();
/** Test for Login Manager: form fill, multiple forms. **/
function startTest() {
@ -52,10 +53,7 @@ function startTest() {
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

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

@ -12,8 +12,10 @@ Test limiting number of forms filled.
<p id="display"></p>
<div id="content" style="display: none"></div>
<script>
commonInit();
SimpleTest.waitForExplicitFinish();
var FORMS_TO_CREATE = 41;
function createForm(id) {
@ -34,7 +36,6 @@ theDiv.innerHTML = formsHtml;
<pre id="test">
<script class="testbody" type="text/javascript">
commonInit();
/** Test for Login Manager: form fill, multiple forms. **/
function startTest() {
@ -52,10 +53,7 @@ function startTest() {
}
window.onload = startTest;
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

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

@ -73,10 +73,14 @@ function DeferredSave(aPath, aDataProvider, aDelay) {
// Some counters for telemetry
// The total number of times the file was written
this.totalSaves = 0;
// The number of times the data became dirty while
// another save was in progress
this.overlappedSaves = 0;
// Error returned by the most recent write (if any)
this._lastError = null;
if (aDelay && (aDelay > 0))
this._delay = aDelay;
else
@ -88,7 +92,7 @@ DeferredSave.prototype = {
return this._pending || this.writeInProgress;
},
get error() {
get lastError() {
return this._lastError;
},

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

@ -15,7 +15,7 @@ endif
# This is used in multiple places, so is defined here to avoid it getting
# out of sync.
DEFINES += -DMOZ_EXTENSIONS_DB_SCHEMA=14
DEFINES += -DMOZ_EXTENSIONS_DB_SCHEMA=15
# Additional debugging info is exposed in debug builds, or by setting the
# MOZ_EM_DEBUG environment variable when building.

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

@ -78,7 +78,7 @@ const DIR_STAGE = "staged";
const DIR_XPI_STAGE = "staged-xpis";
const DIR_TRASH = "trash";
const FILE_DATABASE = "extensions.sqlite";
const FILE_DATABASE = "extensions.json";
const FILE_OLD_CACHE = "extensions.cache";
const FILE_INSTALL_MANIFEST = "install.rdf";
const FILE_XPI_ADDONS_LIST = "extensions.ini";
@ -120,7 +120,12 @@ const PROP_TARGETAPP = ["id", "minVersion", "maxVersion"];
// or calculated
const DB_MIGRATE_METADATA= ["installDate", "userDisabled", "softDisabled",
"sourceURI", "applyBackgroundUpdates",
"releaseNotesURI", "isForeignInstall", "syncGUID"];
"releaseNotesURI", "foreignInstall", "syncGUID"];
// Properties to cache and reload when an addon installation is pending
const PENDING_INSTALL_METADATA =
["syncGUID", "targetApplications", "userDisabled", "softDisabled",
"existingAddonID", "sourceURI", "releaseNotesURI", "installDate",
"updateDate", "applyBackgroundUpdates", "compatibilityOverrides"];
// Note: When adding/changing/removing items here, remember to change the
// DB schema version to ensure changes are picked up ASAP.
@ -169,12 +174,15 @@ var gGlobalScope = this;
var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]*\@[a-z0-9-\._]+)$/i;
["LOG", "WARN", "ERROR"].forEach(function(aName) {
this.__defineGetter__(aName, function logFuncGetter() {
Components.utils.import("resource://gre/modules/AddonLogging.jsm");
Object.defineProperty(this, aName, {
get: function logFuncGetter() {
Components.utils.import("resource://gre/modules/AddonLogging.jsm");
LogManager.getLogger("addons.xpi", this);
return this[aName];
})
LogManager.getLogger("addons.xpi", this);
return this[aName];
},
configurable: true
});
}, this);
@ -197,9 +205,12 @@ function loadLazyObjects() {
}
for (let name of LAZY_OBJECTS) {
gGlobalScope.__defineGetter__(name, function lazyObjectGetter() {
let objs = loadLazyObjects();
return objs[name];
Object.defineProperty(gGlobalScope, name, {
get: function lazyObjectGetter() {
let objs = loadLazyObjects();
return objs[name];
},
configurable: true
});
}
@ -498,6 +509,9 @@ function findClosestLocale(aLocales) {
* previous instance may be a previous install or in the case of an application
* version change the same add-on.
*
* NOTE: this may modify aNewAddon in place; callers should save the database if
* necessary
*
* @param aOldAddon
* The previous instance of the add-on
* @param aNewAddon
@ -584,11 +598,8 @@ function isAddonDisabled(aAddon) {
return aAddon.appDisabled || aAddon.softDisabled || aAddon.userDisabled;
}
this.__defineGetter__("gRDF", function gRDFGetter() {
delete this.gRDF;
return this.gRDF = Cc["@mozilla.org/rdf/rdf-service;1"].
getService(Ci.nsIRDFService);
});
XPCOMUtils.defineLazyServiceGetter(this, "gRDF", "@mozilla.org/rdf/rdf-service;1",
Ci.nsIRDFService);
function EM_R(aProperty) {
return gRDF.GetResource(PREFIX_NS_EM + aProperty);
@ -694,8 +705,11 @@ function loadManifestFromRDF(aUri, aStream) {
});
PROP_LOCALE_MULTI.forEach(function(aProp) {
locale[aProp] = getPropertyArray(aDs, aSource,
aProp.substring(0, aProp.length - 1));
// Don't store empty arrays
let props = getPropertyArray(aDs, aSource,
aProp.substring(0, aProp.length - 1));
if (props.length > 0)
locale[aProp] = props;
});
return locale;
@ -1321,19 +1335,24 @@ function recursiveRemove(aFile) {
* @return Epoch time, as described above. 0 for an empty directory.
*/
function recursiveLastModifiedTime(aFile) {
if (aFile.isFile())
return aFile.lastModifiedTime;
try {
if (aFile.isFile())
return aFile.lastModifiedTime;
if (aFile.isDirectory()) {
let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
let entry, time;
let maxTime = aFile.lastModifiedTime;
while ((entry = entries.nextFile)) {
time = recursiveLastModifiedTime(entry);
maxTime = Math.max(time, maxTime);
if (aFile.isDirectory()) {
let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
let entry, time;
let maxTime = aFile.lastModifiedTime;
while ((entry = entries.nextFile)) {
time = recursiveLastModifiedTime(entry);
maxTime = Math.max(time, maxTime);
}
entries.close();
return maxTime;
}
entries.close();
return maxTime;
}
catch (e) {
WARN("Problem getting last modified time for " + aFile.path, e);
}
// If the file is something else, just ignore it.
@ -1748,7 +1767,7 @@ var XPIProvider = {
null);
this.minCompatiblePlatformVersion = Prefs.getCharPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
null);
this.enabledAddons = [];
this.enabledAddons = "";
Services.prefs.addObserver(PREF_EM_MIN_COMPAT_APP_VERSION, this, false);
Services.prefs.addObserver(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, this, false);
@ -1865,11 +1884,13 @@ var XPIProvider = {
delete this._uriMappings;
if (gLazyObjectsLoaded) {
XPIDatabase.shutdown(function shutdownCallback() {
Services.obs.notifyObservers(null, "xpi-provider-shutdown", null);
XPIDatabase.shutdown(function shutdownCallback(saveError) {
LOG("Notifying XPI shutdown observers");
Services.obs.notifyObservers(null, "xpi-provider-shutdown", saveError);
});
}
else {
LOG("Notifying XPI shutdown observers");
Services.obs.notifyObservers(null, "xpi-provider-shutdown", null);
}
},
@ -1927,7 +1948,7 @@ var XPIProvider = {
},
/**
* Persists changes to XPIProvider.bootstrappedAddons to it's store (a pref).
* Persists changes to XPIProvider.bootstrappedAddons to its store (a pref).
*/
persistBootstrappedAddons: function XPI_persistBootstrappedAddons() {
Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
@ -2487,7 +2508,7 @@ var XPIProvider = {
applyBlocklistChanges(aOldAddon, newAddon);
// Carry over any pendingUninstall state to add-ons modified directly
// in the profile. This is impoprtant when the attempt to remove the
// in the profile. This is important when the attempt to remove the
// add-on in processPendingFileChanges failed and caused an mtime
// change to the add-ons files.
newAddon.pendingUninstall = aOldAddon.pendingUninstall;
@ -2518,31 +2539,33 @@ var XPIProvider = {
newAddon.visible = !(newAddon.id in visibleAddons);
// Update the database
XPIDatabase.updateAddonMetadata(aOldAddon, newAddon, aAddonState.descriptor);
if (newAddon.visible) {
visibleAddons[newAddon.id] = newAddon;
let newDBAddon = XPIDatabase.updateAddonMetadata(aOldAddon, newAddon,
aAddonState.descriptor);
if (newDBAddon.visible) {
visibleAddons[newDBAddon.id] = newDBAddon;
// Remember add-ons that were changed during startup
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
newAddon.id);
newDBAddon.id);
// If this was the active theme and it is now disabled then enable the
// default theme
if (aOldAddon.active && isAddonDisabled(newAddon))
if (aOldAddon.active && isAddonDisabled(newDBAddon))
XPIProvider.enableDefaultTheme();
// If the new add-on is bootstrapped and active then call its install method
if (newAddon.active && newAddon.bootstrap) {
if (newDBAddon.active && newDBAddon.bootstrap) {
// Startup cache must be flushed before calling the bootstrap script
flushStartupCache();
let installReason = Services.vc.compare(aOldAddon.version, newAddon.version) < 0 ?
let installReason = Services.vc.compare(aOldAddon.version, newDBAddon.version) < 0 ?
BOOTSTRAP_REASONS.ADDON_UPGRADE :
BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, newAddon.type, file,
"install", installReason, { oldVersion: aOldAddon.version });
XPIProvider.callBootstrapMethod(newDBAddon.id, newDBAddon.version,
newDBAddon.type, file, "install",
installReason, { oldVersion: aOldAddon.version });
return false;
}
@ -2569,11 +2592,10 @@ var XPIProvider = {
function updateDescriptor(aInstallLocation, aOldAddon, aAddonState) {
LOG("Add-on " + aOldAddon.id + " moved to " + aAddonState.descriptor);
aOldAddon._descriptor = aAddonState.descriptor;
aOldAddon.descriptor = aAddonState.descriptor;
aOldAddon.visible = !(aOldAddon.id in visibleAddons);
XPIDatabase.saveChanges();
// Update the database
XPIDatabase.setAddonDescriptor(aOldAddon, aAddonState.descriptor);
if (aOldAddon.visible) {
visibleAddons[aOldAddon.id] = aOldAddon;
@ -2630,8 +2652,7 @@ var XPIProvider = {
// If it should be active then mark it as active otherwise unload
// its scope
if (!isAddonDisabled(aOldAddon)) {
aOldAddon.active = true;
XPIDatabase.updateAddonActive(aOldAddon);
XPIDatabase.updateAddonActive(aOldAddon, true);
}
else {
XPIProvider.unloadBootstrapScope(newAddon.id);
@ -2646,38 +2667,27 @@ var XPIProvider = {
// App version changed, we may need to update the appDisabled property.
if (aUpdateCompatibility) {
// Create a basic add-on object for the new state to save reproducing
// the applyBlocklistChanges code
let newAddon = new AddonInternal();
newAddon.id = aOldAddon.id;
newAddon.syncGUID = aOldAddon.syncGUID;
newAddon.version = aOldAddon.version;
newAddon.type = aOldAddon.type;
newAddon.appDisabled = !isUsableAddon(aOldAddon);
// Sync the userDisabled flag to the selectedSkin
if (aOldAddon.type == "theme")
newAddon.userDisabled = aOldAddon.internalName != XPIProvider.selectedSkin;
applyBlocklistChanges(aOldAddon, newAddon, aOldAppVersion,
aOldPlatformVersion);
let wasDisabled = isAddonDisabled(aOldAddon);
let isDisabled = isAddonDisabled(newAddon);
let wasAppDisabled = aOldAddon.appDisabled;
let wasUserDisabled = aOldAddon.userDisabled;
let wasSoftDisabled = aOldAddon.softDisabled;
// This updates the addon's JSON cached data in place
applyBlocklistChanges(aOldAddon, aOldAddon, aOldAppVersion,
aOldPlatformVersion);
aOldAddon.appDisabled = !isUsableAddon(aOldAddon);
let isDisabled = isAddonDisabled(aOldAddon);
// If either property has changed update the database.
if (newAddon.appDisabled != aOldAddon.appDisabled ||
newAddon.userDisabled != aOldAddon.userDisabled ||
newAddon.softDisabled != aOldAddon.softDisabled) {
if (wasAppDisabled != aOldAddon.appDisabled ||
wasUserDisabled != aOldAddon.userDisabled ||
wasSoftDisabled != aOldAddon.softDisabled) {
LOG("Add-on " + aOldAddon.id + " changed appDisabled state to " +
newAddon.appDisabled + ", userDisabled state to " +
newAddon.userDisabled + " and softDisabled state to " +
newAddon.softDisabled);
XPIDatabase.setAddonProperties(aOldAddon, {
appDisabled: newAddon.appDisabled,
userDisabled: newAddon.userDisabled,
softDisabled: newAddon.softDisabled
});
aOldAddon.appDisabled + ", userDisabled state to " +
aOldAddon.userDisabled + " and softDisabled state to " +
aOldAddon.softDisabled);
XPIDatabase.saveChanges();
}
// If this is a visible add-on and it has changed disabled state then we
@ -2690,8 +2700,7 @@ var XPIProvider = {
AddonManagerPrivate.addStartupChange(change, aOldAddon.id);
if (aOldAddon.bootstrap) {
// Update the add-ons active state
aOldAddon.active = !isDisabled;
XPIDatabase.updateAddonActive(aOldAddon);
XPIDatabase.updateAddonActive(aOldAddon, !isDisabled);
}
else {
changed = true;
@ -2713,17 +2722,15 @@ var XPIProvider = {
/**
* Called when an add-on has been removed.
*
* @param aInstallLocation
* The install location containing the add-on
* @param aOldAddon
* The AddonInternal as it appeared the last time the application
* ran
* @return a boolean indicating if flushing caches is required to complete
* changing this add-on
*/
function removeMetadata(aInstallLocation, aOldAddon) {
function removeMetadata(aOldAddon) {
// This add-on has disappeared
LOG("Add-on " + aOldAddon.id + " removed from " + aInstallLocation);
LOG("Add-on " + aOldAddon.id + " removed from " + aOldAddon.location);
XPIDatabase.removeAddonMetadata(aOldAddon);
// Remember add-ons that were uninstalled during startup
@ -2886,49 +2893,38 @@ var XPIProvider = {
newAddon.active = (newAddon.visible && !isAddonDisabled(newAddon))
}
try {
// Update the database.
XPIDatabase.addAddonMetadata(newAddon, aAddonState.descriptor);
}
catch (e) {
// Failing to write the add-on into the database is non-fatal, the
// add-on will just be unavailable until we try again in a subsequent
// startup
ERROR("Failed to add add-on " + aId + " in " + aInstallLocation.name +
" to database", e);
return false;
}
let newDBAddon = XPIDatabase.addAddonMetadata(newAddon, aAddonState.descriptor);
if (newAddon.visible) {
if (newDBAddon.visible) {
// Remember add-ons that were first detected during startup.
if (isDetectedInstall) {
// If a copy from a higher priority location was removed then this
// add-on has changed
if (AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_UNINSTALLED)
.indexOf(newAddon.id) != -1) {
.indexOf(newDBAddon.id) != -1) {
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
newAddon.id);
newDBAddon.id);
}
else {
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_INSTALLED,
newAddon.id);
newDBAddon.id);
}
}
// Note if any visible add-on is not in the application install location
if (newAddon._installLocation.name != KEY_APP_GLOBAL)
if (newDBAddon._installLocation.name != KEY_APP_GLOBAL)
XPIProvider.allAppGlobal = false;
visibleAddons[newAddon.id] = newAddon;
visibleAddons[newDBAddon.id] = newDBAddon;
let installReason = BOOTSTRAP_REASONS.ADDON_INSTALL;
let extraParams = {};
// If we're hiding a bootstrapped add-on then call its uninstall method
if (newAddon.id in oldBootstrappedAddons) {
let oldBootstrap = oldBootstrappedAddons[newAddon.id];
if (newDBAddon.id in oldBootstrappedAddons) {
let oldBootstrap = oldBootstrappedAddons[newDBAddon.id];
extraParams.oldVersion = oldBootstrap.version;
XPIProvider.bootstrappedAddons[newAddon.id] = oldBootstrap;
XPIProvider.bootstrappedAddons[newDBAddon.id] = oldBootstrap;
// If the old version is the same as the new version, or we're
// recovering from a corrupt DB, don't call uninstall and install
@ -2936,7 +2932,7 @@ var XPIProvider = {
if (sameVersion || !isNewInstall)
return false;
installReason = Services.vc.compare(oldBootstrap.version, newAddon.version) < 0 ?
installReason = Services.vc.compare(oldBootstrap.version, newDBAddon.version) < 0 ?
BOOTSTRAP_REASONS.ADDON_UPGRADE :
BOOTSTRAP_REASONS.ADDON_DOWNGRADE;
@ -2944,27 +2940,27 @@ var XPIProvider = {
createInstance(Ci.nsIFile);
oldAddonFile.persistentDescriptor = oldBootstrap.descriptor;
XPIProvider.callBootstrapMethod(newAddon.id, oldBootstrap.version,
XPIProvider.callBootstrapMethod(newDBAddon.id, oldBootstrap.version,
oldBootstrap.type, oldAddonFile, "uninstall",
installReason, { newVersion: newAddon.version });
XPIProvider.unloadBootstrapScope(newAddon.id);
installReason, { newVersion: newDBAddon.version });
XPIProvider.unloadBootstrapScope(newDBAddon.id);
// If the new add-on is bootstrapped then we must flush the caches
// before calling the new bootstrap script
if (newAddon.bootstrap)
if (newDBAddon.bootstrap)
flushStartupCache();
}
if (!newAddon.bootstrap)
if (!newDBAddon.bootstrap)
return true;
// Visible bootstrapped add-ons need to have their install method called
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.persistentDescriptor = aAddonState.descriptor;
XPIProvider.callBootstrapMethod(newAddon.id, newAddon.version, newAddon.type, file,
XPIProvider.callBootstrapMethod(newDBAddon.id, newDBAddon.version, newDBAddon.type, file,
"install", installReason, extraParams);
if (!newAddon.active)
XPIProvider.unloadBootstrapScope(newAddon.id);
if (!newDBAddon.active)
XPIProvider.unloadBootstrapScope(newDBAddon.id);
}
return false;
@ -2989,9 +2985,8 @@ var XPIProvider = {
let addonStates = aSt.addons;
// Check if the database knows about any add-ons in this install location.
let pos = knownLocations.indexOf(installLocation.name);
if (pos >= 0) {
knownLocations.splice(pos, 1);
if (knownLocations.has(installLocation.name)) {
knownLocations.delete(installLocation.name);
let addons = XPIDatabase.getAddonsInLocation(installLocation.name);
// Iterate through the add-ons installed the last time the application
// ran
@ -3034,7 +3029,7 @@ var XPIProvider = {
changed = updateMetadata(installLocation, aOldAddon, addonState) ||
changed;
}
else if (aOldAddon._descriptor != addonState.descriptor) {
else if (aOldAddon.descriptor != addonState.descriptor) {
changed = updateDescriptor(installLocation, aOldAddon, addonState) ||
changed;
}
@ -3047,7 +3042,7 @@ var XPIProvider = {
XPIProvider.allAppGlobal = false;
}
else {
changed = removeMetadata(installLocation.name, aOldAddon) || changed;
changed = removeMetadata(aOldAddon) || changed;
}
}, this);
}
@ -3068,12 +3063,12 @@ var XPIProvider = {
// have any add-ons installed in them, or the locations no longer exist.
// The metadata for the add-ons that were in them must be removed from the
// database.
knownLocations.forEach(function(aLocation) {
let addons = XPIDatabase.getAddonsInLocation(aLocation);
for (let location of knownLocations) {
let addons = XPIDatabase.getAddonsInLocation(location);
addons.forEach(function(aOldAddon) {
changed = removeMetadata(aLocation, aOldAddon) || changed;
changed = removeMetadata(aOldAddon) || changed;
}, this);
}, this);
}
// Tell Telemetry what we found
AddonManagerPrivate.recordSimpleMeasure("modifiedUnpacked", modifiedUnpacked);
@ -3192,8 +3187,6 @@ var XPIProvider = {
// If the database doesn't exist and there are add-ons installed then we
// must update the database however if there are no add-ons then there is
// no need to update the database.
// Avoid using XPIDatabase.dbFileExists, as that code is lazy-loaded,
// and we want to avoid loading it until absolutely necessary.
let dbFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_DATABASE], true);
if (!dbFile.exists())
updateDatabase = state.length > 0;
@ -3216,17 +3209,13 @@ var XPIProvider = {
}
}
// Catch any errors during the main startup and rollback the database changes
let transationBegun = false;
// Catch and log any errors during the main startup
try {
let extensionListChanged = false;
// If the database needs to be updated then open it and then update it
// from the filesystem
if (updateDatabase || hasPendingChanges) {
XPIDatabase.beginTransaction();
transationBegun = true;
XPIDatabase.openConnection(false, true);
XPIDatabase.syncLoadDB(false);
try {
extensionListChanged = this.processFileChanges(state, manifests,
aAppChanged,
@ -3234,7 +3223,7 @@ var XPIProvider = {
aOldPlatformVersion);
}
catch (e) {
ERROR("Error processing file changes", e);
ERROR("Failed to process extension changes at startup", e);
}
}
AddonManagerPrivate.recordSimpleMeasure("installedUnpacked", this.unpackedAddons);
@ -3243,10 +3232,6 @@ var XPIProvider = {
// When upgrading the app and using a custom skin make sure it is still
// compatible otherwise switch back the default
if (this.currentSkin != this.defaultSkin) {
if (!transationBegun) {
XPIDatabase.beginTransaction();
transationBegun = true;
}
let oldSkin = XPIDatabase.getVisibleAddonForInternalName(this.currentSkin);
if (!oldSkin || isAddonDisabled(oldSkin))
this.enableDefaultTheme();
@ -3254,21 +3239,21 @@ var XPIProvider = {
// When upgrading remove the old extensions cache to force older
// versions to rescan the entire list of extensions
let oldCache = FileUtils.getFile(KEY_PROFILEDIR, [FILE_OLD_CACHE], true);
if (oldCache.exists())
oldCache.remove(true);
try {
let oldCache = FileUtils.getFile(KEY_PROFILEDIR, [FILE_OLD_CACHE], true);
if (oldCache.exists())
oldCache.remove(true);
}
catch (e) {
WARN("Unable to remove old extension cache " + oldCache.path, e);
}
}
// If the application crashed before completing any pending operations then
// we should perform them now.
if (extensionListChanged || hasPendingChanges) {
LOG("Updating database with changes to installed add-ons");
if (!transationBegun) {
XPIDatabase.beginTransaction();
transationBegun = true;
}
XPIDatabase.updateActiveAddons();
XPIDatabase.commitTransaction();
XPIDatabase.writeAddonsList();
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
Services.prefs.setCharPref(PREF_BOOTSTRAP_ADDONS,
@ -3277,14 +3262,9 @@ var XPIProvider = {
}
LOG("No changes found");
if (transationBegun)
XPIDatabase.commitTransaction();
}
catch (e) {
ERROR("Error during startup file checks, rolling back any database " +
"changes", e);
if (transationBegun)
XPIDatabase.rollbackTransaction();
ERROR("Error during startup file checks", e);
}
// Check that the add-ons list still exists
@ -3465,7 +3445,7 @@ var XPIProvider = {
let results = [createWrapper(a) for each (a in aAddons)];
XPIProvider.installs.forEach(function(aInstall) {
if (aInstall.state == AddonManager.STATE_INSTALLED &&
!(aInstall.addon instanceof DBAddonInternal))
!(aInstall.addon.inDatabase))
results.push(createWrapper(aInstall.addon));
});
aCallback(results);
@ -3673,7 +3653,7 @@ var XPIProvider = {
null);
this.minCompatiblePlatformVersion = Prefs.getCharPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
null);
this.updateAllAddonDisabledStates();
this.updateAddonAppDisabledStates();
break;
}
},
@ -3783,7 +3763,7 @@ var XPIProvider = {
// This wouldn't normally be called for an already installed add-on (except
// for forming the operationsRequiringRestart flags) so is really here as
// a safety measure.
if (aAddon instanceof DBAddonInternal)
if (aAddon.inDatabase)
return false;
// If we have an AddonInstall for this add-on then we can see if there is
@ -3992,8 +3972,7 @@ var XPIProvider = {
this.bootstrapScopes[aId][aMethod](params, aReason);
}
catch (e) {
WARN("Exception running bootstrap method " + aMethod + " on " +
aId, e);
WARN("Exception running bootstrap method " + aMethod + " on " + aId, e);
}
}
finally {
@ -4004,20 +3983,10 @@ var XPIProvider = {
}
},
/**
* Updates the appDisabled property for all add-ons.
*/
updateAllAddonDisabledStates: function XPI_updateAllAddonDisabledStates() {
let addons = XPIDatabase.getAddons();
addons.forEach(function(aAddon) {
this.updateAddonDisabledState(aAddon);
}, this);
},
/**
* Updates the disabled state for an add-on. Its appDisabled property will be
* calculated and if the add-on is changed appropriate notifications will be
* sent out to the registered AddonListeners.
* calculated and if the add-on is changed the database will be saved and
* appropriate notifications will be sent out to the registered AddonListeners.
*
* @param aAddon
* The DBAddonInternal to update
@ -4032,7 +4001,7 @@ var XPIProvider = {
updateAddonDisabledState: function XPI_updateAddonDisabledState(aAddon,
aUserDisabled,
aSoftDisabled) {
if (!(aAddon instanceof DBAddonInternal))
if (!(aAddon.inDatabase))
throw new Error("Can only update addon states for installed addons.");
if (aUserDisabled !== undefined && aSoftDisabled !== undefined) {
throw new Error("Cannot change userDisabled and softDisabled at the " +
@ -4105,8 +4074,7 @@ var XPIProvider = {
}
if (!needsRestart) {
aAddon.active = !isDisabled;
XPIDatabase.updateAddonActive(aAddon);
XPIDatabase.updateAddonActive(aAddon, !isDisabled);
if (isDisabled) {
if (aAddon.bootstrap) {
let file = aAddon._installLocation.getLocationForID(aAddon.id);
@ -4142,7 +4110,7 @@ var XPIProvider = {
* location that does not allow it
*/
uninstallAddon: function XPI_uninstallAddon(aAddon) {
if (!(aAddon instanceof DBAddonInternal))
if (!(aAddon.inDatabase))
throw new Error("Can only uninstall installed addons.");
if (aAddon._installLocation.locked)
@ -4184,8 +4152,7 @@ var XPIProvider = {
AddonManagerPrivate.callAddonListeners("onInstalling", wrappedAddon, false);
if (!isAddonDisabled(aAddon) && !XPIProvider.enableRequiresRestart(aAddon)) {
aAddon.active = true;
XPIDatabase.updateAddonActive(aAddon);
XPIDatabase.updateAddonActive(aAddon, true);
}
if (aAddon.bootstrap) {
@ -4255,7 +4222,7 @@ var XPIProvider = {
* The DBAddonInternal to cancel uninstall for
*/
cancelUninstallAddon: function XPI_cancelUninstallAddon(aAddon) {
if (!(aAddon instanceof DBAddonInternal))
if (!(aAddon.inDatabase))
throw new Error("Can only cancel uninstall for installed addons.");
cleanStagingDir(aAddon._installLocation.getStagingDir(), [aAddon.id]);
@ -5244,7 +5211,7 @@ AddonInstall.prototype = {
// Point the add-on to its extracted files as the xpi may get deleted
this.addon._sourceBundle = stagedAddon;
// Cache the AddonInternal as it may have updated compatibiltiy info
// Cache the AddonInternal as it may have updated compatibility info
let stagedJSON = stagedAddon.clone();
stagedJSON.leafName = this.addon.id + ".json";
if (stagedJSON.exists())
@ -5313,8 +5280,7 @@ AddonInstall.prototype = {
}
if (!isUpgrade && this.existingAddon.active) {
this.existingAddon.active = false;
XPIDatabase.updateAddonActive(this.existingAddon);
XPIDatabase.updateAddonActive(this.existingAddon, false);
}
}
@ -5327,54 +5293,50 @@ AddonInstall.prototype = {
// Update the metadata in the database
this.addon._sourceBundle = file;
this.addon._installLocation = this.installLocation;
this.addon.updateDate = recursiveLastModifiedTime(file);
this.addon.updateDate = recursiveLastModifiedTime(file); // XXX sync recursive scan
this.addon.visible = true;
if (isUpgrade) {
XPIDatabase.updateAddonMetadata(this.existingAddon, this.addon,
file.persistentDescriptor);
this.addon = XPIDatabase.updateAddonMetadata(this.existingAddon, this.addon,
file.persistentDescriptor);
}
else {
this.addon.installDate = this.addon.updateDate;
this.addon.active = (this.addon.visible && !isAddonDisabled(this.addon))
XPIDatabase.addAddonMetadata(this.addon, file.persistentDescriptor);
this.addon = XPIDatabase.addAddonMetadata(this.addon, file.persistentDescriptor);
}
// Retrieve the new DBAddonInternal for the add-on we just added
let self = this;
XPIDatabase.getAddonInLocation(this.addon.id, this.installLocation.name,
function startInstall_getAddonInLocation(a) {
self.addon = a;
let extraParams = {};
if (self.existingAddon) {
extraParams.oldVersion = self.existingAddon.version;
}
let extraParams = {};
if (this.existingAddon) {
extraParams.oldVersion = this.existingAddon.version;
}
if (self.addon.bootstrap) {
XPIProvider.callBootstrapMethod(self.addon.id, self.addon.version,
self.addon.type, file, "install",
if (this.addon.bootstrap) {
XPIProvider.callBootstrapMethod(this.addon.id, this.addon.version,
this.addon.type, file, "install",
reason, extraParams);
}
AddonManagerPrivate.callAddonListeners("onInstalled",
createWrapper(this.addon));
LOG("Install of " + this.sourceURI.spec + " completed.");
this.state = AddonManager.STATE_INSTALLED;
AddonManagerPrivate.callInstallListeners("onInstallEnded",
this.listeners, this.wrapper,
createWrapper(this.addon));
if (this.addon.bootstrap) {
if (this.addon.active) {
XPIProvider.callBootstrapMethod(this.addon.id, this.addon.version,
this.addon.type, file, "startup",
reason, extraParams);
}
AddonManagerPrivate.callAddonListeners("onInstalled",
createWrapper(self.addon));
LOG("Install of " + self.sourceURI.spec + " completed.");
self.state = AddonManager.STATE_INSTALLED;
AddonManagerPrivate.callInstallListeners("onInstallEnded",
self.listeners, self.wrapper,
createWrapper(self.addon));
if (self.addon.bootstrap) {
if (self.addon.active) {
XPIProvider.callBootstrapMethod(self.addon.id, self.addon.version,
self.addon.type, file, "startup",
reason, extraParams);
}
else {
XPIProvider.unloadBootstrapScope(self.addon.id);
}
else {
// XXX this makes it dangerous to do many things in onInstallEnded
// listeners because important cleanup hasn't been done yet
XPIProvider.unloadBootstrapScope(this.addon.id);
}
});
}
}
}
catch (e) {
@ -5749,8 +5711,8 @@ UpdateChecker.prototype = {
/**
* The AddonInternal is an internal only representation of add-ons. It may
* have come from the database (see DBAddonInternal below) or an install
* manifest.
* have come from the database (see DBAddonInternal in XPIProviderUtils.jsm)
* or an install manifest.
*/
function AddonInternal() {
}
@ -5766,13 +5728,6 @@ AddonInternal.prototype = {
releaseNotesURI: null,
foreignInstall: false,
get isForeignInstall() {
return this.foreignInstall;
},
set isForeignInstall(aVal) {
this.foreignInstall = aVal;
},
get selectedLocale() {
if (this._selectedLocale)
return this._selectedLocale;
@ -5967,10 +5922,7 @@ AddonInternal.prototype = {
* A JS object containing the cached metadata
*/
importMetadata: function AddonInternal_importMetaData(aObj) {
["syncGUID", "targetApplications", "userDisabled", "softDisabled",
"existingAddonID", "sourceURI", "releaseNotesURI", "installDate",
"updateDate", "applyBackgroundUpdates", "compatibilityOverrides"]
.forEach(function(aProp) {
PENDING_INSTALL_METADATA.forEach(function(aProp) {
if (!(aProp in aObj))
return;
@ -5982,77 +5934,6 @@ AddonInternal.prototype = {
}
};
/**
* The DBAddonInternal is a special AddonInternal that has been retrieved from
* the database. Add-ons retrieved synchronously only have the basic metadata
* the rest is filled out synchronously when needed. Asynchronously read add-ons
* have all data available.
*/
function DBAddonInternal() {
this.__defineGetter__("targetApplications", function DBA_targetApplicationsGetter() {
delete this.targetApplications;
return this.targetApplications = XPIDatabase._getTargetApplications(this);
});
this.__defineGetter__("targetPlatforms", function DBA_targetPlatformsGetter() {
delete this.targetPlatforms;
return this.targetPlatforms = XPIDatabase._getTargetPlatforms(this);
});
this.__defineGetter__("locales", function DBA_localesGetter() {
delete this.locales;
return this.locales = XPIDatabase._getLocales(this);
});
this.__defineGetter__("defaultLocale", function DBA_defaultLocaleGetter() {
delete this.defaultLocale;
return this.defaultLocale = XPIDatabase._getDefaultLocale(this);
});
this.__defineGetter__("pendingUpgrade", function DBA_pendingUpgradeGetter() {
delete this.pendingUpgrade;
for (let install of XPIProvider.installs) {
if (install.state == AddonManager.STATE_INSTALLED &&
!(install.addon instanceof DBAddonInternal) &&
install.addon.id == this.id &&
install.installLocation == this._installLocation) {
return this.pendingUpgrade = install.addon;
}
};
});
}
DBAddonInternal.prototype = {
applyCompatibilityUpdate: function DBA_applyCompatibilityUpdate(aUpdate, aSyncCompatibility) {
let changes = [];
this.targetApplications.forEach(function(aTargetApp) {
aUpdate.targetApplications.forEach(function(aUpdateTarget) {
if (aTargetApp.id == aUpdateTarget.id && (aSyncCompatibility ||
Services.vc.compare(aTargetApp.maxVersion, aUpdateTarget.maxVersion) < 0)) {
aTargetApp.minVersion = aUpdateTarget.minVersion;
aTargetApp.maxVersion = aUpdateTarget.maxVersion;
changes.push(aUpdateTarget);
}
});
});
try {
XPIDatabase.updateTargetApplications(this, changes);
}
catch (e) {
// A failure just means that we discard the compatibility update
ERROR("Failed to update target application info in the database for " +
"add-on " + this.id, e);
return;
}
XPIProvider.updateAddonDisabledState(this);
}
}
DBAddonInternal.prototype.__proto__ = AddonInternal.prototype;
// Make it accessible to XPIDatabase.
XPIProvider.DBAddonInternal = DBAddonInternal;
/**
* Creates an AddonWrapper for an AddonInternal.
*
@ -6304,7 +6185,7 @@ function AddonWrapper(aAddon) {
if (aAddon.syncGUID == val)
return val;
if (aAddon instanceof DBAddonInternal)
if (aAddon.inDatabase)
XPIDatabase.setAddonSyncGUID(aAddon, val);
aAddon.syncGUID = val;
@ -6331,7 +6212,7 @@ function AddonWrapper(aAddon) {
this.__defineGetter__("pendingOperations", function AddonWrapper_pendingOperationsGetter() {
let pending = 0;
if (!(aAddon instanceof DBAddonInternal)) {
if (!(aAddon.inDatabase)) {
// Add-on is pending install if there is no associated install (shouldn't
// happen here) or if the install is in the process of or has successfully
// completed the install. If an add-on is pending install then we ignore
@ -6375,7 +6256,7 @@ function AddonWrapper(aAddon) {
let permissions = 0;
// Add-ons that aren't installed cannot be modified in any way
if (!(aAddon instanceof DBAddonInternal))
if (!(aAddon.inDatabase))
return permissions;
if (!aAddon.appDisabled) {
@ -6410,7 +6291,7 @@ function AddonWrapper(aAddon) {
if (val == this.userDisabled)
return val;
if (aAddon instanceof DBAddonInternal) {
if (aAddon.inDatabase) {
if (aAddon.type == "theme" && val) {
if (aAddon.internalName == XPIProvider.defaultSkin)
throw new Error("Cannot disable the default theme");
@ -6434,7 +6315,7 @@ function AddonWrapper(aAddon) {
if (val == aAddon.softDisabled)
return val;
if (aAddon instanceof DBAddonInternal) {
if (aAddon.inDatabase) {
// When softDisabling a theme just enable the active theme
if (aAddon.type == "theme" && val && !aAddon.userDisabled) {
if (aAddon.internalName == XPIProvider.defaultSkin)
@ -6459,7 +6340,7 @@ function AddonWrapper(aAddon) {
};
this.uninstall = function AddonWrapper_uninstall() {
if (!(aAddon instanceof DBAddonInternal))
if (!(aAddon.inDatabase))
throw new Error("Cannot uninstall an add-on that isn't installed");
if (aAddon.pendingUninstall)
throw new Error("Add-on is already marked to be uninstalled");
@ -6467,7 +6348,7 @@ function AddonWrapper(aAddon) {
};
this.cancelUninstall = function AddonWrapper_cancelUninstall() {
if (!(aAddon instanceof DBAddonInternal))
if (!(aAddon.inDatabase))
throw new Error("Cannot cancel uninstall for an add-on that isn't installed");
if (!aAddon.pendingUninstall)
throw new Error("Add-on is not marked to be uninstalled");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -344,6 +344,10 @@ function do_check_icons(aActual, aExpected) {
}
}
// Record the error (if any) from trying to save the XPI
// database at shutdown time
let gXPISaveError = null;
/**
* Starts up the add-on manager as if it was started by the application.
*
@ -396,26 +400,24 @@ function shutdownManager() {
if (!gInternalManager)
return;
let obs = AM_Cc["@mozilla.org/observer-service;1"].
getService(AM_Ci.nsIObserverService);
let xpiShutdown = false;
obs.addObserver({
Services.obs.addObserver({
observe: function(aSubject, aTopic, aData) {
xpiShutdown = true;
obs.removeObserver(this, "xpi-provider-shutdown");
gXPISaveError = aData;
Services.obs.removeObserver(this, "xpi-provider-shutdown");
}
}, "xpi-provider-shutdown", false);
let repositoryShutdown = false;
obs.addObserver({
Services.obs.addObserver({
observe: function(aSubject, aTopic, aData) {
repositoryShutdown = true;
obs.removeObserver(this, "addon-repository-shutdown");
Services.obs.removeObserver(this, "addon-repository-shutdown");
}
}, "addon-repository-shutdown", false);
obs.notifyObservers(null, "quit-application-granted", null);
Services.obs.notifyObservers(null, "quit-application-granted", null);
let scope = Components.utils.import("resource://gre/modules/AddonManager.jsm");
scope.AddonManagerInternal.shutdown();
gInternalManager = null;
@ -428,14 +430,11 @@ function shutdownManager() {
// Clear any crash report annotations
gAppInfo.annotations = {};
let thr = AM_Cc["@mozilla.org/thread-manager;1"].
getService(AM_Ci.nsIThreadManager).
mainThread;
let thr = Services.tm.mainThread;
// Wait until we observe the shutdown notifications
while (!repositoryShutdown || !xpiShutdown) {
if (thr.hasPendingEvents())
thr.processNextEvent(false);
thr.processNextEvent(true);
}
// Force the XPIProvider provider to reload to better
@ -1394,6 +1393,60 @@ function do_exception_wrap(func) {
};
}
const EXTENSIONS_DB = "extensions.json";
let gExtensionsJSON = gProfD.clone();
gExtensionsJSON.append(EXTENSIONS_DB);
/**
* Change the schema version of the JSON extensions database
*/
function changeXPIDBVersion(aNewVersion) {
let jData = loadJSON(gExtensionsJSON);
jData.schemaVersion = aNewVersion;
saveJSON(jData, gExtensionsJSON);
}
/**
* Raw load of a JSON file
*/
function loadJSON(aFile) {
let data = "";
let fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
let cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Components.interfaces.nsIConverterInputStream);
fstream.init(aFile, -1, 0, 0);
cstream.init(fstream, "UTF-8", 0, 0);
let (str = {}) {
let read = 0;
do {
read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value
data += str.value;
} while (read != 0);
}
cstream.close();
do_print("Loaded JSON file " + aFile.path);
return(JSON.parse(data));
}
/**
* Raw save of a JSON blob to file
*/
function saveJSON(aData, aFile) {
do_print("Starting to save JSON file " + aFile.path);
let stream = FileUtils.openSafeFileOutputStream(aFile);
let converter = AM_Cc["@mozilla.org/intl/converter-output-stream;1"].
createInstance(AM_Ci.nsIConverterOutputStream);
converter.init(stream, "UTF-8", 0, 0x0000);
// XXX pretty print the JSON while debugging
converter.writeString(JSON.stringify(aData, null, 2));
converter.flush();
// nsConverterOutputStream doesn't finish() safe output streams on close()
FileUtils.closeSafeFileOutputStream(stream);
converter.close();
do_print("Done saving JSON file " + aFile.path);
}
/**
* Create a callback function that calls do_execute_soon on an actual callback and arguments
*/

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

@ -512,7 +512,7 @@ function check_cache(aExpectedToFind, aExpectedImmediately, aCallback) {
* A callback to call once the checks are complete
*/
function check_initialized_cache(aExpectedToFind, aCallback) {
check_cache(aExpectedToFind, true, function() {
check_cache(aExpectedToFind, true, function restart_initialized_cache() {
restartManager();
// If cache is disabled, then expect results immediately
@ -534,13 +534,13 @@ function waitForFlushedData(aCallback) {
function run_test() {
// Setup for test
do_test_pending();
do_test_pending("test_AddonRepository_cache");
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
startupManager();
// Install XPI add-ons
installAllFiles(ADDON_FILES, function() {
installAllFiles(ADDON_FILES, function first_installs() {
restartManager();
gServer = new HttpServer();
@ -552,7 +552,7 @@ function run_test() {
}
function end_test() {
gServer.stop(do_test_finished);
gServer.stop(function() {do_test_finished("test_AddonRepository_cache");});
}
// Tests AddonRepository.cacheEnabled
@ -578,7 +578,7 @@ function run_test_3() {
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_FAILED);
AddonRepository.repopulateCache(ADDON_IDS, function() {
AddonRepository.repopulateCache(ADDON_IDS, function test_3_repopulated() {
check_initialized_cache([false, false, false], run_test_4);
});
}
@ -695,7 +695,7 @@ function run_test_12() {
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_RESULTS);
AddonManager.getAddonsByIDs(ADDON_IDS, function(aAddons) {
AddonManager.getAddonsByIDs(ADDON_IDS, function test_12_check(aAddons) {
check_results(aAddons, WITHOUT_CACHE);
do_execute_soon(run_test_13);
});

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

@ -103,6 +103,6 @@ function run_test_1() {
do_check_eq(JSON.stringify(manifest[i]), JSON.stringify(expected[i]));
}
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -37,8 +37,8 @@ function DeferredSaveTester(aDelay, aDataProvider) {
return tester.saver.flush();
},
get error() {
return tester.saver.error;
get lastError() {
return tester.saver.lastError;
}
};
@ -154,11 +154,11 @@ add_task(function test_error_immediate() {
count => do_throw("Did not get expected error"),
error => do_check_eq(testError.message, error.message)
);
do_check_eq(testError, tester.error);
do_check_eq(testError, tester.lastError);
// This write should succeed and clear the error
yield tester.save("test_error_immediate succeeds");
do_check_eq(null, tester.error);
do_check_eq(null, tester.lastError);
// The failed save attempt counts in our total
do_check_eq(2, tester.saver.totalSaves);
});

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

@ -0,0 +1,54 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that we rebuild the database correctly if it contains
// JSON data that parses correctly but doesn't contain required fields
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "2.0",
name: "Test 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
function run_test() {
do_test_pending("Bad JSON");
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
// This addon will be auto-installed at startup
writeInstallRDFForExtension(addon1, profileDir);
startupManager();
shutdownManager();
// First startup/shutdown finished
// Replace the JSON store with something bogus
saveJSON({not: "what we expect to find"}, gExtensionsJSON);
startupManager(false);
// Retrieve an addon to force the database to rebuild
AddonManager.getAddonsByIDs([addon1.id], callback_soon(after_db_rebuild));
}
function after_db_rebuild([a1]) {
do_check_eq(a1.id, addon1.id);
shutdownManager();
// Make sure our JSON database has schemaVersion and our installed extension
let data = loadJSON(gExtensionsJSON);
do_check_true("schemaVersion" in data);
do_check_eq(data.addons[0].id, addon1.id);
do_test_finished("Bad JSON");
}

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

@ -254,14 +254,11 @@ function run_test_1() {
function run_test_1_modified_db() {
// After restarting the database won't be open and so can be replaced with
// a bad file
restartManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
var db = Services.storage.openDatabase(dbfile);
db.schemaVersion = 100;
db.close();
// After restarting the database won't be open so we can alter
// the schema
shutdownManager();
changeXPIDBVersion(100);
startupManager();
// Accessing the add-ons should open and recover the database. Since
// migration occurs everything should be recovered correctly

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

@ -335,12 +335,12 @@ const ADDON_IDS = ["softblock1@tests.mozilla.org",
// Don't need the full interface, attempts to call other methods will just
// throw which is just fine
var WindowWatcher = {
openWindow: function(parent, url, name, features, arguments) {
openWindow: function(parent, url, name, features, openArgs) {
// Should be called to list the newly blocklisted items
do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
// Simulate auto-disabling any softblocks
var list = arguments.wrappedJSObject.list;
var list = openArgs.wrappedJSObject.list;
list.forEach(function(aItem) {
if (!aItem.blocked)
aItem.disable = true;
@ -531,10 +531,10 @@ function manual_update(aVersion, aCallback) {
// Checks that an add-ons properties match expected values
function check_addon(aAddon, aExpectedVersion, aExpectedUserDisabled,
aExpectedSoftDisabled, aExpectedState) {
do_check_neq(aAddon, null);
dump("Testing " + aAddon.id + " version " + aAddon.version + "\n");
dump(aAddon.userDisabled + " " + aAddon.softDisabled + "\n");
do_check_neq(aAddon, null);
do_check_eq(aAddon.version, aExpectedVersion);
do_check_eq(aAddon.blocklistState, aExpectedState);
do_check_eq(aAddon.userDisabled, aExpectedUserDisabled);
@ -706,11 +706,7 @@ add_test(function run_app_update_schema_test() {
function update_schema_2() {
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
var db = Services.storage.openDatabase(dbfile);
db.schemaVersion = 100;
db.close();
changeXPIDBVersion(100);
gAppInfo.version = "2";
startupManager(true);
@ -738,11 +734,7 @@ add_test(function run_app_update_schema_test() {
restartManager();
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
var db = Services.storage.openDatabase(dbfile);
db.schemaVersion = 100;
db.close();
changeXPIDBVersion(100);
gAppInfo.version = "2.5";
startupManager(true);
@ -764,11 +756,7 @@ add_test(function run_app_update_schema_test() {
function update_schema_4() {
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
var db = Services.storage.openDatabase(dbfile);
db.schemaVersion = 100;
db.close();
changeXPIDBVersion(100);
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
@ -789,11 +777,7 @@ add_test(function run_app_update_schema_test() {
function update_schema_5() {
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
var db = Services.storage.openDatabase(dbfile);
db.schemaVersion = 100;
db.close();
changeXPIDBVersion(100);
gAppInfo.version = "1";
startupManager(true);
@ -1345,7 +1329,7 @@ add_test(function run_manual_update_2_test() {
startupManager(false);
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
AddonManager.getAddonsByIDs(ADDON_IDS, callback_soon(function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -1363,7 +1347,8 @@ add_test(function run_manual_update_2_test() {
manual_update("2", function manual_update_2_2() {
restartManager();
AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h, r]) {
AddonManager.getAddonsByIDs(ADDON_IDS,
callback_soon(function([s1, s2, s3, s4, s5, h, r]) {
check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
@ -1391,9 +1376,9 @@ add_test(function run_manual_update_2_test() {
run_next_test();
});
});
});
}));
});
});
}));
});
// Uses the API to install blocked add-ons from the local filesystem

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

@ -11,8 +11,6 @@ const ADDON_UNINSTALL = 6;
const ADDON_UPGRADE = 7;
const ADDON_DOWNGRADE = 8;
const EXTENSIONS_DB = "extensions.sqlite";
// This verifies that bootstrappable add-ons can be used without restarts.
Components.utils.import("resource://gre/modules/Services.jsm");
@ -148,10 +146,9 @@ function run_test() {
startupManager();
let file = gProfD.clone();
file.append(EXTENSIONS_DB);
do_check_false(file.exists());
do_check_false(gExtensionsJSON.exists());
let file = gProfD.clone();
file.leafName = "extensions.ini";
do_check_false(file.exists());
@ -208,9 +205,6 @@ function run_test_1() {
function check_test_1(installSyncGUID) {
let file = gProfD.clone();
file.append(EXTENSIONS_DB);
do_check_true(file.exists());
file.leafName = "extensions.ini";
do_check_false(file.exists());
@ -356,6 +350,9 @@ function run_test_4() {
// Tests that a restart shuts down and restarts the add-on
function run_test_5() {
shutdownManager();
// By the time we've shut down, the database must have been written
do_check_true(gExtensionsJSON.exists());
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 0);
do_check_eq(getShutdownReason(), APP_SHUTDOWN);
@ -458,7 +455,7 @@ function check_test_7() {
do_check_eq(getShutdownNewVersion(), 0);
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "2.0");
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
do_check_eq(b1, null);
restartManager();
@ -468,7 +465,7 @@ function check_test_7() {
do_check_bootstrappedPref(run_test_8);
});
});
}));
}
// Test that a bootstrapped extension dropped into the profile loads properly
@ -674,12 +671,15 @@ function run_test_12() {
do_check_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
b1.uninstall();
restartManager();
do_check_bootstrappedPref(run_test_13);
do_execute_soon(test_12_restart);
});
}
function test_12_restart() {
restartManager();
do_check_bootstrappedPref(run_test_13);
}
// Tests that installing a bootstrapped extension with an invalid application
// entry doesn't call it's startup method
@ -706,7 +706,7 @@ function run_test_13() {
}, [
"onInstallStarted",
"onInstallEnded",
], function() {do_execute_soon(check_test_13)});
], callback_soon(check_test_13));
install.install();
});
}
@ -727,23 +727,27 @@ function check_test_13() {
do_check_eq(getActiveVersion(), 0); // Should not have called startup though
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "3.0");
restartManager();
do_execute_soon(test_13_restart);
});
});
}
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "3.0");
do_check_true(b1.appDisabled);
do_check_false(b1.userDisabled);
do_check_false(b1.isActive);
do_check_eq(getInstalledVersion(), 3); // We call install even for disabled add-ons
do_check_eq(getActiveVersion(), 0); // Should not have called startup though
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "3.0");
function test_13_restart() {
restartManager();
do_check_bootstrappedPref(function() {
b1.uninstall();
do_execute_soon(run_test_14);
});
});
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "3.0");
do_check_true(b1.appDisabled);
do_check_false(b1.userDisabled);
do_check_false(b1.isActive);
do_check_eq(getInstalledVersion(), 3); // We call install even for disabled add-ons
do_check_eq(getActiveVersion(), 0); // Should not have called startup though
do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "3.0");
do_check_bootstrappedPref(function() {
b1.uninstall();
do_execute_soon(run_test_14);
});
});
}
@ -815,7 +819,7 @@ function run_test_15() {
}, [
"onInstallStarted",
"onInstallEnded",
], function() {do_execute_soon(check_test_15)});
], callback_soon(check_test_15));
install.install();
});
});
@ -857,7 +861,7 @@ function check_test_15() {
function run_test_16() {
resetPrefs();
waitForPref("bootstraptest.startup_reason", function test_16_after_startup() {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
// Should have installed and started
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 1);
@ -875,7 +879,7 @@ function run_test_16() {
gAppInfo.inSafeMode = true;
startupManager(false);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
// Should still be stopped
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 0);
@ -895,10 +899,10 @@ function run_test_16() {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
b1.uninstall();
run_test_17();
do_execute_soon(run_test_17);
});
});
});
}));
}));
});
installAllFiles([do_get_addon("test_bootstrap1_1")], function() { });
}
@ -1025,7 +1029,7 @@ function run_test_20() {
do_check_eq(getInstallOldVersion(), 1);
do_check_eq(getStartupOldVersion(), 0);
run_test_21();
do_execute_soon(run_test_21);
});
}
@ -1082,7 +1086,7 @@ function run_test_22() {
startupManager();
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
// Should have installed and started
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 1);
@ -1126,7 +1130,7 @@ function run_test_22() {
run_test_23();
});
});
});
}));
}
@ -1200,17 +1204,17 @@ function check_test_23() {
let dir = do_get_addon_root_uri(profileDir, "bootstrap1@tests.mozilla.org");
do_check_eq(b1.getResourceURI("bootstrap.js").spec, dir + "bootstrap.js");
AddonManager.getAddonsWithOperationsByTypes(null, function(list) {
AddonManager.getAddonsWithOperationsByTypes(null, callback_soon(function(list) {
do_check_eq(list.length, 0);
restartManager();
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
b1.uninstall();
restartManager();
testserver.stop(run_test_24);
});
});
}));
}));
});
});
});
@ -1277,7 +1281,7 @@ function run_test_25() {
do_check_eq(getInstalledVersion(), 1);
do_check_eq(getActiveVersion(), 1);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "1.0");
do_check_true(b1.isActive);
@ -1298,7 +1302,7 @@ function run_test_25() {
do_check_bootstrappedPref(run_test_26);
});
});
}));
});
});
installAllFiles([do_get_addon("test_bootstrap1_1")], function test_25_installed() {
@ -1314,7 +1318,7 @@ function run_test_26() {
do_check_eq(getInstalledVersion(), 0);
do_check_eq(getActiveVersion(), 0);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "4.0");
do_check_true(b1.isActive);
@ -1335,7 +1339,7 @@ function run_test_26() {
do_check_bootstrappedPref(run_test_27);
});
});
}));
});
}
@ -1358,7 +1362,7 @@ function run_test_27() {
do_check_eq(getUninstallNewVersion(), 4);
do_check_eq(getActiveVersion(), 0);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "4.0");
do_check_false(b1.isActive);
@ -1377,7 +1381,7 @@ function run_test_27() {
do_check_bootstrappedPref(run_test_28);
});
});
}));
});
});
}
@ -1393,7 +1397,7 @@ function run_test_28() {
do_check_eq(getInstallOldVersion(), 4);
do_check_eq(getActiveVersion(), 0);
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", callback_soon(function(b1) {
do_check_neq(b1, null);
do_check_eq(b1.version, "1.0");
do_check_false(b1.isActive);
@ -1417,7 +1421,7 @@ function run_test_28() {
do_check_bootstrappedPref(do_test_finished);
});
});
}));
});
});
}

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

@ -138,7 +138,7 @@ function run_test() {
installAllFiles([do_get_addon(a.addon) for each (a in ADDONS)], function() {
restartManager();
AddonManager.getAddonByID(ADDONS[0].id, function(addon) {
AddonManager.getAddonByID(ADDONS[0].id, callback_soon(function(addon) {
do_check_true(!(!addon));
addon.userDisabled = true;
restartManager();
@ -168,7 +168,7 @@ function run_test() {
}
}
});
});
}));
});
}

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

@ -165,7 +165,7 @@ function run_test() {
installAllFiles([do_get_addon(a.addon) for each (a in ADDONS)], function() {
restartManager();
AddonManager.getAddonByID(ADDONS[1].id, function(addon) {
AddonManager.getAddonByID(ADDONS[1].id, callback_soon(function(addon) {
do_check_true(!(!addon));
addon.userDisabled = true;
restartManager();
@ -176,6 +176,6 @@ function run_test() {
item.findUpdates(updateListener, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
});
});
}));
});
}

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

@ -28,7 +28,7 @@ function run_test()
do_check_eq(addon.optionsURL, null);
do_check_eq(addon.aboutURL, null);
do_test_finished();
do_execute_soon(do_test_finished);
});
});
});

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

@ -96,7 +96,7 @@ function run_test()
onUpdateFinished: function(addon, error) {
do_check_eq(error, AddonManager.UPDATE_STATUS_DOWNLOAD_ERROR);
do_check_true(gSeenExpectedURL);
shutdownTest();
do_execute_soon(shutdownTest);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});

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

@ -27,7 +27,7 @@ function run_test()
}
function run_test_1() {
AddonManager.getAddonByID(ID, function(addon) {
AddonManager.getAddonByID(ID, callback_soon(function(addon) {
do_check_neq(addon, null);
do_check_eq(addon.name, "fr Name");
do_check_eq(addon.description, "fr Description");
@ -40,9 +40,9 @@ function run_test_1() {
do_check_neq(newAddon, null);
do_check_eq(newAddon.name, "fr Name");
run_test_2();
do_execute_soon(run_test_2);
});
});
}));
}
function run_test_2() {
@ -55,7 +55,7 @@ function run_test_2() {
do_check_eq(addon.name, "de-DE Name");
do_check_eq(addon.description, null);
run_test_3();
do_execute_soon(run_test_3);
});
}
@ -69,7 +69,7 @@ function run_test_3() {
do_check_eq(addon.name, "de-DE Name");
do_check_eq(addon.description, null);
run_test_4();
do_execute_soon(run_test_4);
});
}
@ -83,7 +83,7 @@ function run_test_4() {
do_check_eq(addon.name, "es-ES Name");
do_check_eq(addon.description, "es-ES Description");
run_test_5();
do_execute_soon(run_test_5);
});
}
@ -97,7 +97,7 @@ function run_test_5() {
if (addon.name != "zh-TW Name" && addon.name != "zh-CN Name")
do_throw("zh matched to " + addon.name);
run_test_6();
do_execute_soon(run_test_6);
});
}
@ -112,6 +112,6 @@ function run_test_6() {
do_check_eq(addon.name, "en Name");
do_check_eq(addon.description, "en Description");
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -21,7 +21,7 @@ function run_test()
do_check_eq(addon.name, "Deutsches W\u00f6rterbuch");
do_check_eq(addon.name.length, 20);
do_test_finished();
do_execute_soon(do_test_finished);
});
});
}

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

@ -285,7 +285,7 @@ function check_initial_state(callback) {
function check_test_pt1() {
dump("Checking pt 1\n");
AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], function(addons) {
AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], callback_soon(function(addons) {
for (var i = 0; i < ADDONS.length; i++) {
if (!addons[i])
do_throw("Addon " + (i + 1) + " did not get installed correctly");
@ -316,7 +316,7 @@ function check_test_pt1() {
gTestCheck = check_test_pt2;
load_blocklist("bug455906_warn.xml");
});
});
}));
}
function check_notification_pt2(args) {
@ -357,7 +357,7 @@ function check_test_pt2() {
restartManager();
dump("Checking results pt 2\n");
AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], function(addons) {
AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], callback_soon(function(addons) {
// Should have disabled this add-on as requested
do_check_eq(check_addon_state(addons[2]), "true,true,false");
do_check_eq(check_plugin_state(PLUGINS[2]), "true,false");
@ -386,7 +386,7 @@ function check_test_pt2() {
gNotificationCheck = null;
gTestCheck = run_test_pt3;
load_blocklist("bug455906_start.xml");
});
}));
}
function run_test_pt3() {
@ -485,7 +485,7 @@ function check_test_pt3() {
}
function run_test_pt4() {
AddonManager.getAddonByID(ADDONS[4].id, function(addon) {
AddonManager.getAddonByID(ADDONS[4].id, callback_soon(function(addon) {
addon.userDisabled = false;
PLUGINS[4].enabledState = Ci.nsIPluginTag.STATE_ENABLED;
restartManager();
@ -494,7 +494,7 @@ function run_test_pt4() {
gTestCheck = check_test_pt4;
load_blocklist("bug455906_empty.xml");
});
});
}));
}
function check_notification_pt4(args) {

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

@ -90,6 +90,6 @@ function run_test_2() {
do_check_neq(a5, null);
do_check_true(a5.isActive);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -89,6 +89,6 @@ function run_test_2() {
do_check_neq(a5, null);
do_check_true(a5.isActive);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -87,6 +87,6 @@ function run_test_2() {
do_check_neq(a5, null);
do_check_true(a5.isActive);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -54,6 +54,6 @@ function run_test_2() {
do_check_neq(addon, null);
do_check_false(addon.isActive);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -16,7 +16,7 @@ function run_test() {
AddonManager.getAddonsByIDs(["bug526598_1@tests.mozilla.org",
"bug526598_2@tests.mozilla.org"],
function([a1, a2]) {
callback_soon(function([a1, a2]) {
do_check_neq(a1, null);
do_check_true(a1.hasResource("install.rdf"));
@ -47,8 +47,8 @@ function run_test() {
do_check_eq(newa1, null);
do_check_eq(newa2, null);
do_test_finished();
do_execute_soon(do_test_finished);
});
});
}));
});
}

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

@ -31,7 +31,7 @@ function run_test() {
if (!("nsIWindowsRegKey" in Components.interfaces))
do_check_true((file.permissions & 0100) == 0100);
do_test_finished();
do_execute_soon(do_test_finished);
});
});
}

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

@ -332,7 +332,7 @@ function run_test() {
AddonManager.getAddonsByIDs(["bug542391_2@tests.mozilla.org",
"bug542391_4@tests.mozilla.org"],
function disable_and_restart([a2, a4]) {
callback_soon(function disable_and_restart([a2, a4]) {
do_check_true(a2 != null && a4 != null);
a2.userDisabled = true;
a4.userDisabled = true;
@ -349,7 +349,7 @@ function run_test() {
"bug542391_4@tests.mozilla.org",
"bug542391_5@tests.mozilla.org",
"bug542391_6@tests.mozilla.org"],
function(addons) {
callback_soon(function(addons) {
check_state_v1(addons);
WindowWatcher.expected = true;
@ -372,8 +372,8 @@ function run_test() {
do_execute_soon(run_test_1);
});
});
});
}));
}));
});
}

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

@ -5,8 +5,6 @@
// This verifies that deleting the database from the profile doesn't break
// anything
const EXTENSIONS_DB = "extensions.sqlite";
const profileDir = gProfD.clone();
profileDir.append("extensions");
@ -43,32 +41,31 @@ function end_test() {
}
function run_test_1() {
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
do_check_neq(a1, null);
do_check_eq(a1.version, "1.0");
shutdownManager();
let db = gProfD.clone();
db.append(EXTENSIONS_DB);
db.remove(true);
gExtensionsJSON.remove(true);
do_execute_soon(check_test_1);
});
}));
}
function check_test_1() {
startupManager(false);
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
do_check_neq(a1, null);
do_check_eq(a1.version, "1.0");
let db = gProfD.clone();
db.append(EXTENSIONS_DB);
do_check_true(db.exists());
do_check_true(db.fileSize > 0);
// due to delayed write, the file may not exist until
// after shutdown
shutdownManager();
do_check_true(gExtensionsJSON.exists());
do_check_true(gExtensionsJSON.fileSize > 0);
end_test();
});
}));
}

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

@ -65,7 +65,7 @@ function run_test() {
}
function end_test() {
do_test_finished();
do_execute_soon(do_test_finished);
}
// Checks switching to a different theme and back again leaves everything the
@ -196,7 +196,7 @@ function run_test_2() {
function check_test_2() {
restartManager();
AddonManager.getAddonsByIDs(["default@tests.mozilla.org",
"alternate@tests.mozilla.org"], function([d, a]) {
"alternate@tests.mozilla.org"], callback_soon(function([d, a]) {
do_check_eq(Services.prefs.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN), "alternate/1.0");
do_check_true(d.userDisabled);
@ -255,5 +255,5 @@ function check_test_2() {
end_test();
});
});
}));
}

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

@ -28,7 +28,7 @@ function run_test() {
startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a) {
do_check_neq(a, null);
do_check_eq(a.version, "1.0");
do_check_false(a.userDisabled);
@ -57,7 +57,7 @@ function run_test() {
do_check_true(a.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a.id));
do_test_finished();
do_execute_soon(do_test_finished);
});
});
}));
}

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

@ -106,7 +106,7 @@ function run_test_2() {
do_check_eq(a1, gAddon);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -47,7 +47,7 @@ function check_test_1() {
do_check_false(b1.userDisabled);
do_check_false(b1.isActive);
do_test_finished();
do_execute_soon(do_test_finished);
});
});
}

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

@ -141,7 +141,7 @@ function run_test() {
do_check_true(a6.appDisabled);
do_check_false(a6.isActive);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -38,7 +38,7 @@ function run_test() {
startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
a1.uninstall();
shutdownManager();
@ -60,7 +60,7 @@ function run_test() {
// Addon2 should have been detected
do_check_neq(a2, null);
do_test_finished();
do_execute_soon(do_test_finished);
});
});
}));
}

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

@ -96,12 +96,12 @@ function run_test_1() {
restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
check_addon_upgrading(a1);
restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
check_addon_upgrading(a1);
fstream.close();
@ -114,8 +114,8 @@ function run_test_1() {
a1.uninstall();
do_execute_soon(run_test_2);
});
});
});
}));
}));
});
});
});
@ -128,7 +128,7 @@ function run_test_2() {
installAllFiles([do_get_addon("test_bug587088_1")], function() {
restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
check_addon(a1, "1.0");
// Lock either install.rdf for unpacked add-ons or the xpi for packed add-ons.
@ -146,12 +146,12 @@ function run_test_2() {
restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
check_addon_uninstalling(a1, true);
restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
check_addon_uninstalling(a1, true);
fstream.close();
@ -165,10 +165,10 @@ function run_test_2() {
do_check_false(dir.exists());
do_check_false(isExtensionInAddonsList(profileDir, "addon1@tests.mozilla.org"));
do_test_finished();
do_execute_soon(do_test_finished);
});
});
});
});
}));
}));
}));
});
}

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

@ -35,6 +35,6 @@ function run_test_2() {
do_check_neq(a1, null);
do_check_true(isExtensionInAddonsList(profileDir, a1.id));
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -135,6 +135,6 @@ function run_test_3() {
do_check_eq(a3, null);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -21,6 +21,6 @@ function run_test() {
AddonManager.getAddonByID("foo", function(aAddon) {
test_string_compare();
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -14,7 +14,13 @@ gTestserver.start(-1);
gPort = gTestserver.identity.primaryPort;
mapFile("/data/test_bug619730.xml", gTestserver);
function load_blocklist(file) {
function load_blocklist(file, aCallback) {
Services.obs.addObserver(function() {
Services.obs.removeObserver(arguments.callee, "blocklist-updated");
do_execute_soon(aCallback);
}, "blocklist-updated", false);
Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:" +
gPort + "/data/" + file);
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
@ -49,9 +55,10 @@ function run_test() {
Services.obs.addObserver(function(aSubject, aTopic, aData) {
do_check_true(gSawGFX);
do_check_true(gSawTest);
gTestserver.stop(do_test_finished);
}, "blocklist-data-fooItems", false);
load_blocklist("test_bug619730.xml");
// Need to wait for the blocklist to load; Bad Things happen if the test harness
// shuts down AddonManager before the blocklist service is done telling it about
// changes
load_blocklist("test_bug619730.xml", () => gTestserver.stop(do_test_finished));
}

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

@ -84,7 +84,7 @@ function run_test_1() {
onUpdateFinished: function() {
restartManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(function(a1) {
do_check_neq(a1, null);
do_check_false(a1.appDisabled);
do_check_true(a1.isActive);
@ -115,9 +115,9 @@ function run_test_1() {
do_check_false(isExtensionInAddonsList(userDir, a2.id));
do_check_eq(Services.prefs.getIntPref("bootstraptest.active_version"), 1);
run_test_2();
do_execute_soon(run_test_2);
});
});
}));
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
@ -125,7 +125,7 @@ function run_test_1() {
//Set up the profile
function run_test_2() {
AddonManager.getAddonByID("addon2@tests.mozilla.org", function(a2) {
AddonManager.getAddonByID("addon2@tests.mozilla.org", callback_soon(function(a2) {
do_check_neq(a2, null);
do_check_false(a2.appDisabled);
do_check_true(a2.isActive);
@ -160,5 +160,5 @@ function run_test_2() {
end_test();
});
});
}));
}

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

@ -108,14 +108,8 @@ function run_test_1() {
shutdownManager();
// Make it look like the next time the app is started it has a new DB schema
let dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
let db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
db.schemaVersion = 1;
changeXPIDBVersion(1);
Services.prefs.setIntPref("extensions.databaseSchema", 1);
db.close();
let jsonfile = gProfD.clone();
jsonfile.append("extensions");
@ -173,10 +167,10 @@ function run_test_1() {
// the previous version of the DB
do_check_neq(a3, null);
do_check_eq(a3.version, "2.0");
do_check_false(a3.appDisabled);
todo_check_false(a3.appDisabled); // XXX unresolved issue
do_check_false(a3.userDisabled);
do_check_true(a3.isActive);
do_check_true(isExtensionInAddonsList(profileDir, addon3.id));
todo_check_true(a3.isActive); // XXX same
todo_check_true(isExtensionInAddonsList(profileDir, addon3.id)); // XXX same
do_check_neq(a4, null);
do_check_eq(a4.version, "2.0");
@ -255,14 +249,8 @@ function run_test_2() {
shutdownManager();
// Make it look like the next time the app is started it has a new DB schema
let dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
let db = AM_Cc["@mozilla.org/storage/service;1"].
getService(AM_Ci.mozIStorageService).
openDatabase(dbfile);
db.schemaVersion = 1;
changeXPIDBVersion(1);
Services.prefs.setIntPref("extensions.databaseSchema", 1);
db.close();
let jsonfile = gProfD.clone();
jsonfile.append("extensions");
@ -302,7 +290,7 @@ function run_test_2() {
"addon2@tests.mozilla.org",
"addon3@tests.mozilla.org",
"addon4@tests.mozilla.org"],
function([a1, a2, a3, a4]) {
callback_soon(function([a1, a2, a3, a4]) {
do_check_neq(a1, null);
do_check_eq(a1.version, "2.0");
do_check_true(a1.appDisabled);
@ -321,10 +309,10 @@ function run_test_2() {
// the previous version of the DB
do_check_neq(a3, null);
do_check_eq(a3.version, "2.0");
do_check_true(a3.appDisabled);
todo_check_true(a3.appDisabled);
do_check_false(a3.userDisabled);
do_check_false(a3.isActive);
do_check_false(isExtensionInAddonsList(profileDir, addon3.id));
todo_check_false(a3.isActive);
todo_check_false(isExtensionInAddonsList(profileDir, addon3.id));
do_check_neq(a4, null);
do_check_eq(a4.version, "2.0");
@ -346,7 +334,7 @@ function run_test_2() {
shutdownManager();
do_test_finished();
});
}));
};
});
}

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

@ -24,9 +24,7 @@ function run_test() {
}, [
"onInstallStarted",
"onInstallEnded",
], function() {
do_execute_soon(check_test)
});
], callback_soon(check_test));
install.install();
});
}
@ -88,6 +86,6 @@ function check_test() {
do_check_false(target.active);
}
do_test_finished();
do_execute_soon(do_test_finished);
}));
}

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

@ -35,6 +35,6 @@ function run_test() {
do_check_eq(getInstalledVersion(), "1.0");
do_check_eq(getActiveVersion(), "1.0");
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -81,6 +81,6 @@ function run_test() {
do_check_neq(a4, null);
do_check_in_crash_annotation(addon4.id, addon4.version);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -107,6 +107,6 @@ function run_test_2() {
AddonManager.removeInstallListener(listener2);
AddonManager.removeInstallListener(listener3);
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -117,6 +117,6 @@ function run_test_4() {
do_check_true(gCacheFlushed);
gCacheFlushed = false;
do_test_finished();
do_execute_soon(do_test_finished);
});
}

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

@ -191,6 +191,6 @@ function run_test_4() {
function([a1, a2, a3, a4, a5]) {
check_state(false, a1, a2, a3, a4, a5);
do_test_finished("checkcompatibility.js");
do_execute_soon(do_test_finished);
});
}

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

@ -251,10 +251,8 @@ function run_test_1() {
// serves this purpose). On startup the add-ons manager won't rebuild
// because there is a file there still.
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
dbfile.remove(true);
dbfile.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
gExtensionsJSON.remove(true);
gExtensionsJSON.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
startupManager(false);
// Accessing the add-ons should open and recover the database

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

@ -252,10 +252,8 @@ function run_test_1() {
// serves this purpose). On startup the add-ons manager won't rebuild
// because there is a file there still.
shutdownManager();
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
dbfile.remove(true);
dbfile.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755);
gExtensionsJSON.remove(true);
gExtensionsJSON.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
startupManager(false);
// Accessing the add-ons should open and recover the database

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

@ -1,181 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// This tests the data in extensions.sqlite for general sanity, making sure
// rows in one table only reference rows in another table that actually exist.
function check_db() {
do_print("Checking DB sanity...");
var dbfile = gProfD.clone();
dbfile.append("extensions.sqlite");
var db = Services.storage.openDatabase(dbfile);
do_print("Checking locale_strings references rows in locale correctly...");
let localeStringsStmt = db.createStatement("SELECT * FROM locale_strings");
let localeStmt = db.createStatement("SELECT COUNT(*) AS count FROM locale WHERE id=:locale_id");
let i = 0;
while (localeStringsStmt.executeStep()) {
i++;
localeStmt.params.locale_id = localeStringsStmt.row.locale_id;
do_check_true(localeStmt.executeStep());
do_check_eq(localeStmt.row.count, 1);
localeStmt.reset();
}
localeStmt.finalize();
localeStringsStmt.finalize();
do_print("Done. " + i + " rows in locale_strings checked.");
do_print("Checking locale references rows in addon_locale and addon correctly...");
localeStmt = db.createStatement("SELECT * FROM locale");
let addonLocaleStmt = db.createStatement("SELECT COUNT(*) AS count FROM addon_locale WHERE locale_id=:locale_id");
let addonStmt = db.createStatement("SELECT COUNT(*) AS count FROM addon WHERE defaultLocale=:locale_id");
i = 0;
while (localeStmt.executeStep()) {
i++;
addonLocaleStmt.params.locale_id = localeStmt.row.id;
do_check_true(addonLocaleStmt.executeStep());
if (addonLocaleStmt.row.count == 0) {
addonStmt.params.locale_id = localeStmt.row.id;
do_check_true(addonStmt.executeStep());
do_check_eq(addonStmt.row.count, 1);
} else {
do_check_eq(addonLocaleStmt.row.count, 1);
}
addonLocaleStmt.reset();
addonStmt.reset();
}
addonLocaleStmt.finalize();
localeStmt.finalize();
addonStmt.finalize();
do_print("Done. " + i + " rows in locale checked.");
do_print("Checking addon_locale references rows in locale correctly...");
addonLocaleStmt = db.createStatement("SELECT * FROM addon_locale");
localeStmt = db.createStatement("SELECT COUNT(*) AS count FROM locale WHERE id=:locale_id");
i = 0;
while (addonLocaleStmt.executeStep()) {
i++;
localeStmt.params.locale_id = addonLocaleStmt.row.locale_id;
do_check_true(localeStmt.executeStep());
do_check_eq(localeStmt.row.count, 1);
localeStmt.reset();
}
addonLocaleStmt.finalize();
localeStmt.finalize();
do_print("Done. " + i + " rows in addon_locale checked.");
do_print("Checking addon_locale references rows in addon correctly...");
addonLocaleStmt = db.createStatement("SELECT * FROM addon_locale");
addonStmt = db.createStatement("SELECT COUNT(*) AS count FROM addon WHERE internal_id=:addon_internal_id");
i = 0;
while (addonLocaleStmt.executeStep()) {
i++;
addonStmt.params.addon_internal_id = addonLocaleStmt.row.addon_internal_id;
do_check_true(addonStmt.executeStep());
do_check_eq(addonStmt.row.count, 1);
addonStmt.reset();
}
addonLocaleStmt.finalize();
addonStmt.finalize();
do_print("Done. " + i + " rows in addon_locale checked.");
do_print("Checking addon references rows in locale correctly...");
addonStmt = db.createStatement("SELECT * FROM addon");
localeStmt = db.createStatement("SELECT COUNT(*) AS count FROM locale WHERE id=:defaultLocale");
i = 0;
while (addonStmt.executeStep()) {
i++;
localeStmt.params.defaultLocale = addonStmt.row.defaultLocale;
do_check_true(localeStmt.executeStep());
do_check_eq(localeStmt.row.count, 1);
localeStmt.reset();
}
addonStmt.finalize();
localeStmt.finalize();
do_print("Done. " + i + " rows in addon checked.");
do_print("Checking targetApplication references rows in addon correctly...");
let targetAppStmt = db.createStatement("SELECT * FROM targetApplication");
addonStmt = db.createStatement("SELECT COUNT(*) AS count FROM addon WHERE internal_id=:addon_internal_id");
i = 0;
while (targetAppStmt.executeStep()) {
i++;
addonStmt.params.addon_internal_id = targetAppStmt.row.addon_internal_id;
do_check_true(addonStmt.executeStep());
do_check_eq(addonStmt.row.count, 1);
addonStmt.reset();
}
targetAppStmt.finalize();
addonStmt.finalize();
do_print("Done. " + i + " rows in targetApplication checked.");
do_print("Checking targetPlatform references rows in addon correctly...");
let targetPlatformStmt = db.createStatement("SELECT * FROM targetPlatform");
addonStmt = db.createStatement("SELECT COUNT(*) AS count FROM addon WHERE internal_id=:addon_internal_id");
i = 0;
while (targetPlatformStmt.executeStep()) {
i++;
addonStmt.params.addon_internal_id = targetPlatformStmt.row.addon_internal_id;
do_check_true(addonStmt.executeStep());
do_check_eq(addonStmt.row.count, 1);
addonStmt.reset();
}
targetPlatformStmt.finalize();
addonStmt.finalize();
do_print("Done. " + i + " rows in targetPlatform checked.");
db.close();
do_print("Done checking DB sanity.");
}
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
startupManager();
installAllFiles([do_get_addon("test_db_sanity_1_1")], run_test_1);
}
function run_test_1() {
shutdownManager();
check_db();
startupManager();
AddonManager.getAddonByID("test_db_sanity_1@tests.mozilla.org", function(aAddon) {
aAddon.uninstall();
shutdownManager();
check_db();
startupManager();
installAllFiles([do_get_addon("test_db_sanity_1_1")], run_test_2);
});
}
function run_test_2() {
installAllFiles([do_get_addon("test_db_sanity_1_2")], function() {
shutdownManager();
check_db();
startupManager();
run_test_3();
});
}
function run_test_3() {
AddonManager.getAddonByID("test_db_sanity_1@tests.mozilla.org", function(aAddon) {
aAddon.uninstall();
shutdownManager();
check_db();
do_test_finished();
});
}

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