зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to m-c, a=merge
MozReview-Commit-ID: 3unzaMHXBGa
This commit is contained in:
Коммит
b6cc8777ce
|
@ -5631,7 +5631,12 @@ function middleMousePaste(event) {
|
|||
function stripUnsafeProtocolOnPaste(pasteData) {
|
||||
// Don't allow pasting javascript URIs since we don't support
|
||||
// LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those.
|
||||
return pasteData.replace(/\r?\n/g, "").replace(/^(?:\s*javascript:)+/i, "");
|
||||
let changed = false;
|
||||
let pasteDataNoJS = pasteData.replace(/\r?\n/g, "")
|
||||
.replace(/^(?:\s*javascript:)+/i,
|
||||
() => { changed = true;
|
||||
return ""; });
|
||||
return changed ? pasteDataNoJS : pasteData;
|
||||
}
|
||||
|
||||
// handleDroppedLink has the following 2 overloads:
|
||||
|
|
|
@ -4612,7 +4612,11 @@
|
|||
} else {
|
||||
label = tab.getAttribute("label") +
|
||||
(this.AppConstants.E10S_TESTING_ONLY && tab.linkedBrowser && tab.linkedBrowser.isRemoteBrowser ? " - e10s" : "");
|
||||
if (tab.userContextId) {
|
||||
label = this.mStringBundle.getFormattedString("tabs.containers.tooltip", [label, ContextualIdentityService.getUserContextLabel(tab.userContextId)]);
|
||||
}
|
||||
}
|
||||
|
||||
event.target.setAttribute("label", label);
|
||||
]]></body>
|
||||
</method>
|
||||
|
|
|
@ -38,6 +38,8 @@ support-files =
|
|||
skip-if = true # bug 917535, bug 1289765
|
||||
[browser_locationBarExternalLoad.js]
|
||||
[browser_moz_action_link.js]
|
||||
[browser_pasteAndGo.js]
|
||||
subsuite = clipboard
|
||||
[browser_removeUnsafeProtocolsFromURLBarPaste.js]
|
||||
subsuite = clipboard
|
||||
[browser_search_favicon.js]
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
"use strict";
|
||||
|
||||
let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
||||
|
||||
add_task(function*() {
|
||||
const kURLs = [
|
||||
"http://example.com/1",
|
||||
"http://example.org/2\n",
|
||||
"http://\nexample.com/3\n",
|
||||
];
|
||||
for (let url of kURLs) {
|
||||
yield BrowserTestUtils.withNewTab("about:blank", function* (browser) {
|
||||
gURLBar.focus();
|
||||
yield new Promise((resolve, reject) => {
|
||||
waitForClipboard(url, function() {
|
||||
clipboardHelper.copyString(url);
|
||||
}, resolve,
|
||||
() => reject(new Error(`Failed to copy string '${url}' to clipboard`))
|
||||
);
|
||||
});
|
||||
let textBox = document.getAnonymousElementByAttribute(gURLBar,
|
||||
"anonid", "textbox-input-box");
|
||||
let cxmenu = document.getAnonymousElementByAttribute(textBox,
|
||||
"anonid", "input-box-contextmenu");
|
||||
let cxmenuPromise = BrowserTestUtils.waitForEvent(cxmenu, "popupshown");
|
||||
EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "contextmenu", button: 2});
|
||||
yield cxmenuPromise;
|
||||
let menuitem = document.getAnonymousElementByAttribute(textBox,
|
||||
"anonid", "paste-and-go");
|
||||
let browserLoadedPromise = BrowserTestUtils.browserLoaded(browser, url.replace(/\n/g, ""));
|
||||
EventUtils.synthesizeMouseAtCenter(menuitem, {});
|
||||
// Using toSource in order to get the newlines escaped:
|
||||
info("Paste and go, loading " + url.toSource());
|
||||
yield browserLoadedPromise;
|
||||
ok(true, "Successfully loaded " + url);
|
||||
});
|
||||
}
|
||||
});
|
|
@ -7,6 +7,9 @@ var pairs = [
|
|||
["javascript:", ""],
|
||||
["javascript:1+1", "1+1"],
|
||||
["javascript:document.domain", "document.domain"],
|
||||
["java\nscript:foo", "foo"],
|
||||
["http://\nexample.com", "http://example.com"],
|
||||
["http://\nexample.com\n", "http://example.com"],
|
||||
["data:text/html,<body>hi</body>", "data:text/html,<body>hi</body>"],
|
||||
// Nested things get confusing because some things don't parse as URIs:
|
||||
["javascript:javascript:alert('hi!')", "alert('hi!')"],
|
||||
|
|
|
@ -49,3 +49,9 @@ tabs.unblockAudio.tooltip=Play tab
|
|||
# LOCALIZATION NOTE (tabs.allowTabFocusByPromptForSite):
|
||||
# %S is the hostname of the site where dialogs are allowed to switch tabs
|
||||
tabs.allowTabFocusByPromptForSite=Allow dialogs from %S to take you to their tab
|
||||
|
||||
# LOCALIZATION NOTE (tabs.containers.tooltip):
|
||||
# Displayed as a tooltip on container tabs
|
||||
# %1$S is the title of the current tab
|
||||
# %2$S is the name of the current container
|
||||
tabs.containers.tooltip=%1$S - %2$S
|
||||
|
|
|
@ -60,7 +60,7 @@ table.headers.indexedDB.value=Value
|
|||
table.headers.indexedDB.origin=Origin
|
||||
table.headers.indexedDB.version=Version
|
||||
table.headers.indexedDB.objectStores=Object Stores
|
||||
table.headers.indexedDB.keyPath=Key
|
||||
table.headers.indexedDB.keyPath2=Key Path
|
||||
table.headers.indexedDB.autoIncrement=Auto Increment
|
||||
table.headers.indexedDB.indexes=Indexes
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ support-files =
|
|||
storage-cookies.html
|
||||
storage-empty-objectstores.html
|
||||
storage-idb-delete-blocked.html
|
||||
storage-indexeddb-duplicate-names.html
|
||||
storage-listings.html
|
||||
storage-localstorage.html
|
||||
storage-overflow.html
|
||||
|
@ -35,6 +36,7 @@ support-files =
|
|||
[browser_storage_empty_objectstores.js]
|
||||
[browser_storage_indexeddb_delete.js]
|
||||
[browser_storage_indexeddb_delete_blocked.js]
|
||||
[browser_storage_indexeddb_duplicate_names.js]
|
||||
[browser_storage_localstorage_edit.js]
|
||||
[browser_storage_localstorage_error.js]
|
||||
[browser_storage_overflow.js]
|
||||
|
|
|
@ -53,28 +53,28 @@ const testCases = [
|
|||
[["sessionStorage", "https://sectest1.example.org"],
|
||||
["iframe-s-ss1"]],
|
||||
[["indexedDB", "http://test1.example.org"],
|
||||
["idb1", "idb2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1"],
|
||||
["idb1 (default)", "idb2 (default)"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)"],
|
||||
["obj1", "obj2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb2"],
|
||||
[["indexedDB", "http://test1.example.org", "idb2 (default)"],
|
||||
["obj3"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
|
||||
[1, 2, 3]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj2"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
|
||||
[1]],
|
||||
[["indexedDB", "http://test1.example.org", "idb2", "obj3"],
|
||||
[["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
|
||||
[]],
|
||||
[["indexedDB", "http://sectest1.example.org"],
|
||||
[]],
|
||||
[["indexedDB", "https://sectest1.example.org"],
|
||||
["idb-s1", "idb-s2"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s1"],
|
||||
["idb-s1 (default)", "idb-s2 (default)"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
|
||||
["obj-s1"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2"],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
|
||||
["obj-s2"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s1", "obj-s1"],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
|
||||
[6, 7]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
|
||||
[16]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js",
|
||||
|
|
|
@ -17,7 +17,7 @@ const TEST_CASES = [
|
|||
["cookies", "test1.example.org"],
|
||||
getCookieId("c1", "test1.example.org", "/browser"), "name"
|
||||
],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
|
||||
1, "name"],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
MAIN_DOMAIN + "404_cached_file.js", "url"],
|
||||
|
|
|
@ -29,7 +29,7 @@ add_task(function* () {
|
|||
["iframe-u-ss1", "iframe-u-ss2"]],
|
||||
[["sessionStorage", "https://sectest1.example.org"],
|
||||
["iframe-s-ss1"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
|
||||
[1, 2, 3]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
|
||||
|
@ -41,7 +41,7 @@ add_task(function* () {
|
|||
const deleteHosts = [
|
||||
[["localStorage", "https://sectest1.example.org"], "iframe-s-ls1", "name"],
|
||||
[["sessionStorage", "https://sectest1.example.org"], "iframe-s-ss1", "name"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"], 1, "name"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], 1, "name"],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
MAIN_DOMAIN + "404_cached_file.js", "url"],
|
||||
];
|
||||
|
@ -78,7 +78,7 @@ add_task(function* () {
|
|||
["iframe-u-ss1", "iframe-u-ss2"]],
|
||||
[["sessionStorage", "https://sectest1.example.org"],
|
||||
[]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
|
||||
[]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[]],
|
||||
|
|
|
@ -28,7 +28,7 @@ add_task(function* () {
|
|||
],
|
||||
[["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
|
||||
[["sessionStorage", "http://test1.example.org"], ["ss1"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"], [1, 2, 3]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], [1, 2, 3]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
|
||||
]);
|
||||
|
@ -38,7 +38,7 @@ add_task(function* () {
|
|||
["cookies", "test1.example.org"],
|
||||
["localStorage", "http://test1.example.org"],
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
|
||||
["Cache", "http://test1.example.org", "plop"],
|
||||
];
|
||||
|
||||
|
@ -67,7 +67,7 @@ add_task(function* () {
|
|||
[["cookies", "test1.example.org"], []],
|
||||
[["localStorage", "http://test1.example.org"], []],
|
||||
[["sessionStorage", "http://test1.example.org"], []],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"], []],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], []],
|
||||
[["Cache", "http://test1.example.org", "plop"], []],
|
||||
]);
|
||||
|
||||
|
|
|
@ -21,14 +21,14 @@
|
|||
// storage-secured-iframe.html and storage-unsecured-iframe.html
|
||||
const storeItems = [
|
||||
[["indexedDB", "http://test1.example.org"],
|
||||
["idb1", "idb2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1"],
|
||||
["idb1 (default)", "idb2 (default)"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)"],
|
||||
["obj1", "obj2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb2"],
|
||||
[["indexedDB", "http://test1.example.org", "idb2 (default)"],
|
||||
[]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
|
||||
[1, 2, 3]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj2"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
|
||||
[1]]
|
||||
];
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ add_task(function* () {
|
|||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb1", "idb2"]],
|
||||
[["indexedDB", "http://test1.example.org"], ["idb1 (default)", "idb2 (default)"]],
|
||||
]);
|
||||
|
||||
info("do the delete");
|
||||
const deletedDb = ["indexedDB", "http://test1.example.org", "idb1"];
|
||||
const deletedDb = ["indexedDB", "http://test1.example.org", "idb1 (default)"];
|
||||
|
||||
yield selectTreeItem(deletedDb);
|
||||
|
||||
|
@ -40,7 +40,7 @@ add_task(function* () {
|
|||
|
||||
info("test state after delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb2"]],
|
||||
[["indexedDB", "http://test1.example.org"], ["idb2 (default)"]],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
|
|
|
@ -13,19 +13,19 @@ add_task(function* () {
|
|||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb"]]
|
||||
[["indexedDB", "http://test1.example.org"], ["idb (default)"]]
|
||||
]);
|
||||
|
||||
info("do the delete");
|
||||
yield selectTreeItem(["indexedDB", "http://test1.example.org"]);
|
||||
let actor = gUI.getCurrentActor();
|
||||
let result = yield actor.removeDatabase("http://test1.example.org", "idb");
|
||||
let result = yield actor.removeDatabase("http://test1.example.org", "idb (default)");
|
||||
|
||||
ok(result.blocked, "removeDatabase attempt is blocked");
|
||||
|
||||
info("test state after blocked delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb"]]
|
||||
[["indexedDB", "http://test1.example.org"], ["idb (default)"]]
|
||||
]);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
@ -47,7 +47,7 @@ add_task(function* () {
|
|||
info("try to delete database from nonexistent host");
|
||||
let errorThrown = false;
|
||||
try {
|
||||
result = yield actor.removeDatabase("http://test2.example.org", "idb");
|
||||
result = yield actor.removeDatabase("http://test2.example.org", "idb (default)");
|
||||
} catch (ex) {
|
||||
errorThrown = true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* 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/. */
|
||||
|
||||
// Test to verify that indexedDBs with duplicate names (different types / paths)
|
||||
// work as expected.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
const TESTPAGE = MAIN_DOMAIN + "storage-indexeddb-duplicate-names.html";
|
||||
|
||||
setPermission(TESTPAGE, "indexedDB");
|
||||
|
||||
yield openTabAndSetupStorage(TESTPAGE);
|
||||
|
||||
yield checkState([
|
||||
[
|
||||
["indexedDB", "http://test1.example.org"], [
|
||||
"idb1 (default)",
|
||||
"idb1 (temporary)",
|
||||
"idb1 (persistent)",
|
||||
"idb2 (default)",
|
||||
"idb2 (temporary)",
|
||||
"idb2 (persistent)"
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
|
@ -72,17 +72,17 @@ const testCases = [
|
|||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "idb2",
|
||||
location: "idb2 (default)",
|
||||
sidebarHidden: false
|
||||
},
|
||||
|
||||
{
|
||||
location: ["indexedDB", "http://test1.example.org", "idb2", "obj3"],
|
||||
location: ["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
|
||||
{
|
||||
location: ["indexedDB", "https://sectest1.example.org", "idb-s2"],
|
||||
location: ["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
|
|
|
@ -124,7 +124,7 @@ const testCases = [
|
|||
{name: "ss5.3", value: `${LONG_WORD}&${LONG_WORD}`},
|
||||
{name: "ss5.4", value: `${LONG_WORD}&${LONG_WORD}`},
|
||||
], true],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"]],
|
||||
[1, [
|
||||
{name: 1, value: JSON.stringify({id: 1, name: "foo", email: "foo@bar.com"})}
|
||||
]],
|
||||
|
@ -133,7 +133,7 @@ const testCases = [
|
|||
{name: "1.name", value: "foo"},
|
||||
{name: "1.email", value: "foo@bar.com"},
|
||||
], true],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"]],
|
||||
[1, [
|
||||
{name: 1, value: JSON.stringify({
|
||||
id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"
|
||||
|
|
|
@ -880,3 +880,19 @@ var focusSearchBoxUsingShortcut = Task.async(function* (panelWin, callback) {
|
|||
function getCookieId(name, domain, path) {
|
||||
return `${name}${SEPARATOR_GUID}${domain}${SEPARATOR_GUID}${path}`;
|
||||
}
|
||||
|
||||
function setPermission(url, permission) {
|
||||
const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
|
||||
|
||||
let uri = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService)
|
||||
.newURI(url, null, null);
|
||||
let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
let principal = ssm.createCodebasePrincipal(uri, {});
|
||||
|
||||
Components.classes["@mozilla.org/permissionmanager;1"]
|
||||
.getService(nsIPermissionManager)
|
||||
.addFromPrincipal(principal, permission,
|
||||
nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector IndexedDBs with duplicate names</title>
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
function createIndexedDBs() {
|
||||
createIndexedDB("idb1", "temporary");
|
||||
createIndexedDB("idb1", "default");
|
||||
createIndexedDB("idb1", "persistent");
|
||||
createIndexedDB("idb2", "temporary");
|
||||
createIndexedDB("idb2", "default");
|
||||
createIndexedDB("idb2", "persistent");
|
||||
}
|
||||
|
||||
function createIndexedDB(name, storage) {
|
||||
let open = indexedDB.open(name, {storage: storage});
|
||||
|
||||
open.onsuccess = function () {
|
||||
let db = open.result;
|
||||
db.close();
|
||||
};
|
||||
}
|
||||
|
||||
function deleteDB(dbName, storage) {
|
||||
return new Promise(resolve => {
|
||||
dump(`removing database ${dbName} (${storage}) from ${document.location}\n`);
|
||||
indexedDB.deleteDatabase(dbName, { storage: storage }).onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
window.clear = function* () {
|
||||
yield deleteDB("idb1", "temporary");
|
||||
yield deleteDB("idb1", "default");
|
||||
yield deleteDB("idb1", "persistent");
|
||||
yield deleteDB("idb2", "temporary");
|
||||
yield deleteDB("idb2", "default");
|
||||
yield deleteDB("idb2", "persistent");
|
||||
|
||||
dump(`removed indexedDB data from ${document.location}\n`);
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body onload="createIndexedDBs()">
|
||||
<h1>storage-indexeddb-duplicate-names.html</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -809,7 +809,10 @@ StorageUI.prototype = {
|
|||
columns[f.name] = f.name;
|
||||
let columnName;
|
||||
try {
|
||||
columnName = L10N.getStr("table.headers." + type + "." + f.name);
|
||||
// Path key names for l10n in the case of a string change.
|
||||
let name = f.name === "keyPath" ? "keyPath2" : f.name;
|
||||
|
||||
columnName = L10N.getStr("table.headers." + type + "." + name);
|
||||
} catch (e) {
|
||||
columnName = COOKIE_KEY_MAP[f.name];
|
||||
}
|
||||
|
|
|
@ -12,24 +12,6 @@ const { l10n } = require("devtools/client/webconsole/new-console-output/utils/me
|
|||
|
||||
add_task(function* () {
|
||||
let hud = yield openNewTabAndConsole(TEST_URI);
|
||||
|
||||
const store = hud.ui.newConsoleOutput.getStore();
|
||||
// Adding loggin each time the store is modified in order to check
|
||||
// the store state in case of failure.
|
||||
store.subscribe(() => {
|
||||
const messages = store.getState().messages.messagesById.toJS()
|
||||
.map(message => {
|
||||
return {
|
||||
id: message.id,
|
||||
type: message.type,
|
||||
parameters: message.parameters,
|
||||
messageText: message.messageText
|
||||
};
|
||||
}
|
||||
);
|
||||
info("messages : " + JSON.stringify(messages));
|
||||
});
|
||||
|
||||
const messageNumber = 100;
|
||||
yield testSimpleBatchLogging(hud, messageNumber);
|
||||
yield testBatchLoggingAndClear(hud, messageNumber);
|
||||
|
|
|
@ -95,7 +95,7 @@ function waitForMessages({ hud, messages }) {
|
|||
* @return object
|
||||
* A promise that is resolved with the result of the condition.
|
||||
*/
|
||||
function* waitFor(condition, message = "waitFor", interval = 100, maxTries = 50) {
|
||||
function* waitFor(condition, message = "waitFor", interval = 10, maxTries = 500) {
|
||||
return new Promise(resolve => {
|
||||
BrowserTestUtils.waitForCondition(condition, message, interval, maxTries)
|
||||
.then(() => resolve(condition()));
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* globals StopIteration */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, CC} = require("chrome");
|
||||
|
@ -93,7 +95,7 @@ var StorageActors = {};
|
|||
* - observe : Method which gets triggered on the notificaiton of the watched
|
||||
* topic.
|
||||
* - getNamesForHost : Given a host, get list of all known store names.
|
||||
* - getValuesForHost : Given a host (and optianally a name) get all known
|
||||
* - getValuesForHost : Given a host (and optionally a name) get all known
|
||||
* store objects.
|
||||
* - toStoreObject : Given a store object, convert it to the required format
|
||||
* so that it can be transferred over wire.
|
||||
|
@ -141,6 +143,9 @@ StorageActors.defaults = function (typeName, observationTopics) {
|
|||
* Converts the window.location object into host.
|
||||
*/
|
||||
getHostName(location) {
|
||||
if (location.protocol === "chrome:") {
|
||||
return location.href;
|
||||
}
|
||||
return location.hostname || location.href;
|
||||
},
|
||||
|
||||
|
@ -755,6 +760,7 @@ var cookieHelpers = {
|
|||
|
||||
let enumerator =
|
||||
Services.cookies.getCookiesFromHost(origHost, data.originAttributes || {});
|
||||
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let nsiCookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
|
||||
if (nsiCookie.name === origName &&
|
||||
|
@ -1052,6 +1058,9 @@ function getObjectForLocalOrSessionStorage(type) {
|
|||
if (!location.host) {
|
||||
return location.href;
|
||||
}
|
||||
if (location.protocol === "chrome:") {
|
||||
return location.href;
|
||||
}
|
||||
return location.protocol + "//" + location.host;
|
||||
},
|
||||
|
||||
|
@ -1264,6 +1273,9 @@ StorageActors.createActor({
|
|||
if (!location.host) {
|
||||
return location.href;
|
||||
}
|
||||
if (location.protocol === "chrome:") {
|
||||
return location.href;
|
||||
}
|
||||
return location.protocol + "//" + location.host;
|
||||
},
|
||||
|
||||
|
@ -1436,12 +1448,15 @@ ObjectStoreMetadata.prototype = {
|
|||
* The host associated with this indexed db.
|
||||
* @param {IDBDatabase} db
|
||||
* The particular indexed db.
|
||||
* @param {String} storage
|
||||
* Storage type, either "temporary", "default" or "persistent".
|
||||
*/
|
||||
function DatabaseMetadata(origin, db) {
|
||||
function DatabaseMetadata(origin, db, storage) {
|
||||
this._origin = origin;
|
||||
this._name = db.name;
|
||||
this._version = db.version;
|
||||
this._objectStores = [];
|
||||
this.storage = storage;
|
||||
|
||||
if (db.objectStoreNames.length) {
|
||||
let transaction = db.transaction(db.objectStoreNames, "readonly");
|
||||
|
@ -1461,7 +1476,7 @@ DatabaseMetadata.prototype = {
|
|||
|
||||
toObject() {
|
||||
return {
|
||||
name: this._name,
|
||||
name: `${this._name} (${this.storage})`,
|
||||
origin: this._origin,
|
||||
version: this._version,
|
||||
objectStores: this._objectStores.size
|
||||
|
@ -1541,6 +1556,9 @@ StorageActors.createActor({
|
|||
if (!location.host) {
|
||||
return location.href;
|
||||
}
|
||||
if (location.protocol === "chrome:") {
|
||||
return location.href;
|
||||
}
|
||||
return location.protocol + "//" + location.host;
|
||||
},
|
||||
|
||||
|
@ -1633,15 +1651,17 @@ StorageActors.createActor({
|
|||
populateStoresForHost: Task.async(function* (host) {
|
||||
let storeMap = new Map();
|
||||
let {names} = yield this.getDBNamesForHost(host);
|
||||
|
||||
let win = this.storageActor.getWindowFromHost(host);
|
||||
if (win) {
|
||||
let principal = win.document.nodePrincipal;
|
||||
|
||||
for (let name of names) {
|
||||
let metadata = yield this.getDBMetaData(host, principal, name);
|
||||
for (let {name, storage} of names) {
|
||||
let metadata = yield this.getDBMetaData(host, principal, name, storage);
|
||||
|
||||
metadata = indexedDBHelpers.patchMetadataMapsAndProtos(metadata);
|
||||
storeMap.set(name, metadata);
|
||||
|
||||
storeMap.set(`${name} (${storage})`, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1674,10 +1694,22 @@ StorageActors.createActor({
|
|||
objectStores: item.objectStores
|
||||
};
|
||||
}
|
||||
|
||||
let value = JSON.stringify(item.value);
|
||||
|
||||
// FIXME: Bug 1318029 - Due to a bug that is thrown whenever a
|
||||
// LongStringActor string reaches DebuggerServer.LONG_STRING_LENGTH we need
|
||||
// to trim the value. When the bug is fixed we should stop trimming the
|
||||
// string here.
|
||||
let maxLength = DebuggerServer.LONG_STRING_LENGTH - 1;
|
||||
if (value.length > maxLength) {
|
||||
value = value.substr(0, maxLength);
|
||||
}
|
||||
|
||||
// Indexed db entry
|
||||
return {
|
||||
name: item.name,
|
||||
value: new LongStringActor(this.conn, JSON.stringify(item.value))
|
||||
value: new LongStringActor(this.conn, value)
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -1713,16 +1745,18 @@ StorageActors.createActor({
|
|||
maybeSetupChildProcess() {
|
||||
if (!DebuggerServer.isInChildProcess) {
|
||||
this.backToChild = (func, rv) => rv;
|
||||
this.clearDBStore = indexedDBHelpers.clearDBStore;
|
||||
this.gatherFilesOrFolders = indexedDBHelpers.gatherFilesOrFolders;
|
||||
this.getDBMetaData = indexedDBHelpers.getDBMetaData;
|
||||
this.openWithPrincipal = indexedDBHelpers.openWithPrincipal;
|
||||
this.getDBNamesForHost = indexedDBHelpers.getDBNamesForHost;
|
||||
this.getSanitizedHost = indexedDBHelpers.getSanitizedHost;
|
||||
this.getNameFromDatabaseFile = indexedDBHelpers.getNameFromDatabaseFile;
|
||||
this.getValuesForHost = indexedDBHelpers.getValuesForHost;
|
||||
this.getObjectStoreData = indexedDBHelpers.getObjectStoreData;
|
||||
this.getSanitizedHost = indexedDBHelpers.getSanitizedHost;
|
||||
this.getValuesForHost = indexedDBHelpers.getValuesForHost;
|
||||
this.openWithPrincipal = indexedDBHelpers.openWithPrincipal;
|
||||
this.removeDB = indexedDBHelpers.removeDB;
|
||||
this.removeDBRecord = indexedDBHelpers.removeDBRecord;
|
||||
this.clearDBStore = indexedDBHelpers.clearDBStore;
|
||||
this.splitNameAndStorage = indexedDBHelpers.splitNameAndStorage;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1735,6 +1769,7 @@ StorageActors.createActor({
|
|||
});
|
||||
|
||||
this.getDBMetaData = callParentProcessAsync.bind(null, "getDBMetaData");
|
||||
this.splitNameAndStorage = callParentProcessAsync.bind(null, "splitNameAndStorage");
|
||||
this.getDBNamesForHost = callParentProcessAsync.bind(null, "getDBNamesForHost");
|
||||
this.getValuesForHost = callParentProcessAsync.bind(null, "getValuesForHost");
|
||||
this.removeDB = callParentProcessAsync.bind(null, "removeDB");
|
||||
|
@ -1830,14 +1865,13 @@ var indexedDBHelpers = {
|
|||
* `name` for the given `host` with its `principal`. The stored metadata
|
||||
* information is of `DatabaseMetadata` type.
|
||||
*/
|
||||
getDBMetaData: Task.async(function* (host, principal, name) {
|
||||
let request = this.openWithPrincipal(principal, name);
|
||||
getDBMetaData: Task.async(function* (host, principal, name, storage) {
|
||||
let request = this.openWithPrincipal(principal, name, storage);
|
||||
let success = promise.defer();
|
||||
|
||||
request.onsuccess = event => {
|
||||
let db = event.target.result;
|
||||
|
||||
let dbData = new DatabaseMetadata(host, db);
|
||||
let dbData = new DatabaseMetadata(host, db, storage);
|
||||
db.close();
|
||||
|
||||
success.resolve(this.backToChild("getDBMetaData", dbData));
|
||||
|
@ -1850,21 +1884,37 @@ var indexedDBHelpers = {
|
|||
return success.promise;
|
||||
}),
|
||||
|
||||
splitNameAndStorage: function (name) {
|
||||
let lastOpenBracketIndex = name.lastIndexOf("(");
|
||||
let lastCloseBracketIndex = name.lastIndexOf(")");
|
||||
let delta = lastCloseBracketIndex - lastOpenBracketIndex - 1;
|
||||
|
||||
let storage = name.substr(lastOpenBracketIndex + 1, delta);
|
||||
|
||||
name = name.substr(0, lastOpenBracketIndex - 1);
|
||||
|
||||
return { storage, name };
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens an indexed db connection for the given `principal` and
|
||||
* database `name`.
|
||||
*/
|
||||
openWithPrincipal(principal, name) {
|
||||
return indexedDBForStorage.openForPrincipal(principal, name);
|
||||
openWithPrincipal: function (principal, name, storage) {
|
||||
return indexedDBForStorage.openForPrincipal(principal, name,
|
||||
{ storage: storage });
|
||||
},
|
||||
|
||||
removeDB: Task.async(function* (host, principal, name) {
|
||||
removeDB: Task.async(function* (host, principal, dbName) {
|
||||
let result = new promise(resolve => {
|
||||
let request = indexedDBForStorage.deleteForPrincipal(principal, name);
|
||||
let {name, storage} = this.splitNameAndStorage(dbName);
|
||||
let request =
|
||||
indexedDBForStorage.deleteForPrincipal(principal, name,
|
||||
{ storage: storage });
|
||||
|
||||
request.onsuccess = () => {
|
||||
resolve({});
|
||||
this.onItemUpdated("deleted", host, [name]);
|
||||
this.onItemUpdated("deleted", host, [dbName]);
|
||||
};
|
||||
|
||||
request.onblocked = () => {
|
||||
|
@ -1890,10 +1940,11 @@ var indexedDBHelpers = {
|
|||
|
||||
removeDBRecord: Task.async(function* (host, principal, dbName, storeName, id) {
|
||||
let db;
|
||||
let {name, storage} = this.splitNameAndStorage(dbName);
|
||||
|
||||
try {
|
||||
db = yield new promise((resolve, reject) => {
|
||||
let request = this.openWithPrincipal(principal, dbName);
|
||||
let request = this.openWithPrincipal(principal, name, storage);
|
||||
request.onsuccess = ev => resolve(ev.target.result);
|
||||
request.onerror = ev => reject(ev.target.error);
|
||||
});
|
||||
|
@ -1922,10 +1973,11 @@ var indexedDBHelpers = {
|
|||
|
||||
clearDBStore: Task.async(function* (host, principal, dbName, storeName) {
|
||||
let db;
|
||||
let {name, storage} = this.splitNameAndStorage(dbName);
|
||||
|
||||
try {
|
||||
db = yield new promise((resolve, reject) => {
|
||||
let request = this.openWithPrincipal(principal, dbName);
|
||||
let request = this.openWithPrincipal(principal, name, storage);
|
||||
request.onsuccess = ev => resolve(ev.target.result);
|
||||
request.onerror = ev => reject(ev.target.error);
|
||||
});
|
||||
|
@ -1957,46 +2009,107 @@ var indexedDBHelpers = {
|
|||
*/
|
||||
getDBNamesForHost: Task.async(function* (host) {
|
||||
let sanitizedHost = this.getSanitizedHost(host);
|
||||
let directory = OS.Path.join(OS.Constants.Path.profileDir, "storage",
|
||||
"default", sanitizedHost, "idb");
|
||||
|
||||
let exists = yield OS.File.exists(directory);
|
||||
if (!exists && host.startsWith("about:")) {
|
||||
// try for moz-safe-about directory
|
||||
sanitizedHost = this.getSanitizedHost("moz-safe-" + host);
|
||||
directory = OS.Path.join(OS.Constants.Path.profileDir, "storage",
|
||||
"permanent", sanitizedHost, "idb");
|
||||
exists = yield OS.File.exists(directory);
|
||||
}
|
||||
if (!exists) {
|
||||
return this.backToChild("getDBNamesForHost", {names: []});
|
||||
}
|
||||
|
||||
let profileDir = OS.Constants.Path.profileDir;
|
||||
let files = [];
|
||||
let names = [];
|
||||
let dirIterator = new OS.File.DirectoryIterator(directory);
|
||||
try {
|
||||
yield dirIterator.forEach(file => {
|
||||
// Skip directories.
|
||||
if (file.isDir) {
|
||||
return null;
|
||||
}
|
||||
let storagePath = OS.Path.join(profileDir, "storage");
|
||||
|
||||
// Skip any non-sqlite files.
|
||||
if (!file.name.endsWith(".sqlite")) {
|
||||
return null;
|
||||
}
|
||||
// We expect sqlite DB paths to look something like this:
|
||||
// - PathToProfileDir/storage/default/http+++www.example.com/
|
||||
// idb/1556056096MeysDaabta.sqlite
|
||||
// - PathToProfileDir/storage/permanent/http+++www.example.com/
|
||||
// idb/1556056096MeysDaabta.sqlite
|
||||
// - PathToProfileDir/storage/temporary/http+++www.example.com/
|
||||
// idb/1556056096MeysDaabta.sqlite
|
||||
//
|
||||
// The subdirectory inside the storage folder is determined by the storage
|
||||
// type:
|
||||
// - default: { storage: "default" } or not specified.
|
||||
// - permanent: { storage: "persistent" }.
|
||||
// - temporary: { storage: "temporary" }.
|
||||
let sqliteFiles = yield this.gatherFilesOrFolders(storagePath, path => {
|
||||
if (path.endsWith(".sqlite")) {
|
||||
let { components } = OS.Path.split(path);
|
||||
let isIDB = components[components.length - 2] === "idb";
|
||||
|
||||
return this.getNameFromDatabaseFile(file.path).then(name => {
|
||||
if (name) {
|
||||
names.push(name);
|
||||
}
|
||||
return null;
|
||||
return isIDB;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
for (let file of sqliteFiles) {
|
||||
let splitPath = OS.Path.split(file).components;
|
||||
let idbIndex = splitPath.indexOf("idb");
|
||||
let name = splitPath[idbIndex - 1];
|
||||
let storage = splitPath[idbIndex - 2];
|
||||
let relative = file.substr(profileDir.length + 1);
|
||||
|
||||
if (name.startsWith(sanitizedHost)) {
|
||||
files.push({
|
||||
file: relative,
|
||||
storage: storage === "permanent" ? "persistent" : storage
|
||||
});
|
||||
});
|
||||
} finally {
|
||||
dirIterator.close();
|
||||
}
|
||||
}
|
||||
return this.backToChild("getDBNamesForHost", {names: names});
|
||||
|
||||
if (files.length > 0) {
|
||||
for (let {file, storage} of files) {
|
||||
let name = yield this.getNameFromDatabaseFile(file);
|
||||
if (name) {
|
||||
names.push({
|
||||
name,
|
||||
storage
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.backToChild("getDBNamesForHost", {names});
|
||||
}),
|
||||
|
||||
/**
|
||||
* Gather together all of the files in path and pass each path through a
|
||||
* validation function.
|
||||
*
|
||||
* @param {String}
|
||||
* Path in which to begin searching.
|
||||
* @param {Function}
|
||||
* Validation function, which checks each file path. If this function
|
||||
* Returns true the file path is kept.
|
||||
*
|
||||
* @returns {Array}
|
||||
* An array of file paths.
|
||||
*/
|
||||
gatherFilesOrFolders: Task.async(function* (path, validationFunc) {
|
||||
let files = [];
|
||||
let iterator;
|
||||
let paths = [path];
|
||||
|
||||
while (paths.length > 0) {
|
||||
try {
|
||||
iterator = new OS.File.DirectoryIterator(paths.pop());
|
||||
|
||||
for (let child in iterator) {
|
||||
child = yield child;
|
||||
|
||||
path = child.path;
|
||||
|
||||
if (child.isDir) {
|
||||
paths.push(path);
|
||||
} else if (validationFunc(path)) {
|
||||
files.push(path);
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
// Ignore StopIteration to prevent exiting the loop.
|
||||
if (ex != StopIteration) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
iterator.close();
|
||||
|
||||
return files;
|
||||
}),
|
||||
|
||||
/**
|
||||
|
@ -2004,6 +2117,9 @@ var indexedDBHelpers = {
|
|||
* name.
|
||||
*/
|
||||
getSanitizedHost(host) {
|
||||
if (host.startsWith("about:")) {
|
||||
host = "moz-safe-" + host;
|
||||
}
|
||||
return host.replace(ILLEGAL_CHAR_REGEX, "+");
|
||||
},
|
||||
|
||||
|
@ -2017,7 +2133,7 @@ var indexedDBHelpers = {
|
|||
|
||||
// Content pages might be having an open transaction for the same indexed db
|
||||
// which this sqlite file belongs to. In that case, sqlite.openConnection
|
||||
// will throw. Thus we retey for some time to see if lock is removed.
|
||||
// will throw. Thus we retry for some time to see if lock is removed.
|
||||
while (!connection && retryCount++ < 25) {
|
||||
try {
|
||||
connection = yield Sqlite.openConnection({ path: path });
|
||||
|
@ -2078,8 +2194,14 @@ var indexedDBHelpers = {
|
|||
return this.backToChild("getValuesForHost", {objectStores: objectStores});
|
||||
}
|
||||
// Get either all entries from the object store, or a particular id
|
||||
let result = yield this.getObjectStoreData(host, principal, db2,
|
||||
objectStore, id, options.index, options.size);
|
||||
let storage = hostVsStores.get(host).get(db2).storage;
|
||||
let result = yield this.getObjectStoreData(host, principal, db2, storage, {
|
||||
objectStore: objectStore,
|
||||
id: id,
|
||||
index: options.index,
|
||||
offset: 0,
|
||||
size: options.size
|
||||
});
|
||||
return this.backToChild("getValuesForHost", {result: result});
|
||||
}),
|
||||
|
||||
|
@ -2093,23 +2215,27 @@ var indexedDBHelpers = {
|
|||
* The principal of the given document.
|
||||
* @param {string} dbName
|
||||
* The name of the indexed db from the above host.
|
||||
* @param {string} objectStore
|
||||
* The name of the object store from the above db.
|
||||
* @param {string} id
|
||||
* id of the requested entry from the above object store.
|
||||
* null if all entries from the above object store are requested.
|
||||
* @param {string} index
|
||||
* name of the IDBIndex to be iterated on while fetching entries.
|
||||
* null or "name" if no index is to be iterated.
|
||||
* @param {number} offset
|
||||
* ofsset of the entries to be fetched.
|
||||
* @param {number} size
|
||||
* The intended size of the entries to be fetched.
|
||||
* @param {String} storage
|
||||
* Storage type, either "temporary", "default" or "persistent".
|
||||
* @param {Object} requestOptions
|
||||
* An object in the following format:
|
||||
* {
|
||||
* objectStore: The name of the object store from the above db,
|
||||
* id: Id of the requested entry from the above object
|
||||
* store. null if all entries from the above object
|
||||
* store are requested,
|
||||
* index: Name of the IDBIndex to be iterated on while fetching
|
||||
* entries. null or "name" if no index is to be
|
||||
* iterated,
|
||||
* offset: offset of the entries to be fetched,
|
||||
* size: The intended size of the entries to be fetched
|
||||
* }
|
||||
*/
|
||||
getObjectStoreData(host, principal, dbName, objectStore, id, index,
|
||||
offset, size) {
|
||||
let request = this.openWithPrincipal(principal, dbName);
|
||||
getObjectStoreData(host, principal, dbName, storage, requestOptions) {
|
||||
let {name} = this.splitNameAndStorage(dbName);
|
||||
let request = this.openWithPrincipal(principal, name, storage);
|
||||
let success = promise.defer();
|
||||
let {objectStore, id, index, offset, size} = requestOptions;
|
||||
let data = [];
|
||||
let db;
|
||||
|
||||
|
@ -2211,8 +2337,12 @@ var indexedDBHelpers = {
|
|||
|
||||
switch (msg.json.method) {
|
||||
case "getDBMetaData": {
|
||||
let [host, principal, name] = args;
|
||||
return indexedDBHelpers.getDBMetaData(host, principal, name);
|
||||
let [host, principal, name, storage] = args;
|
||||
return indexedDBHelpers.getDBMetaData(host, principal, name, storage);
|
||||
}
|
||||
case "splitNameAndStorage": {
|
||||
let [name] = args;
|
||||
return indexedDBHelpers.splitNameAndStorage(name);
|
||||
}
|
||||
case "getDBNamesForHost": {
|
||||
let [host] = args;
|
||||
|
@ -2224,8 +2354,8 @@ var indexedDBHelpers = {
|
|||
hostVsStores, principal);
|
||||
}
|
||||
case "removeDB": {
|
||||
let [host, principal, name] = args;
|
||||
return indexedDBHelpers.removeDB(host, principal, name);
|
||||
let [host, principal, dbName] = args;
|
||||
return indexedDBHelpers.removeDB(host, principal, dbName);
|
||||
}
|
||||
case "removeDBRecord": {
|
||||
let [host, principal, db, store, id] = args;
|
||||
|
|
|
@ -121,24 +121,24 @@ const storeMap = {
|
|||
const IDBValues = {
|
||||
listStoresResponse: {
|
||||
"http://test1.example.org": [
|
||||
["idb1", "obj1"], ["idb1", "obj2"], ["idb2", "obj3"]
|
||||
["idb1 (default)", "obj1"], ["idb1 (default)", "obj2"], ["idb2 (default)", "obj3"]
|
||||
],
|
||||
"http://sectest1.example.org": [
|
||||
],
|
||||
"https://sectest1.example.org": [
|
||||
["idb-s1", "obj-s1"], ["idb-s2", "obj-s2"]
|
||||
["idb-s1 (default)", "obj-s1"], ["idb-s2 (default)", "obj-s2"]
|
||||
]
|
||||
},
|
||||
dbDetails : {
|
||||
dbDetails: {
|
||||
"http://test1.example.org": [
|
||||
{
|
||||
db: "idb1",
|
||||
db: "idb1 (default)",
|
||||
origin: "http://test1.example.org",
|
||||
version: 1,
|
||||
objectStores: 2
|
||||
},
|
||||
{
|
||||
db: "idb2",
|
||||
db: "idb2 (default)",
|
||||
origin: "http://test1.example.org",
|
||||
version: 1,
|
||||
objectStores: 1
|
||||
|
@ -148,13 +148,13 @@ const IDBValues = {
|
|||
],
|
||||
"https://sectest1.example.org": [
|
||||
{
|
||||
db: "idb-s1",
|
||||
db: "idb-s1 (default)",
|
||||
origin: "https://sectest1.example.org",
|
||||
version: 1,
|
||||
objectStores: 1
|
||||
},
|
||||
{
|
||||
db: "idb-s2",
|
||||
db: "idb-s2 (default)",
|
||||
origin: "https://sectest1.example.org",
|
||||
version: 1,
|
||||
objectStores: 1
|
||||
|
@ -163,7 +163,7 @@ const IDBValues = {
|
|||
},
|
||||
objectStoreDetails: {
|
||||
"http://test1.example.org": {
|
||||
idb1: [
|
||||
"idb1 (default)": [
|
||||
{
|
||||
objectStore: "obj1",
|
||||
keyPath: "id",
|
||||
|
@ -190,7 +190,7 @@ const IDBValues = {
|
|||
indexes: []
|
||||
}
|
||||
],
|
||||
idb2: [
|
||||
"idb2 (default)": [
|
||||
{
|
||||
objectStore: "obj3",
|
||||
keyPath: "id3",
|
||||
|
@ -208,7 +208,7 @@ const IDBValues = {
|
|||
},
|
||||
"http://sectest1.example.org" : {},
|
||||
"https://sectest1.example.org": {
|
||||
"idb-s1": [
|
||||
"idb-s1 (default)": [
|
||||
{
|
||||
objectStore: "obj-s1",
|
||||
keyPath: "id",
|
||||
|
@ -216,7 +216,7 @@ const IDBValues = {
|
|||
indexes: []
|
||||
},
|
||||
],
|
||||
"idb-s2": [
|
||||
"idb-s2 (default)": [
|
||||
{
|
||||
objectStore: "obj-s2",
|
||||
keyPath: "id3",
|
||||
|
@ -236,7 +236,7 @@ const IDBValues = {
|
|||
},
|
||||
entries: {
|
||||
"http://test1.example.org": {
|
||||
"idb1#obj1": [
|
||||
"idb1 (default)#obj1": [
|
||||
{
|
||||
name: 1,
|
||||
value: {
|
||||
|
@ -262,7 +262,7 @@ const IDBValues = {
|
|||
}
|
||||
}
|
||||
],
|
||||
"idb1#obj2": [
|
||||
"idb1 (default)#obj2": [
|
||||
{
|
||||
name: 1,
|
||||
value: {
|
||||
|
@ -273,11 +273,11 @@ const IDBValues = {
|
|||
}
|
||||
}
|
||||
],
|
||||
"idb2#obj3": []
|
||||
"idb2 (default)#obj3": []
|
||||
},
|
||||
"http://sectest1.example.org" : {},
|
||||
"https://sectest1.example.org": {
|
||||
"idb-s1#obj-s1": [
|
||||
"idb-s1 (default)#obj-s1": [
|
||||
{
|
||||
name: 6,
|
||||
value: {
|
||||
|
@ -295,7 +295,7 @@ const IDBValues = {
|
|||
}
|
||||
}
|
||||
],
|
||||
"idb-s2#obj-s2": [
|
||||
"idb-s2 (default)#obj-s2": [
|
||||
{
|
||||
name: 13,
|
||||
value: {
|
||||
|
|
|
@ -61,7 +61,7 @@ types.addDictType("cookiestoreobject", {
|
|||
|
||||
// Common methods for edit/remove
|
||||
const editRemoveMethods = {
|
||||
getEditableFields: {
|
||||
getFields: {
|
||||
request: {},
|
||||
response: {
|
||||
value: RetVal("json")
|
||||
|
|
|
@ -74,7 +74,16 @@ MediaShutdownManager::EnsureCorrectShutdownObserverState()
|
|||
nsresult rv = GetShutdownBarrier()->AddBlocker(
|
||||
this, NS_LITERAL_STRING(__FILE__), __LINE__,
|
||||
NS_LITERAL_STRING("MediaShutdownManager shutdown"));
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv)) {
|
||||
// Leak the buffer on the heap to make sure that it lives long enough,
|
||||
// as MOZ_CRASH_ANNOTATE expects the pointer passed to it to live to
|
||||
// the end of the program.
|
||||
const size_t CAPACITY = 256;
|
||||
auto buf = new char[CAPACITY];
|
||||
snprintf(buf, CAPACITY, "Failed to add shutdown blocker! rv=%x", uint32_t(rv));
|
||||
MOZ_CRASH_ANNOTATE(buf);
|
||||
MOZ_REALLY_CRASH();
|
||||
}
|
||||
} else {
|
||||
GetShutdownBarrier()->RemoveBlocker(this);
|
||||
// Clear our singleton reference. This will probably delete
|
||||
|
@ -89,7 +98,7 @@ void
|
|||
MediaShutdownManager::Register(MediaDecoder* aDecoder)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mIsDoingXPCOMShutDown);
|
||||
MOZ_RELEASE_ASSERT(!mIsDoingXPCOMShutDown);
|
||||
// Don't call Register() after you've Unregistered() all the decoders,
|
||||
// that's not going to work.
|
||||
MOZ_ASSERT(!mDecoders.Contains(aDecoder));
|
||||
|
|
|
@ -1548,7 +1548,8 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
|||
stateenum.addId(_deadState().name)
|
||||
stateenum.addId(_nullState().name)
|
||||
stateenum.addId(_errorState().name)
|
||||
stateenum.addId(_dyingState().name)
|
||||
if self.protocol.decl.type.hasReentrantDelete:
|
||||
stateenum.addId(_dyingState().name)
|
||||
for ts in p.transitionStmts:
|
||||
stateenum.addId(ts.state.decl.cxxname)
|
||||
if len(p.transitionStmts):
|
||||
|
@ -1769,19 +1770,15 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
|
|||
fromswitch.addcase(CaseLabel(_deadState().name), deadblock)
|
||||
|
||||
# special case for Dying
|
||||
dyingblock = Block()
|
||||
if ptype.hasReentrantDelete:
|
||||
dyingblock = Block()
|
||||
ifdelete = StmtIf(ExprBinary(_deleteReplyId(), '==', msgexpr))
|
||||
ifdelete.addifstmt(
|
||||
StmtExpr(ExprAssn(ExprDeref(nextvar), _deadState())))
|
||||
dyingblock.addstmt(ifdelete)
|
||||
dyingblock.addstmt(
|
||||
StmtReturn(ExprLiteral.TRUE))
|
||||
else:
|
||||
dyingblock.addstmts([
|
||||
_logicError('__delete__()d (and unexpectedly dying) actor'),
|
||||
StmtReturn(ExprLiteral.FALSE) ])
|
||||
fromswitch.addcase(CaseLabel(_dyingState().name), dyingblock)
|
||||
fromswitch.addcase(CaseLabel(_dyingState().name), dyingblock)
|
||||
|
||||
unreachedblock = Block()
|
||||
unreachedblock.addstmts([
|
||||
|
|
|
@ -7,11 +7,6 @@ from ply import lex, yacc
|
|||
|
||||
from ipdl.ast import *
|
||||
|
||||
def _getcallerpath():
|
||||
'''Return the absolute path of the file containing the code that
|
||||
**CALLED** this function.'''
|
||||
return os.path.abspath(sys._getframe(1).f_code.co_filename)
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
|
||||
class ParseError(Exception):
|
||||
|
|
|
@ -104,6 +104,18 @@ Char16ToUChar(char16_t* chars)
|
|||
MOZ_CRASH("Char16ToUChar: Intl API disabled");
|
||||
}
|
||||
|
||||
inline char16_t*
|
||||
UCharToChar16(UChar* chars)
|
||||
{
|
||||
MOZ_CRASH("UCharToChar16: Intl API disabled");
|
||||
}
|
||||
|
||||
inline const char16_t*
|
||||
UCharToChar16(const UChar* chars)
|
||||
{
|
||||
MOZ_CRASH("UCharToChar16: Intl API disabled");
|
||||
}
|
||||
|
||||
struct UEnumeration;
|
||||
|
||||
int32_t
|
||||
|
@ -352,6 +364,27 @@ enum UCalendarDateFields {
|
|||
UCAL_DAY_OF_MONTH = UCAL_DATE
|
||||
};
|
||||
|
||||
enum UCalendarMonths {
|
||||
UCAL_JANUARY,
|
||||
UCAL_FEBRUARY,
|
||||
UCAL_MARCH,
|
||||
UCAL_APRIL,
|
||||
UCAL_MAY,
|
||||
UCAL_JUNE,
|
||||
UCAL_JULY,
|
||||
UCAL_AUGUST,
|
||||
UCAL_SEPTEMBER,
|
||||
UCAL_OCTOBER,
|
||||
UCAL_NOVEMBER,
|
||||
UCAL_DECEMBER,
|
||||
UCAL_UNDECIMBER
|
||||
};
|
||||
|
||||
enum UCalendarAMPMs {
|
||||
UCAL_AM,
|
||||
UCAL_PM
|
||||
};
|
||||
|
||||
UCalendar*
|
||||
ucal_open(const UChar* zoneID, int32_t len, const char* locale,
|
||||
UCalendarType type, UErrorCode* status)
|
||||
|
@ -416,6 +449,13 @@ ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* statu
|
|||
MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled");
|
||||
}
|
||||
|
||||
enum UDateTimePatternField {
|
||||
UDATPG_YEAR_FIELD,
|
||||
UDATPG_MONTH_FIELD,
|
||||
UDATPG_WEEK_OF_YEAR_FIELD,
|
||||
UDATPG_DAY_FIELD,
|
||||
};
|
||||
|
||||
typedef void* UDateTimePatternGenerator;
|
||||
|
||||
UDateTimePatternGenerator*
|
||||
|
@ -432,6 +472,14 @@ udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton,
|
|||
MOZ_CRASH("udatpg_getBestPattern: Intl API disabled");
|
||||
}
|
||||
|
||||
static const UChar *
|
||||
udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg,
|
||||
UDateTimePatternField field,
|
||||
int32_t *pLength)
|
||||
{
|
||||
MOZ_CRASH("udatpg_getAppendItemName: Intl API disabled");
|
||||
}
|
||||
|
||||
void
|
||||
udatpg_close(UDateTimePatternGenerator* dtpg)
|
||||
{
|
||||
|
@ -484,10 +532,46 @@ enum UDateFormatField {
|
|||
};
|
||||
|
||||
enum UDateFormatStyle {
|
||||
UDAT_FULL,
|
||||
UDAT_LONG,
|
||||
UDAT_MEDIUM,
|
||||
UDAT_SHORT,
|
||||
UDAT_DEFAULT = UDAT_MEDIUM,
|
||||
UDAT_PATTERN = -2,
|
||||
UDAT_IGNORE = UDAT_PATTERN
|
||||
};
|
||||
|
||||
enum UDateFormatSymbolType {
|
||||
UDAT_ERAS,
|
||||
UDAT_MONTHS,
|
||||
UDAT_SHORT_MONTHS,
|
||||
UDAT_WEEKDAYS,
|
||||
UDAT_SHORT_WEEKDAYS,
|
||||
UDAT_AM_PMS,
|
||||
UDAT_LOCALIZED_CHARS,
|
||||
UDAT_ERA_NAMES,
|
||||
UDAT_NARROW_MONTHS,
|
||||
UDAT_NARROW_WEEKDAYS,
|
||||
UDAT_STANDALONE_MONTHS,
|
||||
UDAT_STANDALONE_SHORT_MONTHS,
|
||||
UDAT_STANDALONE_NARROW_MONTHS,
|
||||
UDAT_STANDALONE_WEEKDAYS,
|
||||
UDAT_STANDALONE_SHORT_WEEKDAYS,
|
||||
UDAT_STANDALONE_NARROW_WEEKDAYS,
|
||||
UDAT_QUARTERS,
|
||||
UDAT_SHORT_QUARTERS,
|
||||
UDAT_STANDALONE_QUARTERS,
|
||||
UDAT_STANDALONE_SHORT_QUARTERS,
|
||||
UDAT_SHORTER_WEEKDAYS,
|
||||
UDAT_STANDALONE_SHORTER_WEEKDAYS,
|
||||
UDAT_CYCLIC_YEARS_WIDE,
|
||||
UDAT_CYCLIC_YEARS_ABBREVIATED,
|
||||
UDAT_CYCLIC_YEARS_NARROW,
|
||||
UDAT_ZODIAC_NAMES_WIDE,
|
||||
UDAT_ZODIAC_NAMES_ABBREVIATED,
|
||||
UDAT_ZODIAC_NAMES_NARROW
|
||||
};
|
||||
|
||||
int32_t
|
||||
udat_countAvailable()
|
||||
{
|
||||
|
@ -561,6 +645,13 @@ udat_close(UDateFormat* format)
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
static int32_t
|
||||
udat_getSymbols(const UDateFormat *fmt, UDateFormatSymbolType type, int32_t symbolIndex,
|
||||
UChar *result, int32_t resultLength, UErrorCode *status)
|
||||
{
|
||||
MOZ_CRASH("udat_getSymbols: Intl API disabled");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -2922,6 +3013,296 @@ js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
inline bool
|
||||
MatchPart(const char** pattern, const char (&part)[N])
|
||||
{
|
||||
if (strncmp(*pattern, part, N - 1))
|
||||
return false;
|
||||
|
||||
*pattern += N - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 3);
|
||||
// 1. Assert: locale is a string.
|
||||
MOZ_ASSERT(args[0].isString());
|
||||
// 2. Assert: style is a string.
|
||||
MOZ_ASSERT(args[1].isString());
|
||||
// 3. Assert: keys is an Array.
|
||||
MOZ_ASSERT(args[2].isObject());
|
||||
|
||||
JSAutoByteString locale(cx, args[0].toString());
|
||||
if (!locale)
|
||||
return false;
|
||||
|
||||
JSAutoByteString style(cx, args[1].toString());
|
||||
if (!style)
|
||||
return false;
|
||||
|
||||
RootedArrayObject keys(cx, &args[2].toObject().as<ArrayObject>());
|
||||
if (!keys)
|
||||
return false;
|
||||
|
||||
// 4. Let result be ArrayCreate(0).
|
||||
RootedArrayObject result(cx, NewDenseUnallocatedArray(cx, keys->length()));
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
UDateFormat* fmt =
|
||||
udat_open(UDAT_DEFAULT, UDAT_DEFAULT, icuLocale(locale.ptr()),
|
||||
nullptr, 0, nullptr, 0, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||
return false;
|
||||
}
|
||||
ScopedICUObject<UDateFormat, udat_close> datToClose(fmt);
|
||||
|
||||
// UDateTimePatternGenerator will be needed for translations of date and
|
||||
// time fields like "month", "week", "day" etc.
|
||||
UDateTimePatternGenerator* dtpg = udatpg_open(icuLocale(locale.ptr()), &status);
|
||||
if (U_FAILURE(status)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||
return false;
|
||||
}
|
||||
ScopedICUObject<UDateTimePatternGenerator, udatpg_close> datPgToClose(dtpg);
|
||||
|
||||
RootedValue keyValue(cx);
|
||||
RootedString keyValStr(cx);
|
||||
RootedValue wordVal(cx);
|
||||
Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
|
||||
if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
|
||||
return false;
|
||||
|
||||
// 5. For each element of keys,
|
||||
for (uint32_t i = 0; i < keys->length(); i++) {
|
||||
/**
|
||||
* We iterate over keys array looking for paths that we have code
|
||||
* branches for.
|
||||
*
|
||||
* For any unknown path branch, the wordVal will keep NullValue and
|
||||
* we'll throw at the end.
|
||||
*/
|
||||
|
||||
if (!GetElement(cx, keys, keys, i, &keyValue))
|
||||
return false;
|
||||
|
||||
JSAutoByteString pattern;
|
||||
keyValStr = keyValue.toString();
|
||||
if (!pattern.encodeUtf8(cx, keyValStr))
|
||||
return false;
|
||||
|
||||
wordVal.setNull();
|
||||
|
||||
// 5.a. Perform an implementation dependent algorithm to map a key to a
|
||||
// corresponding display name.
|
||||
const char* pat = pattern.ptr();
|
||||
|
||||
if (!MatchPart(&pat, "dates")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MatchPart(&pat, "/")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MatchPart(&pat, "fields")) {
|
||||
if (!MatchPart(&pat, "/")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
UDateTimePatternField fieldType;
|
||||
|
||||
if (MatchPart(&pat, "year")) {
|
||||
fieldType = UDATPG_YEAR_FIELD;
|
||||
} else if (MatchPart(&pat, "month")) {
|
||||
fieldType = UDATPG_MONTH_FIELD;
|
||||
} else if (MatchPart(&pat, "week")) {
|
||||
fieldType = UDATPG_WEEK_OF_YEAR_FIELD;
|
||||
} else if (MatchPart(&pat, "day")) {
|
||||
fieldType = UDATPG_DAY_FIELD;
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
// This part must be the final part with no trailing data.
|
||||
if (*pat != '\0') {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t resultSize;
|
||||
|
||||
const UChar* value = udatpg_getAppendItemName(dtpg, fieldType, &resultSize);
|
||||
if (U_FAILURE(status)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* word = NewStringCopyN<CanGC>(cx, UCharToChar16(value), resultSize);
|
||||
if (!word)
|
||||
return false;
|
||||
|
||||
wordVal.setString(word);
|
||||
} else if (MatchPart(&pat, "gregorian")) {
|
||||
if (!MatchPart(&pat, "/")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
UDateFormatSymbolType symbolType;
|
||||
int32_t index;
|
||||
|
||||
if (MatchPart(&pat, "months")) {
|
||||
if (!MatchPart(&pat, "/")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (equal(style, "narrow")) {
|
||||
symbolType = UDAT_STANDALONE_NARROW_MONTHS;
|
||||
} else if (equal(style, "short")) {
|
||||
symbolType = UDAT_STANDALONE_SHORT_MONTHS;
|
||||
} else {
|
||||
MOZ_ASSERT(equal(style, "long"));
|
||||
symbolType = UDAT_STANDALONE_MONTHS;
|
||||
}
|
||||
|
||||
if (MatchPart(&pat, "january")) {
|
||||
index = UCAL_JANUARY;
|
||||
} else if (MatchPart(&pat, "february")) {
|
||||
index = UCAL_FEBRUARY;
|
||||
} else if (MatchPart(&pat, "march")) {
|
||||
index = UCAL_MARCH;
|
||||
} else if (MatchPart(&pat, "april")) {
|
||||
index = UCAL_APRIL;
|
||||
} else if (MatchPart(&pat, "may")) {
|
||||
index = UCAL_MAY;
|
||||
} else if (MatchPart(&pat, "june")) {
|
||||
index = UCAL_JUNE;
|
||||
} else if (MatchPart(&pat, "july")) {
|
||||
index = UCAL_JULY;
|
||||
} else if (MatchPart(&pat, "august")) {
|
||||
index = UCAL_AUGUST;
|
||||
} else if (MatchPart(&pat, "september")) {
|
||||
index = UCAL_SEPTEMBER;
|
||||
} else if (MatchPart(&pat, "october")) {
|
||||
index = UCAL_OCTOBER;
|
||||
} else if (MatchPart(&pat, "november")) {
|
||||
index = UCAL_NOVEMBER;
|
||||
} else if (MatchPart(&pat, "december")) {
|
||||
index = UCAL_DECEMBER;
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
} else if (MatchPart(&pat, "weekdays")) {
|
||||
if (!MatchPart(&pat, "/")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (equal(style, "narrow")) {
|
||||
symbolType = UDAT_STANDALONE_NARROW_WEEKDAYS;
|
||||
} else if (equal(style, "short")) {
|
||||
symbolType = UDAT_STANDALONE_SHORT_WEEKDAYS;
|
||||
} else {
|
||||
MOZ_ASSERT(equal(style, "long"));
|
||||
symbolType = UDAT_STANDALONE_WEEKDAYS;
|
||||
}
|
||||
|
||||
if (MatchPart(&pat, "monday")) {
|
||||
index = UCAL_MONDAY;
|
||||
} else if (MatchPart(&pat, "tuesday")) {
|
||||
index = UCAL_TUESDAY;
|
||||
} else if (MatchPart(&pat, "wednesday")) {
|
||||
index = UCAL_WEDNESDAY;
|
||||
} else if (MatchPart(&pat, "thursday")) {
|
||||
index = UCAL_THURSDAY;
|
||||
} else if (MatchPart(&pat, "friday")) {
|
||||
index = UCAL_FRIDAY;
|
||||
} else if (MatchPart(&pat, "saturday")) {
|
||||
index = UCAL_SATURDAY;
|
||||
} else if (MatchPart(&pat, "sunday")) {
|
||||
index = UCAL_SUNDAY;
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
} else if (MatchPart(&pat, "dayperiods")) {
|
||||
if (!MatchPart(&pat, "/")) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
symbolType = UDAT_AM_PMS;
|
||||
|
||||
if (MatchPart(&pat, "am")) {
|
||||
index = UCAL_AM;
|
||||
} else if (MatchPart(&pat, "pm")) {
|
||||
index = UCAL_PM;
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
// This part must be the final part with no trailing data.
|
||||
if (*pat != '\0') {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t resultSize =
|
||||
udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()),
|
||||
INITIAL_CHAR_BUFFER_SIZE, &status);
|
||||
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
||||
if (!chars.resize(resultSize))
|
||||
return false;
|
||||
status = U_ZERO_ERROR;
|
||||
udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()),
|
||||
resultSize, &status);
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* word = NewStringCopyN<CanGC>(cx, chars.begin(), resultSize);
|
||||
if (!word)
|
||||
return false;
|
||||
|
||||
wordVal.setString(word);
|
||||
} else {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(wordVal.isString());
|
||||
|
||||
// 5.b. Append the result string to result.
|
||||
if (!DefineElement(cx, result, i, wordVal))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 6. Return result.
|
||||
args.rval().setObject(*result);
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************** Intl ********************/
|
||||
|
||||
const Class js::IntlClass = {
|
||||
|
|
|
@ -389,6 +389,48 @@ intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp);
|
|||
extern MOZ_MUST_USE bool
|
||||
intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
/**
|
||||
* Returns an Array with CLDR-based fields display names.
|
||||
* The function takes three arguments:
|
||||
*
|
||||
* locale
|
||||
* BCP47 compliant locale string
|
||||
* style
|
||||
* A string with values: long or short or narrow
|
||||
* keys
|
||||
* An array or path-like strings that identify keys to be returned
|
||||
* At the moment the following types of keys are supported:
|
||||
*
|
||||
* 'dates/fields/{year|month|week|day}'
|
||||
* 'dates/gregorian/months/{january|...|december}'
|
||||
* 'dates/gregorian/weekdays/{sunday|...|saturday}'
|
||||
* 'dates/gregorian/dayperiods/{am|pm}'
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* let info = intl_ComputeDisplayNames(
|
||||
* 'en-US',
|
||||
* 'long',
|
||||
* [
|
||||
* 'dates/fields/year',
|
||||
* 'dates/gregorian/months/january',
|
||||
* 'dates/gregorian/weekdays/monday',
|
||||
* 'dates/gregorian/dayperiods/am',
|
||||
* ]
|
||||
* );
|
||||
*
|
||||
* Returned value:
|
||||
*
|
||||
* [
|
||||
* 'year',
|
||||
* 'January',
|
||||
* 'Monday',
|
||||
* 'AM'
|
||||
* ]
|
||||
*/
|
||||
extern MOZ_MUST_USE bool
|
||||
intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
#if ENABLE_INTL_API
|
||||
/**
|
||||
* Cast char16_t* strings to UChar* strings used by ICU.
|
||||
|
@ -404,6 +446,18 @@ Char16ToUChar(char16_t* chars)
|
|||
{
|
||||
return reinterpret_cast<UChar*>(chars);
|
||||
}
|
||||
|
||||
inline char16_t*
|
||||
UCharToChar16(UChar* chars)
|
||||
{
|
||||
return reinterpret_cast<char16_t*>(chars);
|
||||
}
|
||||
|
||||
inline const char16_t*
|
||||
UCharToChar16(const UChar* chars)
|
||||
{
|
||||
return reinterpret_cast<const char16_t*>(chars);
|
||||
}
|
||||
#endif // ENABLE_INTL_API
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false,
|
||||
JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false,
|
||||
JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false,
|
||||
JSMSG_DATE_NOT_FINITE: false,
|
||||
JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false,
|
||||
JSMSG_INVALID_KEY: false,
|
||||
intl_Collator_availableLocales: false,
|
||||
intl_availableCollations: false,
|
||||
intl_CompareStrings: false,
|
||||
|
@ -3004,3 +3005,126 @@ function Intl_getCalendarInfo(locales) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is a custom method designed after Intl API, but currently
|
||||
* not part of the spec or spec proposal.
|
||||
* We want to use it internally to retrieve translated values from CLDR in
|
||||
* order to ensure they're aligned with what Intl API returns.
|
||||
*
|
||||
* This API may one day be a foundation for an ECMA402 API spec proposal.
|
||||
*
|
||||
* The function takes two arguments - locales which is a list of locale strings
|
||||
* and options which is an object with two optional properties:
|
||||
*
|
||||
* keys:
|
||||
* an Array of string values that are paths to individual terms
|
||||
*
|
||||
* style:
|
||||
* a String with a value "long", "short" or "narrow"
|
||||
*
|
||||
* It returns an object with properties:
|
||||
*
|
||||
* locale:
|
||||
* a negotiated locale string
|
||||
*
|
||||
* style:
|
||||
* negotiated style
|
||||
*
|
||||
* values:
|
||||
* A key-value pair list of requested keys and corresponding
|
||||
* translated values
|
||||
*
|
||||
*/
|
||||
function Intl_getDisplayNames(locales, options) {
|
||||
// 1. Let requestLocales be ? CanonicalizeLocaleList(locales).
|
||||
const requestedLocales = CanonicalizeLocaleList(locales);
|
||||
|
||||
// 2. If options is undefined, then
|
||||
if (options === undefined)
|
||||
// a. Let options be ObjectCreate(%ObjectPrototype%).
|
||||
options = {};
|
||||
// 3. Else,
|
||||
else
|
||||
// a. Let options be ? ToObject(options).
|
||||
options = ToObject(options);
|
||||
|
||||
const DateTimeFormat = dateTimeFormatInternalProperties;
|
||||
|
||||
// 4. Let localeData be %DateTimeFormat%.[[localeData]].
|
||||
const localeData = DateTimeFormat.localeData;
|
||||
|
||||
// 5. Let opt be a new Record.
|
||||
const localeOpt = new Record();
|
||||
// 6. Set localeOpt.[[localeMatcher]] to "best fit".
|
||||
localeOpt.localeMatcher = "best fit";
|
||||
|
||||
// 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt,
|
||||
// %DateTimeFormat%.[[relevantExtensionKeys]], localeData).
|
||||
const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat),
|
||||
requestedLocales,
|
||||
localeOpt,
|
||||
DateTimeFormat.relevantExtensionKeys,
|
||||
localeData);
|
||||
|
||||
// 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
|
||||
const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long");
|
||||
// 9. Let keys be ? Get(options, "keys").
|
||||
let keys = options.keys;
|
||||
|
||||
// 10. If keys is undefined,
|
||||
if (keys === undefined) {
|
||||
// a. Let keys be ArrayCreate(0).
|
||||
keys = [];
|
||||
} else if (!IsObject(keys)) {
|
||||
// 11. Else,
|
||||
// a. If Type(keys) is not Object, throw a TypeError exception.
|
||||
ThrowTypeError(JSMSG_INVALID_KEYS_TYPE);
|
||||
}
|
||||
|
||||
// 12. Let processedKeys be ArrayCreate(0).
|
||||
// (This really should be a List, but we use an Array here in order that
|
||||
// |intl_ComputeDisplayNames| may infallibly access the list's length via
|
||||
// |ArrayObject::length|.)
|
||||
let processedKeys = [];
|
||||
// 13. Let len be ? ToLength(? Get(keys, "length")).
|
||||
let len = ToLength(keys.length);
|
||||
// 14. Let i be 0.
|
||||
// 15. Repeat, while i < len
|
||||
for (let i = 0; i < len; i++) {
|
||||
// a. Let processedKey be ? ToString(? Get(keys, i)).
|
||||
// b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey).
|
||||
callFunction(std_Array_push, processedKeys, ToString(keys[i]));
|
||||
}
|
||||
|
||||
// 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys).
|
||||
const names = intl_ComputeDisplayNames(r.locale, style, processedKeys);
|
||||
|
||||
// 17. Let values be ObjectCreate(%ObjectPrototype%).
|
||||
const values = {};
|
||||
|
||||
// 18. Set i to 0.
|
||||
// 19. Repeat, while i < len
|
||||
for (let i = 0; i < len; i++) {
|
||||
// a. Let key be ? Get(processedKeys, i).
|
||||
const key = processedKeys[i];
|
||||
// b. Let name be ? Get(names, i).
|
||||
const name = names[i];
|
||||
// c. Assert: Type(name) is string.
|
||||
assert(typeof name === "string", "unexpected non-string value");
|
||||
// d. Assert: the length of name is greater than zero.
|
||||
assert(name.length > 0, "empty string value");
|
||||
// e. Perform ? DefinePropertyOrThrow(values, key, name).
|
||||
_DefineDataProperty(values, key, name);
|
||||
}
|
||||
|
||||
// 20. Let options be ObjectCreate(%ObjectPrototype%).
|
||||
// 21. Perform ! DefinePropertyOrThrow(result, "locale", r.[[locale]]).
|
||||
// 22. Perform ! DefinePropertyOrThrow(result, "style", style).
|
||||
// 23. Perform ! DefinePropertyOrThrow(result, "values", values).
|
||||
const result = { locale: r.locale, style, values };
|
||||
|
||||
// 24. Return result.
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -477,6 +477,8 @@ MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1}
|
|||
MSG_DEF(JSMSG_INTL_OBJECT_REINITED, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor")
|
||||
MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}")
|
||||
MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}")
|
||||
MSG_DEF(JSMSG_INVALID_KEYS_TYPE, 0, JSEXN_TYPEERR, "calendar info keys must be an object or undefined")
|
||||
MSG_DEF(JSMSG_INVALID_KEY, 1, JSEXN_RANGEERR, "invalid key: {0}")
|
||||
MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG, 1, JSEXN_RANGEERR, "invalid language tag: {0}")
|
||||
MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument")
|
||||
MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}")
|
||||
|
|
|
@ -907,6 +907,7 @@ AddIntlExtras(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
static const JSFunctionSpec funcs[] = {
|
||||
JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0),
|
||||
JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty('Intl')||!this.hasOwnProperty('addIntlExtras'))
|
||||
/* 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/. */
|
||||
|
||||
// Tests the getCalendarInfo function with a diverse set of arguments.
|
||||
|
||||
/*
|
||||
* Test if getDisplayNames return value matches expected values.
|
||||
*/
|
||||
function checkDisplayNames(names, expected)
|
||||
{
|
||||
assertEq(Object.getPrototypeOf(names), Object.prototype);
|
||||
|
||||
assertEq(names.locale, expected.locale);
|
||||
assertEq(names.style, expected.style);
|
||||
|
||||
const nameValues = names.values;
|
||||
const expectedValues = expected.values;
|
||||
|
||||
const nameValuesKeys = Object.getOwnPropertyNames(nameValues).sort();
|
||||
const expectedValuesKeys = Object.getOwnPropertyNames(expectedValues).sort();
|
||||
|
||||
assertEqArray(nameValuesKeys, expectedValuesKeys);
|
||||
|
||||
for (let key of expectedValuesKeys)
|
||||
assertEq(nameValues[key], expectedValues[key]);
|
||||
}
|
||||
|
||||
addIntlExtras(Intl);
|
||||
|
||||
let gDN = Intl.getDisplayNames;
|
||||
|
||||
assertEq(gDN.length, 2);
|
||||
|
||||
checkDisplayNames(gDN('en-US', {
|
||||
}), {
|
||||
locale: 'en-US',
|
||||
style: 'long',
|
||||
values: {}
|
||||
});
|
||||
|
||||
checkDisplayNames(gDN('en-US', {
|
||||
keys: [
|
||||
'dates/gregorian/weekdays/wednesday'
|
||||
],
|
||||
style: 'narrow'
|
||||
}), {
|
||||
locale: 'en-US',
|
||||
style: 'narrow',
|
||||
values: {
|
||||
'dates/gregorian/weekdays/wednesday': 'W'
|
||||
}
|
||||
});
|
||||
|
||||
checkDisplayNames(gDN('en-US', {
|
||||
keys: [
|
||||
'dates/fields/year',
|
||||
'dates/fields/month',
|
||||
'dates/fields/week',
|
||||
'dates/fields/day',
|
||||
'dates/gregorian/months/january',
|
||||
'dates/gregorian/months/february',
|
||||
'dates/gregorian/months/march',
|
||||
'dates/gregorian/weekdays/tuesday'
|
||||
]
|
||||
}), {
|
||||
locale: 'en-US',
|
||||
style: 'long',
|
||||
values: {
|
||||
'dates/fields/year': 'year',
|
||||
'dates/fields/month': 'month',
|
||||
'dates/fields/week': 'week',
|
||||
'dates/fields/day': 'day',
|
||||
'dates/gregorian/months/january': 'January',
|
||||
'dates/gregorian/months/february': 'February',
|
||||
'dates/gregorian/months/march': 'March',
|
||||
'dates/gregorian/weekdays/tuesday': 'Tuesday',
|
||||
}
|
||||
});
|
||||
|
||||
checkDisplayNames(gDN('fr', {
|
||||
keys: [
|
||||
'dates/fields/year',
|
||||
'dates/fields/day',
|
||||
'dates/gregorian/months/october',
|
||||
'dates/gregorian/weekdays/saturday',
|
||||
'dates/gregorian/dayperiods/pm'
|
||||
]
|
||||
}), {
|
||||
locale: 'fr',
|
||||
style: 'long',
|
||||
values: {
|
||||
'dates/fields/year': 'année',
|
||||
'dates/fields/day': 'jour',
|
||||
'dates/gregorian/months/october': 'octobre',
|
||||
'dates/gregorian/weekdays/saturday': 'samedi',
|
||||
'dates/gregorian/dayperiods/pm': 'PM'
|
||||
}
|
||||
});
|
||||
|
||||
checkDisplayNames(gDN('it', {
|
||||
style: 'short',
|
||||
keys: [
|
||||
'dates/gregorian/weekdays/thursday',
|
||||
'dates/gregorian/months/august',
|
||||
'dates/gregorian/dayperiods/am',
|
||||
'dates/fields/month',
|
||||
]
|
||||
}), {
|
||||
locale: 'it',
|
||||
style: 'short',
|
||||
values: {
|
||||
'dates/gregorian/weekdays/thursday': 'gio',
|
||||
'dates/gregorian/months/august': 'ago',
|
||||
'dates/gregorian/dayperiods/am': 'AM',
|
||||
'dates/fields/month': 'mese'
|
||||
}
|
||||
});
|
||||
|
||||
checkDisplayNames(gDN('ar', {
|
||||
style: 'long',
|
||||
keys: [
|
||||
'dates/gregorian/weekdays/thursday',
|
||||
'dates/gregorian/months/august',
|
||||
'dates/gregorian/dayperiods/am',
|
||||
'dates/fields/month',
|
||||
]
|
||||
}), {
|
||||
locale: 'ar',
|
||||
style: 'long',
|
||||
values: {
|
||||
'dates/gregorian/weekdays/thursday': 'الخميس',
|
||||
'dates/gregorian/months/august': 'أغسطس',
|
||||
'dates/gregorian/dayperiods/am': 'ص',
|
||||
'dates/fields/month': 'الشهر'
|
||||
}
|
||||
});
|
||||
|
||||
/* Invalid input */
|
||||
|
||||
assertThrowsInstanceOf(() => {
|
||||
gDN('en-US', {
|
||||
style: '',
|
||||
keys: [
|
||||
'dates/gregorian/weekdays/thursday',
|
||||
]
|
||||
});
|
||||
}, RangeError);
|
||||
|
||||
assertThrowsInstanceOf(() => {
|
||||
gDN('en-US', {
|
||||
style: 'bogus',
|
||||
keys: [
|
||||
'dates/gregorian/weekdays/thursday',
|
||||
]
|
||||
});
|
||||
}, RangeError);
|
||||
|
||||
assertThrowsInstanceOf(() => {
|
||||
gDN('foo-X', {
|
||||
keys: [
|
||||
'dates/gregorian/weekdays/thursday',
|
||||
]
|
||||
});
|
||||
}, RangeError);
|
||||
|
||||
const typeErrorKeys = [
|
||||
null,
|
||||
'string',
|
||||
Symbol.iterator,
|
||||
15,
|
||||
1,
|
||||
3.7,
|
||||
NaN,
|
||||
Infinity
|
||||
];
|
||||
|
||||
for (let keys of typeErrorKeys) {
|
||||
assertThrowsInstanceOf(() => {
|
||||
gDN('en-US', {
|
||||
keys
|
||||
});
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
const rangeErrorKeys = [
|
||||
[''],
|
||||
['foo'],
|
||||
['dates/foo'],
|
||||
['/dates/foo'],
|
||||
['dates/foo/foo'],
|
||||
['dates/fields'],
|
||||
['dates/fields/'],
|
||||
['dates/fields/foo'],
|
||||
['dates/fields/foo/month'],
|
||||
['/dates/foo/faa/bar/baz'],
|
||||
['dates///bar/baz'],
|
||||
['dates/gregorian'],
|
||||
['dates/gregorian/'],
|
||||
['dates/gregorian/foo'],
|
||||
['dates/gregorian/months'],
|
||||
['dates/gregorian/months/foo'],
|
||||
['dates/gregorian/weekdays'],
|
||||
['dates/gregorian/weekdays/foo'],
|
||||
['dates/gregorian/dayperiods'],
|
||||
['dates/gregorian/dayperiods/foo'],
|
||||
['dates/gregorian/months/الشهر'],
|
||||
[3],
|
||||
[null],
|
||||
['d', 'a', 't', 'e', 's'],
|
||||
['datesEXTRA'],
|
||||
['dates/fieldsEXTRA'],
|
||||
['dates/gregorianEXTRA'],
|
||||
['dates/gregorian/monthsEXTRA'],
|
||||
['dates/gregorian/weekdaysEXTRA'],
|
||||
['dates/fields/dayperiods/amEXTRA'],
|
||||
['dates/gregori\u1161n/months/january'],
|
||||
["dates/fields/year/"],
|
||||
["dates/fields/month/"],
|
||||
["dates/fields/week/"],
|
||||
["dates/fields/day/"],
|
||||
["dates/gregorian/months/january/"],
|
||||
["dates/gregorian/weekdays/saturday/"],
|
||||
["dates/gregorian/dayperiods/am/"],
|
||||
["dates/fields/months/january/"],
|
||||
];
|
||||
|
||||
for (let keys of rangeErrorKeys) {
|
||||
assertThrowsInstanceOf(() => {
|
||||
gDN('en-US', {
|
||||
keys
|
||||
});
|
||||
}, RangeError);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0, 0);
|
|
@ -2477,6 +2477,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0),
|
||||
JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0),
|
||||
JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0),
|
||||
JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0),
|
||||
JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0),
|
||||
JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0),
|
||||
JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0),
|
||||
|
|
|
@ -344,7 +344,7 @@ public:
|
|||
if (mFrame->IsSVGText()) {
|
||||
return 0.0f;
|
||||
}
|
||||
nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth.GetCoordValue();
|
||||
nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth;
|
||||
return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);
|
||||
}
|
||||
|
||||
|
@ -5701,7 +5701,7 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
|||
}
|
||||
|
||||
// text-stroke overflows
|
||||
nscoord textStrokeWidth = StyleText()->mWebkitTextStrokeWidth.GetCoordValue();
|
||||
nscoord textStrokeWidth = StyleText()->mWebkitTextStrokeWidth;
|
||||
if (textStrokeWidth > 0) {
|
||||
nsRect strokeRect = *aVisualOverflowRect;
|
||||
strokeRect.x -= textStrokeWidth;
|
||||
|
|
|
@ -3194,7 +3194,7 @@ CSS_PROP_OUTLINE(
|
|||
VARIANT_HKL | VARIANT_CALC,
|
||||
kBorderWidthKTable,
|
||||
offsetof(nsStyleOutline, mOutlineWidth),
|
||||
eStyleAnimType_Coord)
|
||||
eStyleAnimType_nscoord)
|
||||
CSS_PROP_SHORTHAND(
|
||||
overflow,
|
||||
overflow,
|
||||
|
|
|
@ -4064,7 +4064,7 @@ already_AddRefed<CSSValue>
|
|||
nsComputedDOMStyle::DoGetWebkitTextStrokeWidth()
|
||||
{
|
||||
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||
val->SetAppUnits(StyleText()->mWebkitTextStrokeWidth.GetCoordValue());
|
||||
val->SetAppUnits(StyleText()->mWebkitTextStrokeWidth);
|
||||
return val.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
|
@ -1156,6 +1157,46 @@ SetComplexColor(const nsCSSValue& aValue,
|
|||
}
|
||||
}
|
||||
|
||||
template<UnsetAction UnsetTo>
|
||||
static Maybe<nscoord>
|
||||
ComputeLineWidthValue(const nsCSSValue& aValue,
|
||||
const nscoord aParentCoord,
|
||||
const nscoord aInitialCoord,
|
||||
nsStyleContext* aStyleContext,
|
||||
nsPresContext* aPresContext,
|
||||
RuleNodeCacheConditions& aConditions)
|
||||
{
|
||||
nsCSSUnit unit = aValue.GetUnit();
|
||||
if (unit == eCSSUnit_Initial ||
|
||||
(UnsetTo == eUnsetInitial && unit == eCSSUnit_Unset)) {
|
||||
return Some(aInitialCoord);
|
||||
} else if (unit == eCSSUnit_Inherit ||
|
||||
(UnsetTo == eUnsetInherit && unit == eCSSUnit_Unset)) {
|
||||
aConditions.SetUncacheable();
|
||||
return Some(aParentCoord);
|
||||
} else if (unit == eCSSUnit_Enumerated) {
|
||||
NS_ASSERTION(aValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
|
||||
aValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
|
||||
aValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
|
||||
"Unexpected line-width keyword!");
|
||||
return Some(nsPresContext::GetBorderWidthForKeyword(aValue.GetIntValue()));
|
||||
} else if (aValue.IsLengthUnit() ||
|
||||
aValue.IsCalcUnit()) {
|
||||
nscoord len =
|
||||
CalcLength(aValue, aStyleContext, aPresContext, aConditions);
|
||||
if (len < 0) {
|
||||
NS_ASSERTION(aValue.IsCalcUnit(),
|
||||
"Parser should have rejected negative length!");
|
||||
len = 0;
|
||||
}
|
||||
return Some(len);
|
||||
} else {
|
||||
NS_ASSERTION(unit == eCSSUnit_Null,
|
||||
"Missing case handling for line-width computing!");
|
||||
return Maybe<nscoord>(Nothing());
|
||||
}
|
||||
}
|
||||
|
||||
static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
|
||||
nsStyleContext* aContext, nsStyleCoord& aResult,
|
||||
RuleNodeCacheConditions& aConditions)
|
||||
|
@ -4924,22 +4965,13 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
|
|||
&nsStyleText::mWebkitTextStrokeColor);
|
||||
|
||||
// -webkit-text-stroke-width: length, inherit, initial, enum
|
||||
const nsCSSValue*
|
||||
webkitTextStrokeWidthValue = aRuleData->ValueForWebkitTextStrokeWidth();
|
||||
if (webkitTextStrokeWidthValue->GetUnit() == eCSSUnit_Enumerated) {
|
||||
NS_ASSERTION(webkitTextStrokeWidthValue->GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
|
||||
webkitTextStrokeWidthValue->GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
|
||||
webkitTextStrokeWidthValue->GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
|
||||
"Unexpected enum value");
|
||||
text->mWebkitTextStrokeWidth.SetCoordValue(
|
||||
nsPresContext::GetBorderWidthForKeyword(webkitTextStrokeWidthValue->GetIntValue()));
|
||||
} else {
|
||||
SetCoord(*webkitTextStrokeWidthValue, text->mWebkitTextStrokeWidth,
|
||||
parentText->mWebkitTextStrokeWidth,
|
||||
SETCOORD_LH | SETCOORD_CALC_LENGTH_ONLY |
|
||||
SETCOORD_CALC_CLAMP_NONNEGATIVE |
|
||||
SETCOORD_INITIAL_ZERO | SETCOORD_UNSET_INHERIT,
|
||||
aContext, mPresContext, conditions);
|
||||
Maybe<nscoord> coord =
|
||||
ComputeLineWidthValue<eUnsetInherit>(
|
||||
*aRuleData->ValueForWebkitTextStrokeWidth(),
|
||||
parentText->mWebkitTextStrokeWidth, 0,
|
||||
aContext, mPresContext, conditions);
|
||||
if (coord.isSome()) {
|
||||
text->mWebkitTextStrokeWidth = *coord;
|
||||
}
|
||||
|
||||
// -moz-control-character-visibility: enum, inherit, initial
|
||||
|
@ -7531,35 +7563,13 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
|
|||
"method, the "
|
||||
"nsLineLayout::IsPercentageAwareReplacedElement method "
|
||||
"and probably some other places");
|
||||
if (eCSSUnit_Enumerated == value.GetUnit()) {
|
||||
NS_ASSERTION(value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
|
||||
value.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
|
||||
value.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
|
||||
"Unexpected enum value");
|
||||
border->SetBorderWidth(side,
|
||||
nsPresContext::GetBorderWidthForKeyword(value.GetIntValue()));
|
||||
}
|
||||
// OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
|
||||
else if (SetCoord(value, coord, nsStyleCoord(),
|
||||
SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
|
||||
aContext, mPresContext, conditions)) {
|
||||
NS_ASSERTION(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
||||
// clamp negative calc() to 0.
|
||||
border->SetBorderWidth(side, std::max(coord.GetCoordValue(), 0));
|
||||
}
|
||||
else if (eCSSUnit_Inherit == value.GetUnit()) {
|
||||
conditions.SetUncacheable();
|
||||
border->SetBorderWidth(side,
|
||||
parentBorder->GetComputedBorder().Side(side));
|
||||
}
|
||||
else if (eCSSUnit_Initial == value.GetUnit() ||
|
||||
eCSSUnit_Unset == value.GetUnit()) {
|
||||
border->SetBorderWidth(side,
|
||||
nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM));
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(eCSSUnit_Null == value.GetUnit(),
|
||||
"missing case handling border width");
|
||||
Maybe<nscoord> coord =
|
||||
ComputeLineWidthValue<eUnsetInitial>(
|
||||
value, parentBorder->GetComputedBorder().Side(side),
|
||||
nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM),
|
||||
aContext, mPresContext, conditions);
|
||||
if (coord.isSome()) {
|
||||
border->SetBorderWidth(side, *coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7819,17 +7829,13 @@ nsRuleNode::ComputeOutlineData(void* aStartStruct,
|
|||
COMPUTE_START_RESET(Outline, outline, parentOutline)
|
||||
|
||||
// outline-width: length, enum, inherit
|
||||
const nsCSSValue* outlineWidthValue = aRuleData->ValueForOutlineWidth();
|
||||
if (eCSSUnit_Initial == outlineWidthValue->GetUnit() ||
|
||||
eCSSUnit_Unset == outlineWidthValue->GetUnit()) {
|
||||
outline->mOutlineWidth =
|
||||
nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
|
||||
}
|
||||
else {
|
||||
SetCoord(*outlineWidthValue, outline->mOutlineWidth,
|
||||
parentOutline->mOutlineWidth,
|
||||
SETCOORD_LEH | SETCOORD_CALC_LENGTH_ONLY, aContext,
|
||||
mPresContext, conditions);
|
||||
Maybe<nscoord> coord =
|
||||
ComputeLineWidthValue<eUnsetInitial>(
|
||||
*aRuleData->ValueForOutlineWidth(), parentOutline->mOutlineWidth,
|
||||
nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM),
|
||||
aContext, mPresContext, conditions);
|
||||
if (coord.isSome()) {
|
||||
outline->mOutlineWidth = *coord;
|
||||
}
|
||||
|
||||
// outline-offset: length, inherit
|
||||
|
@ -9157,36 +9163,14 @@ nsRuleNode::ComputeColumnData(void* aStartStruct,
|
|||
}
|
||||
|
||||
// column-rule-width: length, enum, inherit
|
||||
const nsCSSValue& widthValue = *aRuleData->ValueForColumnRuleWidth();
|
||||
if (eCSSUnit_Initial == widthValue.GetUnit() ||
|
||||
eCSSUnit_Unset == widthValue.GetUnit()) {
|
||||
column->SetColumnRuleWidth(
|
||||
nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM));
|
||||
}
|
||||
else if (eCSSUnit_Enumerated == widthValue.GetUnit()) {
|
||||
NS_ASSERTION(widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
|
||||
widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
|
||||
widthValue.GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
|
||||
"Unexpected enum value");
|
||||
column->SetColumnRuleWidth(
|
||||
nsPresContext::GetBorderWidthForKeyword(widthValue.GetIntValue()));
|
||||
}
|
||||
else if (eCSSUnit_Inherit == widthValue.GetUnit()) {
|
||||
column->SetColumnRuleWidth(parent->GetComputedColumnRuleWidth());
|
||||
conditions.SetUncacheable();
|
||||
}
|
||||
else if (widthValue.IsLengthUnit() || widthValue.IsCalcUnit()) {
|
||||
nscoord len =
|
||||
CalcLength(widthValue, aContext, mPresContext, conditions);
|
||||
if (len < 0) {
|
||||
// FIXME: This is untested (by test_value_storage.html) for
|
||||
// column-rule-width since it gets covered up by the border
|
||||
// rounding code.
|
||||
NS_ASSERTION(widthValue.IsCalcUnit(),
|
||||
"parser should have rejected negative length");
|
||||
len = 0;
|
||||
}
|
||||
column->SetColumnRuleWidth(len);
|
||||
Maybe<nscoord> coord =
|
||||
ComputeLineWidthValue<eUnsetInitial>(
|
||||
*aRuleData->ValueForColumnRuleWidth(),
|
||||
parent->GetComputedColumnRuleWidth(),
|
||||
nsPresContext::GetBorderWidthForKeyword(NS_STYLE_BORDER_WIDTH_MEDIUM),
|
||||
aContext, mPresContext, conditions);
|
||||
if (coord.isSome()) {
|
||||
column->SetColumnRuleWidth(*coord);
|
||||
}
|
||||
|
||||
// column-rule-style: enum, inherit
|
||||
|
|
|
@ -239,22 +239,6 @@ nsStyleFont::GetLanguage(StyleStructContext aContext)
|
|||
return language.forget();
|
||||
}
|
||||
|
||||
static nscoord
|
||||
CalcCoord(const nsStyleCoord& aCoord, const nscoord* aEnumTable, int32_t aNumEnums)
|
||||
{
|
||||
if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
|
||||
MOZ_ASSERT(aEnumTable, "must have enum table");
|
||||
int32_t value = aCoord.GetIntValue();
|
||||
if (0 <= value && value < aNumEnums) {
|
||||
return aEnumTable[aCoord.GetIntValue()];
|
||||
}
|
||||
NS_NOTREACHED("unexpected enum value");
|
||||
return 0;
|
||||
}
|
||||
MOZ_ASSERT(aCoord.ConvertsToLength(), "unexpected unit");
|
||||
return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
|
||||
}
|
||||
|
||||
nsStyleMargin::nsStyleMargin(StyleStructContext aContext)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStyleMargin);
|
||||
|
@ -547,7 +531,8 @@ nsStyleBorder::CalcDifference(const nsStyleBorder& aNewData) const
|
|||
}
|
||||
|
||||
nsStyleOutline::nsStyleOutline(StyleStructContext aContext)
|
||||
: mOutlineWidth(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated)
|
||||
: mOutlineWidth((StaticPresData::Get()
|
||||
->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM])
|
||||
, mOutlineOffset(0)
|
||||
, mOutlineColor(StyleComplexColor::CurrentColor())
|
||||
, mOutlineStyle(NS_STYLE_BORDER_STYLE_NONE)
|
||||
|
@ -580,14 +565,8 @@ nsStyleOutline::RecalcData()
|
|||
if (NS_STYLE_BORDER_STYLE_NONE == mOutlineStyle) {
|
||||
mActualOutlineWidth = 0;
|
||||
} else {
|
||||
MOZ_ASSERT(mOutlineWidth.ConvertsToLength() ||
|
||||
mOutlineWidth.GetUnit() == eStyleUnit_Enumerated);
|
||||
// Clamp negative calc() to 0.
|
||||
mActualOutlineWidth =
|
||||
std::max(CalcCoord(mOutlineWidth,
|
||||
StaticPresData::Get()->GetBorderWidthTable(), 3), 0);
|
||||
mActualOutlineWidth =
|
||||
NS_ROUND_BORDER_TO_PIXELS(mActualOutlineWidth, mTwipsPerPixel);
|
||||
NS_ROUND_BORDER_TO_PIXELS(mOutlineWidth, mTwipsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3791,7 +3770,7 @@ nsStyleText::nsStyleText(StyleStructContext aContext)
|
|||
, mLetterSpacing(eStyleUnit_Normal)
|
||||
, mLineHeight(eStyleUnit_Normal)
|
||||
, mTextIndent(0, nsStyleCoord::CoordConstructor)
|
||||
, mWebkitTextStrokeWidth(0, nsStyleCoord::CoordConstructor)
|
||||
, mWebkitTextStrokeWidth(0)
|
||||
, mTextShadow(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsStyleText);
|
||||
|
|
|
@ -1486,7 +1486,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleOutline
|
|||
// value used by layout. (We must store mOutlineWidth for the same
|
||||
// style struct resolution reasons that we do nsStyleBorder::mBorder;
|
||||
// see that field's comment.)
|
||||
nsStyleCoord mOutlineWidth; // [reset] coord, enum (see nsStyleConsts.h)
|
||||
nscoord mOutlineWidth; // [reset] coord, enum (see nsStyleConsts.h)
|
||||
nscoord mOutlineOffset; // [reset]
|
||||
mozilla::StyleComplexColor mOutlineColor; // [reset]
|
||||
uint8_t mOutlineStyle; // [reset] See nsStyleConsts.h
|
||||
|
@ -2092,7 +2092,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
|
|||
nsStyleCoord mLetterSpacing; // [inherited] coord, normal
|
||||
nsStyleCoord mLineHeight; // [inherited] coord, factor, normal
|
||||
nsStyleCoord mTextIndent; // [inherited] coord, percent, calc
|
||||
nsStyleCoord mWebkitTextStrokeWidth; // [inherited] coord
|
||||
nscoord mWebkitTextStrokeWidth; // [inherited] coord
|
||||
|
||||
RefPtr<nsCSSShadowArray> mTextShadow; // [inherited] nullptr in case of a zero-length
|
||||
|
||||
|
@ -2138,7 +2138,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
|
|||
}
|
||||
|
||||
bool HasWebkitTextStroke() const {
|
||||
return mWebkitTextStrokeWidth.GetCoordValue() > 0;
|
||||
return mWebkitTextStrokeWidth > 0;
|
||||
}
|
||||
|
||||
// These are defined in nsStyleStructInlines.h.
|
||||
|
|
|
@ -550,14 +550,16 @@ class TransportConduitTest : public ::testing::Test
|
|||
mozilla::SyncRunnable::DispatchToThread(gMainThread,
|
||||
WrapRunnableNMRet(&mAudioSession,
|
||||
&mozilla::AudioSessionConduit::Create));
|
||||
if( !mAudioSession )
|
||||
if( !mAudioSession ) {
|
||||
ASSERT_NE(mAudioSession, (void*)nullptr);
|
||||
}
|
||||
|
||||
mozilla::SyncRunnable::DispatchToThread(gMainThread,
|
||||
WrapRunnableNMRet(&mAudioSession2,
|
||||
&mozilla::AudioSessionConduit::Create));
|
||||
if( !mAudioSession2 )
|
||||
if( !mAudioSession2 ) {
|
||||
ASSERT_NE(mAudioSession2, (void*)nullptr);
|
||||
}
|
||||
|
||||
WebrtcMediaTransport* xport = new WebrtcMediaTransport();
|
||||
ASSERT_NE(xport, (void*)nullptr);
|
||||
|
@ -615,15 +617,17 @@ class TransportConduitTest : public ::testing::Test
|
|||
mozilla::SyncRunnable::DispatchToThread(gMainThread,
|
||||
WrapRunnableNMRet(&mVideoSession,
|
||||
&mozilla::VideoSessionConduit::Create));
|
||||
if( !mVideoSession )
|
||||
if( !mVideoSession ) {
|
||||
ASSERT_NE(mVideoSession, (void*)nullptr);
|
||||
}
|
||||
|
||||
// This session is for other one
|
||||
mozilla::SyncRunnable::DispatchToThread(gMainThread,
|
||||
WrapRunnableNMRet(&mVideoSession2,
|
||||
&mozilla::VideoSessionConduit::Create));
|
||||
if( !mVideoSession2 )
|
||||
if( !mVideoSession2 ) {
|
||||
ASSERT_NE(mVideoSession2,(void*)nullptr);
|
||||
}
|
||||
|
||||
if (!send_vp8) {
|
||||
SetGmpCodecs();
|
||||
|
@ -716,8 +720,9 @@ class TransportConduitTest : public ::testing::Test
|
|||
mozilla::SyncRunnable::DispatchToThread(gMainThread,
|
||||
WrapRunnableNMRet(&videoSession,
|
||||
&mozilla::VideoSessionConduit::Create));
|
||||
if( !videoSession )
|
||||
if( !videoSession ) {
|
||||
ASSERT_NE(videoSession, (void*)nullptr);
|
||||
}
|
||||
|
||||
//Test Configure Recv Codec APIS
|
||||
cerr << " *************************************************" << endl;
|
||||
|
@ -831,8 +836,9 @@ class TransportConduitTest : public ::testing::Test
|
|||
mozilla::SyncRunnable::DispatchToThread(gMainThread,
|
||||
WrapRunnableNMRet(&mVideoSession,
|
||||
&mozilla::VideoSessionConduit::Create));
|
||||
if( !mVideoSession )
|
||||
if( !mVideoSession ) {
|
||||
ASSERT_NE(mVideoSession, (void*)nullptr);
|
||||
}
|
||||
|
||||
mozilla::EncodingConstraints constraints;
|
||||
constraints.maxFs = max_fs;
|
||||
|
|
|
@ -1475,8 +1475,8 @@ class SignalingAgent {
|
|||
pObserver->addIceCandidateState = TestObserver::stateNoResponse;
|
||||
pc->AddIceCandidate(candidate.c_str(), mid.c_str(), level);
|
||||
ASSERT_TRUE(pObserver->addIceCandidateState ==
|
||||
expectSuccess ? TestObserver::stateSuccess :
|
||||
TestObserver::stateError
|
||||
(expectSuccess ? TestObserver::stateSuccess :
|
||||
TestObserver::stateError)
|
||||
);
|
||||
|
||||
// Verify that adding ICE candidates does not change the signaling state
|
||||
|
|
|
@ -61,11 +61,6 @@ public class DataReportingNotification {
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentVersion >= DATA_REPORTING_VERSION) {
|
||||
// Do nothing, we're at a current (or future) version.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,7 +33,7 @@ public class Fetched {
|
|||
public static @NonNull Fetched fromJSONObject(@NonNull JSONObject json) {
|
||||
final String value = json.optString("value", null);
|
||||
final String timestampString = json.optString("timestamp", null);
|
||||
final long timestamp = timestampString != null ? Long.valueOf(timestampString) : 0L;
|
||||
final long timestamp = timestampString != null ? Long.parseLong(timestampString) : 0L;
|
||||
return new Fetched(value, timestamp);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,9 @@
|
|||
<dimen name="tab_thumbnail_height">90dp</dimen>
|
||||
<dimen name="tab_panel_item_width">129dp</dimen>
|
||||
<dimen name="tab_panel_grid_hpadding">20dp</dimen>
|
||||
<dimen name="tab_panel_grid_vpadding">19dp</dimen>
|
||||
<!-- Top and bottom tab panel grid padding is split between tab_panel_grid_vpadding (the
|
||||
RecyclerView padding) and tab_panel_grid_item_vpadding (individual item padding). -->
|
||||
<dimen name="tab_panel_grid_vpadding">9dp</dimen>
|
||||
<dimen name="tab_panel_grid_ideal_item_hspacing">20dp</dimen>
|
||||
<dimen name="tab_panel_grid_min_item_hspacing">2dp</dimen>
|
||||
<dimen name="tab_panel_grid_item_vpadding">10dp</dimen>
|
||||
|
|
|
@ -48,6 +48,14 @@
|
|||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "rustc 1.14.0-beta.2 (e627a2e6e 2016-11-16) repack",
|
||||
"size": 75964276,
|
||||
"digest": "3a83a42330cdc42fbffcd91aa80f8e33749c716068047699fbd0ee5b5c51ec350f60285b34fd45d9bb038a5af9118e16ab66cbf0a7167eed5a6d239f50e32462",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"algorithm": "sha512",
|
||||
"visibility": "public",
|
||||
"filename": "jcentral.tar.xz",
|
||||
|
|
|
@ -74,8 +74,8 @@
|
|||
},
|
||||
{
|
||||
"version": "rustc 1.14.0-beta.2 (e627a2e6e 2016-11-16) repack",
|
||||
"size": 96360828,
|
||||
"digest": "6f9f6c5fde5366fe7c67f9a7699b8c64c2e14940d57e9cf87026b61a9cbf4aabe0d35933c1365034980031164817fd51c3bc02d6449bd9e8f2225981b053e47e",
|
||||
"size": 75964276,
|
||||
"digest": "3a83a42330cdc42fbffcd91aa80f8e33749c716068047699fbd0ee5b5c51ec350f60285b34fd45d9bb038a5af9118e16ab66cbf0a7167eed5a6d239f50e32462",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
|
|
@ -617,10 +617,6 @@ public class FormHistoryRepositorySession extends
|
|||
}
|
||||
|
||||
Logger.trace(LOG_TAG, "Remote is older, local is not deleted. Ignoring.");
|
||||
if (!locallyModified) {
|
||||
Logger.warn(LOG_TAG, "Inconsistency: old remote record is deleted, but local record not modified!");
|
||||
// Ensure that this is tracked for upload.
|
||||
}
|
||||
return;
|
||||
}
|
||||
// End deletion logic.
|
||||
|
@ -672,10 +668,6 @@ public class FormHistoryRepositorySession extends
|
|||
}
|
||||
|
||||
Logger.trace(LOG_TAG, "Remote is older, local is not deleted. Ignoring.");
|
||||
if (!locallyModified) {
|
||||
Logger.warn(LOG_TAG, "Inconsistency: old remote record is not deleted, but local record not modified!");
|
||||
}
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
Logger.error(LOG_TAG, "Store failed for " + record.guid, e);
|
||||
delegate.onRecordStoreFailed(e, record.guid);
|
||||
|
|
|
@ -316,10 +316,7 @@ public class PasswordsRepositorySession extends
|
|||
}
|
||||
|
||||
trace("Remote is older, local is not deleted. Ignoring.");
|
||||
if (!locallyModified) {
|
||||
Logger.warn(LOG_TAG, "Inconsistency: old remote record is deleted, but local record not modified!");
|
||||
// Ensure that this is tracked for upload.
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// End deletion logic.
|
||||
|
|
|
@ -44,6 +44,32 @@ MozIntl::AddGetCalendarInfo(JS::Handle<JS::Value> val, JSContext* cx)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MozIntl::AddGetDisplayNames(JS::Handle<JS::Value> val, JSContext* cx)
|
||||
{
|
||||
if (!val.isObject()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
|
||||
if (!realIntlObj) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
JSAutoCompartment ac(cx, realIntlObj);
|
||||
|
||||
static const JSFunctionSpec funcs[] = {
|
||||
JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
if (!JS_DefineFunctions(cx, realIntlObj, funcs)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(MozIntl)
|
||||
NS_DEFINE_NAMED_CID(MOZ_MOZINTL_CID);
|
||||
|
||||
|
|
|
@ -9,4 +9,5 @@
|
|||
interface mozIMozIntl : nsISupports
|
||||
{
|
||||
[implicit_jscontext] void addGetCalendarInfo(in jsval intlObject);
|
||||
[implicit_jscontext] void addGetDisplayNames(in jsval intlObject);
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ function run_test() {
|
|||
|
||||
test_this_global(mozIntl);
|
||||
test_cross_global(mozIntl);
|
||||
test_methods_presence(mozIntl);
|
||||
|
||||
ok(true);
|
||||
}
|
||||
|
@ -30,3 +31,16 @@ function test_cross_global(mozIntl) {
|
|||
equal(waivedX.getCalendarInfo() instanceof Object, false);
|
||||
equal(waivedX.getCalendarInfo() instanceof global.Object, true);
|
||||
}
|
||||
|
||||
function test_methods_presence(mozIntl) {
|
||||
equal(mozIntl.addGetCalendarInfo instanceof Function, true);
|
||||
equal(mozIntl.addGetDisplayNames instanceof Function, true);
|
||||
|
||||
let x = {};
|
||||
|
||||
mozIntl.addGetCalendarInfo(x);
|
||||
equal(x.getCalendarInfo instanceof Function, true);
|
||||
|
||||
mozIntl.addGetDisplayNames(x);
|
||||
equal(x.getDisplayNames instanceof Function, true);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче