зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1547877 - enable configuration of new XULStore implementation r=mossop
Differential Revision: https://phabricator.services.mozilla.com/D29304 --HG-- rename : toolkit/components/xulstore/XULStore.jsm => toolkit/components/xulstore/new/XULStore.jsm extra : moz-landing-system : lando
This commit is contained in:
Родитель
910be2ccef
Коммит
1b3f6d1faf
|
@ -5,7 +5,12 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "XULPersist.h"
|
||||
#include "mozilla/XULStore.h"
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
# include "mozilla/XULStore.h"
|
||||
#else
|
||||
# include "nsIXULStore.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -79,6 +84,15 @@ void XULPersist::Persist(Element* aElement, int32_t aNameSpaceID,
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef MOZ_NEW_XULSTORE
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsAutoString id;
|
||||
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
|
||||
|
@ -95,14 +109,23 @@ void XULPersist::Persist(Element* aElement, int32_t aNameSpaceID,
|
|||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
bool hasAttr;
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
rv = XULStore::HasValue(uri, id, attrstr, hasAttr);
|
||||
#else
|
||||
rv = mLocalStore->HasValue(uri, id, attrstr, &hasAttr);
|
||||
#endif
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasAttr && valuestr.IsEmpty()) {
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
rv = XULStore::RemoveValue(uri, id, attrstr);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "value removed");
|
||||
#else
|
||||
mLocalStore->RemoveValue(uri, id, attrstr);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -114,7 +137,11 @@ void XULPersist::Persist(Element* aElement, int32_t aNameSpaceID,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
rv = XULStore::SetValue(uri, id, attrstr, valuestr);
|
||||
#else
|
||||
mLocalStore->SetValue(uri, id, attrstr, valuestr);
|
||||
#endif
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "value set");
|
||||
}
|
||||
|
||||
|
@ -129,6 +156,15 @@ nsresult XULPersist::ApplyPersistentAttributes() {
|
|||
|
||||
// Add all of the 'persisted' attributes into the content
|
||||
// model.
|
||||
#ifndef MOZ_NEW_XULSTORE
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ApplyPersistentAttributesInternal();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -145,18 +181,35 @@ nsresult XULPersist::ApplyPersistentAttributesInternal() {
|
|||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of element IDs for which persisted values are available
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
UniquePtr<XULStoreIterator> ids;
|
||||
rv = XULStore::GetIDs(uri, ids);
|
||||
#else
|
||||
nsCOMPtr<nsIStringEnumerator> ids;
|
||||
rv = mLocalStore->GetIDsEnumerator(uri, getter_AddRefs(ids));
|
||||
#endif
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
while (ids->HasMore()) {
|
||||
nsAutoString id;
|
||||
rv = ids->GetNext(&id);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
#else
|
||||
while (1) {
|
||||
bool hasmore = false;
|
||||
ids->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString id;
|
||||
ids->GetNext(id);
|
||||
#endif
|
||||
|
||||
// We want to hold strong refs to the elements while applying
|
||||
// persistent attributes, just in case.
|
||||
|
@ -189,12 +242,18 @@ nsresult XULPersist::ApplyPersistentAttributesToElements(
|
|||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
// Get a list of attributes for which persisted values are available
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
UniquePtr<XULStoreIterator> attrs;
|
||||
rv = XULStore::GetAttrs(uri, aID, attrs);
|
||||
#else
|
||||
nsCOMPtr<nsIStringEnumerator> attrs;
|
||||
rv = mLocalStore->GetAttributeEnumerator(uri, aID, getter_AddRefs(attrs));
|
||||
#endif
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
while (attrs->HasMore()) {
|
||||
nsAutoString attrstr;
|
||||
rv = attrs->GetNext(&attrstr);
|
||||
|
@ -204,6 +263,20 @@ nsresult XULPersist::ApplyPersistentAttributesToElements(
|
|||
|
||||
nsAutoString value;
|
||||
rv = XULStore::GetValue(uri, aID, attrstr, value);
|
||||
#else
|
||||
while (1) {
|
||||
bool hasmore = PR_FALSE;
|
||||
attrs->HasMore(&hasmore);
|
||||
if (!hasmore) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoString attrstr;
|
||||
attrs->GetNext(attrstr);
|
||||
|
||||
nsAutoString value;
|
||||
rv = mLocalStore->GetValue(uri, aID, attrstr, value);
|
||||
#endif
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#ifndef mozilla_dom_XULPersist_h
|
||||
#define mozilla_dom_XULPersist_h
|
||||
|
||||
#ifndef MOZ_NEW_XULSTORE
|
||||
class nsIXULStore;
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -31,6 +35,10 @@ class XULPersist final : public nsStubDocumentObserver {
|
|||
nsresult ApplyPersistentAttributesToElements(const nsAString& aID,
|
||||
nsCOMArray<Element>& aElements);
|
||||
|
||||
#ifndef MOZ_NEW_XULSTORE
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
#endif
|
||||
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
Document* MOZ_NON_OWNING_REF mDocument;
|
||||
};
|
||||
|
|
|
@ -566,16 +566,22 @@
|
|||
"minbytes": 6000,
|
||||
"maxbytes": 6000
|
||||
},
|
||||
"{talos}\\talos\\tests\\{tp5n_files}": {
|
||||
"{profile}\\xulstore.json": {
|
||||
"mincount": 0,
|
||||
"maxcount": 2,
|
||||
"maxcount": 0,
|
||||
"minbytes": 0,
|
||||
"maxbytes": 16384
|
||||
"maxbytes": 702
|
||||
},
|
||||
"{profile}\\xulstore\\data.mdb": {
|
||||
"mincount": 0,
|
||||
"maxcount": 4,
|
||||
"minbytes": 0,
|
||||
"maxbytes": 608
|
||||
},
|
||||
"{talos}\\talos\\tests\\{tp5n_files}": {
|
||||
"mincount": 0,
|
||||
"maxcount": 2,
|
||||
"minbytes": 0,
|
||||
"maxbytes": 16384
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,23 @@
|
|||
# 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/.
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{be70bf11-0c28-4a02-a38c-0148538d42cf}',
|
||||
'contract_ids': ['@mozilla.org/xul/xulstore;1'],
|
||||
'type': 'nsIXULStore',
|
||||
'headers': ['mozilla/XULStore.h'],
|
||||
'singleton': True,
|
||||
'constructor': 'mozilla::XULStore::GetService',
|
||||
},
|
||||
]
|
||||
if defined('MOZ_NEW_XULSTORE'):
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{be70bf11-0c28-4a02-a38c-0148538d42cf}',
|
||||
'contract_ids': ['@mozilla.org/xul/xulstore;1'],
|
||||
'type': 'nsIXULStore',
|
||||
'headers': ['mozilla/XULStore.h'],
|
||||
'singleton': True,
|
||||
'constructor': 'mozilla::XULStore::GetService',
|
||||
},
|
||||
]
|
||||
else:
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{6f46b6f4-c8b1-4bd4-a4fa-9ebbed0753ea}',
|
||||
'contract_ids': ['@mozilla.org/xul/xulstore;1'],
|
||||
'jsm': 'resource://gre/modules/XULStore.jsm',
|
||||
'constructor': 'XULStore',
|
||||
},
|
||||
]
|
||||
|
|
|
@ -10,30 +10,35 @@ with Files('**'):
|
|||
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
|
||||
|
||||
XPIDL_MODULE = 'toolkit_xulstore'
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIXULStore.idl',
|
||||
]
|
||||
|
||||
TEST_DIRS += [
|
||||
'tests/gtest',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'XULStore.h',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'XULStore.jsm',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'xulstore'
|
||||
|
||||
XPCOM_MANIFESTS += [
|
||||
'components.conf',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'XULStore.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_NEW_XULSTORE']:
|
||||
EXTRA_JS_MODULES += [
|
||||
'new/XULStore.jsm',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
TEST_DIRS += [
|
||||
'tests/gtest',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'XULStore.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'XULStore.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
else:
|
||||
EXTRA_JS_MODULES += [
|
||||
'old/XULStore.jsm',
|
||||
]
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
|
||||
const EXPORTED_SYMBOLS = ["XULStore"];
|
||||
|
||||
// Services.xulStore loads this module and returns its `XULStore` symbol
|
||||
// when this implementation of XULStore is enabled, so using it here
|
||||
// would loop infinitely. But the mozilla/use-services rule is a good
|
||||
// requiremnt for every other consumer of XULStore.
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
const xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
|
||||
|
||||
// Enables logging.
|
|
@ -5,19 +5,30 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIStringEnumerator;
|
||||
webidl Node;
|
||||
|
||||
/**
|
||||
* The XUL store is used to store information related to a XUL document/application.
|
||||
* Typically it is used to store the persisted state for the document, such as
|
||||
* window location, toolbars that are open and nodes that are open and closed in a tree.
|
||||
*
|
||||
* XULStore.jsm wraps this API in useful abstractions for JS consumers.
|
||||
* XULStore.h provides a more idiomatic API for C++ consumers.
|
||||
* You should use those APIs unless you have good reasons to use this one.
|
||||
* The data is serialized to [profile directory]/xulstore.json
|
||||
*/
|
||||
[scriptable, uuid(987c4b35-c426-4dd7-ad49-3c9fa4c65d20)]
|
||||
interface nsIXULStore: nsISupports
|
||||
{
|
||||
/**
|
||||
* Sets a value for a specified node's attribute, except in
|
||||
* the case below (following the original XULDocument::persist):
|
||||
* If the value is empty and if calling `hasValue` with the node's
|
||||
* document and ID and `attr` would return true, then the
|
||||
* value instead gets removed from the store (see Bug 1476680).
|
||||
*
|
||||
* @param node - DOM node
|
||||
* @param attr - attribute to store
|
||||
*/
|
||||
void persist(in Node aNode, in AString attr);
|
||||
|
||||
/**
|
||||
* Sets a value in the store.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,308 @@
|
|||
/* 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/. */
|
||||
|
||||
// Enables logging and shorter save intervals.
|
||||
const debugMode = false;
|
||||
|
||||
// Delay when a change is made to when the file is saved.
|
||||
// 30 seconds normally, or 3 seconds for testing
|
||||
const WRITE_DELAY_MS = (debugMode ? 3 : 30) * 1000;
|
||||
|
||||
const XULSTORE_CID = Components.ID("{6f46b6f4-c8b1-4bd4-a4fa-9ebbed0753ea}");
|
||||
const STOREDB_FILENAME = "xulstore.json";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
||||
function XULStore() {
|
||||
if (!Services.appinfo.inSafeMode)
|
||||
this.load();
|
||||
}
|
||||
|
||||
XULStore.prototype = {
|
||||
classID: XULSTORE_CID,
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsIXULStore,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
_xpcom_factory: XPCOMUtils.generateSingletonFactory(XULStore),
|
||||
|
||||
/* ---------- private members ---------- */
|
||||
|
||||
/*
|
||||
* The format of _data is _data[docuri][elementid][attribute]. For example:
|
||||
* {
|
||||
* "chrome://blah/foo.xul" : {
|
||||
* "main-window" : { aaa : 1, bbb : "c" },
|
||||
* "barColumn" : { ddd : 9, eee : "f" },
|
||||
* },
|
||||
*
|
||||
* "chrome://foopy/b.xul" : { ... },
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
_data: {},
|
||||
_storeFile: null,
|
||||
_needsSaving: false,
|
||||
_saveAllowed: true,
|
||||
_writeTimer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
|
||||
|
||||
load() {
|
||||
Services.obs.addObserver(this, "profile-before-change", true);
|
||||
|
||||
try {
|
||||
this._storeFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
} catch (ex) {
|
||||
try {
|
||||
this._storeFile = Services.dirsvc.get("ProfDS", Ci.nsIFile);
|
||||
} catch (ex) {
|
||||
throw new Error("Can't find profile directory.");
|
||||
}
|
||||
}
|
||||
this._storeFile.append(STOREDB_FILENAME);
|
||||
|
||||
this.readFile();
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
this.writeFile();
|
||||
if (topic == "profile-before-change") {
|
||||
this._saveAllowed = false;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Internal function for logging debug messages to the Error Console window
|
||||
*/
|
||||
log(message) {
|
||||
if (!debugMode)
|
||||
return;
|
||||
console.log("XULStore: " + message);
|
||||
},
|
||||
|
||||
readFile() {
|
||||
try {
|
||||
this._data = JSON.parse(Cu.readUTF8File(this._storeFile));
|
||||
} catch (e) {
|
||||
this.log("Error reading JSON: " + e);
|
||||
// This exception could mean that the file didn't exist.
|
||||
// We'll just ignore the error and start with a blank slate.
|
||||
}
|
||||
},
|
||||
|
||||
async writeFile() {
|
||||
if (!this._needsSaving)
|
||||
return;
|
||||
|
||||
this._needsSaving = false;
|
||||
|
||||
this.log("Writing to xulstore.json");
|
||||
|
||||
try {
|
||||
let data = JSON.stringify(this._data);
|
||||
let encoder = new TextEncoder();
|
||||
|
||||
data = encoder.encode(data);
|
||||
await OS.File.writeAtomic(this._storeFile.path, data,
|
||||
{ tmpPath: this._storeFile.path + ".tmp" });
|
||||
} catch (e) {
|
||||
this.log("Failed to write xulstore.json: " + e);
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
markAsChanged() {
|
||||
if (this._needsSaving || !this._storeFile)
|
||||
return;
|
||||
|
||||
// Don't write the file more than once every 30 seconds.
|
||||
this._needsSaving = true;
|
||||
this._writeTimer.init(this, WRITE_DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
},
|
||||
|
||||
/* ---------- interface implementation ---------- */
|
||||
|
||||
persist(node, attr) {
|
||||
if (!node.id) {
|
||||
throw new Error("Node without ID passed into persist()");
|
||||
}
|
||||
|
||||
const uri = node.ownerDocument.documentURI;
|
||||
const value = node.getAttribute(attr);
|
||||
|
||||
if (node.localName == "window") {
|
||||
this.log("Persisting attributes to windows is handled by nsXULWindow.");
|
||||
return;
|
||||
}
|
||||
|
||||
// See Bug 1476680 - we could drop the `hasValue` check so that
|
||||
// any time there's an empty attribute it gets removed from the
|
||||
// store. Since this is copying behavior from document.persist,
|
||||
// callers would need to be updated with that change.
|
||||
if (!value && this.hasValue(uri, node.id, attr)) {
|
||||
this.removeValue(uri, node.id, attr);
|
||||
} else {
|
||||
this.setValue(uri, node.id, attr, value);
|
||||
}
|
||||
},
|
||||
|
||||
setValue(docURI, id, attr, value) {
|
||||
this.log("Saving " + attr + "=" + value + " for id=" + id + ", doc=" + docURI);
|
||||
|
||||
if (!this._saveAllowed) {
|
||||
Services.console.logStringMessage("XULStore: Changes after profile-before-change are ignored!");
|
||||
return;
|
||||
}
|
||||
|
||||
// bug 319846 -- don't save really long attributes or values.
|
||||
if (id.length > 512 || attr.length > 512) {
|
||||
throw Components.Exception("id or attribute name too long", Cr.NS_ERROR_ILLEGAL_VALUE);
|
||||
}
|
||||
|
||||
if (value.length > 4096) {
|
||||
Services.console.logStringMessage("XULStore: Warning, truncating long attribute value");
|
||||
value = value.substr(0, 4096);
|
||||
}
|
||||
|
||||
let obj = this._data;
|
||||
if (!(docURI in obj)) {
|
||||
obj[docURI] = {};
|
||||
}
|
||||
obj = obj[docURI];
|
||||
if (!(id in obj)) {
|
||||
obj[id] = {};
|
||||
}
|
||||
obj = obj[id];
|
||||
|
||||
// Don't set the value if it is already set to avoid saving the file.
|
||||
if (attr in obj && obj[attr] == value)
|
||||
return;
|
||||
|
||||
obj[attr] = value; // IE, this._data[docURI][id][attr] = value;
|
||||
|
||||
this.markAsChanged();
|
||||
},
|
||||
|
||||
hasValue(docURI, id, attr) {
|
||||
this.log("has store value for id=" + id + ", attr=" + attr + ", doc=" + docURI);
|
||||
|
||||
let ids = this._data[docURI];
|
||||
if (ids) {
|
||||
let attrs = ids[id];
|
||||
if (attrs) {
|
||||
return attr in attrs;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
getValue(docURI, id, attr) {
|
||||
this.log("get store value for id=" + id + ", attr=" + attr + ", doc=" + docURI);
|
||||
|
||||
let ids = this._data[docURI];
|
||||
if (ids) {
|
||||
let attrs = ids[id];
|
||||
if (attrs) {
|
||||
return attrs[attr] || "";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
|
||||
removeValue(docURI, id, attr) {
|
||||
this.log("remove store value for id=" + id + ", attr=" + attr + ", doc=" + docURI);
|
||||
|
||||
if (!this._saveAllowed) {
|
||||
Services.console.logStringMessage("XULStore: Changes after profile-before-change are ignored!");
|
||||
return;
|
||||
}
|
||||
|
||||
let ids = this._data[docURI];
|
||||
if (ids) {
|
||||
let attrs = ids[id];
|
||||
if (attrs && attr in attrs) {
|
||||
delete attrs[attr];
|
||||
|
||||
if (Object.getOwnPropertyNames(attrs).length == 0) {
|
||||
delete ids[id];
|
||||
|
||||
if (Object.getOwnPropertyNames(ids).length == 0) {
|
||||
delete this._data[docURI];
|
||||
}
|
||||
}
|
||||
|
||||
this.markAsChanged();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeDocument(docURI) {
|
||||
this.log("remove store values for doc=" + docURI);
|
||||
|
||||
if (!this._saveAllowed) {
|
||||
Services.console.logStringMessage("XULStore: Changes after profile-before-change are ignored!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._data[docURI]) {
|
||||
delete this._data[docURI];
|
||||
this.markAsChanged();
|
||||
}
|
||||
},
|
||||
|
||||
getIDsEnumerator(docURI) {
|
||||
this.log("Getting ID enumerator for doc=" + docURI);
|
||||
|
||||
if (!(docURI in this._data))
|
||||
return new nsStringEnumerator([]);
|
||||
|
||||
let result = [];
|
||||
let ids = this._data[docURI];
|
||||
if (ids) {
|
||||
for (let id in this._data[docURI]) {
|
||||
result.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
return new nsStringEnumerator(result);
|
||||
},
|
||||
|
||||
getAttributeEnumerator(docURI, id) {
|
||||
this.log("Getting attribute enumerator for id=" + id + ", doc=" + docURI);
|
||||
|
||||
if (!(docURI in this._data) || !(id in this._data[docURI]))
|
||||
return new nsStringEnumerator([]);
|
||||
|
||||
let attrs = [];
|
||||
for (let attr in this._data[docURI][id]) {
|
||||
attrs.push(attr);
|
||||
}
|
||||
|
||||
return new nsStringEnumerator(attrs);
|
||||
},
|
||||
};
|
||||
|
||||
function nsStringEnumerator(items) {
|
||||
this._items = items;
|
||||
}
|
||||
|
||||
nsStringEnumerator.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIStringEnumerator]),
|
||||
_nextIndex: 0,
|
||||
[Symbol.iterator]() {
|
||||
return this._items.values();
|
||||
},
|
||||
hasMore() {
|
||||
return this._nextIndex < this._items.length;
|
||||
},
|
||||
getNext() {
|
||||
if (!this.hasMore())
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
return this._items[this._nextIndex++];
|
||||
},
|
||||
};
|
||||
|
||||
var EXPORTED_SYMBOLS = ["XULStore"];
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate as XULStore;
|
||||
use crate::{iter::XULStoreIterator, persist::clear_on_shutdown, statics::update_profile_dir};
|
||||
use libc::c_char;
|
||||
use libc::{c_char, c_void};
|
||||
use nserror::{nsresult, NS_ERROR_NOT_IMPLEMENTED, NS_OK};
|
||||
use nsstring::{nsAString, nsString};
|
||||
use std::cell::RefCell;
|
||||
|
@ -30,6 +30,11 @@ impl XULStoreService {
|
|||
XULStoreService::allocate(InitXULStoreService {})
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn Persist(&self, _node: *const c_void, _attr: *const nsAString) -> nsresult {
|
||||
NS_ERROR_NOT_IMPLEMENTED
|
||||
}
|
||||
|
||||
xpcom_method!(
|
||||
set_value => SetValue(
|
||||
doc: *const nsAString,
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
<script>
|
||||
<![CDATA[
|
||||
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const XULStore = Services.xulStore;
|
||||
let URI = "chrome://mochitests/content/chrome/toolkit/components/xulstore/tests/chrome/window_persistence.xul";
|
||||
|
||||
function opened()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
|
@ -7,7 +8,9 @@ function run_test() {
|
|||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(async function test_create_old_datastore() {
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_create_old_datastore() {
|
||||
const path = OS.Path.join(OS.Constants.Path.profileDir, "xulstore.json");
|
||||
|
||||
const xulstoreJSON = {
|
||||
|
@ -33,8 +36,10 @@ add_task(async function test_create_old_datastore() {
|
|||
await OS.File.writeAtomic(path, JSON.stringify(xulstoreJSON));
|
||||
});
|
||||
|
||||
add_task(async function test_get_values() {
|
||||
// We wait until now to import XULStore.jsm to ensure we've created
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_get_values() {
|
||||
// We wait until now to import XULStore to ensure we've created
|
||||
// the old datastore, as importing that module will initiate the attempt
|
||||
// to migrate the old datastore to the new one.
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
|
@ -7,7 +8,9 @@ function run_test() {
|
|||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(async function test_create_old_datastore() {
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_create_old_datastore() {
|
||||
const path = OS.Path.join(OS.Constants.Path.profileDir, "xulstore.json");
|
||||
|
||||
// Valid JSON, but invalid data: attr1's value is a number, not a string.
|
||||
|
@ -27,8 +30,10 @@ add_task(async function test_create_old_datastore() {
|
|||
await OS.File.writeAtomic(path, JSON.stringify(xulstoreJSON));
|
||||
});
|
||||
|
||||
add_task(async function test_get_values() {
|
||||
// We wait until now to import XULStore.jsm to ensure we've created
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_get_values() {
|
||||
// We wait until now to import XULStore to ensure we've created
|
||||
// the old store, as importing that module will initiate the attempt
|
||||
// to migrate the old store to the new one.
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
|
@ -7,7 +8,9 @@ function run_test() {
|
|||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(async function test_create_old_datastore() {
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_create_old_datastore() {
|
||||
const path = OS.Path.join(OS.Constants.Path.profileDir, "xulstore.json");
|
||||
|
||||
// Invalid JSON: it's missing the final closing brace.
|
||||
|
@ -16,8 +19,10 @@ add_task(async function test_create_old_datastore() {
|
|||
await OS.File.writeAtomic(path, xulstoreJSON);
|
||||
});
|
||||
|
||||
add_task(async function test_get_value() {
|
||||
// We wait until now to import XULStore.jsm to ensure we've created
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_get_value() {
|
||||
// We wait until now to import XULStore to ensure we've created
|
||||
// the old store, as importing that module will initiate the attempt
|
||||
// to migrate the old store to the new one.
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
add_task(async function test_get_values() {
|
||||
// Import XULStore.jsm before getting the profile to ensure that the new store
|
||||
add_task({
|
||||
skip_if: () => !AppConstants.MOZ_NEW_XULSTORE,
|
||||
}, async function test_get_values() {
|
||||
// Import XULStore before getting the profile to ensure that the new store
|
||||
// is initialized, as the purpose of this test is to confirm that the old
|
||||
// store data gets migrated if the profile change happens post-initialization.
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
skip-if = toolkit == 'android'
|
||||
|
||||
[test_XULStore.js]
|
||||
|
||||
# These tests only run on the new implementation of XULStore, since they
|
||||
# test migration of data from the old implementation to the new one.
|
||||
# But there isn't a skip-if condition we can add here to disable them,
|
||||
# so we disable them within each test file using add_task() properties.
|
||||
[test_XULStore_migration.js]
|
||||
[test_XULStore_migration_fail_invalid_json.js]
|
||||
[test_XULStore_migration_fail_invalid_data.js]
|
||||
|
|
|
@ -23,6 +23,7 @@ cranelift_none = ["gkrust-shared/cranelift_none"]
|
|||
gecko_profiler = ["gkrust-shared/gecko_profiler"]
|
||||
gecko_profiler_parse_elf = ["gkrust-shared/gecko_profiler_parse_elf"]
|
||||
bitsdownload = ["gkrust-shared/bitsdownload"]
|
||||
new_xulstore = ["gkrust-shared/new_xulstore"]
|
||||
|
||||
[dependencies]
|
||||
bench-collections-gtest = { path = "../../../../xpcom/rust/gtest/bench-collections" }
|
||||
|
|
|
@ -24,6 +24,7 @@ cranelift_none = ["gkrust-shared/cranelift_none"]
|
|||
gecko_profiler = ["gkrust-shared/gecko_profiler"]
|
||||
gecko_profiler_parse_elf = ["gkrust-shared/gecko_profiler_parse_elf"]
|
||||
bitsdownload = ["gkrust-shared/bitsdownload"]
|
||||
new_xulstore = ["gkrust-shared/new_xulstore"]
|
||||
|
||||
[dependencies]
|
||||
gkrust-shared = { path = "shared" }
|
||||
|
|
|
@ -50,3 +50,6 @@ if CONFIG['MOZ_GECKO_PROFILER_PARSE_ELF']:
|
|||
|
||||
if CONFIG['MOZ_BITS_DOWNLOAD']:
|
||||
gkrust_features += ['bitsdownload']
|
||||
|
||||
if CONFIG['MOZ_NEW_XULSTORE']:
|
||||
gkrust_features += ['new_xulstore']
|
||||
|
|
|
@ -27,7 +27,7 @@ audioipc-server = { path = "../../../../media/audioipc/server", optional = true
|
|||
u2fhid = { path = "../../../../dom/webauthn/u2f-hid-rs" }
|
||||
gkrust_utils = { path = "../../../../xpcom/rust/gkrust_utils" }
|
||||
rsdparsa_capi = { path = "../../../../media/webrtc/signaling/src/sdp/rsdparsa_capi" }
|
||||
xulstore = { path = "../../../components/xulstore" }
|
||||
xulstore = { path = "../../../components/xulstore", optional = true }
|
||||
# We have these to enforce common feature sets for said crates.
|
||||
log = {version = "0.4", features = ["release_max_level_info"]}
|
||||
env_logger = {version = "0.5", default-features = false} # disable `regex` to reduce code size
|
||||
|
@ -61,6 +61,7 @@ cranelift_arm64 = ["jsrust_shared/cranelift_arm64"]
|
|||
cranelift_none = ["jsrust_shared/cranelift_none"]
|
||||
gecko_profiler = ["profiler_helper"]
|
||||
gecko_profiler_parse_elf = ["profiler_helper/parse_elf"]
|
||||
new_xulstore = ["xulstore"]
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
|
|
@ -34,6 +34,7 @@ extern crate log;
|
|||
extern crate cert_storage;
|
||||
extern crate cosec;
|
||||
extern crate rsdparsa_capi;
|
||||
#[cfg(feature = "new_xulstore")]
|
||||
extern crate xulstore;
|
||||
#[cfg(feature = "spidermonkey_rust")]
|
||||
extern crate jsrust_shared;
|
||||
|
|
|
@ -350,4 +350,11 @@ this.AppConstants = Object.freeze({
|
|||
#endif
|
||||
|
||||
TELEMETRY_PING_FORMAT_VERSION: @TELEMETRY_PING_FORMAT_VERSION@,
|
||||
|
||||
MOZ_NEW_XULSTORE:
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
true,
|
||||
#else
|
||||
false,
|
||||
#endif
|
||||
});
|
||||
|
|
|
@ -51,11 +51,6 @@ if (AppConstants.MOZ_CRASHREPORTER) {
|
|||
});
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, "xulStore", () => {
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
return XULStore;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, "io", () => {
|
||||
return Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService)
|
||||
|
@ -117,6 +112,15 @@ if ("@mozilla.org/enterprisepolicies;1" in Cc) {
|
|||
initTable.policies = ["@mozilla.org/enterprisepolicies;1", "nsIEnterprisePolicies"];
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_NEW_XULSTORE) {
|
||||
XPCOMUtils.defineLazyGetter(Services, "xulStore", () => {
|
||||
const {XULStore} = ChromeUtils.import("resource://gre/modules/XULStore.jsm");
|
||||
return XULStore;
|
||||
});
|
||||
} else {
|
||||
initTable.xulStore = ["@mozilla.org/xul/xulstore;1", "nsIXULStore"];
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetters(Services, initTable);
|
||||
|
||||
initTable = undefined;
|
||||
|
|
|
@ -1726,3 +1726,15 @@ def has_remote(toolkit):
|
|||
|
||||
set_config('MOZ_HAS_REMOTE', has_remote)
|
||||
set_define('MOZ_HAS_REMOTE', has_remote)
|
||||
|
||||
|
||||
# new XULStore implementation
|
||||
# ==============================================================
|
||||
|
||||
@depends(milestone)
|
||||
def new_xulstore(milestone):
|
||||
if milestone.is_nightly:
|
||||
return True
|
||||
|
||||
set_config('MOZ_NEW_XULSTORE', True, when=new_xulstore)
|
||||
set_define('MOZ_NEW_XULSTORE', True, when=new_xulstore)
|
||||
|
|
|
@ -55,13 +55,16 @@
|
|||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/XULStore.h"
|
||||
#include "mozilla/dom/BarProps.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/BrowserParent.h"
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
# include "mozilla/XULStore.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using dom::AutoNoJSAPI;
|
||||
|
||||
|
@ -1605,8 +1608,20 @@ nsresult nsXULWindow::GetPersistentValue(const nsAtom* aAttr,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ConvertUTF8toUTF16 uri(utf8uri);
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
nsDependentAtomString attrString(aAttr);
|
||||
rv = XULStore::GetValue(uri, windowElementId, attrString, aValue);
|
||||
#else
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
rv = mLocalStore->GetValue(uri, windowElementId, nsDependentAtomString(aAttr),
|
||||
aValue);
|
||||
#endif
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1656,9 +1671,21 @@ nsresult nsXULWindow::SetPersistentValue(const nsAtom* aAttr,
|
|||
maybeConvertedValue);
|
||||
}
|
||||
|
||||
#ifdef MOZ_NEW_XULSTORE
|
||||
nsDependentAtomString attrString(aAttr);
|
||||
return XULStore::SetValue(uri, windowElementId, attrString,
|
||||
maybeConvertedValue);
|
||||
#else
|
||||
if (!mLocalStore) {
|
||||
mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
|
||||
if (NS_WARN_IF(!mLocalStore)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
return mLocalStore->SetValue(
|
||||
uri, windowElementId, nsDependentAtomString(aAttr), maybeConvertedValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXULWindow::SavePersistentAttributes() {
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
#include "nsIWidgetListener.h"
|
||||
#include "nsIRemoteTab.h"
|
||||
|
||||
#ifndef MOZ_NEW_XULSTORE
|
||||
# include "nsIXULStore.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
|
@ -194,6 +198,9 @@ class nsXULWindow : public nsIBaseWindow,
|
|||
GetPrimaryRemoteTabSize(int32_t* aWidth, int32_t* aHeight);
|
||||
nsresult GetPrimaryContentShellSize(int32_t* aWidth, int32_t* aHeight);
|
||||
nsresult SetPrimaryRemoteTabSize(int32_t aWidth, int32_t aHeight);
|
||||
#ifndef MOZ_NEW_XULSTORE
|
||||
nsCOMPtr<nsIXULStore> mLocalStore;
|
||||
#endif
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsXULWindow, NS_XULWINDOW_IMPL_CID)
|
||||
|
|
Загрузка…
Ссылка в новой задаче