зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
2cab48f64d
|
@ -2428,34 +2428,6 @@ function getLocalHandlerApp(aFile) {
|
|||
return localHandlerApp;
|
||||
}
|
||||
|
||||
/**
|
||||
* An enumeration of items in a JS array.
|
||||
*
|
||||
* FIXME: use ArrayConverter once it lands (bug 380839).
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ArrayEnumerator(aItems) {
|
||||
this._index = 0;
|
||||
this._contents = aItems;
|
||||
}
|
||||
|
||||
ArrayEnumerator.prototype = {
|
||||
_index: 0,
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this._contents.values();
|
||||
},
|
||||
|
||||
hasMoreElements() {
|
||||
return this._index < this._contents.length;
|
||||
},
|
||||
|
||||
getNext() {
|
||||
return this._contents[this._index++];
|
||||
},
|
||||
};
|
||||
|
||||
function isFeedType(t) {
|
||||
return t == TYPE_MAYBE_FEED || t == TYPE_MAYBE_VIDEO_FEED || t == TYPE_MAYBE_AUDIO_FEED;
|
||||
}
|
||||
|
@ -3006,7 +2978,7 @@ class FeedHandlerInfo extends HandlerInfoWrapper {
|
|||
},
|
||||
|
||||
enumerate() {
|
||||
return new ArrayEnumerator(this._inner);
|
||||
return this._inner.values();
|
||||
},
|
||||
|
||||
appendElement(aHandlerApp, aWeak) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "xpcprivate.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsQueryObject.h"
|
||||
|
|
|
@ -611,6 +611,29 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// If we're asked to QI to nsISimpleEnumerator and the wrapped object does not have a
|
||||
// QueryInterface method, assume it is a JS iterator, and wrap it into an equivalent
|
||||
// nsISimpleEnumerator.
|
||||
if (aIID.Equals(NS_GET_IID(nsISimpleEnumerator))) {
|
||||
bool found;
|
||||
XPCJSContext* xpccx = ccx.GetContext();
|
||||
if (JS_HasPropertyById(aes.cx(), obj,
|
||||
xpccx->GetStringID(xpccx->IDX_QUERY_INTERFACE),
|
||||
&found) && !found) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIJSEnumerator> jsEnum;
|
||||
if (!XPCConvert::JSObject2NativeInterface(aes.cx(),
|
||||
getter_AddRefs(jsEnum), obj,
|
||||
&NS_GET_IID(nsIJSEnumerator),
|
||||
nullptr, &rv)) {
|
||||
return rv;
|
||||
}
|
||||
nsCOMPtr<nsISimpleEnumerator> res = new XPCWrappedJSIterator(jsEnum);
|
||||
res.forget(aInstancePtr);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// else we do the more expensive stuff...
|
||||
|
||||
// check if the JSObject claims to implement this interface
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=4 et sw=4 tw=99: */
|
||||
/* 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/. */
|
||||
|
||||
#include "xpcprivate.h"
|
||||
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/dom/IteratorResultBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace xpc;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(XPCWrappedJSIterator, mEnum, mGlobal, mNext)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCWrappedJSIterator)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCWrappedJSIterator)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCWrappedJSIterator)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISimpleEnumerator)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISimpleEnumeratorBase)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, XPCWrappedJSIterator)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
XPCWrappedJSIterator::XPCWrappedJSIterator(nsIJSEnumerator* aEnum)
|
||||
: mEnum(aEnum)
|
||||
{
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(aEnum);
|
||||
MOZ_ASSERT(wrapped);
|
||||
mGlobal = NativeGlobal(wrapped->GetJSObjectGlobal());
|
||||
}
|
||||
|
||||
nsresult
|
||||
XPCWrappedJSIterator::HasMoreElements(bool* aRetVal)
|
||||
{
|
||||
if (mHasNext.isNothing()) {
|
||||
AutoJSAPI jsapi;
|
||||
MOZ_ALWAYS_TRUE(jsapi.Init(mGlobal));
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
MOZ_TRY(mEnum->Next(cx, &val));
|
||||
|
||||
RootedDictionary<IteratorResult> result(cx);
|
||||
if (!result.Init(cx, val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!result.mDone) {
|
||||
if (result.mValue.isObject()) {
|
||||
JS::RootedObject obj(cx, &result.mValue.toObject());
|
||||
|
||||
nsresult rv;
|
||||
if (!XPCConvert::JSObject2NativeInterface(
|
||||
cx, getter_AddRefs(mNext), obj,
|
||||
&NS_GET_IID(nsISupports), nullptr,
|
||||
&rv)) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
mNext = XPCVariant::newVariant(cx, result.mValue);
|
||||
}
|
||||
}
|
||||
mHasNext = Some(!result.mDone);
|
||||
}
|
||||
*aRetVal = *mHasNext;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XPCWrappedJSIterator::GetNext(nsISupports** aRetVal)
|
||||
{
|
||||
bool hasMore;
|
||||
MOZ_TRY(HasMoreElements(&hasMore));
|
||||
if (!hasMore) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mNext.forget(aRetVal);
|
||||
mHasNext = Nothing();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XPCWrappedJSIterator::Iterator(nsIJSEnumerator** aRetVal)
|
||||
{
|
||||
nsCOMPtr<nsIJSEnumerator> jsEnum = mEnum;
|
||||
jsEnum.forget(aRetVal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
XPCWrappedJSIterator::Entries(const nsID&, nsIJSEnumerator** aRetVal)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
|
@ -35,6 +35,7 @@ UNIFIED_SOURCES += [
|
|||
'XPCVariant.cpp',
|
||||
'XPCWrappedJS.cpp',
|
||||
'XPCWrappedJSClass.cpp',
|
||||
'XPCWrappedJSIterator.cpp',
|
||||
'XPCWrappedNative.cpp',
|
||||
'XPCWrappedNativeInfo.cpp',
|
||||
'XPCWrappedNativeJSOps.cpp',
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
#include "nsIComponentManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIXPCScriptable.h"
|
||||
|
@ -1944,6 +1945,31 @@ private:
|
|||
nsCOMPtr<nsIVariant> mValue;
|
||||
};
|
||||
|
||||
namespace xpc {
|
||||
|
||||
// A wrapper around JS iterators which presents an equivalent
|
||||
// nsISimpleEnumerator interface for their contents.
|
||||
class XPCWrappedJSIterator final : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(XPCWrappedJSIterator)
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
NS_DECL_NSISIMPLEENUMERATORBASE
|
||||
|
||||
explicit XPCWrappedJSIterator(nsIJSEnumerator* aEnum);
|
||||
|
||||
private:
|
||||
~XPCWrappedJSIterator() = default;
|
||||
|
||||
nsCOMPtr<nsIJSEnumerator> mEnum;
|
||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||
nsCOMPtr<nsISupports> mNext;
|
||||
mozilla::Maybe<bool> mHasNext;
|
||||
};
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
/***************************************************************************/
|
||||
// class here just for static methods
|
||||
class XPCConvert
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
|
||||
// Tests that JS iterators are automatically wrapped into
|
||||
// equivalent nsISimpleEnumerator objects.
|
||||
|
||||
const Variant = Components.Constructor("@mozilla.org/variant;1",
|
||||
"nsIWritableVariant",
|
||||
"setFromVariant");
|
||||
const SupportsInterfacePointer = Components.Constructor(
|
||||
"@mozilla.org/supports-interface-pointer;1", "nsISupportsInterfacePointer");
|
||||
|
||||
function wrapEnumerator(iter) {
|
||||
var ip = SupportsInterfacePointer();
|
||||
ip.data = iter;
|
||||
return ip.data.QueryInterface(Ci.nsISimpleEnumerator);
|
||||
}
|
||||
|
||||
function enumToArray(iter) {
|
||||
let result = [];
|
||||
while (iter.hasMoreElements()) {
|
||||
result.push(iter.getNext().QueryInterface(Ci.nsIVariant));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
add_task(async function test_wrapped_js_enumerator() {
|
||||
let array = [1, 2, 3, 4];
|
||||
|
||||
// Test a plain JS iterator. This should automatically be wrapped into
|
||||
// an equivalent nsISimpleEnumerator.
|
||||
{
|
||||
let iter = wrapEnumerator(array.values());
|
||||
let result = enumToArray(iter);
|
||||
|
||||
deepEqual(result, array, "Got correct result");
|
||||
}
|
||||
|
||||
// Test an object with a QueryInterface method, which implements
|
||||
// nsISimpleEnumerator. This should be wrapped and used directly.
|
||||
{
|
||||
let obj = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsISimpleEnumerator"]),
|
||||
_idx: 0,
|
||||
hasMoreElements() {
|
||||
return this._idx < array.length;
|
||||
},
|
||||
getNext() {
|
||||
return Variant(array[this._idx++]);
|
||||
},
|
||||
};
|
||||
|
||||
let iter = wrapEnumerator(obj);
|
||||
let result = enumToArray(iter);
|
||||
|
||||
deepEqual(result, array, "Got correct result");
|
||||
}
|
||||
});
|
|
@ -148,3 +148,4 @@ head = head_watchdog.js
|
|||
[test_SubscriptLoaderSandboxEnvironment.js]
|
||||
[test_SubscriptLoaderJSMEnvironment.js]
|
||||
[test_ComponentEnvironment.js]
|
||||
[test_wrapped_js_enumerator.js]
|
||||
|
|
|
@ -137,19 +137,7 @@ DirectoryProvider.prototype = {
|
|||
|
||||
let result = [];
|
||||
this._appendDistroSearchDirs(result);
|
||||
|
||||
return {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]),
|
||||
[Symbol.iterator]() {
|
||||
return result.values();
|
||||
},
|
||||
hasMoreElements: function() {
|
||||
return result.length > 0;
|
||||
},
|
||||
getNext: function() {
|
||||
return result.shift();
|
||||
}
|
||||
};
|
||||
return result.values();
|
||||
},
|
||||
|
||||
_getDistributionDirectories: function() {
|
||||
|
|
|
@ -138,7 +138,7 @@ FilePicker.prototype = {
|
|||
},
|
||||
|
||||
get files() {
|
||||
return this.getEnumerator([this.file]);
|
||||
return [this.file].values();
|
||||
},
|
||||
|
||||
// We don't support directory selection yet.
|
||||
|
@ -147,7 +147,7 @@ FilePicker.prototype = {
|
|||
},
|
||||
|
||||
get domFileOrDirectoryEnumerator() {
|
||||
return this.getEnumerator([this._domFile]);
|
||||
return [this._domFile].values();
|
||||
},
|
||||
|
||||
get addToRecentDocs() {
|
||||
|
@ -248,26 +248,6 @@ FilePicker.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
getEnumerator: function(files) {
|
||||
return {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]),
|
||||
mFiles: files,
|
||||
mIndex: 0,
|
||||
[Symbol.iterator]() {
|
||||
return this.mFiles.values();
|
||||
},
|
||||
hasMoreElements: function() {
|
||||
return (this.mIndex < this.mFiles.length);
|
||||
},
|
||||
getNext: function() {
|
||||
if (this.mIndex >= this.mFiles.length) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
return this.mFiles[this.mIndex++];
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
fireDialogEvent: function(aDomWin, aEventName) {
|
||||
// accessing the document object can throw if this window no longer exists. See bug 789888.
|
||||
try {
|
||||
|
|
|
@ -865,36 +865,17 @@ FilePickerDelegate.prototype = {
|
|||
return Services.io.newFileURI(this.file);
|
||||
},
|
||||
|
||||
_getEnumerator(aDOMFile) {
|
||||
* _getEnumerator(aDOMFile) {
|
||||
if (!this._files) {
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
return {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]),
|
||||
_owner: this,
|
||||
_index: 0,
|
||||
* [Symbol.iterator]() {
|
||||
for (let file of this._owner._files) {
|
||||
if (aDOMFile) {
|
||||
yield this._owner._getDOMFile(file);
|
||||
}
|
||||
yield new FileUtils.File(file);
|
||||
}
|
||||
},
|
||||
hasMoreElements: function() {
|
||||
return this._index < this._owner._files.length;
|
||||
},
|
||||
getNext: function() {
|
||||
let files = this._owner._files;
|
||||
if (this._index >= files.length) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
if (aDOMFile) {
|
||||
return this._owner._getDOMFile(files[this._index++]);
|
||||
}
|
||||
return new FileUtils.File(files[this._index++]);
|
||||
|
||||
for (let file of this._files) {
|
||||
if (aDOMFile) {
|
||||
yield this._getDOMFile(file);
|
||||
}
|
||||
};
|
||||
yield new FileUtils.File(file);
|
||||
}
|
||||
},
|
||||
|
||||
get files() {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/HashTable.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
@ -538,15 +539,6 @@ public:
|
|||
|
||||
// Other operations.
|
||||
|
||||
bool MatchEntry(const char* aPrefName)
|
||||
{
|
||||
if (!mName || !aPrefName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strcmp(mName, aPrefName) == 0;
|
||||
}
|
||||
|
||||
bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const
|
||||
{
|
||||
MOZ_ASSERT(IsTypeBool());
|
||||
|
@ -955,33 +947,20 @@ private:
|
|||
PrefValue mUserValue;
|
||||
};
|
||||
|
||||
class PrefEntry : public PLDHashEntryHdr
|
||||
struct PrefHasher
|
||||
{
|
||||
public:
|
||||
Pref* mPref; // Note: this is never null in a live entry.
|
||||
using Key = mozilla::UniquePtr<Pref>;
|
||||
using Lookup = const char*;
|
||||
|
||||
static bool MatchEntry(const PLDHashEntryHdr* aEntry, const void* aKey)
|
||||
static HashNumber hash(const Lookup& aLookup) { return HashString(aLookup); }
|
||||
|
||||
static bool match(const Key& aKey, const Lookup& aLookup)
|
||||
{
|
||||
auto entry = static_cast<const PrefEntry*>(aEntry);
|
||||
auto prefName = static_cast<const char*>(aKey);
|
||||
if (!aLookup || !aKey->Name()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return entry->mPref->MatchEntry(prefName);
|
||||
}
|
||||
|
||||
static void InitEntry(PLDHashEntryHdr* aEntry, const void* aKey)
|
||||
{
|
||||
auto entry = static_cast<PrefEntry*>(aEntry);
|
||||
auto prefName = static_cast<const char*>(aKey);
|
||||
|
||||
entry->mPref = new Pref(prefName);
|
||||
}
|
||||
|
||||
static void ClearEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
|
||||
{
|
||||
auto entry = static_cast<PrefEntry*>(aEntry);
|
||||
|
||||
delete entry->mPref;
|
||||
entry->mPref = nullptr;
|
||||
return strcmp(aLookup, aKey->Name()) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1301,7 +1280,9 @@ private:
|
|||
uintptr_t mNextAndMatchKind;
|
||||
};
|
||||
|
||||
static PLDHashTable* gHashTable;
|
||||
using PrefsHashTable = mozilla::HashSet<mozilla::UniquePtr<Pref>, PrefHasher>;
|
||||
|
||||
static PrefsHashTable* gHashTable;
|
||||
|
||||
// The callback list contains all the priority callbacks followed by the
|
||||
// non-priority callbacks. gLastPriorityNode records where the first part ends.
|
||||
|
@ -1349,22 +1330,16 @@ AddAccessCount(const char* aPrefName)
|
|||
static bool gCallbacksInProgress = false;
|
||||
static bool gShouldCleanupDeadNodes = false;
|
||||
|
||||
static PLDHashTableOps pref_HashTableOps = {
|
||||
PLDHashTable::HashStringKey, PrefEntry::MatchEntry,
|
||||
PLDHashTable::MoveEntryStub, PrefEntry::ClearEntry,
|
||||
PrefEntry::InitEntry,
|
||||
};
|
||||
|
||||
class PrefsHashIter
|
||||
{
|
||||
using Iterator = decltype(gHashTable->Iter());
|
||||
using Iterator = decltype(gHashTable->modIter());
|
||||
using ElemType = Pref*;
|
||||
|
||||
Iterator mIter;
|
||||
|
||||
public:
|
||||
explicit PrefsHashIter(PLDHashTable* aTable)
|
||||
: mIter(aTable->Iter())
|
||||
explicit PrefsHashIter(PrefsHashTable* aTable)
|
||||
: mIter(aTable->modIter())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1391,7 +1366,7 @@ public:
|
|||
if (mDone) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<PrefEntry*>(Iter().Get())->mPref;
|
||||
return Iter().get().get();
|
||||
}
|
||||
ElemType get() const { return const_cast<Elem*>(this)->get(); }
|
||||
|
||||
|
@ -1400,13 +1375,13 @@ public:
|
|||
|
||||
operator ElemType() { return get(); }
|
||||
|
||||
void Remove() { Iter().Remove(); }
|
||||
void Remove() { Iter().remove(); }
|
||||
|
||||
Elem& operator++()
|
||||
{
|
||||
MOZ_ASSERT(!mDone);
|
||||
Iter().Next();
|
||||
mDone = Iter().Done();
|
||||
Iter().next();
|
||||
mDone = Iter().done();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1416,14 +1391,14 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
Elem begin() { return Elem(*this, mIter.Done()); }
|
||||
Elem begin() { return Elem(*this, mIter.done()); }
|
||||
|
||||
Elem end() { return Elem(*this, true); }
|
||||
};
|
||||
|
||||
class PrefsIter
|
||||
{
|
||||
using Iterator = decltype(gHashTable->Iter());
|
||||
using Iterator = decltype(gHashTable->iter());
|
||||
using ElemType = PrefWrapper;
|
||||
|
||||
using HashElem = PrefsHashIter::Elem;
|
||||
|
@ -1432,7 +1407,7 @@ class PrefsIter
|
|||
using ElemTypeVariant = Variant<HashElem, SharedElem>;
|
||||
|
||||
SharedPrefMap* mSharedMap;
|
||||
PLDHashTable* mHashTable;
|
||||
PrefsHashTable* mHashTable;
|
||||
PrefsHashIter mIter;
|
||||
|
||||
ElemTypeVariant mPos;
|
||||
|
@ -1441,7 +1416,7 @@ class PrefsIter
|
|||
Maybe<PrefWrapper> mEntry;
|
||||
|
||||
public:
|
||||
PrefsIter(PLDHashTable* aHashTable, SharedPrefMap* aSharedMap)
|
||||
PrefsIter(PrefsHashTable* aHashTable, SharedPrefMap* aSharedMap)
|
||||
: mSharedMap(aSharedMap)
|
||||
, mHashTable(aHashTable)
|
||||
, mIter(aHashTable)
|
||||
|
@ -1531,9 +1506,9 @@ public:
|
|||
|
||||
void SkipDuplicates()
|
||||
{
|
||||
while (!mDone && (mParent.IteratingBase()
|
||||
? !!mParent.mHashTable->Search(ref().Name())
|
||||
: ref().IsTypeNone())) {
|
||||
while (!mDone &&
|
||||
(mParent.IteratingBase() ? mParent.mHashTable->has(ref().Name())
|
||||
: ref().IsTypeNone())) {
|
||||
Next();
|
||||
}
|
||||
}
|
||||
|
@ -1621,7 +1596,7 @@ pref_savePrefs()
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
PrefSaveData savedPrefs(gHashTable->EntryCount());
|
||||
PrefSaveData savedPrefs(gHashTable->count());
|
||||
|
||||
for (auto& pref : PrefsIter(gHashTable, gSharedMap)) {
|
||||
nsAutoCString prefValueStr;
|
||||
|
@ -1649,25 +1624,19 @@ static bool gContentProcessPrefsAreInited = false;
|
|||
|
||||
#endif // DEBUG
|
||||
|
||||
static PrefEntry*
|
||||
pref_HashTableLookupInner(const char* aPrefName)
|
||||
static Pref*
|
||||
pref_HashTableLookup(const char* aPrefName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() || mozilla::ServoStyleSet::IsInServoTraversal());
|
||||
|
||||
MOZ_ASSERT_IF(!XRE_IsParentProcess(), gContentProcessPrefsAreInited);
|
||||
|
||||
return static_cast<PrefEntry*>(gHashTable->Search(aPrefName));
|
||||
}
|
||||
|
||||
static Pref*
|
||||
pref_HashTableLookup(const char* aPrefName)
|
||||
{
|
||||
PrefEntry* entry = pref_HashTableLookupInner(aPrefName);
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return entry->mPref;
|
||||
// We use readonlyThreadsafeLookup() because we often have concurrent lookups
|
||||
// from multiple Stylo threads. This is safe because those threads cannot
|
||||
// modify gHashTable, and the main thread is blocked while Stylo threads are
|
||||
// doing these lookups.
|
||||
auto p = gHashTable->readonlyThreadsafeLookup(aPrefName);
|
||||
return p ? p->get() : nullptr;
|
||||
}
|
||||
|
||||
// While notifying preference callbacks, this holds the wrapper for the
|
||||
|
@ -1718,11 +1687,11 @@ pref_LookupForModify(const char* aPrefName,
|
|||
return wrapper->as<Pref*>();
|
||||
}
|
||||
|
||||
auto entry = static_cast<PrefEntry*>(gHashTable->Add(aPrefName, fallible));
|
||||
if (!entry) {
|
||||
Pref* pref = new Pref(aPrefName);
|
||||
if (!gHashTable->putNew(aPrefName, pref)) {
|
||||
delete pref;
|
||||
return Err(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
Pref* pref = entry->mPref;
|
||||
pref->FromWrapper(*wrapper);
|
||||
return pref;
|
||||
}
|
||||
|
@ -1755,15 +1724,16 @@ pref_SetPref(const char* aPrefName,
|
|||
}
|
||||
|
||||
if (!pref) {
|
||||
auto entry = static_cast<PrefEntry*>(gHashTable->Add(aPrefName, fallible));
|
||||
if (!entry) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
pref = entry->mPref;
|
||||
|
||||
if (pref->IsTypeNone()) {
|
||||
// New entry. Set the type.
|
||||
auto p = gHashTable->lookupForAdd(aPrefName);
|
||||
if (!p) {
|
||||
pref = new Pref(aPrefName);
|
||||
pref->SetType(aType);
|
||||
if (!gHashTable->add(p, pref)) {
|
||||
delete pref;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
pref = p->get();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2882,16 +2852,14 @@ nsPrefBranch::DeleteBranch(const char* aStartingAt)
|
|||
const nsACString& branchNameNoDot =
|
||||
Substring(branchName, 0, branchName.Length() - 1);
|
||||
|
||||
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
|
||||
|
||||
for (auto iter = gHashTable->modIter(); !iter.done(); iter.next()) {
|
||||
// The first disjunct matches branches: e.g. a branch name "foo.bar."
|
||||
// matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz").
|
||||
// The second disjunct matches leaf nodes: e.g. a branch name "foo.bar."
|
||||
// matches a name "foo.bar" (by ignoring the trailing '.').
|
||||
nsDependentCString name(pref->Name());
|
||||
nsDependentCString name(iter.get()->Name());
|
||||
if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) {
|
||||
iter.Remove();
|
||||
iter.remove();
|
||||
// The saved callback pref may be invalid now.
|
||||
gCallbackPref = nullptr;
|
||||
}
|
||||
|
@ -2943,8 +2911,8 @@ nsPrefBranch::GetChildList(const char* aStartingAt,
|
|||
// back to us because if they do we are going to add mPrefRoot again.
|
||||
const nsCString& element = prefArray[dwIndex];
|
||||
outArray[dwIndex] =
|
||||
(char*) moz_xmemdup(element.get() + mPrefRoot.Length(),
|
||||
element.Length() - mPrefRoot.Length() + 1);
|
||||
(char*)moz_xmemdup(element.get() + mPrefRoot.Length(),
|
||||
element.Length() - mPrefRoot.Length() + 1);
|
||||
}
|
||||
*aChildArray = outArray;
|
||||
}
|
||||
|
@ -3535,10 +3503,9 @@ PreferenceServiceReporter::CollectReports(
|
|||
Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes);
|
||||
|
||||
if (gHashTable) {
|
||||
sizes.mHashTable += gHashTable->ShallowSizeOfIncludingThis(mallocSizeOf);
|
||||
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
|
||||
pref->AddSizeOfIncludingThis(mallocSizeOf, sizes);
|
||||
sizes.mHashTable += gHashTable->shallowSizeOfIncludingThis(mallocSizeOf);
|
||||
for (auto iter = gHashTable->iter(); !iter.done(); iter.next()) {
|
||||
iter.get()->AddSizeOfIncludingThis(mallocSizeOf, sizes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3850,10 +3817,8 @@ Preferences::GetInstanceForService()
|
|||
|
||||
MOZ_ASSERT(!gHashTable);
|
||||
gHashTable =
|
||||
new PLDHashTable(&pref_HashTableOps,
|
||||
sizeof(PrefEntry),
|
||||
(XRE_IsParentProcess() ? kHashTableInitialLengthParent
|
||||
: kHashTableInitialLengthContent));
|
||||
new PrefsHashTable(XRE_IsParentProcess() ? kHashTableInitialLengthParent
|
||||
: kHashTableInitialLengthContent);
|
||||
|
||||
gTelemetryLoadData =
|
||||
new nsDataHashtable<nsCStringHashKey, TelemetryLoadData>();
|
||||
|
@ -4018,8 +3983,8 @@ Preferences::SerializePreferences(nsCString& aStr)
|
|||
|
||||
aStr.Truncate();
|
||||
|
||||
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
|
||||
for (auto iter = gHashTable->iter(); !iter.done(); iter.next()) {
|
||||
Pref* pref = iter.get().get();
|
||||
if (!pref->IsTypeNone() && pref->HasAdvisablySizedValues()) {
|
||||
pref->SerializeAndAppend(aStr);
|
||||
}
|
||||
|
@ -4061,10 +4026,8 @@ Preferences::EnsureSnapshot(size_t* aSize)
|
|||
if (!gSharedMap) {
|
||||
SharedPrefMapBuilder builder;
|
||||
|
||||
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
|
||||
|
||||
pref->AddToMap(builder);
|
||||
for (auto iter = gHashTable->iter(); !iter.done(); iter.next()) {
|
||||
iter.get()->AddToMap(builder);
|
||||
}
|
||||
|
||||
gSharedMap = new SharedPrefMap(std::move(builder));
|
||||
|
@ -4078,7 +4041,9 @@ Preferences::EnsureSnapshot(size_t* aSize)
|
|||
// we can initialize the hashtable with the expected number of per-session
|
||||
// changed preferences, rather than the expected total number of
|
||||
// preferences.
|
||||
gHashTable->ClearAndPrepareForLength(kHashTableInitialLengthContent);
|
||||
gHashTable->clearAndCompact();
|
||||
Unused << gHashTable->reserve(kHashTableInitialLengthContent);
|
||||
|
||||
gPrefNameArena.Clear();
|
||||
}
|
||||
|
||||
|
@ -4197,7 +4162,9 @@ Preferences::ResetPrefs()
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
gHashTable->ClearAndPrepareForLength(kHashTableInitialLengthParent);
|
||||
gHashTable->clearAndCompact();
|
||||
Unused << gHashTable->reserve(kHashTableInitialLengthParent);
|
||||
|
||||
gPrefNameArena.Clear();
|
||||
|
||||
return InitInitialObjects(/* isStartup */ false).isOk() ? NS_OK
|
||||
|
@ -4212,8 +4179,8 @@ Preferences::ResetUserPrefs()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Vector<const char*> prefNames;
|
||||
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
|
||||
for (auto iter = gHashTable->modIter(); !iter.done(); iter.next()) {
|
||||
Pref* pref = iter.get().get();
|
||||
|
||||
if (pref->HasUserValue()) {
|
||||
if (!prefNames.append(pref->Name())) {
|
||||
|
@ -4222,7 +4189,7 @@ Preferences::ResetUserPrefs()
|
|||
|
||||
pref->ClearUserValue();
|
||||
if (!pref->HasDefaultValue()) {
|
||||
iter.Remove();
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4290,13 +4257,18 @@ Preferences::SetPreference(const dom::Pref& aDomPref)
|
|||
|
||||
const char* prefName = aDomPref.name().get();
|
||||
|
||||
auto entry = static_cast<PrefEntry*>(gHashTable->Add(prefName, fallible));
|
||||
if (!entry) {
|
||||
return;
|
||||
Pref* pref;
|
||||
auto p = gHashTable->lookupForAdd(prefName);
|
||||
if (!p) {
|
||||
pref = new Pref(prefName);
|
||||
if (!gHashTable->add(p, pref)) {
|
||||
delete pref;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
pref = p->get();
|
||||
}
|
||||
|
||||
Pref* pref = entry->mPref;
|
||||
|
||||
bool valueChanged = false;
|
||||
pref->FromDomPref(aDomPref, &valueChanged);
|
||||
|
||||
|
@ -4316,7 +4288,7 @@ Preferences::SetPreference(const dom::Pref& aDomPref)
|
|||
if (gSharedMap->Has(pref->Name())) {
|
||||
pref->SetType(PrefType::None);
|
||||
} else {
|
||||
gHashTable->RemoveEntry(entry);
|
||||
gHashTable->remove(prefName);
|
||||
}
|
||||
pref = nullptr;
|
||||
}
|
||||
|
@ -5269,7 +5241,7 @@ Preferences::ClearUser(const char* aPrefName)
|
|||
|
||||
if (!pref->HasDefaultValue()) {
|
||||
if (!gSharedMap || !gSharedMap->Has(pref->Name())) {
|
||||
gHashTable->Remove(aPrefName);
|
||||
gHashTable->remove(aPrefName);
|
||||
} else {
|
||||
pref->SetType(PrefType::None);
|
||||
}
|
||||
|
|
|
@ -318,7 +318,8 @@ class SharedPrefMap
|
|||
uint8_t mIsSticky : 1;
|
||||
// True if the preference is locked, as defined by the preference service.
|
||||
uint8_t mIsLocked : 1;
|
||||
// True if the preference's default value has changed since it was first set.
|
||||
// True if the preference's default value has changed since it was first
|
||||
// set.
|
||||
uint8_t mDefaultChanged : 1;
|
||||
};
|
||||
|
||||
|
|
|
@ -210,44 +210,22 @@ MockFilePickerInstance.prototype = {
|
|||
|
||||
return null;
|
||||
},
|
||||
get files() {
|
||||
return {
|
||||
index: 0,
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]),
|
||||
[Symbol.iterator]() {
|
||||
return Array.from(MockFilePicker.returnData, d => d.nsIFile).values();
|
||||
},
|
||||
hasMoreElements() {
|
||||
return this.index < MockFilePicker.returnData.length;
|
||||
},
|
||||
getNext() {
|
||||
if (!MockFilePicker.returnData[this.index].nsIFile) {
|
||||
throw Components.Exception("", Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
return MockFilePicker.returnData[this.index++].nsIFile;
|
||||
* getFiles(asDOM) {
|
||||
for (let d of MockFilePicker.returnData) {
|
||||
if (asDOM) {
|
||||
yield d.domFile || d.domDirectory;
|
||||
} else if (d.nsIFile) {
|
||||
yield d.nsIFile;
|
||||
} else {
|
||||
throw Components.Exception("", Cr.NS_ERROR_FAILURE);
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
get files() {
|
||||
return this.getFiles(false);
|
||||
},
|
||||
get domFileOrDirectoryEnumerator() {
|
||||
return {
|
||||
index: 0,
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]),
|
||||
hasMoreElements() {
|
||||
return this.index < MockFilePicker.returnData.length;
|
||||
},
|
||||
getNext() {
|
||||
// window.File does not implement nsIFile
|
||||
if (MockFilePicker.returnData[this.index].domFile) {
|
||||
return MockFilePicker.returnData[this.index++].domFile;
|
||||
}
|
||||
|
||||
if (MockFilePicker.returnData[this.index].domDirectory) {
|
||||
return MockFilePicker.returnData[this.index++].domDirectory;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return this.getFiles(true);
|
||||
},
|
||||
open(aFilePickerShownCallback) {
|
||||
MockFilePicker.showing = true;
|
||||
|
|
|
@ -96,21 +96,11 @@ function installAddonEngine(name = "engine-addon") {
|
|||
},
|
||||
|
||||
getFiles(prop) {
|
||||
let result = [];
|
||||
|
||||
switch (prop) {
|
||||
case XRE_EXTENSIONS_DIR_LIST:
|
||||
result.push(addonDir);
|
||||
break;
|
||||
default:
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
if (prop == XRE_EXTENSIONS_DIR_LIST) {
|
||||
return [addonDir].values();
|
||||
}
|
||||
|
||||
return {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]),
|
||||
hasMoreElements: () => result.length > 0,
|
||||
getNext: () => result.shift(),
|
||||
};
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
До Ширина: | Высота: | Размер: 825 B После Ширина: | Высота: | Размер: 825 B |
|
@ -87,7 +87,7 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
|
|||
|
||||
if CONFIG['OS_ARCH'] == 'Linux' or CONFIG['OS_ARCH'] == 'SunOS':
|
||||
FINAL_TARGET_FILES += [
|
||||
'/toolkit/themes/windows/global/throbber/Throbber-small.gif',
|
||||
'Throbber-small.gif',
|
||||
]
|
||||
|
||||
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
|
||||
|
|
|
@ -810,38 +810,6 @@ function cleanupActiveUpdate() {
|
|||
cleanUpUpdatesDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* An enumeration of items in a JS array.
|
||||
* @constructor
|
||||
*/
|
||||
function ArrayEnumerator(aItems) {
|
||||
this._index = 0;
|
||||
if (aItems) {
|
||||
for (var i = 0; i < aItems.length; ++i) {
|
||||
if (!aItems[i])
|
||||
aItems.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this._contents = aItems;
|
||||
}
|
||||
|
||||
ArrayEnumerator.prototype = {
|
||||
_index: 0,
|
||||
_contents: [],
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this._contents.values();
|
||||
},
|
||||
|
||||
hasMoreElements: function ArrayEnumerator_hasMoreElements() {
|
||||
return this._index < this._contents.length;
|
||||
},
|
||||
|
||||
getNext: function ArrayEnumerator_getNext() {
|
||||
return this._contents[this._index++];
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a string of text to a file. A newline will be appended to the data
|
||||
* written to the file. This function only works with ASCII text.
|
||||
|
@ -1158,10 +1126,16 @@ UpdatePatch.prototype = {
|
|||
* See nsIPropertyBag.idl
|
||||
*/
|
||||
get enumerator() {
|
||||
var properties = [];
|
||||
for (var p in this._properties)
|
||||
properties.push(this._properties[p].data);
|
||||
return new ArrayEnumerator(properties);
|
||||
return this.enumerate();
|
||||
},
|
||||
|
||||
* enumerate() {
|
||||
for (var p in this._properties) {
|
||||
let prop = this.properties[p].data;
|
||||
if (prop) {
|
||||
yield prop;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1479,11 +1453,16 @@ Update.prototype = {
|
|||
* See nsIPropertyBag.idl
|
||||
*/
|
||||
get enumerator() {
|
||||
var properties = [];
|
||||
for (let p in this._properties) {
|
||||
properties.push(this._properties[p].data);
|
||||
return this.enumerate();
|
||||
},
|
||||
|
||||
* enumerate() {
|
||||
for (var p in this._properties) {
|
||||
let prop = this.properties[p].data;
|
||||
if (prop) {
|
||||
yield prop;
|
||||
}
|
||||
}
|
||||
return new ArrayEnumerator(properties);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче