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:
Myk Melez 2019-05-02 23:01:57 +00:00
parent 910be2ccef
commit 1b3f6d1faf
25 changed files with 574 additions and 55 deletions

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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
}
}

View File

@ -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',
},
]

View File

@ -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',
]

View File

@ -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.

View File

@ -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.
*

View File

@ -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"];

View File

@ -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,

View File

@ -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()

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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]

View File

@ -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" }

View File

@ -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" }

View File

@ -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']

View File

@ -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"

View File

@ -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;

View File

@ -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
});

View File

@ -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;

View File

@ -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)

View File

@ -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() {

View File

@ -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)