Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-09-13 21:53:35 -04:00
commit 4d6acb9941
73 changed files with 3370 additions and 3228 deletions

View File

@ -394,6 +394,7 @@ pref("browser.tabs.tabClipWidth", 140);
pref("browser.tabs.animate", true);
pref("browser.tabs.onTop", true);
pref("browser.tabs.drawInTitlebar", true);
pref("browser.tabs.cropTitleRedundancy", true);
// Where to show tab close buttons:
// 0 on active tab only

View File

@ -160,6 +160,12 @@ XPCOMUtils.defineLazyGetter(this, "gBrowserNewTabPreloader", function () {
return new tmp.BrowserNewTabPreloader();
});
XPCOMUtils.defineLazyGetter(this, "TabTitleAbridger", function() {
let tmp = {};
Cu.import("resource:///modules/TabTitleAbridger.jsm", tmp);
return new tmp.TabTitleAbridger(window);
});
let gInitialPages = [
"about:blank",
"about:newtab",
@ -1417,6 +1423,7 @@ var gBrowserInit = {
gBrowserThumbnails.init();
TabView.init();
TabTitleAbridger.init();
setUrlAndSearchBarWidthForConditionalForwardButton();
window.addEventListener("resize", function resizeHandler(event) {
@ -1604,6 +1611,7 @@ var gBrowserInit = {
TabView.uninit();
gBrowserThumbnails.uninit();
FullZoom.destroy();
TabTitleAbridger.destroy();
Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-disabled");
@ -5687,13 +5695,11 @@ var OfflineApps = {
// OfflineApps Public Methods
init: function ()
{
Services.obs.addObserver(this, "dom-storage-warn-quota-exceeded", false);
Services.obs.addObserver(this, "offline-cache-update-completed", false);
},
uninit: function ()
{
Services.obs.removeObserver(this, "dom-storage-warn-quota-exceeded");
Services.obs.removeObserver(this, "offline-cache-update-completed");
},
@ -5935,19 +5941,7 @@ var OfflineApps = {
// nsIObserver
observe: function (aSubject, aTopic, aState)
{
if (aTopic == "dom-storage-warn-quota-exceeded") {
if (aSubject) {
var uri = makeURI(aSubject.location.href);
if (OfflineApps._checkUsage(uri)) {
var browserWindow =
this._getBrowserWindowForContentWindow(aSubject);
var browser = this._getBrowserForContentWindow(browserWindow,
aSubject);
OfflineApps._warnUsage(browser, uri);
}
}
} else if (aTopic == "offline-cache-update-completed") {
if (aTopic == "offline-cache-update-completed") {
var cacheUpdate = aSubject.QueryInterface(Ci.nsIOfflineCacheUpdate);
var uri = cacheUpdate.manifestURI;

View File

@ -1228,11 +1228,6 @@
var uriIsBlankPage = !aURI || isBlankPageURL(aURI);
var uriIsNotAboutBlank = aURI && aURI != "about:blank";
if (uriIsBlankPage)
t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
else
t.setAttribute("label", aURI);
t.setAttribute("crop", "end");
t.setAttribute("validate", "never");
t.setAttribute("onerror", "this.removeAttribute('image');");
@ -1346,6 +1341,14 @@
// initialized by this point.
this.mPanelContainer.appendChild(notificationbox);
// Happens after the browser is in the DOM: the TabTitleAbridger
// classifies tabs by domains, requiring access to the browser.
if (uriIsBlankPage) {
t.label = this.mStringBundle.getString("tabs.emptyTabTitle");
} else {
t.label = aURI;
}
this.tabContainer.updateVisibility();
if (uriIsNotAboutBlank) {
@ -2838,8 +2841,7 @@
this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab");
var tab = this.firstChild;
tab.setAttribute("label",
this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle"));
tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle");
tab.setAttribute("crop", "end");
tab.setAttribute("validate", "never");
tab.setAttribute("onerror", "this.removeAttribute('image');");
@ -3957,7 +3959,8 @@
class="tab-icon-image"
role="presentation"/>
<xul:label flex="1"
xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected"
anonid="tab-label"
xbl:inherits="value=visibleLabel,crop,accesskey,fadein,pinned,selected"
class="tab-text tab-label"
role="presentation"/>
<xul:toolbarbutton anonid="close-button"
@ -3968,6 +3971,30 @@
</content>
<implementation>
<property name="label">
<getter>
return this.getAttribute("label");
</getter>
<setter>
this.setAttribute("label", val);
let event = new CustomEvent("TabLabelModified", {
bubbles: true,
cancelable: true
});
this.dispatchEvent(event);
if (!event.defaultPrevented)
this.visibleLabel = val;
</setter>
</property>
<property name="visibleLabel">
<getter>
return this.getAttribute("visibleLabel");
</getter>
<setter>
this.setAttribute("visibleLabel", val);
</setter>
</property>
<property name="pinned" readonly="true">
<getter>
return this.getAttribute("pinned") == "true";

View File

@ -131,6 +131,8 @@ _BROWSER_FILES = \
browser_bug581242.js \
browser_bug581253.js \
browser_bug581947.js \
browser_bug583890.js \
browser_bug583890_label.js \
browser_bug585785.js \
browser_bug585830.js \
browser_bug590206.js \

View File

@ -0,0 +1,377 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Call the aCallback when aTab's label is equal to the aExpectedLabel.
* Either happens immediately, or after successive checks.
* In the case of failure, this will cause timeout of the test.
*
* @param aTab the tab whose label is being tested
* @param aExpectedLabel the value the tab's label must match
* @param aCallback the callback for use upon success
*/
function waitForTabLabel(aTab, aExpectedLabel, aCallback) {
if (aTab.visibleLabel == aExpectedLabel) {
executeSoon(aCallback);
} else {
executeSoon(function () { waitForTabLabel(aTab, aExpectedLabel, aCallback); });
}
}
/**
* Call the aCallback after adding aCount tabs.
*
* @param aCount the number of tabs to add
* @param aCallback the callback for use upon success
*/
function addTabs(aCount, aCallback) {
let addedTabs = [];
for (let i = aCount; i > 0; i--) {
addedTabs.push(gBrowser.addTab(null, {skipAnimation: true}));
}
executeSoon(function () { aCallback(addedTabs); });
}
/**
* Call the aCallback after updating aTab's title and waiting for a label update
* In the case of failure, this will cause timeout of the test.
*
* @param aTab the tab whose title is set
* @param aTitle the value to give the tab title
* @param aExpectedLabel the value the tab's label must match
* @param aCallback the callback for use upon success
*/
function setTitleForTab(aTab, aTitle, aExpectedLabel, aCallback) {
gBrowser.tabContainer.addEventListener("TabLabelModified",
afterTabLabelModified, false);
// Only start polling for the label after the event has hit
function afterTabLabelModified() {
gBrowser.tabContainer.removeEventListener("TabLabelModified",
afterTabLabelModified, false);
waitForTabLabel(aTab, aExpectedLabel, aCallback);
}
// On the off chance we're trying to set the title on a too-young tab,
// we wait until it's mature
function doSetTitle() {
if (aTab.linkedBrowser && aTab.linkedBrowser.contentDocument) {
aTab.linkedBrowser.contentDocument.title = aTitle;
} else {
executeSoon(doSetTitle);
}
}
executeSoon(doSetTitle);
}
/**
* Call the aCallback after updating aTab's label and waiting for a label update
* In the case of failure, this will cause timeout of the test.
*
* @param aTab the tab whose title is set
* @param aTitle the value to give the tab title
* @param aExpectedLabel the value the tab's label must match
* @param aCallback the callback for use upon success
*/
function setLabelForTab(aTab, aTitle, aExpectedLabel, aCallback) {
executeSoon(function () {
aTab.label = aTitle;
waitForTabLabel(aTab, aExpectedLabel, aCallback);
});
}
function GroupTest() {
this.groupNumber = 0;
this.tabs = [];
}
GroupTest.prototype = {
groups: [
[
/*
* Test proxying and suffix protection
*/
[
"Foo - Bar - Baz",
"Foo - Baz - Baz",
"Foo - Baz - Baz",
"Foo - Baz - Qux"
],
[
[
"Bar - Baz",
"Baz - Baz"
],
[
"Bar - Baz",
"Baz - Baz",
"Baz - Baz"
],
[
"Bar - Baz",
"Baz",
"Baz",
"Qux"
]
]
],
[
/*
* Test pathmode
*/
[
"http://example.com/foo.html",
"http://example.com/foo/bar.html",
"Browse - ftp://example.com/pub/",
"Browse - ftp://example.com/pub/src/"
],
[
[
"foo.html",
"foo/bar.html"
],
[
"foo.html",
"foo/bar.html",
"Browse - ftp://example.com/pub/"
],
[
"foo.html",
"foo/bar.html",
"pub/",
"src/"
]
]
],
[
/*
* Test that we don't leave a lone suffix
*/
[
"'Zilla and the Foxes - Singles - Musical Monkey",
"'Zilla and the Foxes - Biography - Musical Monkey",
"'Zilla and the Foxes - Musical Monkey",
"'Zilla and the Foxes - Interviews - Musical Monkey"
],
[
[
"Singles - Musical Monkey",
"Biography - Musical Monkey"
],
[
"Singles - Musical Monkey",
"Biography - Musical Monkey",
"'Zilla and the Foxes - Musical Monkey"
],
[
"Singles - Musical Monkey",
"Biography - Musical Monkey",
"'Zilla and the Foxes - Musical Monkey",
"Interviews - Musical Monkey"
]
]
],
/*
* Test short endings for MIN_CHOP
*/
[
[
"Foo - Bar - 0",
"Foo - Bar - 0 - extra - 0",
"Foo - Bar - 1",
"Foo - Bar - 2 - extra",
"Foo - Bar - 3"
],
[
[
"Bar - 0",
"0 - extra - 0"
],
[
"Bar - 0",
"0 - extra - 0",
"Bar - 1"
],
[
"Bar - 0",
"0 - extra - 0",
"Bar - 1",
"2 - extra"
],
[
"Bar - 0",
"0 - extra - 0",
"Bar - 1",
"2 - extra",
"Bar - 3"
]
]
],
[
/*
* Test multiple whitespace
*/
[
"Foo - Bar - Baz",
"Foo - Bar - Baz",
"Foo - Bar - Baz",
"Foo - Baz - Baz"
],
[
[
"Foo - Bar - Baz",
"Foo - Bar - Baz"
],
[
"Foo - Bar - Baz",
"Foo - Bar - Baz",
"Foo - Bar - Baz"
],
[
"Bar - Baz",
"Bar - Baz",
"Bar - Baz",
"Baz - Baz"
]
]
]
],
/**
* Either proceed with the next group, or finish group tests
*/
nextGroup: function GroupTest_nextGroup() {
while (this.tabs.length) {
gBrowser.removeTab(this.tabs.pop());
}
if (this.groups.length) {
this.groupNumber++;
[this.labels, this.expectedLabels] = this.groups.shift();
this.nextTab();
} else {
runNextTest();
}
},
/**
* Runs tests for existing tabs, and adds the next tab (if group isn't empty)
* If the group is empty, starts the next group
*/
nextTab: function GroupTest_nextTab() {
if (this.tabs.length > 1) {
let ourExpected = this.expectedLabels.shift();
for (let i = 0; i < this.tabs.length; i++) {
is(this.tabs[i].visibleLabel, ourExpected[i],
"Tab " + this.groupNumber + "." + (i + 1) + " has correct visibleLabel");
}
}
if (this.labels.length) {
this.tabs.push(gBrowser.addTab(
"data:text/html,<title>" + this.labels.shift() + "</title>",
{skipAnimation: true}));
if (this.tabs.length > 1) {
waitForTabLabel(this.tabs[this.tabs.length - 1],
this.expectedLabels[0][this.expectedLabels[0].length - 1],
this.nextTab.bind(this));
} else {
this.nextTab();
}
} else {
this.nextGroup();
}
}
};
let TESTS = [
function test_about_blank() {
let tab1 = gBrowser.selectedTab;
let tab2;
let tab3;
addTabs(2, setup1);
function setup1(aTabs) {
[tab2, tab3] = aTabs
waitForTabLabel(tab3, "New Tab", setupComplete);
}
function setupComplete() {
is(tab1.visibleLabel, "New Tab", "First tab has original label");
is(tab2.visibleLabel, "New Tab", "Second tab has original label");
is(tab3.visibleLabel, "New Tab", "Third tab has original label");
runNextTest();
}
},
function test_two_tabs() {
let tab1 = gBrowser.selectedTab;
addTabs(1, setup1);
let tab2;
function setup1(aTabs) {
tab2 = aTabs[0];
setTitleForTab(tab1, "Foo - Bar - Baz", "Foo - Bar - Baz", setup2);
}
function setup2() {
setTitleForTab(tab2, "Foo - Baz - Baz", "Baz - Baz", setupComplete);
}
function setupComplete() {
is(tab1.visibleLabel, "Bar - Baz", "Removed exactly two tokens");
is(tab2.visibleLabel, "Baz - Baz", "Removed exactly two tokens");
gBrowser.removeTab(tab2);
waitForTabLabel(tab1, "Foo - Bar - Baz", afterRemoval);
}
function afterRemoval() {
is (tab1.visibleLabel, "Foo - Bar - Baz", "Single tab has full title");
runNextTest();
}
},
function test_direct_label() {
let tab1 = gBrowser.selectedTab;
addTabs(2, setup1);
let tab2;
let tab3;
function setup1(aTabs) {
[tab2, tab3] = aTabs;
setLabelForTab(tab1, "Foo - Bar - Baz", "Foo - Bar - Baz", setup2);
}
function setup2() {
setLabelForTab(tab2, "Foo - Baz - Baz", "Foo - Baz - Baz", setup3);
}
function setup3() {
setLabelForTab(tab3, "Foo - Baz - Baz", "Baz - Baz", setupComplete);
}
function setupComplete() {
is(tab1.visibleLabel, "Bar - Baz", "Removed exactly two tokens");
is(tab2.visibleLabel, "Foo - Baz - Baz", "Irregular spaces mean no match");
is(tab3.visibleLabel, "Baz - Baz", "Removed exactly two tokens");
gBrowser.removeTab(tab3);
waitForTabLabel(tab1, "Foo - Bar - Baz", afterRemoval);
}
function afterRemoval() {
is (tab1.visibleLabel, "Foo - Bar - Baz", "Single tab has full title");
gBrowser.removeTab(tab2);
runNextTest();
}
},
function test_groups() {
let g = new GroupTest();
g.nextGroup();
}
];
function runNextTest() {
if (TESTS.length == 0) {
finish();
return;
}
while (gBrowser.tabs.length > 1) {
gBrowser.removeTab(gBrowser.tabs[1]);
}
info("Running " + TESTS[0].name);
TESTS.shift()();
};
function test() {
waitForExplicitFinish();
runNextTest();
}

View File

@ -0,0 +1,88 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* Tests:
* verify that the visibleLabel attribute works
* verify the TabLabelModified event works
*/
function test() {
waitForExplicitFinish();
let tab = gBrowser.addTab("about:newtab",
{skipAnimation: true});
tab.linkedBrowser.addEventListener("load", function onLoad(event) {
event.currentTarget.removeEventListener("load", onLoad, true);
gBrowser.selectedTab = tab;
executeSoon(afterLoad);
}, true);
tab.addEventListener("TabLabelModified", handleInTest, true);
}
// Prevent interference
function handleInTest(aEvent) {
aEvent.preventDefault();
aEvent.stopPropagation();
aEvent.target.visibleLabel = aEvent.target.label;
}
function afterLoad() {
let tab = gBrowser.selectedTab;
let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid",
"tab-label");
// Verify we're starting out on the right foot
is(tab.label, "New Tab", "Initial tab label is default");
is(xulLabel.value, "New Tab", "Label element is default");
is(tab.visibleLabel, "New Tab", "visibleLabel is default");
// Check that a normal label setting works correctly
tab.label = "Hello, world!";
is(tab.label, "Hello, world!", "tab label attribute set via tab.label");
is(xulLabel.value, "Hello, world!", "xul:label set via tab.label");
is(tab.visibleLabel, "Hello, world!", "visibleLabel set via tab.label");
// Check that setting visibleLabel only affects the label element
tab.visibleLabel = "Goodnight, Irene";
is(tab.label, "Hello, world!", "Tab.label unaffected by visibleLabel setter");
is(xulLabel.value, "Goodnight, Irene",
"xul:label set by visibleLabel setter");
is(tab.visibleLabel, "Goodnight, Irene",
"visibleLabel attribute set by visibleLabel setter");
// Check that setting the label property hits everything
tab.label = "One more label";
is(tab.label, "One more label",
"Tab label set via label property after diverging from visibleLabel");
is(xulLabel.value, "One more label",
"xul:label set via label property after diverging from visibleLabel");
is(tab.visibleLabel, "One more label",
"visibleLabel set from label property after diverging from visibleLabel");
tab.removeEventListener("TabLabelModified", handleInTest, true);
tab.addEventListener("TabLabelModified", handleTabLabel, true);
tab.label = "This won't be the visibleLabel";
}
function handleTabLabel(aEvent) {
aEvent.target.removeEventListener("TabLabelModified", handleTabLabel, true);
aEvent.preventDefault();
aEvent.stopPropagation();
aEvent.target.visibleLabel = "Handler set this as the visible label";
executeSoon(checkTabLabelModified);
}
function checkTabLabelModified() {
let tab = gBrowser.selectedTab;
let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid",
"tab-label");
is(tab.label, "This won't be the visibleLabel",
"Tab label set via label property that triggered event");
is(xulLabel.value, "Handler set this as the visible label",
"xul:label set by TabLabelModified handler");
is(tab.visibleLabel, "Handler set this as the visible label",
"visibleLabel set by TabLabelModified handler");
gBrowser.removeCurrentTab({animate: false});
finish();
}

View File

@ -435,7 +435,7 @@ var gAllTests = [
wh.open();
},
function () {
// Test for offline apps data and cache deletion
// Test for offline cache deletion
// Prepare stuff, we will work with www.example.com
var URL = "http://www.example.com";
@ -454,12 +454,6 @@ var gAllTests = [
pm.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
pm.addFromPrincipal(principal, "offline-app", Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
// Store some user data to localStorage
var dsm = Cc["@mozilla.org/dom/storagemanager;1"]
.getService(Ci.nsIDOMStorageManager);
var localStorage = dsm.getLocalStorageForPrincipal(principal, URL);
localStorage.setItem("test", "value");
// Store something to the offline cache
const nsICache = Components.interfaces.nsICache;
var cs = Components.classes["@mozilla.org/network/cache-service;1"]
@ -477,9 +471,7 @@ var gAllTests = [
this.checkPrefCheckbox("offlineApps", true);
this.acceptDialog();
// Check all has been deleted (data, cache)
is(localStorage.length, 0, "DOM storage cleared");
// Check if the cache has been deleted
var size = -1;
var visitor = {
visitDevice: function (deviceID, deviceInfo)

View File

@ -1,34 +1,178 @@
Copyright (c) 2011 Mozilla Foundation
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Contributors: Andreas Gal <gal@mozilla.com>
Chris G Jones <cjones@mozilla.com>
Shaon Barman <shaon.barman@gmail.com>
Vivien Nicolas <21@vingtetun.org>
Justin D'Arcangelo <justindarc@gmail.com>
Yury Delendik
Kalervo Kujala
Adil Allawi <@ironymark>
Jakob Miland <saebekassebil@gmail.com>
Artur Adib <aadib@mozilla.com>
Brendan Dahl <bdahl@mozilla.com>
David Quintana <gigaherz@gmail.com>
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
1. Definitions.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 0.4.11
Current extension version is: 0.5.22

View File

@ -1,5 +1,19 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
@ -18,6 +32,7 @@ const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
const MAX_DATABASE_LENGTH = 4096;
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
const METRO_ID = '{99bceaaa-e3c6-48c1-b981-ef9b46b67d60}';
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
@ -36,7 +51,8 @@ if (appInfo.ID === FIREFOX_ID) {
privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
.getService(Ci.nsIPrivateBrowsingService);
inPrivateBrowsing = privateBrowsing.privateBrowsingEnabled;
} else if (appInfo.ID === SEAMONKEY_ID) {
} else if (appInfo.ID === SEAMONKEY_ID ||
appInfo.ID === METRO_ID) {
privateBrowsing = null;
inPrivateBrowsing = false;
}

View File

@ -1,3 +1,18 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var EXPORTED_SYMBOLS = ["PdfJs"];
const Cc = Components.classes;

View File

@ -1,5 +1,19 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';

View File

@ -1,3 +1,18 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* {
padding: 0;
margin: 0;
@ -29,29 +44,17 @@ select {
#viewerContainer:-webkit-full-screen {
top: 0px;
padding-top: 6px;
padding-bottom: 24px;
border-top: 5px solid transparent;
background-color: #404040;
background-image: url(images/texture.png);
width: 100%;
height: 100%;
overflow: auto;
}
:-webkit-full-screen #viewer {
margin: 0pt;
padding: 0pt;
height: 100%;
width: 100%;
overflow: hidden;
}
:-webkit-full-screen .page {
margin: 0px auto;
margin-bottom: 10px;
}
#viewerContainer:-moz-full-screen {
top: 0px;
border-top: 5px solid transparent;
background-color: #404040;
background-image: url(images/texture.png);
width: 100%;
@ -59,6 +62,10 @@ select {
overflow: hidden;
}
:-webkit-full-screen .page:last-child {
margin-bottom: 40px;
}
:-moz-full-screen .page:last-child {
margin-bottom: 40px;
}
@ -760,9 +767,9 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
}
#thumbnailView {
position: fixed;
position: absolute;
width: 120px;
top: 33px;
top: 0;
bottom: 0;
padding: 10px 40px 0;
overflow: auto;
@ -771,8 +778,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
.thumbnail {
margin-bottom: 15px;
float: left;
width: 114px;
height: 142px;
}
.thumbnail:not([data-loaded]) {
@ -825,9 +830,9 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
}
#outlineView {
position: fixed;
position: absolute;
width: 192px;
top: 33px;
top: 0;
bottom: 0;
padding: 4px 4px 0;
overflow: auto;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,19 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
@ -21,6 +35,7 @@ var RenderingStates = {
FINISHED: 3
};
PDFJS.workerSrc = '../build/pdf.js';
var mozL10n = document.mozL10n || document.webL10n;
@ -33,6 +48,19 @@ function getFileName(url) {
return url.substring(url.lastIndexOf('/', end) + 1, end);
}
function scrollIntoView(element, spot) {
var parent = element.offsetParent, offsetY = element.offsetTop;
while (parent.clientHeight == parent.scrollHeight) {
offsetY += parent.offsetTop;
parent = parent.offsetParent;
if (!parent)
return; // no need to scroll
}
if (spot)
offsetY += spot.top;
parent.scrollTop = offsetY;
}
var Cache = function cacheCache(size) {
var data = [];
this.push = function cachePush(view) {
@ -98,6 +126,21 @@ var ProgressBar = (function ProgressBarClosure() {
return ProgressBar;
})();
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var FirefoxCom = (function FirefoxComClosure() {
return {
/**
@ -242,6 +285,7 @@ var PDFView = {
thumbnailViewScroll: null,
isFullscreen: false,
previousScale: null,
pageRotation: 0,
// called once when the document is loaded
initialize: function pdfViewInitialize() {
@ -431,7 +475,13 @@ var PDFView = {
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
this.url = url;
document.title = decodeURIComponent(getFileName(url)) || url;
try {
document.title = decodeURIComponent(getFileName(url)) || url;
} catch (e) {
// decodeURIComponent may throw URIError,
// fall back to using the unprocessed url in that case
document.title = url;
}
},
open: function pdfViewOpen(url, scale, password) {
@ -674,6 +724,8 @@ var PDFView = {
storedHash = 'page=' + page + '&zoom=' + zoom + ',' + left + ',' + top;
}
this.pageRotation = 0;
var pages = this.pages = [];
this.pageText = [];
this.startedTextExtraction = false;
@ -1147,6 +1199,34 @@ var PDFView = {
this.isFullscreen = false;
this.parseScale(this.previousScale);
this.page = this.page;
},
rotatePages: function pdfViewPageRotation(delta) {
this.pageRotation = (this.pageRotation + 360 + delta) % 360;
for (var i = 0, l = this.pages.length; i < l; i++) {
var page = this.pages[i];
page.update(page.scale, this.pageRotation);
}
for (var i = 0, l = this.thumbnails.length; i < l; i++) {
var thumb = this.thumbnails[i];
thumb.updateRotation(this.pageRotation);
}
var currentPage = this.pages[this.page - 1];
if (this.isFullscreen) {
this.parseScale('page-fit', true);
}
this.renderHighestPriority();
// Wait for fullscreen to take effect
setTimeout(function() {
currentPage.scrollIntoView();
}, 0);
}
};
@ -1155,8 +1235,9 @@ var PageView = function pageView(container, pdfPage, id, scale,
this.id = id;
this.pdfPage = pdfPage;
this.rotation = 0;
this.scale = scale || 1.0;
this.viewport = this.pdfPage.getViewport(this.scale);
this.viewport = this.pdfPage.getViewport(this.scale, this.pdfPage.rotate);
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
@ -1167,6 +1248,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
var div = this.el = document.createElement('div');
div.id = 'pageContainer' + this.id;
div.className = 'page';
div.style.width = this.viewport.width + 'px';
div.style.height = this.viewport.height + 'px';
container.appendChild(anchor);
container.appendChild(div);
@ -1176,12 +1259,18 @@ var PageView = function pageView(container, pdfPage, id, scale,
this.pdfPage.destroy();
};
this.update = function pageViewUpdate(scale) {
this.update = function pageViewUpdate(scale, rotation) {
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
if (typeof rotation !== 'undefined') {
this.rotation = rotation;
}
this.scale = scale || this.scale;
var viewport = this.pdfPage.getViewport(this.scale);
var totalRotation = (this.rotation + this.pdfPage.rotate) % 360;
var viewport = this.pdfPage.getViewport(this.scale, totalRotation);
this.viewport = viewport;
div.style.width = viewport.width + 'px';
@ -1310,7 +1399,7 @@ var PageView = function pageView(container, pdfPage, id, scale,
this.scrollIntoView = function pageViewScrollIntoView(dest) {
if (!dest) {
div.scrollIntoView(true);
scrollIntoView(div);
return;
}
@ -1369,16 +1458,7 @@ var PageView = function pageView(container, pdfPage, id, scale,
var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]);
var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]);
// using temporary div to scroll it into view
var tempDiv = document.createElement('div');
tempDiv.style.position = 'absolute';
tempDiv.style.left = Math.floor(x) + 'px';
tempDiv.style.top = Math.floor(y) + 'px';
tempDiv.style.width = Math.ceil(width) + 'px';
tempDiv.style.height = Math.ceil(height) + 'px';
div.appendChild(tempDiv);
tempDiv.scrollIntoView(true);
div.removeChild(tempDiv);
scrollIntoView(div, {left: x, top: y, width: width, height: height});
}, 0);
};
@ -1521,7 +1601,9 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
return false;
};
var viewport = pdfPage.getViewport(1);
var rotation = 0;
var totalRotation = (rotation + pdfPage.rotate) % 360;
var viewport = pdfPage.getViewport(1, totalRotation);
var pageWidth = this.width = viewport.width;
var pageHeight = this.height = viewport.height;
var pageRatio = pageWidth / pageHeight;
@ -1536,12 +1618,41 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
div.id = 'thumbnailContainer' + id;
div.className = 'thumbnail';
var ring = document.createElement('div');
ring.className = 'thumbnailSelectionRing';
ring.style.width = canvasWidth + 'px';
ring.style.height = canvasHeight + 'px';
div.appendChild(ring);
anchor.appendChild(div);
container.appendChild(anchor);
this.hasImage = false;
this.renderingState = RenderingStates.INITIAL;
this.updateRotation = function(rot) {
rotation = rot;
totalRotation = (rotation + pdfPage.rotate) % 360;
viewport = pdfPage.getViewport(1, totalRotation);
pageWidth = this.width = viewport.width;
pageHeight = this.height = viewport.height;
pageRatio = pageWidth / pageHeight;
canvasHeight = canvasWidth / this.width * this.height;
scaleX = this.scaleX = (canvasWidth / pageWidth);
scaleY = this.scaleY = (canvasHeight / pageHeight);
div.removeAttribute('data-loaded');
ring.textContent = '';
ring.style.width = canvasWidth + 'px';
ring.style.height = canvasHeight + 'px';
this.hasImage = false;
this.renderingState = RenderingStates.INITIAL;
this.resume = null;
}
function getPageDrawContext() {
var canvas = document.createElement('canvas');
canvas.id = 'thumbnail' + id;
@ -1555,10 +1666,7 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
div.setAttribute('data-loaded', true);
var ring = document.createElement('div');
ring.className = 'thumbnailSelectionRing';
ring.appendChild(canvas);
div.appendChild(ring);
var ctx = canvas.getContext('2d');
ctx.save();
@ -1584,7 +1692,7 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) {
var self = this;
var ctx = getPageDrawContext();
var drawViewport = pdfPage.getViewport(scaleX);
var drawViewport = pdfPage.getViewport(scaleX, totalRotation);
var renderContext = {
canvasContext: ctx,
viewport: drawViewport,
@ -1890,6 +1998,93 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
PDFView.renderHighestPriority();
});
document.getElementById('viewThumbnail').addEventListener('click',
function() {
PDFView.switchSidebarView('thumbs');
});
document.getElementById('viewOutline').addEventListener('click',
function() {
PDFView.switchSidebarView('outline');
});
document.getElementById('viewSearch').addEventListener('click',
function() {
PDFView.switchSidebarView('search');
});
document.getElementById('searchButton').addEventListener('click',
function() {
PDFView.search();
});
document.getElementById('previous').addEventListener('click',
function() {
PDFView.page--;
});
document.getElementById('next').addEventListener('click',
function() {
PDFView.page++;
});
document.querySelector('.zoomIn').addEventListener('click',
function() {
PDFView.zoomIn();
});
document.querySelector('.zoomOut').addEventListener('click',
function() {
PDFView.zoomOut();
});
document.getElementById('fullscreen').addEventListener('click',
function() {
PDFView.fullscreen();
});
document.getElementById('openFile').addEventListener('click',
function() {
document.getElementById('fileInput').click();
});
document.getElementById('print').addEventListener('click',
function() {
window.print();
});
document.getElementById('download').addEventListener('click',
function() {
PDFView.download();
});
document.getElementById('searchTermsInput').addEventListener('keydown',
function() {
if (event.keyCode == 13) {
PDFView.search();
}
});
document.getElementById('pageNumber').addEventListener('change',
function() {
PDFView.page = this.value;
});
document.getElementById('scaleSelect').addEventListener('change',
function() {
PDFView.parseScale(this.value);
});
document.getElementById('page_rotate_ccw').addEventListener('click',
function() {
PDFView.rotatePages(-90);
});
document.getElementById('page_rotate_cw').addEventListener('click',
function() {
PDFView.rotatePages(90);
});
if (FirefoxCom.requestSync('getLoadingType') == 'passive') {
PDFView.setTitleUsingUrl(file);
PDFView.initPassiveLoading();
@ -2050,7 +2245,7 @@ window.addEventListener('pagechange', function pagechange(evt) {
var last = numVisibleThumbs > 1 ?
visibleThumbs.last.id : first;
if (page <= first || page >= last)
thumbnail.scrollIntoView();
scrollIntoView(thumbnail);
}
}
@ -2137,6 +2332,18 @@ window.addEventListener('keydown', function keydown(evt) {
handled = true;
}
break;
case 82: // 'r'
PDFView.rotatePages(90);
break;
}
}
if (cmd == 4) { // shift-key
switch (evt.keyCode) {
case 82: // 'r'
PDFView.rotatePages(-90);
break;
}
}

View File

@ -18,6 +18,8 @@ zoom_in_label=Zoom In
zoom.title=Zoom
print.title=Print
print_label=Print
fullscreen.title=Fullscreen
fullscreen_label=Fullscreen
open_file.title=Open File
open_file_label=Open
download.title=Download
@ -48,6 +50,10 @@ thumb_page_title=Page {{page}}
# number.
thumb_page_canvas=Thumbnail of Page {{page}}
# Context menu
page_rotate_cw=Rotate Clockwise
page_rotate_ccw=Rotate Counter-Clockwise
# Search panel button title and messages
search=Find
search_terms_not_found=(Not found)

View File

@ -21,6 +21,7 @@ EXTRA_JS_MODULES = \
NewTabUtils.jsm \
offlineAppCache.jsm \
SignInToWebsite.jsm \
TabTitleAbridger.jsm \
TelemetryTimestamps.jsm \
Social.jsm \
webappsUI.jsm \

View File

@ -0,0 +1,604 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let EXPORTED_SYMBOLS = ["TabTitleAbridger"];
const Cu = Components.utils;
const ABRIDGMENT_PREF = "browser.tabs.cropTitleRedundancy";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gETLDService",
"@mozilla.org/network/effective-tld-service;1",
"nsIEffectiveTLDService");
function TabTitleAbridger(aBrowserWin) {
this._tabbrowser = aBrowserWin.gBrowser;
}
TabTitleAbridger.prototype = {
/*
* Events we listen to. We specifically do not listen for TabCreate, as we
* get TabLabelModified at the appropriate times.
*/
_eventNames: [
"TabPinned",
"TabUnpinned",
"TabShow",
"TabHide",
"TabClose",
"TabLabelModified"
],
init: function TabTitleAbridger_Initialize() {
this._cropTitleRedundancy = Services.prefs.getBoolPref(ABRIDGMENT_PREF);
Services.prefs.addObserver(ABRIDGMENT_PREF, this, false);
if (this._cropTitleRedundancy) {
this._domainSets = new DomainSets();
this._addListeners();
}
},
destroy: function TabTitleAbridger_Destroy() {
Services.prefs.removeObserver(ABRIDGMENT_PREF, this);
if (this._cropTitleRedundancy) {
this._dropListeners();
}
},
/**
* Preference observer
*/
observe: function TabTitleAbridger_PrefObserver(aSubject, aTopic, aData) {
let val = Services.prefs.getBoolPref(aData);
if (this._cropTitleRedundancy && !val) {
this._dropListeners();
this._domainSets.destroy();
delete this._domainSets;
this._resetTabTitles();
} else if (!this._cropTitleRedundancy && val) {
this._addListeners();
// We're just turned on, so we want to abridge everything
this._domainSets = new DomainSets();
let domains = this._domainSets.bootstrap(this._tabbrowser.visibleTabs);
this._abridgeTabTitles(domains);
}
this._cropTitleRedundancy = val;
},
/**
* Adds all the necessary event listeners and listener-supporting objects for
* the instance.
*/
_addListeners: function TabTitleAbridger_addListeners() {
let tabContainer = this._tabbrowser.tabContainer;
for (let eventName of this._eventNames) {
tabContainer.addEventListener(eventName, this, false);
}
},
/**
* Removes event listeners and listener-supporting objects for the instance.
*/
_dropListeners: function TabTitleAbridger_dropListeners() {
let tabContainer = this._tabbrowser.tabContainer;
for (let eventName of this._eventNames) {
tabContainer.removeEventListener(eventName, this, false);
}
},
handleEvent: function TabTitleAbridger_handler(aEvent) {
let tab = aEvent.target;
let updateSets;
switch (aEvent.type) {
case "TabUnpinned":
case "TabShow":
updateSets = this._domainSets.addTab(tab);
break;
case "TabPinned":
case "TabHide":
case "TabClose":
updateSets = this._domainSets.removeTab(tab);
tab.visibleLabel = tab.label;
break;
case "TabLabelModified":
if (!tab.hidden && !tab.pinned) {
aEvent.preventDefault();
updateSets = this._domainSets.updateTab(tab);
}
break;
}
this._abridgeTabTitles(updateSets);
},
/**
* Make all tabs have their visibleLabels be their labels.
*/
_resetTabTitles: function TabTitleAbridger_resetTabTitles() {
// We're freshly disabled, so reset unpinned, visible tabs (see handleEvent)
for (let tab of this._tabbrowser.visibleTabs) {
if (!tab.pinned && tab.visibleLabel != tab.label) {
tab.visibleLabel = tab.label;
}
}
},
/**
* Apply abridgment for the given tabset and chop list.
* @param aTabSet Array of tabs to abridge
* @param aChopList Corresponding array of chop points for the tabs
*/
_applyAbridgment: function TabTitleAbridger_applyAbridgment(aTabSet,
aChopList) {
for (let i = 0; i < aTabSet.length; i++) {
let tab = aTabSet[i];
let label = tab.label || "";
if (label.length > 0) {
let chop = aChopList[i] || 0;
if (chop > 0) {
label = label.substr(chop);
}
}
if (label != tab.visibleLabel) {
tab.visibleLabel = label;
}
}
},
/**
* Abridges the tabs sets of tabs in the aTabSets array.
* @param aTabSets Array of tab sets needing abridgment
*/
_abridgeTabTitles: function TabTitleAbridger_abridgeTabtitles(aTabSets) {
// Process each set
for (let tabSet of aTabSets) {
// Get a chop list for the set and apply it
let chopList = AbridgmentTools.getChopsForSet(tabSet);
this._applyAbridgment(tabSet, chopList);
}
}
};
/**
* Maintains a mapping between tabs and domains, so that only the tabs involved
* in a TabLabelModified event need to be modified by the TabTitleAbridger.
*/
function DomainSets() {
this._domainSets = {};
this._tabsMappedToDomains = new WeakMap();
}
DomainSets.prototype = {
_noHostSchemes: {
chrome: true,
file: true,
resource: true,
data: true,
about: true
},
destroy: function DomainSets_destroy() {
delete this._domainSets;
delete this._tabsMappedToDomains;
},
/**
* Used to build the domainsets when enabled in mid-air, as opposed to when
* the window is coming up.
* @param The visibleTabs for the browser, or a set of tabs to check.
* @return An array containing the tabs in the domains they belong to, or
* an empty array if none of the tabs belonged to domains.
*/
bootstrap: function DomainSets_bootstrap(aVisibleTabs) {
let needAbridgment = [];
for (let tab of aVisibleTabs) {
let domainSet = this.addTab(aTab)[0] || null;
if (domainSet && needAbridgment.indexOf(domainSet) == -1) {
needAbridgment.push(domainSet);
}
}
return needAbridgment;
},
/**
* Given a tab, include it in the domain sets.
* @param aTab The tab to include in the domain sets
* @param aTabDomain [optional] The known domain for the tab
* @return An array containing the tabs in the domain the tab was added to.
*/
addTab: function DomainSets_addTab(aTab, aTabDomain) {
let tabDomain = aTabDomain || this._getDomainForTab(aTab);
if (!this._domainSets.hasOwnProperty(tabDomain)) {
this._domainSets[tabDomain] = [];
}
this._domainSets[tabDomain].push(aTab);
this._tabsMappedToDomains.set(aTab, tabDomain);
return [this._domainSets[tabDomain]];
},
/**
* Given a tab, remove it from the domain sets.
* @param aTab The tab to remove from the domain sets
* @param aTabDomain [optional] The known domain for the tab
* @return An array containing the tabs in the domain the tab was removed
* from, or an empty array if the tab was not removed from a domain set.
*/
removeTab: function DomainSets_removeTab(aTab, aTabDomain) {
let oldTabDomain = aTabDomain || this._tabsMappedToDomains.get(aTab);
if (!this._domainSets.hasOwnProperty(oldTabDomain)) {
return [];
}
let index = this._domainSets[oldTabDomain].indexOf(aTab);
if (index == -1) {
return [];
}
this._domainSets[oldTabDomain].splice(index, 1);
this._tabsMappedToDomains.delete(aTab);
if (!this._domainSets[oldTabDomain].length) {
// Keep the sets clean of empty domains
delete this._domainSets[oldTabDomain];
return [];
}
return [this._domainSets[oldTabDomain]];
},
/**
* Given a tab, update the domain set it belongs to.
* @param aTab The tab to update the domain set for
* @return An array containing the tabs in the domain the tab belongs to, and
* (if changed) the domain the tab was removed from.
*/
updateTab: function DomainSets_updateTab(aTab) {
let tabDomain = this._getDomainForTab(aTab);
let oldTabDomain = this._tabsMappedToDomains.get(aTab);
if (oldTabDomain != tabDomain) {
let needAbridgment = [];
// Probably swapping domain sets out; we pass the domains along to avoid
// re-getting them in addTab/removeTab
if (oldTabDomain) {
needAbridgment = needAbridgment.concat(
this.removeTab(aTab, oldTabDomain));
}
return needAbridgment.concat(this.addTab(aTab, tabDomain));
}
// No change was needed
return [this._domainSets[tabDomain]];
},
/**
* Given a tab, determine the URI scheme or host to categorize it.
* @param aTab The tab to get the domain for
* @return The domain or scheme for the tab
*/
_getDomainForTab: function DomainSets_getDomainForTab(aTab) {
let browserURI = aTab.linkedBrowser.currentURI;
if (browserURI.scheme in this._noHostSchemes) {
return browserURI.scheme;
}
// throws for empty URI, host is IP, and disallowed characters
try {
return gETLDService.getBaseDomain(browserURI);
}
catch (e) {}
// this nsIURI may not be an nsStandardURL nsIURI, which means it
// might throw for the host
try {
return browserURI.host;
}
catch (e) {}
// Treat this URI as unique
return browserURI.spec;
}
};
let AbridgmentTools = {
/**
* Constant for the minimum remaining length allowed if a label is abridged.
* I.e., original:"abc - de" might be chopped to just "de", which is too
* small, so the label would be reverted to the next-longest version.
*/
MIN_CHOP: 3,
/**
* Helper to determine if aStr is URI-like
* \s? optional leading space
* [^\s\/]* optional scheme or relative path component
* ([^\s\/]+:\/)? optional scheme separator, with at least one scheme char
* \/ at least one slash
* \/? optional second (or third for eg, file scheme on UNIX) slash
* [^\s\/]* optional path component
* ([^\s\/]+\/?)* optional more path components with optional end slash
* @param aStr the string to check for URI-likeness
* @return boolean value of whether aStr matches
*/
_titleIsURI: function AbridgmentTools_titleIsURI(aStr) {
return /^\s?[^\s\/]*([^\s\/]+:\/)?\/\/?[^\s\/]*([^\s\/]+\/?)*$/.test(aStr);
},
/**
* Finds the proper abridgment indexes for the given tabs.
* @param aTabSet the array of tabs to find abridgments for
* @return an array of abridgment indexes corresponding to the tabs
*/
getChopsForSet: function AbridgmentTools_getChopsForSet(aTabSet) {
let chopList = [];
let pathMode = false;
aTabSet.sort(function(aTab, bTab) {
let aLabel = aTab.label;
let bLabel = bTab.label;
return (aLabel < bLabel) ? -1 : (aLabel > bLabel) ? 1 : 0;
});
// build and apply the chopList for the set
for (let i = 0, next = 1; next < aTabSet.length; i = next++) {
next = this._abridgePair(aTabSet, i, next, chopList);
}
return chopList;
},
/**
* Handles the abridgment between aIndex and aNext, or in the case where the
* label at aNext is the same as at aIndex, moves aNext forward appropriately.
* @param aTabSet Sorted array of tabs that the indices refer to
* @param aIndex First tab index to use in abridgment
* @param aNext Second tab index to use as the an initial comparison
* @param aChopList Array to add chop points to for the given tabs
* @return Index to replace aNext with, that is the index of the tab that was
* used in abridging the tab at aIndex
*/
_abridgePair: function TabTitleAbridger_abridgePair(aTabSet, aIndex, aNext,
aChopList) {
let tabStr = aTabSet[aIndex].label;
let pathMode = this._titleIsURI(tabStr);
let chop = RedundancyFinder.indexOfSep(pathMode, tabStr);
// Default to no chop
if (!aChopList[aIndex]) {
aChopList[aIndex] = 0;
}
// Siblings with same label get proxied by the first
let nextStr;
aNext = this._nextUnproxied(aTabSet, tabStr, aNext);
if (aNext < aTabSet.length) {
nextStr = aTabSet[aNext].label;
}
// Bail on these strings early, using the first as the basis
if (chop == -1 || aNext == aTabSet.length ||
!nextStr.startsWith(tabStr.substr(0, chop + 1))) {
chop = aChopList[aIndex];
if (aNext != aTabSet.length) {
aChopList[aNext] = 0;
}
} else {
[pathMode, chop] = this._getCommonChopPoint(pathMode, tabStr, nextStr,
chop);
[chop, aChopList[aNext]] = this._adjustChops(pathMode, tabStr, nextStr,
chop);
aChopList[aIndex] = chop;
}
// Mark chop on the relevant tabs
for (let j = aIndex; j < aNext; j++) {
let oldChop = aChopList[j];
if (!oldChop || oldChop < chop) {
aChopList[j] = chop;
}
}
return aNext;
},
/**
* Gets the index in aTabSet of the next tab that's not equal to aStr.
* @param aTabSet Sorted set of tabs to check
* @param aStr Label string to check against
* @param aStart First item to check for proxying
* @return The index of the next different tab.
*/
_nextUnproxied: function AbridgmentTools_nextUnproxied(aTabSet, aTabStr,
aStart) {
let nextStr = aTabSet[aStart].label;
while (aStart < aTabSet.length && aTabStr == nextStr) {
aStart += 1;
if (aStart < aTabSet.length) {
nextStr = aTabSet[aStart].label;
}
}
return aStart;
},
/**
* Get the common index where the aTabStr and aNextStr diverge.
* @param aPathMode Whether to use path mode
* @param aTabStr Tab label
* @param aNextStr Second tab label
* @param aChop Current chop point being considered (index of aTabStr's
* first separator)
* @return An array containing the resulting path mode (in case it changes)
* and the diverence index for the labels.
*/
_getCommonChopPoint: function AbridgmentTools_getCommonChopPoint(aPathMode,
aTabStr,
aNextStr,
aChop) {
aChop = RedundancyFinder.findCommonPrefix(aPathMode, aTabStr, aNextStr,
aChop);
// Does a URI remain?
if (!aPathMode) {
aPathMode = this._titleIsURI(aTabStr.substr(aChop));
if (aPathMode) {
aChop = RedundancyFinder.findCommonPrefix(aPathMode, aTabStr, aNextStr,
aChop);
}
}
return [aPathMode, aChop + 1];
},
/**
* Adjusts the chop points based on their suffixes and lengths.
* @param aPathMode Whether to use path mode
* @param aTabStr Tab label
* @param aNextStr Second tab label
* @param aChop Current chop point being considered
* @return An array containing the chop point for the two labels.
*/
_adjustChops: function AbridgmentTools_adjustChops(aPathMode, aTabStr,
aNextStr, aChop) {
let suffix = RedundancyFinder.findCommonSuffix(aPathMode, aTabStr,
aNextStr);
let sufPos = aTabStr.length - suffix;
let nextSufPos = aNextStr.length - suffix;
let nextChop = aChop;
// Adjust the chop based on the suffix.
if (sufPos < aChop) {
// Only revert based on suffix for tab and any identicals
aChop = RedundancyFinder.lastIndexOfSep(aPathMode, aTabStr,
sufPos - 1)[1] + 1;
} else if (nextSufPos < aChop) {
// Only revert based on suffix for 'next'
nextChop = RedundancyFinder.lastIndexOfSep(aPathMode, aNextStr,
nextSufPos - 1)[1] + 1;
}
if (aTabStr.length - aChop < this.MIN_CHOP) {
aChop = RedundancyFinder.lastIndexOfSep(aPathMode, aTabStr,
aChop - 2)[1] + 1;
}
if (aNextStr.length - nextChop < this.MIN_CHOP) {
nextChop = RedundancyFinder.lastIndexOfSep(aPathMode, aNextStr,
nextChop - 2)[1] + 1;
}
return [aChop, nextChop];
}
};
let RedundancyFinder = {
/**
* Finds the first index of a matched separator after aStart.
* Separators will either be space-padded punctuation or slashes (in pathmode)
*
* ^.+? at least one character, non-greedy match
* \s+ one or more whitespace characters
* [-:>\|]+ one or more separator characters
* \s+ one or more whitespace characters
*
* @param aPathMode true for path mode, false otherwise
* @param aStr the string to look for a separator in
* @param aStart (optional) an index to start the search from
* @return the next index of a separator or -1 for none
*/
indexOfSep: function RedundancyFinder_indexOfSep(aPathMode, aStr, aStart) {
if (aPathMode) {
return aStr.indexOf('/', aStart);
}
let match = aStr.slice(aStart).match(/^.+?\s+[-:>\|]+\s+/);
if (match) {
return (aStart || 0) + match[0].length - 1;
}
return -1;
},
/**
* Compares a pair of strings, seeking an index where their redundancy ends
* @param aPathMode true for pathmode, false otherwise
* @param aStr the string to decide an abridgment for
* @param aNextStr the lexicographically next string to compare with
* @param aChop the basis index, a best-known index to begin comparison
* @return the index at which aStr's abridged title should begin
*/
findCommonPrefix: function RedundancyFinder_findCommonPrefix(aPathMode, aStr,
aNextStr,
aChop) {
// Advance until the end of the title or the pair diverges
do {
aChop = this.indexOfSep(aPathMode, aStr, aChop + 1);
} while (aChop != -1 && aNextStr.startsWith(aStr.substr(0, aChop + 1)));
if (aChop < 0) {
aChop = aStr.length;
}
// Return the last valid spot
return this.lastIndexOfSep(aPathMode, aStr, aChop - 1)[1];
},
/**
* Finds the range of a separator earlier than aEnd in aStr
* The range is required by findCommonSuffix() needing to know the beginning
* of the separator.
* Separators will either be space-padded punctuation or slashes (in pathmode)
*
* .+ one or more initial characters
* ( first group
* ( second group
* \s+ one or more whitespace characters
* [-:>\|]+ one or more separator characters
* \s+ one or more whitespace characters
* ) end first group
* .*? zero or more characters, non-greedy match
* ) end second group
* $ end of input
*
* @param aPathMode true for pathmode, false otherwise
* @param aStr the string to look for a separator in
* @param aEnd (optional) an index to start the backwards search from
* @return an array containing the endpoints of a separator (-1, -1 for none)
*/
lastIndexOfSep: function RedundancyFinder_lastIndexOfSep(aPathMode, aStr,
aEnd) {
if (aPathMode) {
let path = aStr.lastIndexOf('/', aEnd);
return [path, path];
}
let string = aStr.slice(0, aEnd);
let match = string.match(/.+((\s+[-:>\|]+\s+).*?)$/);
if (match) {
let index = string.length - match[1].length;
return [index, index + match[2].length - 1];
}
return [-1, -1];
},
/**
* Finds a common suffix (redundancy at the end of) a pair of strings.
* @param aPathMode true for pathmode, false otherwise
* @param aStr a base string to look for a suffix in
* @param aNextStr a string that may share a common suffix with aStr
* @return an index indicating the divergence between the strings
*/
findCommonSuffix: function RedundancyFinder_findCommonSuffix(aPathMode, aStr,
aNextStr) {
let last = this.lastIndexOfSep(aPathMode, aStr)[0];
// Is there any suffix match?
if (!aNextStr.endsWith(aStr.slice(last))) {
return 0;
}
// Move backwards on the main string until the suffix diverges
let oldLast;
do {
oldLast = last;
last = this.lastIndexOfSep(aPathMode, aStr, last - 1)[0];
} while (last != -1 && aNextStr.endsWith(aStr.slice(last)));
return aStr.length - oldLast;
}
};

View File

@ -131,26 +131,63 @@ let DOMApplicationRegistry = {
},
#ifdef MOZ_SYS_MSG
_registerSystemMessages: function(aManifest, aApp) {
if (aManifest.messages && Array.isArray(aManifest.messages) &&
aManifest.messages.length > 0) {
let manifest = new DOMApplicationManifest(aManifest, aApp.origin);
let launchPath = Services.io.newURI(manifest.fullLaunchPath(), null, null);
let manifestURL = Services.io.newURI(aApp.manifestURL, null, null);
aManifest.messages.forEach(function registerPages(aMessage) {
msgmgr.registerPage(aMessage, launchPath, manifestURL);
});
}
},
_registerActivities: function(aManifest, aApp) {
if (!aManifest.activities) {
// aEntryPoint is either the entry_point name or the null, in which case we
// use the root of the manifest.
_registerSystemMessagesForEntryPoint: function(aManifest, aApp, aEntryPoint) {
let root = aManifest;
if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
root = aManifest.entry_points[aEntryPoint];
}
if (!root.messages || !Array.isArray(root.messages) ||
root.messages.length == 0) {
return;
}
let manifest = new DOMApplicationManifest(aManifest, aApp.origin);
for (let activity in aManifest.activities) {
let description = aManifest.activities[activity];
let launchPath = Services.io.newURI(manifest.fullLaunchPath(aEntryPoint), null, null);
let manifestURL = Services.io.newURI(aApp.manifestURL, null, null);
root.messages.forEach(function registerPages(aMessage) {
let href = launchPath;
let messageName;
if (typeof(aMessage) === "object" && Object.keys(aMessage).length === 1) {
messageName = Object.keys(aMessage)[0];
href = Services.io.newURI(manifest.resolveFromOrigin(aMessage[messageName]), null, null);
} else {
messageName = aMessage;
}
msgmgr.registerPage(messageName, href, manifestURL);
});
},
_registerSystemMessages: function(aManifest, aApp) {
this._registerSystemMessagesForEntryPoint(aManifest, aApp, null);
if (!aManifest.entry_points) {
return;
}
for (let entryPoint in aManifest.entry_points) {
this._registerSystemMessagesForEntryPoint(aManifest, aApp, entryPoint);
}
},
// aEntryPoint is either the entry_point name or the null, in which case we
// use the root of the manifest.
_registerActivitiesForEntryPoint: function(aManifest, aApp, aEntryPoint) {
let root = aManifest;
if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
root = aManifest.entry_points[aEntryPoint];
}
if (!root.activities) {
return;
}
let manifest = new DOMApplicationManifest(aManifest, aApp.origin);
for (let activity in root.activities) {
let description = root.activities[activity];
if (!description.href) {
description.href = manifest.launch_path;
}
@ -171,13 +208,30 @@ let DOMApplicationRegistry = {
}
},
_unregisterActivities: function(aManifest, aApp) {
if (!aManifest.activities) {
_registerActivities: function(aManifest, aApp) {
this._registerActivitiesForEntryPoint(aManifest, aApp, null);
if (!aManifest.entry_points) {
return;
}
for (let activity in aManifest.activities) {
let description = aManifest.activities[activity];
for (let entryPoint in aManifest.entry_points) {
this._registerActivitiesForEntryPoint(aManifest, aApp, entryPoint);
}
},
_unregisterActivitiesForEntryPoint: function(aManifest, aApp, aEntryPoint) {
let root = aManifest;
if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
root = aManifest.entry_points[aEntryPoint];
}
if (!root.activities) {
return;
}
for (let activity in root.activities) {
let description = root.activities[activity];
let json = {
"manifest": aApp.manifestURL,
"name": activity
@ -186,6 +240,18 @@ let DOMApplicationRegistry = {
}
},
_unregisterActivities: function(aManifest, aApp) {
this._unregisterActivitiesForEntryPoint(aManifest, aApp, null);
if (!aManifest.entry_points) {
return;
}
for (let entryPoint in aManifest.entry_points) {
this._unregisterActivitiesForEntryPoint(aManifest, aApp, entryPoint);
}
},
_processManifestForIds: function(aIds) {
this._readManifests(aIds, (function registerManifests(aResults) {
aResults.forEach(function registerManifest(aResult) {
@ -400,7 +466,8 @@ let DOMApplicationRegistry = {
}).bind(this));
#ifdef MOZ_SYS_MSG
this._registerSystemMessages(id, app);
this._registerSystemMessages(app.manifest, app);
this._registerActivities(app.manifest, app);
#endif
// if the manifest has an appcache_path property, use it to populate the appcache

View File

@ -8,7 +8,7 @@
interface nsIDOMStorage;
interface nsIPrincipal;
[scriptable, uuid(1541da6c-a9fb-4a8f-af9d-4493c981491d)]
[scriptable, uuid(b16b207c-d883-43f5-a27e-548e7f2f5c20)]
interface nsIDOMStorageManager : nsISupports
{
/**
@ -21,12 +21,6 @@ interface nsIDOMStorageManager : nsISupports
*/
long getUsage(in AString aOwnerDomain);
/**
* Clear keys owned by offline applications. All data owned by a domain
* with the "offline-app" permission will be removed from the database.
*/
void clearOfflineApps();
/**
* Returns instance of localStorage object for aURI's origin.
* This method ensures there is always only a single instance

View File

@ -35,9 +35,9 @@ sync protocol PStorage
parent:
__delete__();
Init(bool useDB, bool canUseChromePersist, bool sessionOnly, bool isPrivate,
nsCString domain, nsCString scopeDBKey, nsCString quotaDomainDBKey,
nsCString quotaETLDplus1DomainDBKey, uint32_t storageType);
Init(bool useDB, bool sessionOnly, bool isPrivate,
nsCString domain, nsCString scopeDBKey,
nsCString quotaDBKey, uint32_t storageType);
sync GetKeys(bool callerSecure)
returns (nsString[] keys);

View File

@ -83,8 +83,8 @@ StorageChild::InitRemote()
ContentChild* child = ContentChild::GetSingleton();
AddIPDLReference();
child->SendPStorageConstructor(this, null_t());
SendInit(mUseDB, mCanUseChromePersist, mSessionOnly, mInPrivateBrowsing, mDomain, mScopeDBKey,
mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
SendInit(mUseDB, mSessionOnly, mInPrivateBrowsing, mDomain, mScopeDBKey,
mQuotaDBKey, mStorageType);
}
void
@ -95,9 +95,9 @@ StorageChild::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
}
void
StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate)
StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate)
{
DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist, aPrivate);
DOMStorageBase::InitAsLocalStorage(aDomainURI, aPrivate);
InitRemote();
}
@ -196,12 +196,6 @@ StorageChild::Clear(bool aCallerSecure, int32_t* aOldCount)
return NS_OK;
}
bool
StorageChild::CanUseChromePersist()
{
return mCanUseChromePersist;
}
nsresult
StorageChild::GetDBValue(const nsAString& aKey, nsAString& aValue,
bool* aSecure)
@ -239,8 +233,8 @@ StorageChild::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat)
StorageClone clone(nullptr, other, aCallerSecure);
AddIPDLReference();
child->SendPStorageConstructor(this, clone);
SendInit(mUseDB, mCanUseChromePersist, mSessionOnly, mInPrivateBrowsing, mDomain,
mScopeDBKey, mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
SendInit(mUseDB, mSessionOnly, mInPrivateBrowsing, mDomain,
mScopeDBKey, mQuotaDBKey, mStorageType);
return NS_OK;
}

View File

@ -27,7 +27,7 @@ public:
StorageChild(nsDOMStorage* aOwner, StorageChild& aOther);
virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate);
virtual bool CacheStoragePermissions();
@ -42,8 +42,6 @@ public:
nsAString& aOldValue);
virtual nsresult Clear(bool aCallerSecure, int32_t* aOldCount);
virtual bool CanUseChromePersist();
virtual nsresult GetDBValue(const nsAString& aKey,
nsAString& aValue,
bool* aSecure);

View File

@ -28,17 +28,15 @@ StorageParent::StorageParent(const StorageConstructData& aData)
bool
StorageParent::RecvInit(const bool& aUseDB,
const bool& aCanUseChromePersist,
const bool& aSessionOnly,
const bool& aPrivate,
const nsCString& aDomain,
const nsCString& aScopeDBKey,
const nsCString& aQuotaDomainDBKey,
const nsCString& aQuotaETLDplus1DomainDBKey,
const nsCString& aQuotaDBKey,
const uint32_t& aStorageType)
{
mStorage->InitFromChild(aUseDB, aCanUseChromePersist, aSessionOnly, aPrivate, aDomain,
aScopeDBKey, aQuotaDomainDBKey, aQuotaETLDplus1DomainDBKey,
mStorage->InitFromChild(aUseDB, aSessionOnly, aPrivate, aDomain,
aScopeDBKey, aQuotaDBKey,
aStorageType);
return true;
}

View File

@ -43,13 +43,11 @@ private:
bool RecvSetSecure(const nsString& aKey, const bool& aSecure, nsresult* rv);
bool RecvInit(const bool& aUseDB,
const bool& aCanUseChromePersist,
const bool& aSessionOnly,
const bool& aPrivate,
const nsCString& aDomain,
const nsCString& aScopeDBKey,
const nsCString& aQuotaDomainDBKey,
const nsCString& aQuotaETLDplus1DomainDBKey,
const nsCString& aQuotaDBKey,
const uint32_t& aStorageType);
bool RecvUpdatePrivateState(const bool& aEnabled);

View File

@ -29,9 +29,7 @@ using mozilla::dom::ContentChild;
#include "nsIPermission.h"
#include "nsIPermissionManager.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsIJSContextStack.h"
#include "nsIPrivateBrowsingService.h"
#include "nsDOMString.h"
#include "nsNetCID.h"
#include "mozilla/Preferences.h"
@ -52,23 +50,14 @@ static const uint32_t ASK_BEFORE_ACCEPT = 1;
static const uint32_t ACCEPT_SESSION = 2;
static const uint32_t BEHAVIOR_REJECT = 2;
static const uint32_t DEFAULT_QUOTA = 5 * 1024;
// Be generous with offline apps by default...
static const uint32_t DEFAULT_OFFLINE_APP_QUOTA = 200 * 1024;
// ... but warn if it goes over this amount
static const uint32_t DEFAULT_OFFLINE_WARN_QUOTA = 50 * 1024;
// Intervals to flush the temporary table after in seconds
#define NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_INACTIVITY_TIME (5)
#define NS_DOMSTORAGE_MAXIMUM_TEMPTABLE_AGE (30)
static const char kPermissionType[] = "cookie";
static const char kStorageEnabled[] = "dom.storage.enabled";
static const char kDefaultQuota[] = "dom.storage.default_quota";
static const char kCookiesBehavior[] = "network.cookie.cookieBehavior";
static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
static const char kOfflineAppWarnQuota[] = "offline-apps.quota.warn";
static const char kOfflineAppQuota[] = "offline-apps.quota.max";
// The URI returned is the innermost URI that should be used for
// security-check-like stuff. aHost is its hostname, correctly canonicalized.
@ -140,65 +129,6 @@ IsCallerSecure()
return NS_SUCCEEDED(rv) && isHttps;
}
uint32_t
GetOfflinePermission(const nsACString &aDomain)
{
// Fake a URI for the permission manager
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aDomain);
uint32_t perm;
if (uri) {
nsCOMPtr<nsIPermissionManager> permissionManager =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (permissionManager &&
NS_SUCCEEDED(permissionManager->TestPermission(uri, "offline-app", &perm)))
return perm;
}
return nsIPermissionManager::UNKNOWN_ACTION;
}
bool
IsOfflineAllowed(const nsACString &aDomain)
{
int32_t perm = GetOfflinePermission(aDomain);
return IS_PERMISSION_ALLOWED(perm);
}
// Returns two quotas - A hard limit for which adding data will be an error,
// and a limit after which a warning event will be sent to the observer
// service. The warn limit may be -1, in which case there will be no warning.
// If aOverrideQuota is set, the larger offline apps quota is used and no
// warning is sent.
static uint32_t
GetQuota(const nsACString &aDomain, int32_t *aQuota, int32_t *aWarnQuota,
bool aOverrideQuota)
{
uint32_t perm = GetOfflinePermission(aDomain);
if (IS_PERMISSION_ALLOWED(perm) || aOverrideQuota) {
// This is an offline app, give more space by default.
*aQuota = Preferences::GetInt(kOfflineAppQuota,
DEFAULT_OFFLINE_APP_QUOTA) * 1024;
if (perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN ||
aOverrideQuota) {
*aWarnQuota = -1;
} else {
*aWarnQuota = Preferences::GetInt(kOfflineAppWarnQuota,
DEFAULT_OFFLINE_WARN_QUOTA) * 1024;
}
return perm;
}
// FIXME: per-domain quotas?
*aQuota = Preferences::GetInt(kDefaultQuota, DEFAULT_QUOTA) * 1024;
*aWarnQuota = -1;
return perm;
}
nsSessionStorageEntry::nsSessionStorageEntry(KeyTypePointer aStr)
: nsStringHashKey(aStr), mItem(nullptr)
{
@ -251,8 +181,6 @@ nsDOMStorageManager::Initialize()
nsresult rv;
rv = os->AddObserver(gStorageManager, "cookie-changed", true);
NS_ENSURE_SUCCESS(rv, rv);
rv = os->AddObserver(gStorageManager, "offline-app-removed", true);
NS_ENSURE_SUCCESS(rv, rv);
rv = os->AddObserver(gStorageManager, "profile-after-change", true);
NS_ENSURE_SUCCESS(rv, rv);
rv = os->AddObserver(gStorageManager, "perm-changed", true);
@ -315,59 +243,12 @@ ClearStorageIfDomainMatches(nsDOMStorageEntry* aEntry, void* userArg)
return PL_DHASH_REMOVE;
}
static nsresult
GetOfflineDomains(nsTArray<nsString>& aDomains)
{
nsCOMPtr<nsIPermissionManager> permissionManager =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (permissionManager) {
nsCOMPtr<nsISimpleEnumerator> enumerator;
nsresult rv = permissionManager->GetEnumerator(getter_AddRefs(enumerator));
NS_ENSURE_SUCCESS(rv, rv);
bool hasMore;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supp;
rv = enumerator->GetNext(getter_AddRefs(supp));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPermission> perm(do_QueryInterface(supp, &rv));
NS_ENSURE_SUCCESS(rv, rv);
uint32_t capability;
rv = perm->GetCapability(&capability);
NS_ENSURE_SUCCESS(rv, rv);
if (capability != nsIPermissionManager::DENY_ACTION) {
nsAutoCString type;
rv = perm->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
if (type.EqualsLiteral("offline-app")) {
nsAutoCString host;
rv = perm->GetHost(host);
NS_ENSURE_SUCCESS(rv, rv);
aDomains.AppendElement(NS_ConvertUTF8toUTF16(host));
}
}
}
}
return NS_OK;
}
nsresult
nsDOMStorageManager::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
if (!strcmp(aTopic, "profile-after-change")) {
}
else if (!strcmp(aTopic, "offline-app-removed")) {
nsresult rv = DOMStorageImpl::InitDB();
NS_ENSURE_SUCCESS(rv, rv);
return DOMStorageImpl::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData),
true);
} else if (!strcmp(aTopic, "cookie-changed") &&
!nsCRT::strcmp(aData, NS_LITERAL_STRING("cleared").get())) {
mStorages.EnumerateEntries(ClearStorage, nullptr);
@ -375,11 +256,7 @@ nsDOMStorageManager::Observe(nsISupports *aSubject,
nsresult rv = DOMStorageImpl::InitDB();
NS_ENSURE_SUCCESS(rv, rv);
// Remove global storage for domains that aren't marked for offline use.
nsTArray<nsString> domains;
rv = GetOfflineDomains(domains);
NS_ENSURE_SUCCESS(rv, rv);
return DOMStorageImpl::gStorageDB->RemoveOwners(domains, true, false);
return DOMStorageImpl::gStorageDB->RemoveAll();
} else if (!strcmp(aTopic, "perm-changed")) {
// Check for cookie permission change
nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
@ -425,7 +302,7 @@ nsDOMStorageManager::Observe(nsISupports *aSubject,
}
nsAutoCString key;
rv = nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aceDomain, key);
rv = nsDOMStorageDBWrapper::CreateReversedDomain(aceDomain, key);
NS_ENSURE_SUCCESS(rv, rv);
// Clear the storage entries for matching domains
@ -434,7 +311,7 @@ nsDOMStorageManager::Observe(nsISupports *aSubject,
rv = DOMStorageImpl::InitDB();
NS_ENSURE_SUCCESS(rv, rv);
DOMStorageImpl::gStorageDB->RemoveOwner(aceDomain, true);
DOMStorageImpl::gStorageDB->RemoveOwner(aceDomain);
} else if (!strcmp(aTopic, "profile-before-change")) {
if (DOMStorageImpl::gStorageDB) {
DebugOnly<nsresult> rv =
@ -475,19 +352,7 @@ nsDOMStorageManager::GetUsage(const nsAString& aDomain,
NS_ENSURE_SUCCESS(rv, rv);
return DOMStorageImpl::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain),
false, aUsage, false);
}
NS_IMETHODIMP
nsDOMStorageManager::ClearOfflineApps()
{
nsresult rv = DOMStorageImpl::InitDB();
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsString> domains;
rv = GetOfflineDomains(domains);
NS_ENSURE_SUCCESS(rv, rv);
return DOMStorageImpl::gStorageDB->RemoveOwners(domains, true, true);
aUsage, false);
}
NS_IMETHODIMP
@ -586,7 +451,6 @@ DOMStorageBase::DOMStorageBase()
: mStorageType(nsPIDOMStorage::Unknown)
, mUseDB(false)
, mSessionOnly(true)
, mCanUseChromePersist(false)
, mInPrivateBrowsing(false)
{
}
@ -597,9 +461,7 @@ DOMStorageBase::DOMStorageBase(DOMStorageBase& aThat)
, mSessionOnly(true)
, mDomain(aThat.mDomain)
, mScopeDBKey(aThat.mScopeDBKey)
, mQuotaETLDplus1DomainDBKey(aThat.mQuotaETLDplus1DomainDBKey)
, mQuotaDomainDBKey(aThat.mQuotaDomainDBKey)
, mCanUseChromePersist(aThat.mCanUseChromePersist)
, mQuotaDBKey(aThat.mQuotaDBKey)
, mInPrivateBrowsing(aThat.mInPrivateBrowsing)
{
}
@ -616,14 +478,12 @@ DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
mUseDB = false;
mScopeDBKey.Truncate();
mQuotaDomainDBKey.Truncate();
mStorageType = nsPIDOMStorage::SessionStorage;
mInPrivateBrowsing = aPrivate;
}
void
DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
bool aCanUseChromePersist,
bool aPrivate)
{
// No need to check for a return value. If this would fail we would not get
@ -634,7 +494,7 @@ DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
// mPrincipal in bug 455070. It is not even used for localStorage.
aDomainURI->GetAsciiHost(mDomain);
nsDOMStorageDBWrapper::CreateOriginScopeDBKey(aDomainURI, mScopeDBKey);
nsDOMStorageDBWrapper::CreateScopeDBKey(aDomainURI, mScopeDBKey);
// XXX Bug 357323, we have to solve the issue how to define
// origin for file URLs. In that case CreateOriginScopeDBKey
@ -642,11 +502,7 @@ DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
// in that case because it produces broken entries w/o owner.
mUseDB = !mScopeDBKey.IsEmpty();
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
true, false, mQuotaDomainDBKey);
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
true, true, mQuotaETLDplus1DomainDBKey);
mCanUseChromePersist = aCanUseChromePersist;
nsDOMStorageDBWrapper::CreateQuotaDBKey(mDomain, mQuotaDBKey);
mStorageType = nsPIDOMStorage::LocalStorage;
mInPrivateBrowsing = aPrivate;
}
@ -731,22 +587,19 @@ DOMStorageImpl::InitDB()
}
void
DOMStorageImpl::InitFromChild(bool aUseDB, bool aCanUseChromePersist,
DOMStorageImpl::InitFromChild(bool aUseDB,
bool aSessionOnly, bool aPrivate,
const nsACString& aDomain,
const nsACString& aScopeDBKey,
const nsACString& aQuotaDomainDBKey,
const nsACString& aQuotaETLDplus1DomainDBKey,
const nsACString& aQuotaDBKey,
uint32_t aStorageType)
{
mUseDB = aUseDB;
mCanUseChromePersist = aCanUseChromePersist;
mSessionOnly = aSessionOnly;
mInPrivateBrowsing = aPrivate;
mDomain = aDomain;
mScopeDBKey = aScopeDBKey;
mQuotaDomainDBKey = aQuotaDomainDBKey;
mQuotaETLDplus1DomainDBKey = aQuotaETLDplus1DomainDBKey;
mQuotaDBKey = aQuotaDBKey;
mStorageType = static_cast<nsPIDOMStorage::nsDOMStorageType>(aStorageType);
}
@ -764,10 +617,9 @@ DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
void
DOMStorageImpl::InitAsLocalStorage(nsIURI* aDomainURI,
bool aCanUseChromePersist,
bool aPrivate)
{
DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist, aPrivate);
DOMStorageBase::InitAsLocalStorage(aDomainURI, aPrivate);
}
bool
@ -782,12 +634,6 @@ DOMStorageImpl::CacheStoragePermissions()
return mOwner->CacheStoragePermissions();
}
bool
DOMStorageImpl::CanUseChromePersist()
{
return mCanUseChromePersist;
}
nsresult
DOMStorageImpl::GetCachedValue(const nsAString& aKey, nsAString& aValue,
bool* aSecure)
@ -843,39 +689,11 @@ DOMStorageImpl::SetDBValue(const nsAString& aKey,
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
int32_t offlineAppPermission;
int32_t quota;
int32_t warnQuota;
offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota,
CanUseChromePersist());
CacheKeysFromDB();
int32_t usage;
rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota,
!IS_PERMISSION_ALLOWED(offlineAppPermission),
&usage);
rv = gStorageDB->SetKey(this, aKey, aValue, aSecure);
NS_ENSURE_SUCCESS(rv, rv);
if (warnQuota >= 0 && usage > warnQuota) {
// try to include the window that exceeded the warn quota
nsCOMPtr<nsIDOMWindow> window;
JSContext *cx;
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
nsCOMPtr<nsIScriptContext> scriptContext;
scriptContext = GetScriptContextFromJSContext(cx);
if (scriptContext) {
window = do_QueryInterface(scriptContext->GetGlobalObject());
}
}
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
os->NotifyObservers(window, "dom-storage-warn-quota-exceeded",
NS_ConvertUTF8toUTF16(mDomain).get());
}
return NS_OK;
}
@ -1210,8 +1028,7 @@ DOMStorageImpl::RemoveValue(bool aCallerSecure, const nsAString& aKey,
oldValue = value;
rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain),
aKey.Length() + value.Length());
rv = gStorageDB->RemoveKey(this, aKey);
NS_ENSURE_SUCCESS(rv, rv);
}
else if (entry) {
@ -1364,13 +1181,7 @@ nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aD
mStorageType = LocalStorage;
bool canUseChromePersist = false;
nsCOMPtr<nsIURI> URI;
if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) {
canUseChromePersist = URICanUseChromePersist(URI);
}
mStorageImpl->InitAsLocalStorage(domainURI, canUseChromePersist, aPrivate);
mStorageImpl->InitAsLocalStorage(domainURI, aPrivate);
return NS_OK;
}
@ -1438,9 +1249,7 @@ nsDOMStorage::CanUseStorage(DOMStorageBase* aStorage /* = NULL */)
uint32_t lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
// Treat "ask every time" as "reject always".
// Chrome persistent pages can bypass this check.
if ((cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT) &&
!URICanUseChromePersist(subjectURI))
if ((cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT))
return false;
if (lifetimePolicy == ACCEPT_SESSION && aStorage)
@ -1470,15 +1279,6 @@ nsDOMStorage::CacheStoragePermissions()
return CanAccess(subjectPrincipal);
}
// static
bool
nsDOMStorage::URICanUseChromePersist(nsIURI* aURI) {
bool isAbout;
return
(NS_SUCCEEDED(aURI->SchemeIs("moz-safe-about", &isAbout)) && isAbout) ||
(NS_SUCCEEDED(aURI->SchemeIs("about", &isAbout)) && isAbout);
}
NS_IMETHODIMP
nsDOMStorage::GetLength(uint32_t *aLength)
{

View File

@ -30,10 +30,6 @@
#include "nsDOMStorageDBWrapper.h"
#define IS_PERMISSION_ALLOWED(perm) \
((perm) != nsIPermissionManager::UNKNOWN_ACTION && \
(perm) != nsIPermissionManager::DENY_ACTION)
class nsDOMStorage;
class nsIDOMStorage;
class nsDOMStorageItem;
@ -114,7 +110,7 @@ public:
DOMStorageBase(DOMStorageBase&);
virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate);
virtual nsTArray<nsString>* GetKeys(bool aCallerSecure) = 0;
virtual nsresult GetLength(bool aCallerSecure, uint32_t* aLength) = 0;
@ -170,11 +166,10 @@ public:
// an origin (localStorage).
nsCString& GetScopeDBKey() {return mScopeDBKey;}
// e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain or
// reversed offline application allowed domain.
nsCString& GetQuotaDomainDBKey(bool aOfflineAllowed)
// e.g. "moc.rab.%" - reversed eTLD+1 subpart of the domain.
nsCString& GetQuotaDBKey()
{
return aOfflineAllowed ? mQuotaDomainDBKey : mQuotaETLDplus1DomainDBKey;
return mQuotaDBKey;
}
virtual bool CacheStoragePermissions() = 0;
@ -201,10 +196,8 @@ protected:
// keys are used for database queries.
// see comments of the getters bellow.
nsCString mScopeDBKey;
nsCString mQuotaETLDplus1DomainDBKey;
nsCString mQuotaDomainDBKey;
nsCString mQuotaDBKey;
bool mCanUseChromePersist;
bool mInPrivateBrowsing;
};
@ -221,7 +214,7 @@ public:
~DOMStorageImpl();
virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aPrivate);
bool SessionOnly() {
return mSessionOnly;
@ -244,10 +237,6 @@ public:
uint64_t CachedVersion() { return mItemsCachedVersion; }
void SetCachedVersion(uint64_t version) { mItemsCachedVersion = version; }
// Some privileged internal pages can use a persistent storage even in
// session-only or private-browsing modes.
bool CanUseChromePersist();
// retrieve the value and secure state corresponding to a key out of storage
// that has been cached in mItems hash table.
nsresult
@ -291,11 +280,10 @@ private:
// Cross-process storage implementations never have InitAs(Session|Local|Global)Storage
// called, so the appropriate initialization needs to happen from the child.
void InitFromChild(bool aUseDB, bool aCanUseChromePersist, bool aSessionOnly,
void InitFromChild(bool aUseDB, bool aSessionOnly,
bool aPrivate, const nsACString& aDomain,
const nsACString& aScopeDBKey,
const nsACString& aQuotaDomainDBKey,
const nsACString& aQuotaETLDplus1DomainDBKey,
const nsACString& aQuotaDBKey,
uint32_t aStorageType);
void SetSessionOnly(bool aSessionOnly);
@ -351,12 +339,6 @@ public:
static bool
CanUseStorage(DOMStorageBase* aStorage = nullptr);
// Check whether this URI can use chrome persist storage. This kind of
// storage can bypass cookies limits, private browsing and uses the offline
// apps quota.
static bool
URICanUseChromePersist(nsIURI* aURI);
// Check whether storage may be used. Updates mSessionOnly based on
// the result of CanUseStorage.
bool
@ -503,10 +485,4 @@ protected:
nsresult
NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult);
uint32_t
GetOfflinePermission(const nsACString &aDomain);
bool
IsOfflineAllowed(const nsACString &aDomain);
#endif /* nsDOMStorage_h___ */

View File

@ -5,8 +5,24 @@
#include "nsDOMStorageBaseDB.h"
#include "nsDOMStorage.h"
#include "mozilla/Preferences.h"
// Only allow relatively small amounts of data since performance of
// the synchronous IO is very bad.
#define DEFAULT_QUOTA_LIMIT (5 * 1024)
uint64_t nsDOMStorageBaseDB::sGlobalVersion = 1;
int32_t nsDOMStorageBaseDB::gQuotaLimit = DEFAULT_QUOTA_LIMIT * 1024;
using namespace mozilla;
/* static */
void
nsDOMStorageBaseDB::Init()
{
Preferences::AddIntVarCache(&gQuotaLimit, "dom.storage.default_quota",
DEFAULT_QUOTA_LIMIT);
}
nsDOMStorageBaseDB::nsDOMStorageBaseDB()
{

View File

@ -14,6 +14,8 @@ class DOMStorageImpl;
class nsDOMStorageBaseDB
{
public:
static void Init();
nsDOMStorageBaseDB();
virtual ~nsDOMStorageBaseDB() {}
@ -34,6 +36,10 @@ public:
*/
bool IsScopeDirty(DOMStorageImpl* aStorage);
int32_t GetQuota() {
return gQuotaLimit * 1024;
}
protected:
nsDataHashtable<nsCStringHashKey, uint64_t> mScopesVersion;
@ -45,6 +51,8 @@ protected:
private:
static uint64_t sGlobalVersion;
static int32_t gQuotaLimit;
};
#endif /* nsDOMStorageDB_h___ */

View File

@ -48,7 +48,6 @@ void
nsDOMStorageDBWrapper::Close()
{
mPersistentDB.Close();
mChromePersistentDB.Close();
}
nsresult
@ -59,9 +58,6 @@ nsDOMStorageDBWrapper::Init()
rv = mPersistentDB.Init(NS_LITERAL_STRING("webappsstore.sqlite"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mChromePersistentDB.Init(NS_LITERAL_STRING("chromeappsstore.sqlite"));
NS_ENSURE_SUCCESS(rv, rv);
rv = mSessionOnlyDB.Init(&mPersistentDB);
NS_ENSURE_SUCCESS(rv, rv);
@ -75,12 +71,10 @@ nsresult
nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTables(bool force)
{
nsresult rv1, rv2;
rv1 = mChromePersistentDB.FlushTemporaryTables(force);
rv2 = mPersistentDB.FlushTemporaryTables(force);
// Everything flushed? Then no need for a timer.
if (!mChromePersistentDB.mTempTableLoads.Count() &&
!mPersistentDB.mTempTableLoads.Count())
if (!mPersistentDB.mTempTableLoads.Count())
StopTempTableFlushTimer();
return NS_FAILED(rv1) ? rv1 : rv2;
@ -88,8 +82,6 @@ nsDOMStorageDBWrapper::FlushAndDeleteTemporaryTables(bool force)
#define IMPL_FORWARDER_GUTS(_return, _code) \
PR_BEGIN_MACRO \
if (aStorage->CanUseChromePersist()) \
_return mChromePersistentDB._code; \
if (aStorage->IsPrivate()) \
_return mPrivateBrowsingDB._code; \
if (aStorage->SessionOnly()) \
@ -123,13 +115,9 @@ nsresult
nsDOMStorageDBWrapper::SetKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
const nsAString& aValue,
bool aSecure,
int32_t aQuota,
bool aExcludeOfflineFromUsage,
int32_t *aNewUsage)
bool aSecure)
{
IMPL_FORWARDER(SetKey(aStorage, aKey, aValue, aSecure,
aQuota, aExcludeOfflineFromUsage, aNewUsage));
IMPL_FORWARDER(SetKey(aStorage, aKey, aValue, aSecure));
}
nsresult
@ -142,11 +130,9 @@ nsDOMStorageDBWrapper::SetSecure(DOMStorageImpl* aStorage,
nsresult
nsDOMStorageDBWrapper::RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
bool aExcludeOfflineFromUsage,
int32_t aKeyUsage)
const nsAString& aKey)
{
IMPL_FORWARDER(RemoveKey(aStorage, aKey, aExcludeOfflineFromUsage, aKeyUsage));
IMPL_FORWARDER(RemoveKey(aStorage, aKey));
}
nsresult
@ -170,7 +156,7 @@ nsDOMStorageDBWrapper::IsScopeDirty(DOMStorageImpl* aStorage)
nsresult
nsDOMStorageDBWrapper::DropSessionOnlyStoragesForHost(const nsACString& aHostName)
{
return mSessionOnlyDB.RemoveOwner(aHostName, true);
return mSessionOnlyDB.RemoveOwner(aHostName);
}
nsresult
@ -180,18 +166,17 @@ nsDOMStorageDBWrapper::DropPrivateBrowsingStorages()
}
nsresult
nsDOMStorageDBWrapper::RemoveOwner(const nsACString& aOwner,
bool aIncludeSubDomains)
nsDOMStorageDBWrapper::RemoveOwner(const nsACString& aOwner)
{
nsresult rv;
rv = mPrivateBrowsingDB.RemoveOwner(aOwner, aIncludeSubDomains);
rv = mPrivateBrowsingDB.RemoveOwner(aOwner);
NS_ENSURE_SUCCESS(rv, rv);
rv = mSessionOnlyDB.RemoveOwner(aOwner, aIncludeSubDomains);
rv = mSessionOnlyDB.RemoveOwner(aOwner);
NS_ENSURE_SUCCESS(rv, rv);
rv = mPersistentDB.RemoveOwner(aOwner, aIncludeSubDomains);
rv = mPersistentDB.RemoveOwner(aOwner);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
@ -199,55 +184,53 @@ nsDOMStorageDBWrapper::RemoveOwner(const nsACString& aOwner,
nsresult
nsDOMStorageDBWrapper::RemoveOwners(const nsTArray<nsString> &aOwners,
bool aIncludeSubDomains, bool aMatch)
nsDOMStorageDBWrapper::RemoveAll()
{
nsresult rv;
rv = mPrivateBrowsingDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
rv = mPrivateBrowsingDB.RemoveAll();
NS_ENSURE_SUCCESS(rv, rv);
rv = mSessionOnlyDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
rv = mSessionOnlyDB.RemoveAll();
NS_ENSURE_SUCCESS(rv, rv);
rv = mPersistentDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
rv = mPersistentDB.RemoveAll();
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
nsresult
nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage,
bool aExcludeOfflineFromUsage, int32_t *aUsage)
nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage)
{
IMPL_FORWARDER(GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage));
IMPL_FORWARDER(GetUsage(aStorage, aUsage));
}
nsresult
nsDOMStorageDBWrapper::GetUsage(const nsACString& aDomain,
bool aIncludeSubDomains, int32_t *aUsage, bool aPrivate)
int32_t *aUsage, bool aPrivate)
{
if (aPrivate)
return mPrivateBrowsingDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
return mPrivateBrowsingDB.GetUsage(aDomain, aUsage);
#if 0
// XXX Check where from all this method gets called, not sure this should
// include any potential session-only data
nsresult rv;
rv = mSessionOnlyDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
rv = mSessionOnlyDB.GetUsage(aDomain, aUsage);
if (NS_SUECEEDED(rv))
return rv;
#endif
return mPersistentDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
return mPersistentDB.GetUsage(aDomain, aUsage);
}
nsresult
nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
nsDOMStorageDBWrapper::CreateScopeDBKey(nsIURI* aUri, nsACString& aKey)
{
nsresult rv;
rv = CreateDomainScopeDBKey(aUri, aKey);
rv = CreateReversedDomain(aUri, aKey);
if (NS_FAILED(rv))
return rv;
@ -268,7 +251,7 @@ nsDOMStorageDBWrapper::CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey)
}
nsresult
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(nsIURI* aUri, nsACString& aKey)
nsDOMStorageDBWrapper::CreateReversedDomain(nsIURI* aUri, nsACString& aKey)
{
nsresult rv;
@ -297,15 +280,15 @@ nsDOMStorageDBWrapper::CreateDomainScopeDBKey(nsIURI* aUri, nsACString& aKey)
}
}
rv = CreateDomainScopeDBKey(domainScope, aKey);
rv = CreateReversedDomain(domainScope, aKey);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(const nsACString& aAsciiDomain,
nsACString& aKey)
nsDOMStorageDBWrapper::CreateReversedDomain(const nsACString& aAsciiDomain,
nsACString& aKey)
{
if (aAsciiDomain.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
@ -317,39 +300,30 @@ nsDOMStorageDBWrapper::CreateDomainScopeDBKey(const nsACString& aAsciiDomain,
}
nsresult
nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
bool aIncludeSubDomains,
bool aEffectiveTLDplus1Only,
nsACString& aKey)
nsDOMStorageDBWrapper::CreateQuotaDBKey(const nsACString& aAsciiDomain,
nsACString& aKey)
{
nsresult rv;
nsAutoCString subdomainsDBKey;
if (aEffectiveTLDplus1Only) {
nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aAsciiDomain);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aAsciiDomain);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString eTLDplusOne;
rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
// XXX bug 357323 - what to do for localhost/file exactly?
eTLDplusOne = aAsciiDomain;
rv = NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
CreateDomainScopeDBKey(eTLDplusOne, subdomainsDBKey);
nsAutoCString eTLDplusOne;
rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
// XXX bug 357323 - what to do for localhost/file exactly?
eTLDplusOne = aAsciiDomain;
rv = NS_OK;
}
else
CreateDomainScopeDBKey(aAsciiDomain, subdomainsDBKey);
NS_ENSURE_SUCCESS(rv, rv);
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
CreateReversedDomain(eTLDplusOne, subdomainsDBKey);
aKey.Assign(subdomainsDBKey);
return NS_OK;
@ -357,7 +331,7 @@ nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
nsresult
nsDOMStorageDBWrapper::GetDomainFromScopeKey(const nsACString& aScope,
nsACString& aDomain)
nsACString& aDomain)
{
nsAutoCString reverseDomain, scope;
scope = aScope;

View File

@ -89,10 +89,7 @@ public:
SetKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
const nsAString& aValue,
bool aSecure,
int32_t aQuota,
bool aExcludeOfflineFromUsage,
int32_t* aNewUsage);
bool aSecure);
/**
* Set the secure flag for a key in storage. Does nothing if the key was
@ -108,9 +105,7 @@ public:
*/
nsresult
RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
bool aExcludeOfflineFromUsage,
int32_t aKeyUsage);
const nsAString& aKey);
/**
* Remove all keys belonging to this storage.
@ -134,27 +129,25 @@ public:
* Removes all keys added by a given domain.
*/
nsresult
RemoveOwner(const nsACString& aOwner, bool aIncludeSubDomains);
RemoveOwner(const nsACString& aOwner);
/**
* Removes keys owned by domains that either match or don't match the
* list.
* Removes all keys from storage. Used when clearing storage.
*/
nsresult
RemoveOwners(const nsTArray<nsString>& aOwners,
bool aIncludeSubDomains, bool aMatch);
RemoveAll();
/**
* Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
* Returns usage for a storage using its GetQuotaDBKey() as a key.
*/
nsresult
GetUsage(DOMStorageImpl* aStorage, bool aExcludeOfflineFromUsage, int32_t *aUsage);
GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage);
/**
* Returns usage of the domain and optionaly by any subdomain.
*/
nsresult
GetUsage(const nsACString& aDomain, bool aIncludeSubDomains, int32_t *aUsage, bool aPrivate);
GetUsage(const nsACString& aDomain, int32_t *aUsage, bool aPrivate);
/**
* Marks the storage as "cached" after the DOMStorageImpl object has loaded
@ -180,26 +173,25 @@ public:
* i.e. reverses the host, appends a dot, appends the schema
* and a port number.
*/
static nsresult CreateOriginScopeDBKey(nsIURI* aUri, nsACString& aKey);
static nsresult CreateScopeDBKey(nsIURI* aUri, nsACString& aKey);
/**
* Turns "http://foo.bar.com" to "moc.rab.oof.",
* i.e. reverses the host and appends a dot.
*/
static nsresult CreateDomainScopeDBKey(nsIURI* aUri, nsACString& aKey);
static nsresult CreateDomainScopeDBKey(const nsACString& aAsciiDomain, nsACString& aKey);
static nsresult CreateReversedDomain(nsIURI* aUri, nsACString& aKey);
static nsresult CreateReversedDomain(const nsACString& aAsciiDomain, nsACString& aKey);
/**
* Turns "foo.bar.com" to "moc.rab.",
* i.e. extracts eTLD+1 from the host, reverses the result
* and appends a dot.
*/
static nsresult CreateQuotaDomainDBKey(const nsACString& aAsciiDomain,
bool aIncludeSubDomains, bool aETLDplus1Only,
nsACString& aKey);
static nsresult CreateQuotaDBKey(const nsACString& aAsciiDomain,
nsACString& aKey);
static nsresult GetDomainFromScopeKey(const nsACString& aScope,
nsACString& aDomain);
nsACString& aDomain);
/**
* Ensures the temp table flush timer is running. This is called when we add
@ -221,7 +213,6 @@ public:
void StopTempTableFlushTimer();
protected:
nsDOMStoragePersistentDB mChromePersistentDB;
nsDOMStoragePersistentDB mPersistentDB;
nsDOMStorageMemoryDB mSessionOnlyDB;
nsDOMStorageMemoryDB mPrivateBrowsingDB;

View File

@ -148,10 +148,7 @@ nsresult
nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
const nsAString& aValue,
bool aSecure,
int32_t aQuota,
bool aExcludeOfflineFromUsage,
int32_t *aNewUsage)
bool aSecure)
{
nsresult rv;
@ -160,8 +157,8 @@ nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
NS_ENSURE_SUCCESS(rv, rv);
int32_t usage = 0;
if (!aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage).IsEmpty()) {
rv = GetUsage(aStorage, aExcludeOfflineFromUsage, &usage);
if (!aStorage->GetQuotaDBKey().IsEmpty()) {
rv = GetUsage(aStorage, &usage);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -169,7 +166,7 @@ nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
nsInMemoryItem* item;
if (!storage->mTable.Get(aKey, &item)) {
if (usage > aQuota) {
if (usage > GetQuota()) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
@ -185,7 +182,7 @@ nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
if (!aSecure && item->mSecure)
return NS_ERROR_DOM_SECURITY_ERR;
usage -= aKey.Length() + item->mValue.Length();
if (usage > aQuota) {
if (usage > GetQuota()) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
}
@ -195,8 +192,6 @@ nsDOMStorageMemoryDB::SetKey(DOMStorageImpl* aStorage,
item->mValue = aValue;
item->mSecure = aSecure;
*aNewUsage = usage;
MarkScopeDirty(aStorage);
return NS_OK;
@ -226,9 +221,7 @@ nsDOMStorageMemoryDB::SetSecure(DOMStorageImpl* aStorage,
nsresult
nsDOMStorageMemoryDB::RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
bool aExcludeOfflineFromUsage,
int32_t aKeyUsage)
const nsAString& aKey)
{
nsresult rv;
@ -304,14 +297,10 @@ RemoveOwnersEnum(const nsACString& key,
}
nsresult
nsDOMStorageMemoryDB::RemoveOwner(const nsACString& aOwner,
bool aIncludeSubDomains)
nsDOMStorageMemoryDB::RemoveOwner(const nsACString& aOwner)
{
nsAutoCString subdomainsDBKey;
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aOwner, subdomainsDBKey);
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
nsDOMStorageDBWrapper::CreateReversedDomain(aOwner, subdomainsDBKey);
RemoveOwnersStruc struc;
struc.mSubDomain = &subdomainsDBKey;
@ -323,39 +312,6 @@ nsDOMStorageMemoryDB::RemoveOwner(const nsACString& aOwner,
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::RemoveOwners(const nsTArray<nsString> &aOwners,
bool aIncludeSubDomains,
bool aMatch)
{
if (aOwners.Length() == 0) {
if (aMatch) {
return NS_OK;
}
return RemoveAll();
}
for (uint32_t i = 0; i < aOwners.Length(); i++) {
nsAutoCString quotaKey;
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(
NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey);
if (!aIncludeSubDomains)
quotaKey.AppendLiteral(":");
RemoveOwnersStruc struc;
struc.mSubDomain = &quotaKey;
struc.mMatch = aMatch;
mData.Enumerate(RemoveOwnersEnum, &struc);
}
MarkAllScopesDirty();
return NS_OK;
}
nsresult
nsDOMStorageMemoryDB::RemoveAll()
{
@ -367,34 +323,27 @@ nsDOMStorageMemoryDB::RemoveAll()
}
nsresult
nsDOMStorageMemoryDB::GetUsage(DOMStorageImpl* aStorage,
bool aExcludeOfflineFromUsage, int32_t *aUsage)
nsDOMStorageMemoryDB::GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage)
{
return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage),
aExcludeOfflineFromUsage, aUsage);
return GetUsageInternal(aStorage->GetQuotaDBKey(), aUsage);
}
nsresult
nsDOMStorageMemoryDB::GetUsage(const nsACString& aDomain,
bool aIncludeSubDomains,
int32_t *aUsage)
{
nsresult rv;
nsAutoCString quotadomainDBKey;
rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
aIncludeSubDomains,
false,
quotadomainDBKey);
nsAutoCString quotaDBKey;
rv = nsDOMStorageDBWrapper::CreateQuotaDBKey(aDomain, quotaDBKey);
NS_ENSURE_SUCCESS(rv, rv);
return GetUsageInternal(quotadomainDBKey, false, aUsage);
return GetUsageInternal(quotaDBKey, aUsage);
}
struct GetUsageEnumStruc
{
int32_t mUsage;
int32_t mExcludeOfflineFromUsage;
nsCString mSubdomain;
};
@ -406,13 +355,6 @@ GetUsageEnum(const nsACString& key,
GetUsageEnumStruc* struc = (GetUsageEnumStruc*)closure;
if (StringBeginsWith(key, struc->mSubdomain)) {
if (struc->mExcludeOfflineFromUsage) {
nsAutoCString domain;
nsresult rv = nsDOMStorageDBWrapper::GetDomainFromScopeKey(key, domain);
if (NS_SUCCEEDED(rv) && IsOfflineAllowed(domain))
return PL_DHASH_NEXT;
}
struc->mUsage += storageData->mUsageDelta;
}
@ -420,20 +362,17 @@ GetUsageEnum(const nsACString& key,
}
nsresult
nsDOMStorageMemoryDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
bool aExcludeOfflineFromUsage,
nsDOMStorageMemoryDB::GetUsageInternal(const nsACString& aQuotaDBKey,
int32_t *aUsage)
{
GetUsageEnumStruc struc;
struc.mUsage = 0;
struc.mExcludeOfflineFromUsage = aExcludeOfflineFromUsage;
struc.mSubdomain = aQuotaDomainDBKey;
struc.mSubdomain = aQuotaDBKey;
if (mPreloadDB) {
nsresult rv;
rv = mPreloadDB->GetUsageInternal(aQuotaDomainDBKey,
aExcludeOfflineFromUsage, &struc.mUsage);
rv = mPreloadDB->GetUsageInternal(aQuotaDBKey, &struc.mUsage);
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -78,10 +78,7 @@ public:
SetKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
const nsAString& aValue,
bool aSecure,
int32_t aQuota,
bool aExcludeOfflineFromUsage,
int32_t* aNewUsage);
bool aSecure);
/**
* Set the secure flag for a key in storage. Does nothing if the key was
@ -97,9 +94,7 @@ public:
*/
nsresult
RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
bool aExcludeOfflineFromUsage,
int32_t aKeyUsage);
const nsAString& aKey);
/**
* Remove all keys belonging to this storage.
@ -117,15 +112,7 @@ public:
* Removes all keys added by a given domain.
*/
nsresult
RemoveOwner(const nsACString& aOwner, bool aIncludeSubDomains);
/**
* Removes keys owned by domains that either match or don't match the
* list.
*/
nsresult
RemoveOwners(const nsTArray<nsString>& aOwners,
bool aIncludeSubDomains, bool aMatch);
RemoveOwner(const nsACString& aOwner);
/**
* Removes all keys from storage. Used when clearing storage.
@ -134,16 +121,16 @@ public:
RemoveAll();
/**
* Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
* Returns usage for a storage using its GetQuotaDBKey() as a key.
*/
nsresult
GetUsage(DOMStorageImpl* aStorage, bool aExcludeOfflineFromUsage, int32_t *aUsage);
GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage);
/**
* Returns usage of the domain and optionaly by any subdomain.
*/
nsresult
GetUsage(const nsACString& aDomain, bool aIncludeSubDomains, int32_t *aUsage);
GetUsage(const nsACString& aDomain, int32_t *aUsage);
protected:
@ -152,7 +139,7 @@ protected:
bool mPreloading;
nsresult
GetUsageInternal(const nsACString& aQuotaDomainDBKey, bool aExcludeOfflineFromUsage, int32_t *aUsage);
GetUsageInternal(const nsACString& aQuotaDBKey, int32_t *aUsage);
};
#endif

View File

@ -63,49 +63,12 @@ nsReverseStringSQLFunction::OnFunctionCall(
return NS_OK;
}
class nsIsOfflineSQLFunction MOZ_FINAL : public mozIStorageFunction
{
NS_DECL_ISUPPORTS
NS_DECL_MOZISTORAGEFUNCTION
};
NS_IMPL_ISUPPORTS1(nsIsOfflineSQLFunction, mozIStorageFunction)
nsDOMStoragePersistentDB::nsDOMStoragePersistentDB()
: mStatements(mConnection)
{
mTempTableLoads.Init(16);
}
NS_IMETHODIMP
nsIsOfflineSQLFunction::OnFunctionCall(
mozIStorageValueArray *aFunctionArguments, nsIVariant **aResult)
{
nsresult rv;
nsAutoCString scope;
rv = aFunctionArguments->GetUTF8String(0, scope);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString domain;
rv = nsDOMStorageDBWrapper::GetDomainFromScopeKey(scope, domain);
NS_ENSURE_SUCCESS(rv, rv);
bool hasOfflinePermission = IsOfflineAllowed(domain);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIWritableVariant> outVar(do_CreateInstance(
NS_VARIANT_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = outVar->SetAsBool(hasOfflinePermission);
NS_ENSURE_SUCCESS(rv, rv);
*aResult = outVar.get();
outVar.forget();
return NS_OK;
}
nsresult
nsDOMStoragePersistentDB::Init(const nsString& aDatabaseName)
{
@ -196,12 +159,6 @@ nsDOMStoragePersistentDB::Init(const nsString& aDatabaseName)
rv = mConnection->CreateFunction(NS_LITERAL_CSTRING("REVERSESTRING"), 1, function1);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageFunction> function2(new nsIsOfflineSQLFunction());
NS_ENSURE_TRUE(function2, NS_ERROR_OUT_OF_MEMORY);
rv = mConnection->CreateFunction(NS_LITERAL_CSTRING("ISOFFLINE"), 1, function2);
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
// Check if there is storage of Gecko 1.9.0 and if so, upgrade that storage
@ -476,10 +433,7 @@ nsresult
nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
const nsAString& aValue,
bool aSecure,
int32_t aQuota,
bool aExcludeOfflineFromUsage,
int32_t *aNewUsage)
bool aSecure)
{
nsresult rv;
@ -487,8 +441,8 @@ nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
NS_ENSURE_SUCCESS(rv, rv);
int32_t usage = 0;
if (!aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage).IsEmpty()) {
rv = GetUsage(aStorage, aExcludeOfflineFromUsage, &usage);
if (!aStorage->GetQuotaDBKey().IsEmpty()) {
rv = GetUsage(aStorage, &usage);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -503,7 +457,7 @@ nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
usage -= aKey.Length() + previousValue.Length();
}
if (usage > aQuota) {
if (usage > GetQuota()) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
@ -533,13 +487,11 @@ nsDOMStoragePersistentDB::SetKey(DOMStorageImpl* aStorage,
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
if (!aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage).IsEmpty()) {
if (!aStorage->GetQuotaDBKey().IsEmpty()) {
// No need to set mCachedOwner since it was set by GetUsage()
mCachedUsage = usage;
}
*aNewUsage = usage;
MarkScopeDirty(aStorage);
return NS_OK;
@ -587,9 +539,7 @@ nsDOMStoragePersistentDB::SetSecure(DOMStorageImpl* aStorage,
nsresult
nsDOMStoragePersistentDB::RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
bool aExcludeOfflineFromUsage,
int32_t aKeyUsage)
const nsAString& aKey)
{
nsresult rv;
@ -605,7 +555,7 @@ nsDOMStoragePersistentDB::RemoveKey(DOMStorageImpl* aStorage,
mozStorageStatementScoper scope(stmt);
if (DomainMaybeCached(
aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage))) {
aStorage->GetQuotaDBKey())) {
mCachedUsage = 0;
mCachedOwner.Truncate();
}
@ -656,8 +606,7 @@ nsDOMStoragePersistentDB::ClearStorage(DOMStorageImpl* aStorage)
}
nsresult
nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner,
bool aIncludeSubDomains)
nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner)
{
nsresult rv;
@ -672,15 +621,13 @@ nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner,
mozStorageStatementScoper scope(stmt);
nsAutoCString subdomainsDBKey;
nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aOwner, subdomainsDBKey);
nsDOMStorageDBWrapper::CreateReversedDomain(aOwner, subdomainsDBKey);
if (DomainMaybeCached(subdomainsDBKey)) {
mCachedUsage = 0;
mCachedOwner.Truncate();
}
if (!aIncludeSubDomains)
subdomainsDBKey.AppendLiteral(":");
subdomainsDBKey.AppendLiteral("*");
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"),
@ -695,84 +642,6 @@ nsDOMStoragePersistentDB::RemoveOwner(const nsACString& aOwner,
return NS_OK;
}
nsresult
nsDOMStoragePersistentDB::RemoveOwners(const nsTArray<nsString> &aOwners,
bool aIncludeSubDomains,
bool aMatch)
{
if (aOwners.Length() == 0) {
if (aMatch) {
return NS_OK;
}
return RemoveAll();
}
// Using nsString here because it is going to be very long
nsCString expression;
if (aMatch) {
expression.AppendLiteral("DELETE FROM webappsstore2_view WHERE scope IN (");
} else {
expression.AppendLiteral("DELETE FROM webappsstore2_view WHERE scope NOT IN (");
}
for (uint32_t i = 0; i < aOwners.Length(); i++) {
if (i)
expression.AppendLiteral(" UNION ");
expression.AppendLiteral(
"SELECT DISTINCT scope FROM webappsstore2_temp WHERE scope GLOB :scope");
expression.AppendInt(i);
expression.AppendLiteral(" UNION ");
expression.AppendLiteral(
"SELECT DISTINCT scope FROM webappsstore2 WHERE scope GLOB :scope");
expression.AppendInt(i);
}
expression.AppendLiteral(");");
nsCOMPtr<mozIStorageStatement> statement;
nsresult rv;
rv = MaybeCommitInsertTransaction();
NS_ENSURE_SUCCESS(rv, rv);
rv = mConnection->CreateStatement(expression,
getter_AddRefs(statement));
NS_ENSURE_SUCCESS(rv, rv);
for (uint32_t i = 0; i < aOwners.Length(); i++) {
nsAutoCString quotaKey;
rv = nsDOMStorageDBWrapper::CreateDomainScopeDBKey(
NS_ConvertUTF16toUTF8(aOwners[i]), quotaKey);
if (DomainMaybeCached(quotaKey)) {
mCachedUsage = 0;
mCachedOwner.Truncate();
}
if (!aIncludeSubDomains)
quotaKey.AppendLiteral(":");
quotaKey.AppendLiteral("*");
nsAutoCString paramName;
paramName.Assign("scope");
paramName.AppendInt(i);
rv = statement->BindUTF8StringByName(paramName, quotaKey);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
MarkAllScopesDirty();
return NS_OK;
}
nsresult
nsDOMStoragePersistentDB::RemoveAll()
{
@ -797,37 +666,29 @@ nsDOMStoragePersistentDB::RemoveAll()
nsresult
nsDOMStoragePersistentDB::GetUsage(DOMStorageImpl* aStorage,
bool aExcludeOfflineFromUsage,
int32_t *aUsage)
{
return GetUsageInternal(aStorage->GetQuotaDomainDBKey(!aExcludeOfflineFromUsage),
aExcludeOfflineFromUsage,
aUsage);
return GetUsageInternal(aStorage->GetQuotaDBKey(), aUsage);
}
nsresult
nsDOMStoragePersistentDB::GetUsage(const nsACString& aDomain,
bool aIncludeSubDomains,
int32_t *aUsage)
{
nsresult rv;
nsAutoCString quotadomainDBKey;
rv = nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomain,
aIncludeSubDomains,
false,
quotadomainDBKey);
nsAutoCString quotaDBKey;
rv = nsDOMStorageDBWrapper::CreateQuotaDBKey(aDomain, quotaDBKey);
NS_ENSURE_SUCCESS(rv, rv);
return GetUsageInternal(quotadomainDBKey, false, aUsage);
return GetUsageInternal(quotaDBKey, aUsage);
}
nsresult
nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
bool aExcludeOfflineFromUsage,
nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDBKey,
int32_t *aUsage)
{
if (aQuotaDomainDBKey == mCachedOwner) {
if (aQuotaDBKey == mCachedOwner) {
*aUsage = mCachedUsage;
return NS_OK;
}
@ -838,47 +699,26 @@ nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageStatement> stmt;
if (aExcludeOfflineFromUsage) {
stmt = mStatements.GetCachedStatement(
"SELECT SUM(LENGTH(key) + LENGTH(value)) "
"FROM ( "
"SELECT key, value FROM webappsstore2_temp "
"WHERE scope GLOB :scope "
"AND NOT ISOFFLINE(scope) "
"UNION ALL "
"SELECT key, value FROM webappsstore2 "
"WHERE scope GLOB :scope "
"AND NOT ISOFFLINE(scope) "
"AND NOT EXISTS ( "
"SELECT scope, key "
"FROM webappsstore2_temp "
"WHERE scope = webappsstore2.scope "
"AND key = webappsstore2.key "
") "
") "
);
} else {
stmt = mStatements.GetCachedStatement(
"SELECT SUM(LENGTH(key) + LENGTH(value)) "
"FROM ( "
"SELECT key,value FROM webappsstore2_temp "
"WHERE scope GLOB :scope "
"UNION ALL "
"SELECT key,value FROM webappsstore2 "
"WHERE scope GLOB :scope "
"AND NOT EXISTS ( "
"SELECT scope, key "
"FROM webappsstore2_temp "
"WHERE scope = webappsstore2.scope "
"AND key = webappsstore2.key "
") "
") "
);
}
stmt = mStatements.GetCachedStatement(
"SELECT SUM(LENGTH(key) + LENGTH(value)) "
"FROM ( "
"SELECT key,value FROM webappsstore2_temp "
"WHERE scope GLOB :scope "
"UNION ALL "
"SELECT key,value FROM webappsstore2 "
"WHERE scope GLOB :scope "
"AND NOT EXISTS ( "
"SELECT scope, key "
"FROM webappsstore2_temp "
"WHERE scope = webappsstore2.scope "
"AND key = webappsstore2.key "
") "
") "
);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scope(stmt);
nsAutoCString scopeValue(aQuotaDomainDBKey);
nsAutoCString scopeValue(aQuotaDBKey);
scopeValue += NS_LITERAL_CSTRING("*");
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("scope"), scopeValue);
@ -896,8 +736,8 @@ nsDOMStoragePersistentDB::GetUsageInternal(const nsACString& aQuotaDomainDBKey,
rv = stmt->GetInt32(0, aUsage);
NS_ENSURE_SUCCESS(rv, rv);
if (!aQuotaDomainDBKey.IsEmpty()) {
mCachedOwner = aQuotaDomainDBKey;
if (!aQuotaDBKey.IsEmpty()) {
mCachedOwner = aQuotaDBKey;
mCachedUsage = *aUsage;
}

View File

@ -63,10 +63,7 @@ public:
SetKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
const nsAString& aValue,
bool aSecure,
int32_t aQuota,
bool aExcludeOfflineFromUsage,
int32_t* aNewUsage);
bool aSecure);
/**
* Set the secure flag for a key in storage. Does nothing if the key was
@ -82,9 +79,7 @@ public:
*/
nsresult
RemoveKey(DOMStorageImpl* aStorage,
const nsAString& aKey,
bool aExcludeOfflineFromUsage,
int32_t aKeyUsage);
const nsAString& aKey);
/**
* Remove all keys belonging to this storage.
@ -95,15 +90,7 @@ public:
* Removes all keys added by a given domain.
*/
nsresult
RemoveOwner(const nsACString& aOwner, bool aIncludeSubDomains);
/**
* Removes keys owned by domains that either match or don't match the
* list.
*/
nsresult
RemoveOwners(const nsTArray<nsString>& aOwners,
bool aIncludeSubDomains, bool aMatch);
RemoveOwner(const nsACString& aOwner);
/**
* Removes all keys from storage. Used when clearing storage.
@ -112,16 +99,16 @@ public:
RemoveAll();
/**
* Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
* Returns usage for a storage using its GetQuotaDBKey() as a key.
*/
nsresult
GetUsage(DOMStorageImpl* aStorage, bool aExcludeOfflineFromUsage, int32_t *aUsage);
GetUsage(DOMStorageImpl* aStorage, int32_t *aUsage);
/**
* Returns usage of the domain and optionaly by any subdomain.
*/
nsresult
GetUsage(const nsACString& aDomain, bool aIncludeSubDomains, int32_t *aUsage);
GetUsage(const nsACString& aDomain, int32_t *aUsage);
/**
* Clears all in-memory data from private browsing mode
@ -174,7 +161,7 @@ protected:
friend class nsDOMStorageDBWrapper;
friend class nsDOMStorageMemoryDB;
nsresult
GetUsageInternal(const nsACString& aQuotaDomainDBKey, bool aExcludeOfflineFromUsage, int32_t *aUsage);
GetUsageInternal(const nsACString& aQuotaDBKey, int32_t *aUsage);
// Compares aDomain with the mCachedOwner and returns false if changes
// in aDomain don't affect mCachedUsage.

View File

@ -52,8 +52,6 @@ MOCHITEST_FILES = \
test_localStorageQuotaSessionOnly.html \
test_localStorageQuotaSessionOnly2.html \
test_localStorageKeyOrder.html \
test_removeOwnersAPI.html \
test_removeOwnersAPISessionOnly.html \
test_storageConstructor.html \
$(NULL)

View File

@ -13,36 +13,7 @@ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var currentTest = 1;
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefBranch);
var quota, quotaOffline;
function addOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.addFromPrincipal(principal, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
}
function removeOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.removeFromPrincipal(principal, "offline-app");
}
var quota;
function doNextTest()
{
@ -61,12 +32,6 @@ function doNextTest()
quota = 5*1024;
}
prefs.setIntPref("dom.storage.default_quota", 1);
try {
quotaOffline = prefs.getIntPref("offline-apps.quota.max");
} catch (ex) {
quotaOffline = 200*1024;
}
prefs.setIntPref("offline-apps.quota.max", 2);
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
@ -133,74 +98,8 @@ function doNextTest()
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
case 11:
// test1.example.com is now using its own offline app quota
addOfflineApp("http://test1.example.com");
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
case 12:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
case 13:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
// Now we have 1503 bytes stored, this exceeds the default storage quota
break;
case 14:
// Now check that upper level domain that is not set as an offline app
// domain is allowed to store data and is using the default quota
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
case 15:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
case 16:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&failure";
break;
case 17:
slaveOrigin = "http://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&D&failure";
break;
case 18:
// check an offline app domain may store some more data
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&D&success";
break;
case 19:
// check an offline app domain is using its own (larger) quota
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&E&failure";
break;
case 20:
// Do a clean up...
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
case 21:
// Do a clean up...
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
default: // end
removeOfflineApp("http://test1.example.com");
prefs.setIntPref("dom.storage.default_quota", quota);
prefs.setIntPref("offline-apps.quota.max", quotaOffline);
SimpleTest.finish();
}

View File

@ -21,36 +21,7 @@ var cp = Components.classes["@mozilla.org/cookie/permission;1"]
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
var quota, quotaOffline;
function addOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.addFromPrincipal(principal, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
}
function removeOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.removeFromPrincipal(principal, "offline-app");
}
var quota;
function doNextTest()
{
@ -69,12 +40,6 @@ function doNextTest()
quota = 5*1024;
}
prefs.setIntPref("dom.storage.default_quota", 1);
try {
quotaOffline = prefs.getIntPref("offline-apps.quota.max");
} catch (ex) {
quotaOffline = 200*1024;
}
prefs.setIntPref("offline-apps.quota.max", 2);
slaveOrigin = "http://example.com";
@ -142,74 +107,8 @@ function doNextTest()
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
break;
case 11:
// test1.example.com is now using its own offline app quota
addOfflineApp("http://test1.example.com");
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
case 12:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
case 13:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
// Now we have 1503 bytes stored, this exceeds the default storage quota
break;
case 14:
// Now check that upper level domain that is not set as an offline app
// domain is allowed to store data and is using the default quota
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
case 15:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
case 16:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&failure";
break;
case 17:
slaveOrigin = "http://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&D&failure";
break;
case 18:
// check an offline app domain may store some more data
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&D&success";
break;
case 19:
// check an offline app domain is using its own (larger) quota
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&E&failure";
break;
case 20:
// Do a clean up...
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
case 21:
// Do a clean up...
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
default:
removeOfflineApp("http://test1.example.com");
prefs.setIntPref("dom.storage.default_quota", quota);
prefs.setIntPref("offline-apps.quota.max", quotaOffline);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
SimpleTest.finish();
}

View File

@ -19,36 +19,7 @@ var uri = io.newURI(window.location, "", null);
var cp = Cc["@mozilla.org/cookie/permission;1"]
.getService(Components.interfaces.nsICookiePermission);
var quota, quotaOffline;
function addOfflineApp(url)
{
var permissionManager = Cc["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.addFromPrincipal(principal, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
}
function removeOfflineApp(url)
{
var permissionManager = Cc["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.removeFromPrincipal(principal, "offline-app");
}
var quota;
function doNextTest()
{
@ -65,12 +36,6 @@ function doNextTest()
quota = 5*1024;
}
prefs.setIntPref("dom.storage.default_quota", 1);
try {
quotaOffline = prefs.getIntPref("offline-apps.quota.max");
} catch (ex) {
quotaOffline = 200*1024;
}
prefs.setIntPref("offline-apps.quota.max", 2);
slaveOrigin = "http://example.com";
@ -126,89 +91,8 @@ function doNextTest()
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
break;
case 9:
// test1.example.com is now using its own offline app quota
addOfflineApp("http://test1.example.com");
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
case 10:
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
case 11:
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_SESSION);
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
// Now we have 1503 bytes stored, this exceeds the default storage quota
break;
case 12:
// Now check that upper level domain that is not set as an offline app
// domain is allowed to store data and is using the default quota
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
case 13:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
case 14:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&failure";
break;
case 15:
slaveOrigin = "http://test2.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&D&failure";
break;
case 16:
// Check an offline app domain may store some more data
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&D&success";
break;
case 17:
// Check an offline app domain is using its own (larger) quota
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&E&failure";
break;
case 18:
// This test checks we correctly subtract A from the usage. A is inherited
// from the persistent database before we switch to session-only cookies
// mode
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?remove&A&success";
break;
case 19:
// now we shold have more space to store a new value
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&E&success";
break;
case 20:
// Do a clean up...
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
case 21:
// Do a clean up...
slaveOrigin = "http://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?clear";
break;
default:
removeOfflineApp("http://test1.example.com");
prefs.setIntPref("dom.storage.default_quota", quota);
prefs.setIntPref("offline-apps.quota.max", quotaOffline);
cp.setAccess(uri, Components.interfaces.nsICookiePermission.ACCESS_DEFAULT);
SimpleTest.finish();
}

View File

@ -1,143 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage and DOM quota test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var currentTest = 1;
var currentStep = 1;
function addOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.addFromPrincipal(principal, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
}
function removeOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.removeFromPrincipal(principal, "offline-app");
}
function doNextTest()
{
slave = frame;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
currentStep = 1;
switch (currentTest)
{
// Add something to storage of example.com
case 1:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&A&success";
break;
// Add something to storage of test1.example.com, secure schema
case 2:
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&B&success";
break;
// Add something to storage of http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp, secure schema
case 3:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuota.html?add&C&success";
break;
// Call RemoveOwners API through storage manager.
// Classify the sites above as offline-app using
// the permission manager to let the storage manager
// know about them.
case 4:
addOfflineApp("http://example.com");
addOfflineApp("http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp");
var manager = Components.classes["@mozilla.org/dom/storagemanager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
try {
manager.clearOfflineApps();
}
catch (ex) {
ok(false, "Exception not thrown during clearOfflineApps()");
}
removeOfflineApp("http://example.com");
removeOfflineApp("http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp");
// Now check that those two sites' data disappeared
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?checkclean&A&success";
break;
case 5:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuota.html?checkclean&C&success";
break;
case 6:
// Also subdomains to example.com must be deleted
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?checkclean&B&success";
break;
case 7:
addOfflineApp("https://test1.example.com");
var manager = Components.classes["@mozilla.org/dom/storagemanager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
try {
manager.clearOfflineApps();
}
catch (ex) {
ok(false, "Exception not thrown during clearOfflineApps()");
}
removeOfflineApp("https://test1.example.com");
// Now check that those site's data disappeared
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuota.html?checkclean&B&success";
break;
case 8:
SimpleTest.finish();
}
++currentTest;
}
function doStep()
{
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doNextTest();">
<iframe src="" name="frame"></iframe>
</body>
</html>

View File

@ -1,158 +0,0 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>localStorage and DOM quota test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="interOriginTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var currentTest = 1;
var currentStep = 1;
function addOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.addFromPrincipal(principal, "offline-app",
Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
}
function removeOfflineApp(url)
{
var permissionManager = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
var principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
.getService(Components.interfaces.nsIScriptSecurityManager)
.getNoAppCodebasePrincipal(uri);
permissionManager.removeFromPrincipal(principal, "offline-app");
}
function doNextTest()
{
slave = frame;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
currentStep = 1;
switch (currentTest)
{
// Add something to storage of example.com
case 1:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&A&success";
break;
// Add something to storage of test1.example.com, secure schema
case 2:
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&B&success";
break;
// Add something to storage of http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp, secure schema
case 3:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?add&C&success";
break;
// Call RemoveOwners API through storage manager.
// Classify the sites above as offline-app using
// the permission manager to let the storage manager
// know about them.
case 4:
addOfflineApp("http://example.com");
addOfflineApp("http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp");
var manager = Components.classes["@mozilla.org/dom/storagemanager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
try {
manager.clearOfflineApps();
}
catch (ex) {
ok(false, "Exception not thrown during clearOfflineApps()");
}
removeOfflineApp("http://example.com");
removeOfflineApp("http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp");
// Now check that those two sites' data disappeared
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&A&success";
break;
case 5:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&C&success";
break;
case 6:
// Also subdomains to example.com must be deleted
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&B&success";
break;
case 7:
addOfflineApp("https://test1.example.com");
var manager = Components.classes["@mozilla.org/dom/storagemanager;1"]
.getService(Components.interfaces.nsIDOMStorageManager);
try {
manager.clearOfflineApps();
}
catch (ex) {
ok(false, "Exception not thrown during clearOfflineApps()");
}
removeOfflineApp("https://test1.example.com");
// Now check that those site's data disappeared
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?checkclean&B&success";
break;
case 8:
slaveOrigin = "http://example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
break;
case 9:
slaveOrigin = "https://test1.example.com";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
break;
case 10:
slaveOrigin = "http://sub1.xn--hxajbheg2az3al.xn--jxalpdlp";
slave.location = slaveOrigin + slavePath + "frameQuotaSessionOnly.html?clear";
break;
case 11:
SimpleTest.finish();
}
++currentTest;
}
function doStep()
{
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doNextTest();">
<iframe src="" name="frame"></iframe>
</body>
</html>

View File

@ -1,180 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
Components.utils.import("resource://gre/modules/Services.jsm");
function run_test()
{
// Needs a profile folder for the database.
do_get_profile();
testURI(Services.io.newURI("about:mozilla", null, null));
testURI(Services.io.newURI("moz-safe-about:rights", null, null));
}
function sum(a)
{
return a.reduce(function(prev, current, index, array) {
return prev + current;
});
}
function testURI(aURI)
{
print("Testing: " + aURI.spec);
let storage = getStorageForURI(aURI);
let Telemetry = Components.classes["@mozilla.org/base/telemetry;1"].
getService(Components.interfaces.nsITelemetry);
let key_histogram = Telemetry.getHistogramById("LOCALDOMSTORAGE_KEY_SIZE_BYTES");
let value_histogram = Telemetry.getHistogramById("LOCALDOMSTORAGE_VALUE_SIZE_BYTES");
let before_key_snapshot = key_histogram.snapshot();
let before_value_snapshot = value_histogram.snapshot();
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
let after_key_snapshot = key_histogram.snapshot();
let after_value_snapshot = value_histogram.snapshot();
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
do_check_eq(sum(after_key_snapshot.counts),
sum(before_key_snapshot.counts)+1);
do_check_eq(sum(after_value_snapshot.counts),
sum(before_value_snapshot.counts)+1);
print("Check that our value is correctly removed.");
storage.removeItem("test-item");
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
testURIWithPrivateBrowsing(aURI);
testURIWithClearCookies(aURI);
testURIWithRejectCookies(aURI);
testURIWithCasing(aURI);
}
function testURIWithPrivateBrowsing(aURI) {
print("Testing with private browsing: " + aURI.spec);
// Skip test if PB mode is not supported.
if (!("@mozilla.org/privatebrowsing;1" in Components.classes)) {
print("Skipped.");
return;
}
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
togglePBMode(true);
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
print("Check that our value is correctly removed.");
storage.removeItem("test-item");
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
togglePBMode(false);
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
}
function testURIWithClearCookies(aURI) {
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIObserver);
dsm.observe(null, "cookie-changed", "cleared");
print("Check that our value is still stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
print("Check that we can explicitly clear value.");
storage.clear();
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
}
function testURIWithRejectCookies(aURI) {
// This test acts with chrome privileges, so it's not enough to test content.
function test_storage() {
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
storage.clear();
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
}
// Ask every time.
Services.prefs.setIntPref("network.cookie.lifetimePolicy", 1);
test_storage();
// Reject.
Services.prefs.setIntPref("network.cookie.cookieBehavior", 2);
test_storage();
}
function testURIWithCasing(aURI) {
print("Testing: " + aURI.spec);
let storage = getStorageForURI(aURI);
storage.setItem("test-item", "test-value");
print("Check that our value has been correctly stored.");
do_check_eq(storage.length, 1);
do_check_eq(storage.key(0), "test-item");
do_check_eq(storage.getItem("test-item"), "test-value");
let ucSpec = aURI.spec.toUpperCase();
print("Testing: " + ucSpec);
let ucStorage = getStorageForURI(Services.io.newURI(ucSpec, null, null));
print("Check that our value is accessible in a case-insensitive way.");
do_check_eq(ucStorage.length, 1);
do_check_eq(ucStorage.key(0), "test-item");
do_check_eq(ucStorage.getItem("test-item"), "test-value");
print("Check that our value is correctly removed.");
storage.removeItem("test-item");
do_check_eq(storage.length, 0);
do_check_eq(storage.getItem("test-item"), null);
}
function getStorageForURI(aURI)
{
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
getService(Components.interfaces.nsIScriptSecurityManager).
getNoAppCodebasePrincipal(aURI);
let dsm = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
return dsm.getLocalStorageForPrincipal(principal, "");
}
function togglePBMode(aEnable)
{
let pb = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
if (aEnable) {
Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session",
true);
pb.privateBrowsingEnabled = true;
} else {
try {
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
} catch (ex) {}
pb.privateBrowsingEnabled = false;
}
}

View File

@ -4,7 +4,6 @@ tail =
[test_bug319968.js]
[test_bug465752.js]
[test_domstorage_aboutpages.js]
[test_geolocation_provider.js]
# Bug 684962: test hangs consistently on Android
skip-if = os == "android"

View File

@ -12,9 +12,9 @@
# see also toolkit/locales/en-US/chrome/global/languageNames.properties
# and bug 178491
#
# Strictly speaking, Avestan did not use Arabic script but Aramaic
# Strictly speaking, Avestan did not use Arabic script but Aramaic
# (arc)/Avestan script.)
#ae=ar
#ae=ar
ab=x-cyrillic
af=x-western
@ -35,44 +35,47 @@ ch=x-western
co=x-western
cr=x-cans
cs=x-central-euro
csb=x-central-euro
#cu=x-cyrillic
cv=x-cyrillic
# XXX Latin Ext. A is also used for cy.
# XXX Latin Ext. A is also used for cy.
cy=x-western
da=x-western
de=x-western
dsb=x-central-euro
#dv=Thaanna
dz=x-tibt
#ee=x-western(?) (Ewe uses characters outside Latin-1 as well)
el=el
en=x-western
# Esperanto: Latin-3
eo=x-western
eo=x-western
es=x-western
et=x-baltic
eu=x-western
fa=ar
#ff=x-western(?) : Fulfulde
fi=x-western
# XXX Latin Ext. A is also used for fj.
# XXX Latin Ext. A is also used for fj.
fj=x-western
fo=x-western
fr=x-western
fy=x-western
ga=x-western
#XXX Latin Ext. A and Ext. additional block are used for Gaelic (8859-14)
gd=x-western
gd=x-western
# gl : ISO-8859-13
gl=x-western
gl=x-western
gn=x-western
#ha=x-western : Latin and Ajami scripts
gu=x-gujr
gv=x-western
haw=x-unicode
he=he
hi=x-devanagari
hil=x-western
hr=x-central-euro
# XXX Latin Ext. A is also used for hsb.
hsb=x-western
hsb=x-central-euro
ht=x-western
hu=x-central-euro
hy=x-armn
@ -96,8 +99,8 @@ ku=x-western
# XXX Latin Ext. A is also used for kw(Cornish).
kw=x-western
#ky=x-cyrillic
# XXX Latin Ext. A is also used for Latin.
la=x-western
# XXX Latin Ext. A is also used for Latin.
la=x-western
lb=x-western
ln=x-western
lt=x-baltic
@ -187,8 +190,8 @@ wa=x-western
wo=x-western
xh=x-western
yi=he
#Latin Ext. A and Latin Extended Additional block are used for Yoruba.
#yo=x-western
#Latin Ext. A and Latin Extended Additional block are used for Yoruba.
#yo=x-western
zh-cn=zh-CN
# XXX : The following two entries are added as a quick fix (bug 251241).
# When we have a general solution for ISO 15924 (script codes), the issue has
@ -223,7 +226,7 @@ x-unicode=x-unicode
x-user-def=x-user-def
x-armn=x-armn
x-geor=x-geor
# These self-mappings are not necessary unless somebody use them to specify
# These self-mappings are not necessary unless somebody use them to specify
# lang in (X)HTML/XML documents, which they shouldn't. (see bug 256257)
#x-beng=x-beng
#x-cans=x-cans

View File

@ -2,131 +2,135 @@
# 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/.
aa.accept = true
ab.accept = true
aa.accept = true
ab.accept = true
ae.accept = true
af.accept = true
af.accept = true
ak.accept = true
am.accept = true
an.accept = true
ar.accept = true
ar-ae.accept = true
ar-bh.accept = true
ar-dz.accept = true
ar-eg.accept = true
ar-iq.accept = true
ar-jo.accept = true
ar-kw.accept = true
ar-lb.accept = true
ar-ly.accept = true
ar-ma.accept = true
ar-om.accept = true
ar-qa.accept = true
ar-sa.accept = true
ar-sy.accept = true
ar-tn.accept = true
ar-ye.accept = true
ar.accept = true
ar-ae.accept = true
ar-bh.accept = true
ar-dz.accept = true
ar-eg.accept = true
ar-iq.accept = true
ar-jo.accept = true
ar-kw.accept = true
ar-lb.accept = true
ar-ly.accept = true
ar-ma.accept = true
ar-om.accept = true
ar-qa.accept = true
ar-sa.accept = true
ar-sy.accept = true
ar-tn.accept = true
ar-ye.accept = true
as.accept = true
ast.accept = true
ast.accept = true
av.accept = true
ay.accept = true
az.accept = true
ba.accept = true
be.accept = true
bg.accept = true
bh.accept = true
bi.accept = true
bm.accept = true
ba.accept = true
be.accept = true
bg.accept = true
bh.accept = true
bi.accept = true
bm.accept = true
bn.accept = true
bo.accept = true
bo.accept = true
br.accept = true
bs.accept = true
ca.accept = true
ce.accept = true
bs.accept = true
ca.accept = true
ce.accept = true
ch.accept = true
co.accept = true
cr.accept = true
cs.accept = true
cs.accept = true
csb.accept = true
cu.accept = true
cv.accept = true
cy.accept = true
da.accept = true
de.accept = true
de-at.accept = true
de-ch.accept = true
de-de.accept = true
de-li.accept = true
de-lu.accept = true
cy.accept = true
da.accept = true
de.accept = true
de-at.accept = true
de-ch.accept = true
de-de.accept = true
de-li.accept = true
de-lu.accept = true
dsb.accept = true
dv.accept = true
dz.accept = true
ee.accept = true
el.accept = true
en.accept = true
en-au.accept = true
en-bz.accept = true
en-ca.accept = true
en-gb.accept = true
en-ie.accept = true
en-jm.accept = true
en-nz.accept = true
en-ph.accept = true
en-tt.accept = true
en-us.accept = true
en-za.accept = true
en-zw.accept = true
eo.accept = true
es.accept = true
es-ar.accept = true
es-bo.accept = true
es-cl.accept = true
es-co.accept = true
es-cr.accept = true
es-do.accept = true
es-ec.accept = true
es-es.accept = true
es-gt.accept = true
es-hn.accept = true
es-mx.accept = true
es-ni.accept = true
es-pa.accept = true
es-pe.accept = true
es-pr.accept = true
es-py.accept = true
es-sv.accept = true
es-uy.accept = true
es-ve.accept = true
et.accept = true
eu.accept = true
el.accept = true
en.accept = true
en-au.accept = true
en-bz.accept = true
en-ca.accept = true
en-gb.accept = true
en-ie.accept = true
en-jm.accept = true
en-nz.accept = true
en-ph.accept = true
en-tt.accept = true
en-us.accept = true
en-za.accept = true
en-zw.accept = true
eo.accept = true
es.accept = true
es-ar.accept = true
es-bo.accept = true
es-cl.accept = true
es-co.accept = true
es-cr.accept = true
es-do.accept = true
es-ec.accept = true
es-es.accept = true
es-gt.accept = true
es-hn.accept = true
es-mx.accept = true
es-ni.accept = true
es-pa.accept = true
es-pe.accept = true
es-pr.accept = true
es-py.accept = true
es-sv.accept = true
es-uy.accept = true
es-ve.accept = true
et.accept = true
eu.accept = true
fa.accept = true
fa-ir.accept = true
ff.accept = true
fi.accept = true
fj.accept = true
fo.accept = true
fr.accept = true
fr-be.accept = true
fr-ca.accept = true
fr-ch.accept = true
fr-fr.accept = true
fr-lu.accept = true
fr-mc.accept = true
fi.accept = true
fj.accept = true
fo.accept = true
fr.accept = true
fr-be.accept = true
fr-ca.accept = true
fr-ch.accept = true
fr-fr.accept = true
fr-lu.accept = true
fr-mc.accept = true
fur.accept = true
fy.accept = true
ga.accept = true
gd.accept = true
gl.accept = true
gn.accept = true
ga.accept = true
gd.accept = true
gl.accept = true
gn.accept = true
gu.accept = true
gv.accept = true
ha.accept = true
he.accept = true
hi.accept = true
ha.accept = true
haw.accept = true
he.accept = true
hi.accept = true
hil.accept = true
ho.accept = true
hsb.accept = true
hr.accept = true
hr.accept = true
ht.accept = true
hu.accept = true
hy.accept = true
hu.accept = true
hy.accept = true
hz.accept = true
ia.accept = true
id.accept = true
@ -135,22 +139,22 @@ ig.accept = true
ii.accept = true
ik.accept = true
io.accept = true
is.accept = true
it.accept = true
it-ch.accept = true
is.accept = true
it.accept = true
it-ch.accept = true
iu.accept = true
ja.accept = true
ja.accept = true
jv.accept = true
ka.accept = true
ka.accept = true
kg.accept = true
ki.accept = true
kk.accept = true
kl.accept = true
kl.accept = true
km.accept = true
kn.accept = true
ko.accept = true
ko-kp.accept = true
ko-kr.accept = true
kn.accept = true
ko.accept = true
ko-kp.accept = true
ko-kr.accept = true
kok.accept = true
kr.accept = true
ks.accept = true
@ -164,29 +168,29 @@ lg.accept = true
li.accept = true
ln.accept = true
lo.accept = true
lt.accept = true
lt.accept = true
lu.accept = true
lv.accept = true
lv.accept = true
mg.accept = true
mh.accept = true
mi.accept = true
mk.accept = true
mk-mk.accept = true
mk-mk.accept = true
ml.accept = true
mn.accept = true
mn.accept = true
mr.accept = true
ms.accept = true
ms.accept = true
mt.accept = true
my.accept = true
my.accept = true
na.accept = true
nb.accept = true
nd.accept = true
ne.accept = true
ng.accept = true
nl.accept = true
nl-be.accept = true
nn.accept = true
no.accept = true
ng.accept = true
nl.accept = true
nl-be.accept = true
nn.accept = true
no.accept = true
nr.accept = true
nso.accept = true
nv.accept = true
@ -194,76 +198,76 @@ ny.accept = true
oc.accept = true
oj.accept = true
om.accept = true
or.accept = true
os.accept = true
or.accept = true
os.accept = true
pa.accept = true
pa-in.accept = true
pa-pk.accept = true
pi.accept = true
pl.accept = true
pl.accept = true
ps.accept = true
pt.accept = true
pt-br.accept = true
pt.accept = true
pt-br.accept = true
qu.accept = true
rm.accept = true
rn.accept = true
ro.accept = true
ro-md.accept = true
ro.accept = true
ro-md.accept = true
ro-ro.accept = true
ru.accept = true
ru-md.accept = true
ru.accept = true
ru-md.accept = true
rw.accept = true
sa.accept = true
sc.accept = true
sd.accept = true
sg.accept = true
si.accept = true
sk.accept = true
sl.accept = true
sk.accept = true
sl.accept = true
sm.accept = true
so.accept = true
son-ml.accept = true
sq.accept = true
sr.accept = true
sq.accept = true
sr.accept = true
ss.accept = true
st.accept = true
su.accept = true
sv.accept = true
sv-fi.accept = true
sv.accept = true
sv-fi.accept = true
sv-se.accept = true
sw.accept = true
ta.accept = true
te.accept = true
te.accept = true
tg.accept = true
th.accept = true
th.accept = true
ti.accept = true
tig.accept = true
tk.accept = true
tl.accept = true
tlh.accept = true
tn.accept = true
to.accept = true
tr.accept = true
ts.accept = true
tn.accept = true
to.accept = true
tr.accept = true
ts.accept = true
tt.accept = true
tw.accept = true
ty.accept = true
tw.accept = true
ty.accept = true
ug.accept = true
uk.accept = true
ur.accept = true
uz.accept = true
ve.accept = true
vi.accept = true
vo.accept = true
uk.accept = true
ur.accept = true
uz.accept = true
ve.accept = true
vi.accept = true
vo.accept = true
wa.accept = true
wo.accept = true
xh.accept = true
yi.accept = true
xh.accept = true
yi.accept = true
yo.accept = true
za.accept = true
zh.accept = true
zh-cn.accept = true
zh-hk.accept = true
zh-sg.accept = true
zh-tw.accept = true
zu.accept = true
zh.accept = true
zh-cn.accept = true
zh-hk.accept = true
zh-sg.accept = true
zh-tw.accept = true
zu.accept = true

View File

@ -39,7 +39,7 @@ struct StmtInfoPC : public StmtInfoBase {
typedef HashSet<JSAtom *> FuncStmtSet;
struct Parser;
struct SharedContext;
class SharedContext;
typedef Vector<Definition *, 16> DeclVector;

View File

@ -26,7 +26,7 @@ namespace frontend {
class AnyContextFlags
{
// This class's data is all private and so only visible to these friends.
friend struct SharedContext;
friend class SharedContext;
// True if "use strict"; appears in the body instead of being inherited.
bool hasExplicitUseStrict:1;
@ -64,7 +64,7 @@ class AnyContextFlags
class FunctionContextFlags
{
// This class's data is all private and so only visible to these friends.
friend struct FunctionBox;
friend class FunctionBox;
// We parsed a yield statement in the function.
bool isGenerator:1;

View File

@ -40,3 +40,7 @@ var idx = {valueOf : (function () {
})};
myobj.contains("elephant", idx);
assertEq(gotPos, true);
assertEq("xyzzy".contains("zy\0", 2), false);
var dots = Array(10000).join('.');
assertEq(dots.contains("\x01", 10000), false);
assertEq(dots.contains("\0", 10000), false);

View File

@ -224,23 +224,6 @@ JS_GetEmptyString(JSRuntime *rt)
return rt->emptyString;
}
static JSBool
TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS, jsval **vpp, va_list *app)
{
const char *format;
JSArgumentFormatMap *map;
format = *formatp;
for (map = cx->argumentFormatMap; map; map = map->next) {
if (!strncmp(format, map->format, map->length)) {
*formatp = format + map->length;
return map->formatter(cx, format, fromJS, vpp, app);
}
}
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
return JS_FALSE;
}
static void
AssertHeapIsIdle(JSRuntime *rt)
{
@ -389,65 +372,14 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv, const char *for
case '*':
break;
default:
format--;
if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp,
JS_ADDRESSOF_VA_LIST(ap))) {
return JS_FALSE;
}
/* NB: the formatter already updated sp, so we continue here. */
continue;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
return JS_FALSE;
}
sp++;
}
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_AddArgumentFormatter(JSContext *cx, const char *format, JSArgumentFormatter formatter)
{
size_t length;
JSArgumentFormatMap **mpp, *map;
length = strlen(format);
mpp = &cx->argumentFormatMap;
while ((map = *mpp) != NULL) {
/* Insert before any shorter string to match before prefixes. */
if (map->length < length)
break;
if (map->length == length && !strcmp(map->format, format))
goto out;
mpp = &map->next;
}
map = cx->pod_malloc<JSArgumentFormatMap>();
if (!map)
return JS_FALSE;
map->format = format;
map->length = length;
map->next = *mpp;
*mpp = map;
out:
map->formatter = formatter;
return JS_TRUE;
}
JS_PUBLIC_API(void)
JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
{
size_t length;
JSArgumentFormatMap **mpp, *map;
length = strlen(format);
mpp = &cx->argumentFormatMap;
while ((map = *mpp) != NULL) {
if (map->length == length && !strcmp(map->format, format)) {
*mpp = map->next;
js_free(map);
return;
}
mpp = &map->next;
}
}
JS_PUBLIC_API(JSBool)
JS_ConvertValue(JSContext *cx, jsval valueArg, JSType type, jsval *vp)
{

View File

@ -1944,14 +1944,6 @@ typedef const JSErrorFormatString *
(* JSErrorCallback)(void *userRef, const char *locale,
const unsigned errorNumber);
#ifdef va_start
#define JS_ARGUMENT_FORMATTER_DEFINED 1
typedef JSBool
(* JSArgumentFormatter)(JSContext *cx, const char *format, JSBool fromJS,
jsval **vpp, va_list *app);
#endif
typedef JSBool
(* JSLocaleToUpperCase)(JSContext *cx, JSString *src, jsval *rval);
@ -2606,56 +2598,6 @@ JS_ConvertArgumentsVA(JSContext *cx, unsigned argc, jsval *argv,
const char *format, va_list ap);
#endif
#ifdef JS_ARGUMENT_FORMATTER_DEFINED
/*
* Add and remove a format string handler for JS_{Convert,Push}Arguments{,VA}.
* The handler function has this signature:
*
* JSBool MyArgumentFormatter(JSContext *cx, const char *format,
* JSBool fromJS, jsval **vpp, va_list *app);
*
* It should return true on success, and return false after reporting an error
* or detecting an already-reported error.
*
* For a given format string, for example "AA", the formatter is called from
* JS_ConvertArgumentsVA like so:
*
* formatter(cx, "AA...", JS_TRUE, &sp, &ap);
*
* sp points into the arguments array on the JS stack, while ap points into
* the stdarg.h va_list on the C stack. The JS_TRUE passed for fromJS tells
* the formatter to convert zero or more jsvals at sp to zero or more C values
* accessed via pointers-to-values at ap, updating both sp (via *vpp) and ap
* (via *app) to point past the converted arguments and their result pointers
* on the C stack.
*
* When called from JS_PushArgumentsVA, the formatter is invoked thus:
*
* formatter(cx, "AA...", JS_FALSE, &sp, &ap);
*
* where JS_FALSE for fromJS means to wrap the C values at ap according to the
* format specifier and store them at sp, updating ap and sp appropriately.
*
* The "..." after "AA" is the rest of the format string that was passed into
* JS_{Convert,Push}Arguments{,VA}. The actual format trailing substring used
* in each Convert or PushArguments call is passed to the formatter, so that
* one such function may implement several formats, in order to share code.
*
* Remove just forgets about any handler associated with format. Add does not
* copy format, it points at the string storage allocated by the caller, which
* is typically a string constant. If format is in dynamic storage, it is up
* to the caller to keep the string alive until Remove is called.
*/
extern JS_PUBLIC_API(JSBool)
JS_AddArgumentFormatter(JSContext *cx, const char *format,
JSArgumentFormatter formatter);
extern JS_PUBLIC_API(void)
JS_RemoveArgumentFormatter(JSContext *cx, const char *format);
#endif /* JS_ARGUMENT_FORMATTER_DEFINED */
extern JS_PUBLIC_API(JSBool)
JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp);

View File

@ -1207,7 +1207,6 @@ JSContext::JSContext(JSRuntime *rt)
stack(thisDuringConstruction()),
parseMapPool_(NULL),
cycleDetectorSet(thisDuringConstruction()),
argumentFormatMap(NULL),
lastMessage(NULL),
errorReporter(NULL),
operationCallback(NULL),
@ -1250,14 +1249,6 @@ JSContext::~JSContext()
if (lastMessage)
js_free(lastMessage);
/* Remove any argument formatters. */
JSArgumentFormatMap *map = argumentFormatMap;
while (map) {
JSArgumentFormatMap *temp = map;
map = map->next;
js_free(temp);
}
JS_ASSERT(!resolvingList);
}

View File

@ -1075,20 +1075,6 @@ struct JSRuntime : js::RuntimeFriendFields
#define JS_KEEP_ATOMS(rt) (rt)->gcKeepAtoms++;
#define JS_UNKEEP_ATOMS(rt) (rt)->gcKeepAtoms--;
#ifdef JS_ARGUMENT_FORMATTER_DEFINED
/*
* Linked list mapping format strings for JS_{Convert,Push}Arguments{,VA} to
* formatter functions. Elements are sorted in non-increasing format string
* length order.
*/
struct JSArgumentFormatMap {
const char *format;
size_t length;
JSArgumentFormatter formatter;
JSArgumentFormatMap *next;
};
#endif
namespace js {
struct AutoResolving;
@ -1318,9 +1304,6 @@ struct JSContext : js::ContextFriendFields
/* State for object and array toSource conversion. */
js::ObjectSet cycleDetectorSet;
/* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */
JSArgumentFormatMap *argumentFormatMap;
/* Last message string and log file for debugging. */
char *lastMessage;

View File

@ -113,6 +113,9 @@ JSCompartment::init(JSContext *cx)
if (!gcStoreBuffer.enable())
return false;
} else {
gcNursery.disable();
gcStoreBuffer.disable();
}
#endif

View File

@ -47,7 +47,6 @@ typedef uint8_t jssrcnote;
typedef uintptr_t jsatomid;
/* Struct typedefs. */
typedef struct JSArgumentFormatMap JSArgumentFormatMap;
typedef struct JSGCThing JSGCThing;
typedef struct JSGenerator JSGenerator;
typedef struct JSNativeEnumerator JSNativeEnumerator;
@ -178,7 +177,7 @@ namespace frontend {
struct BytecodeEmitter;
struct Definition;
struct FunctionBox;
class FunctionBox;
struct ObjectBox;
struct Token;
struct TokenPos;

View File

@ -1160,7 +1160,9 @@ str_contains(JSContext *cx, unsigned argc, Value *vp)
return false;
// Step 6
text += uint32_t(Min(double(textlen), Max(0.0, posDouble)));
uint32_t delta = uint32_t(Min(double(textlen), Max(0.0, posDouble)));
text += delta;
textlen -= delta;
}
// Step 7

View File

@ -36,6 +36,8 @@
#include "vm/GlobalObject-inl.h"
#define ENABLE_TYPEDARRAY_MOVE
using namespace mozilla;
using namespace js;
using namespace js::gc;
@ -3020,7 +3022,8 @@ JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
* TypedArray boilerplate
*/
#define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
#ifdef ENABLE_TYPEDARRAY_MOVE
# define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
JSFunctionSpec _typedArray::jsfuncs[] = { \
JS_FN("iterator", JS_ArrayIterator, 0, 0), \
JS_FN("subarray", _typedArray::fun_subarray, 2, JSFUN_GENERIC_NATIVE), \
@ -3028,6 +3031,15 @@ JSFunctionSpec _typedArray::jsfuncs[] = { \
JS_FN("move", _typedArray::fun_move, 3, JSFUN_GENERIC_NATIVE), \
JS_FS_END \
}
#else
# define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
JSFunctionSpec _typedArray::jsfuncs[] = { \
JS_FN("iterator", JS_ArrayIterator, 0, 0), \
JS_FN("subarray", _typedArray::fun_subarray, 2, JSFUN_GENERIC_NATIVE), \
JS_FN("set", _typedArray::fun_set, 2, JSFUN_GENERIC_NATIVE), \
JS_FS_END \
}
#endif
#define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType) \
JS_FRIEND_API(JSObject *) JS_New ## Name ## Array(JSContext *cx, uint32_t nelements) \

View File

@ -2130,129 +2130,6 @@ DumpObject(JSContext *cx, unsigned argc, jsval *vp)
#endif /* DEBUG */
#ifdef TEST_CVTARGS
#include <ctype.h>
static const char *
EscapeWideString(jschar *w)
{
static char enuf[80];
static char hex[] = "0123456789abcdef";
jschar u;
unsigned char b, c;
int i, j;
if (!w)
return "";
for (i = j = 0; i < sizeof enuf - 1; i++, j++) {
u = w[j];
if (u == 0)
break;
b = (unsigned char)(u >> 8);
c = (unsigned char)(u);
if (b) {
if (i >= sizeof enuf - 6)
break;
enuf[i++] = '\\';
enuf[i++] = 'u';
enuf[i++] = hex[b >> 4];
enuf[i++] = hex[b & 15];
enuf[i++] = hex[c >> 4];
enuf[i] = hex[c & 15];
} else if (!isprint(c)) {
if (i >= sizeof enuf - 4)
break;
enuf[i++] = '\\';
enuf[i++] = 'x';
enuf[i++] = hex[c >> 4];
enuf[i] = hex[c & 15];
} else {
enuf[i] = (char)c;
}
}
enuf[i] = 0;
return enuf;
}
#include <stdarg.h>
static JSBool
ZZ_formatter(JSContext *cx, const char *format, bool fromJS, jsval **vpp,
va_list *app)
{
jsval *vp;
va_list ap;
double re, im;
printf("entering ZZ_formatter");
vp = *vpp;
ap = *app;
if (fromJS) {
if (!JS_ValueToNumber(cx, vp[0], &re))
return false;
if (!JS_ValueToNumber(cx, vp[1], &im))
return false;
*va_arg(ap, double *) = re;
*va_arg(ap, double *) = im;
} else {
re = va_arg(ap, double);
im = va_arg(ap, double);
vp[0] = JS_NumberValue(re);
vp[1] = JS_NumberValue(im);
}
*vpp = vp + 2;
*app = ap;
printf("leaving ZZ_formatter");
return true;
}
static JSBool
ConvertArgs(JSContext *cx, unsigned argc, jsval *vp)
{
bool b = false;
jschar c = 0;
int32_t i = 0, j = 0;
uint32_t u = 0;
double d = 0, I = 0, re = 0, im = 0;
JSString *str = NULL;
jschar *w = NULL;
JSObject *obj2 = NULL;
JSFunction *fun = NULL;
jsval v = JSVAL_VOID;
bool ok;
if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter))
return false;
ok = JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "b/ciujdISWofvZZ*",
&b, &c, &i, &u, &j, &d, &I, &str, &w, &obj2,
&fun, &v, &re, &im);
JS_RemoveArgumentFormatter(cx, "ZZ");
if (!ok)
return false;
fprintf(gOutFile,
"b %u, c %x (%c), i %ld, u %lu, j %ld\n",
b, c, (char)c, i, u, j);
ToStringHelper obj2string(cx, obj2);
ToStringHelper valueString(cx, v);
JSAutoByteString strBytes;
if (str)
strBytes.encode(cx, str);
JSString *tmpstr = JS_DecompileFunction(cx, fun, 4);
JSAutoByteString func;
if (!tmpstr || !func.encode(cx, tmpstr))
ReportException(cx);
fprintf(gOutFile,
"d %g, I %g, S %s, W %s, obj %s, fun %s\n"
"v %s, re %g, im %g\n",
d, I, !!strBytes ? strBytes.ptr() : "", EscapeWideString(w),
obj2string.getBytes(),
fun ? (!!func ? func.ptr() : "error decompiling fun") : "",
valueString.getBytes(), re, im);
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
#endif
static JSBool
BuildDate(JSContext *cx, unsigned argc, jsval *vp)
{
@ -3707,12 +3584,6 @@ static JSFunctionSpecWithHelp shell_functions[] = {
" object will have a property named \"edge: machine stack\"; the referrers will\n"
" be 'null', because they are roots."),
#endif
#ifdef TEST_CVTARGS
JS_FN_HELP("cvtargs", ConvertArgs, 0, 0,
"cvtargs(arg1..., arg12)",
" Test argument formatter."),
#endif
JS_FN_HELP("build", BuildDate, 0, 0,
"build()",

View File

@ -47,9 +47,6 @@ XPCContext::~XPCContext()
static_cast<XPCWrappedNativeScope*>(scopeptr);
scope->ClearContext();
}
// we do not call JS_RemoveArgumentFormatter because we now only
// delete XPCContext *after* the underlying JSContext is dead
}
void

View File

@ -9559,7 +9559,7 @@ nsCSSFrameConstructor::CreateNeededAnonFlexItems(
true);
newItem->mIsAllInline = newItem->mHasInlineEnds =
newItem->mStyleContext->GetStyleDisplay()->IsInlineOutside();
newItem->mStyleContext->GetStyleDisplay()->IsInlineOutsideStyle();
newItem->mIsBlock = !newItem->mIsAllInline;
NS_ABORT_IF_FALSE(!newItem->mIsAllInline && newItem->mIsBlock,

View File

@ -6798,8 +6798,12 @@ PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTarge
// an edit box below the current view, you'll get the edit box aligned with
// the top of the window. This is arguably better behavior anyway.
rv = ScrollContentIntoView(content,
ScrollAxis(),
ScrollAxis(),
nsIPresShell::ScrollAxis(
nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::ScrollAxis(
nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
SCROLL_OVERFLOW_HIDDEN);
NS_ENSURE_SUCCESS(rv, false);
frame = content->GetPrimaryFrame();

View File

@ -59,6 +59,7 @@
#include "nsMathMLAtoms.h"
#include "nsMathMLOperators.h"
#include "Navigator.h"
#include "nsDOMStorageBaseDB.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
@ -255,6 +256,8 @@ nsLayoutStatics::Initialize()
nsPermissionManager::AppUninstallObserverInit();
nsDOMStorageBaseDB::Init();
return NS_OK;
}

View File

@ -47,7 +47,7 @@ public:
NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus,
bool aControlHeld) { return NS_OK; }
bool aControlHeld) { return NS_OK; }
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,

View File

@ -113,11 +113,11 @@ public:
NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus,
bool aControlHeld) { return NS_OK; }
bool aControlHeld) { return NS_OK; }
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus) { return NS_OK; }
nsEventStatus* aEventStatus) { return NS_OK; }
NS_IMETHOD HandleRelease(nsPresContext* aPresContext,
nsGUIEvent * aEvent,

View File

@ -28,6 +28,7 @@ struct cubeb_stream {
long queuebuf_len;
long bytespersec;
long framesize;
int draining;
cubeb_data_callback data_callback;
cubeb_state_callback state_callback;
@ -37,24 +38,38 @@ struct cubeb_stream {
static void
bufferqueue_callback(SLBufferQueueItf caller, struct cubeb_stream *stm)
{
void *buf = stm->queuebuf[stm->queuebuf_idx];
SLBufferQueueState state;
(*stm->bufq)->GetState(stm->bufq, &state);
long written = stm->data_callback(stm, stm->user_ptr,
buf, stm->queuebuf_len / stm->framesize);
if (written <= 0)
if (stm->draining) {
if (!state.count) {
stm->draining = 0;
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
}
return;
}
if (state.count > 1)
return;
(*stm->bufq)->Enqueue(stm->bufq, buf, written * stm->framesize);
SLuint32 i;
for (i = state.count; i < NBUFS; i++) {
void *buf = stm->queuebuf[stm->queuebuf_idx];
long written = stm->data_callback(stm, stm->user_ptr,
buf, stm->queuebuf_len / stm->framesize);
if (written == CUBEB_ERROR) {
(*stm->play)->SetPlayState(stm->play, SL_PLAYSTATE_STOPPED);
return;
}
stm->queuebuf_idx = (stm->queuebuf_idx + 1) % NBUFS;
// XXX handle error
}
(*stm->bufq)->Enqueue(stm->bufq, buf, written * stm->framesize);
stm->queuebuf_idx = (stm->queuebuf_idx + 1) % NBUFS;
static void
play_callback(SLPlayItf caller, struct cubeb_stream *stm, SLuint32 event)
{
if (event & SL_PLAYEVENT_HEADSTALLED)
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
if ((written * stm->framesize) < stm->queuebuf_len) {
stm->draining = 1;
return;
}
}
}
int
@ -228,18 +243,6 @@ cubeb_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
return CUBEB_ERROR;
}
res = (*stm->play)->RegisterCallback(stm->play, play_callback, stm);
if (res != SL_RESULT_SUCCESS) {
cubeb_stream_destroy(stm);
return CUBEB_ERROR;
}
res = (*stm->play)->SetCallbackEventsMask(stm->play, SL_PLAYEVENT_HEADSTALLED);
if (res != SL_RESULT_SUCCESS) {
cubeb_stream_destroy(stm);
return CUBEB_ERROR;
}
*stream = stm;
return CUBEB_OK;
@ -283,7 +286,7 @@ cubeb_stream_get_position(cubeb_stream * stm, uint64_t * position)
SLresult res = (*stm->play)->GetPosition(stm->play, &msec);
if (res != SL_RESULT_SUCCESS)
return CUBEB_ERROR;
*position = (stm->bytespersec * msec) / (1000 * stm->framesize);
*position = (stm->bytespersec / (1000 * stm->framesize)) * msec;
return CUBEB_OK;
}

View File

@ -20,7 +20,7 @@ DEFINES += \
-Drestrict= \
$(NULL)
ifneq ($(filter $(OS_ARCH),Linux Darwin),)
ifneq ($(filter $(OS_ARCH),Linux Darwin DragonFly FreeBSD NetBSD OpenBSD),)
DEFINES += -DHAVE_LRINTF
endif
ifeq ($(OS_ARCH), WINNT)

View File

@ -64,8 +64,8 @@ var HelperApps = {
if (permValue == Services.perms.ALLOW_ACTION) {
if (aCallback)
aCallback(aUri);
this.openUriInApp(aUri);
else
this.openUriInApp(aUri);
} else if (permValue == Services.perms.DENY_ACTION) {
// do nothing
}

View File

@ -3437,8 +3437,24 @@ var BrowserEventHandler = {
if (!closest)
closest = aEvent.target;
if (closest)
if (closest) {
let uri = this._getLinkURI(closest);
if (uri) {
Services.io.QueryInterface(Ci.nsISpeculativeConnect).speculativeConnect(uri, null, null);
}
this._doTapHighlight(closest);
}
},
_getLinkURI: function(aElement) {
if (aElement.nodeType == Ci.nsIDOMNode.ELEMENT_NODE &&
((aElement instanceof Ci.nsIDOMHTMLAnchorElement && aElement.href) ||
(aElement instanceof Ci.nsIDOMHTMLAreaElement && aElement.href))) {
try {
return Services.io.newURI(aElement.href, null, null);
} catch (e) {}
}
return null;
},
observe: function(aSubject, aTopic, aData) {
@ -6365,7 +6381,7 @@ var WebappsUI = {
let jni = new JNI();
let cls = jni.findClass("org.mozilla.gecko.GeckoAppShell");
let method = jni.getStaticMethodID(cls, "getPreferredIconSize", "()I");
iconSize = jni.callStaticIntMethod(cls, method, null);
iconSize = jni.callStaticIntMethod(cls, method);
jni.close();
} catch(ex) {
console.log(ex);

View File

@ -67,9 +67,12 @@ SessionStore.prototype = {
this._lastSessionTime = this._sessionFile.lastModifiedTime;
let delta = Date.now() - this._lastSessionTime;
let timeout = Services.prefs.getIntPref("browser.sessionstore.resume_from_crash_timeout");
// Disable crash recovery if we have exceeded the timeout
this._shouldRestore = (delta <= (timeout * 60000));
this._sessionFile.clone().moveTo(null, this._sessionFileBackup.leafName);
if (!this._shouldRestore) {
this._sessionFile.clone().moveTo(null, this._sessionFileBackup.leafName);
}
}
if (!this._sessionCache.exists() || !this._sessionCache.isDirectory())
@ -889,7 +892,22 @@ SessionStore.prototype = {
Services.obs.notifyObservers(null, "sessionstore-windows-restored", aMessage || "");
}
let sessionFile = this._sessionFile;
// aForceRestore will be true when we are recovering from Android OOM kills
if (!aForceRestore) {
// If we are not recovering from an OOM kill (i.e., we actually crashed),
// move sessionstore.js -> sessionstore.bak. sessionstore.bak is used in
// about:home to read the "tabs from last time", so since we've started a
// new session after the crash, we need to make sure sessionstore.bak is
// current. We do not move sessionstore.js -> sessionstore.bak if we had
// an OOM kill since restoring from an OOM kill should look like the same
// session as before (so the "tabs from last time" should stay the same).
if (sessionFile.exists()) {
sessionFile.clone().moveTo(null, this._sessionFileBackup.leafName);
sessionFile = this._sessionFileBackup;
}
let maxCrashes = Services.prefs.getIntPref("browser.sessionstore.max_resumed_crashes");
let recentCrashes = Services.prefs.getIntPref("browser.sessionstore.recent_crashes") + 1;
Services.prefs.setIntPref("browser.sessionstore.recent_crashes", recentCrashes);
@ -901,14 +919,13 @@ SessionStore.prototype = {
}
}
// The previous session data has already been renamed to the backup file
if (!this._sessionFileBackup.exists()) {
if (!sessionFile.exists()) {
notifyObservers("fail");
return;
}
try {
let channel = NetUtil.newChannel(this._sessionFileBackup);
let channel = NetUtil.newChannel(sessionFile);
channel.contentType = "application/json";
NetUtil.asyncFetch(channel, function(aStream, aResult) {
if (!Components.isSuccessCode(aResult)) {
@ -931,7 +948,8 @@ SessionStore.prototype = {
Cu.reportError("SessionStore: Could not parse JSON: " + ex);
}
if (!data || data.windows.length == 0) {
// To do a restore, we must have at least one window with one tab
if (!data || data.windows.length == 0 || !data.windows[0].tabs || data.windows[0].tabs.length == 0) {
notifyObservers("fail");
return;
}

View File

@ -67,7 +67,7 @@ JNI.prototype = {
get _findClass() {
delete this._findClass;
return this._findClass = this.lib.declare("FindClass",
return this._findClass = this.lib.declare("jsjni_FindClass",
ctypes.default_abi,
this.types.jclass,
ctypes.char.ptr);
@ -82,7 +82,7 @@ JNI.prototype = {
get _getStaticMethodID() {
delete this._getStatisMethodID;
return this._getStaticMethodID = this.lib.declare("GetStaticMethodID",
return this._getStaticMethodID = this.lib.declare("jsjni_GetStaticMethodID",
ctypes.default_abi,
this.types.jmethodID,
this.types.jclass, // class
@ -99,7 +99,7 @@ JNI.prototype = {
get _exceptionCheck() {
delete this._exceptionCheck;
return this._exceptionCheck = this.lib.declare("ExceptionCheck",
return this._exceptionCheck = this.lib.declare("jsjni_ExceptionCheck",
ctypes.default_abi,
ctypes.bool);
},
@ -110,7 +110,7 @@ JNI.prototype = {
get _callStaticVoidMethod() {
delete this._callStaticVoidMethod;
return this._callStaticVoidMethod = this.lib.declare("CallStaticVoidMethodA",
return this._callStaticVoidMethod = this.lib.declare("jsjni_CallStaticVoidMethodA",
ctypes.default_abi,
ctypes.void_t,
this.types.jclass,
@ -127,7 +127,7 @@ JNI.prototype = {
get _callStaticIntMethod() {
delete this._callStaticIntMethod;
return this._callStaticIntMethod = this.lib.declare("CallStaticIntMethodA",
return this._callStaticIntMethod = this.lib.declare("jsjni_CallStaticIntMethodA",
ctypes.default_abi,
ctypes.int,
this.types.jclass,

View File

@ -8,6 +8,7 @@
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
# suite (comm): {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
# metro browser: {99bceaaa-e3c6-48c1-b981-ef9b46b67d60}
#
# In theory we should do this for all these instructions, but in practice it is
# sufficient to do it for the app-startup one, and the file is simpler that way.
@ -15,7 +16,7 @@
# Weave.js
component {74b89fb0-f200-4ae8-a3ec-dd164117f6de} Weave.js
contract @mozilla.org/weave/service;1 {74b89fb0-f200-4ae8-a3ec-dd164117f6de}
category app-startup WeaveService service,@mozilla.org/weave/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
category app-startup WeaveService service,@mozilla.org/weave/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} application={99bceaaa-e3c6-48c1-b981-ef9b46b67d60}
component {d28f8a0b-95da-48f4-b712-caf37097be41} Weave.js
contract @mozilla.org/network/protocol/about;1?what=sync-log {d28f8a0b-95da-48f4-b712-caf37097be41}
# Register resource aliases

View File

@ -298,8 +298,12 @@ nsFormFillController::SetPopupOpen(bool aPopupOpen)
docShell->GetPresShell(getter_AddRefs(presShell));
NS_ENSURE_STATE(presShell);
presShell->ScrollContentIntoView(content,
nsIPresShell::ScrollAxis(),
nsIPresShell::ScrollAxis(),
nsIPresShell::ScrollAxis(
nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::ScrollAxis(
nsIPresShell::SCROLL_MINIMUM,
nsIPresShell::SCROLL_IF_NOT_VISIBLE),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
// mFocusedPopup can be destroyed after ScrollContentIntoView, see bug 420089
if (mFocusedPopup)

View File

@ -274,7 +274,7 @@ Submitter.prototype = {
let reportData = parseKeyValuePairsFromFile(extra);
let additionalDumps = [];
if ("additional_minidumps" in reportData) {
let names = extraData.additional_minidumps.split(',');
let names = reportData.additional_minidumps.split(',');
for (let name in names) {
let [dump, extra] = getPendingMiniDump(this.id + "-" + name);
if (!dump.exists()) {

View File

@ -31,11 +31,13 @@ ch = Chamorro
co = Corsican
cr = Cree
cs = Czech
csb = Kashubian
cu = Church Slavic
cv = Chuvash
cy = Welsh
da = Danish
de = German
dsb = Lower Sorbian
dv = Divehi
dz = Dzongkha
ee = Ewe
@ -54,14 +56,16 @@ fr = French
fur = Friulian
fy = Frisian
ga = Irish
gd = Scots Gaelic
gd = Scottish Gaelic
gl = Galician
gn = Guarani
gu = Gujarati
gv = Manx
ha = Hausa
haw = Hawaiian
he = Hebrew
hi = Hindi
hil = Hiligaynon
ho = Hiri Motu
hr = Croatian
hsb = Upper Sorbian