mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 00:32:11 +00:00
Merge the last PGO-green inbound changeset to m-c.
This commit is contained in:
commit
4d6acb9941
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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 \
|
||||
|
377
browser/base/content/test/browser_bug583890.js
Normal file
377
browser/base/content/test/browser_bug583890.js
Normal 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();
|
||||
}
|
||||
|
88
browser/base/content/test/browser_bug583890_label.js
Normal file
88
browser/base/content/test/browser_bug583890_label.js
Normal 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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -21,6 +21,7 @@ EXTRA_JS_MODULES = \
|
||||
NewTabUtils.jsm \
|
||||
offlineAppCache.jsm \
|
||||
SignInToWebsite.jsm \
|
||||
TabTitleAbridger.jsm \
|
||||
TelemetryTimestamps.jsm \
|
||||
Social.jsm \
|
||||
webappsUI.jsm \
|
||||
|
604
browser/modules/TabTitleAbridger.jsm
Normal file
604
browser/modules/TabTitleAbridger.jsm
Normal 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;
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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, "a, &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)
|
||||
{
|
||||
|
@ -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___ */
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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___ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 = "aKey;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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>
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -39,7 +39,7 @@ struct StmtInfoPC : public StmtInfoBase {
|
||||
|
||||
typedef HashSet<JSAtom *> FuncStmtSet;
|
||||
struct Parser;
|
||||
struct SharedContext;
|
||||
class SharedContext;
|
||||
|
||||
typedef Vector<Definition *, 16> DeclVector;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -113,6 +113,9 @@ JSCompartment::init(JSContext *cx)
|
||||
|
||||
if (!gcStoreBuffer.enable())
|
||||
return false;
|
||||
} else {
|
||||
gcNursery.disable();
|
||||
gcStoreBuffer.disable();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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()",
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user