123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 "IDBIndex.h"
- #include "FileInfo.h"
- #include "IDBCursor.h"
- #include "IDBEvents.h"
- #include "IDBKeyRange.h"
- #include "IDBObjectStore.h"
- #include "IDBRequest.h"
- #include "IDBTransaction.h"
- #include "IndexedDatabase.h"
- #include "IndexedDatabaseInlines.h"
- #include "mozilla/ErrorResult.h"
- #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
- #include "ProfilerHelpers.h"
- #include "ReportInternalError.h"
- // Include this last to avoid path problems on Windows.
- #include "ActorsChild.h"
- using namespace mozilla::dom;
- using namespace mozilla::dom::indexedDB;
- namespace mozilla {
- namespace dom {
- namespace {
- already_AddRefed<IDBRequest>
- GenerateRequest(JSContext* aCx, IDBIndex* aIndex)
- {
- MOZ_ASSERT(aIndex);
- aIndex->AssertIsOnOwningThread();
- IDBTransaction* transaction = aIndex->ObjectStore()->Transaction();
- RefPtr<IDBRequest> request =
- IDBRequest::Create(aCx, aIndex, transaction->Database(), transaction);
- MOZ_ASSERT(request);
- return request.forget();
- }
- } // namespace
- IDBIndex::IDBIndex(IDBObjectStore* aObjectStore, const IndexMetadata* aMetadata)
- : mObjectStore(aObjectStore)
- , mCachedKeyPath(JS::UndefinedValue())
- , mMetadata(aMetadata)
- , mId(aMetadata->id())
- , mRooted(false)
- {
- MOZ_ASSERT(aObjectStore);
- aObjectStore->AssertIsOnOwningThread();
- MOZ_ASSERT(aMetadata);
- }
- IDBIndex::~IDBIndex()
- {
- AssertIsOnOwningThread();
- if (mRooted) {
- mCachedKeyPath.setUndefined();
- mozilla::DropJSObjects(this);
- }
- }
- already_AddRefed<IDBIndex>
- IDBIndex::Create(IDBObjectStore* aObjectStore,
- const IndexMetadata& aMetadata)
- {
- MOZ_ASSERT(aObjectStore);
- aObjectStore->AssertIsOnOwningThread();
- RefPtr<IDBIndex> index = new IDBIndex(aObjectStore, &aMetadata);
- return index.forget();
- }
- #ifdef DEBUG
- void
- IDBIndex::AssertIsOnOwningThread() const
- {
- MOZ_ASSERT(mObjectStore);
- mObjectStore->AssertIsOnOwningThread();
- }
- #endif // DEBUG
- void
- IDBIndex::RefreshMetadata(bool aMayDelete)
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT_IF(mDeletedMetadata, mMetadata == mDeletedMetadata);
- const nsTArray<IndexMetadata>& indexes = mObjectStore->Spec().indexes();
- bool found = false;
- for (uint32_t count = indexes.Length(), index = 0;
- index < count;
- index++) {
- const IndexMetadata& metadata = indexes[index];
- if (metadata.id() == Id()) {
- mMetadata = &metadata;
- found = true;
- break;
- }
- }
- MOZ_ASSERT_IF(!aMayDelete && !mDeletedMetadata, found);
- if (found) {
- MOZ_ASSERT(mMetadata != mDeletedMetadata);
- mDeletedMetadata = nullptr;
- } else {
- NoteDeletion();
- }
- }
- void
- IDBIndex::NoteDeletion()
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- MOZ_ASSERT(Id() == mMetadata->id());
- if (mDeletedMetadata) {
- MOZ_ASSERT(mMetadata == mDeletedMetadata);
- return;
- }
- mDeletedMetadata = new IndexMetadata(*mMetadata);
- mMetadata = mDeletedMetadata;
- }
- const nsString&
- IDBIndex::Name() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->name();
- }
- void
- IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- IDBTransaction* transaction = mObjectStore->Transaction();
- if (transaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
- mDeletedMetadata) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
- if (!transaction->IsOpen()) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
- return;
- }
- if (aName == mMetadata->name()) {
- return;
- }
- // Cache logging string of this index before renaming.
- const LoggingString loggingOldIndex(this);
- const int64_t indexId = Id();
- nsresult rv =
- transaction->Database()->RenameIndex(mObjectStore->Id(),
- indexId,
- aName);
- if (NS_FAILED(rv)) {
- aRv.Throw(rv);
- return;
- }
- // Don't do this in the macro because we always need to increment the serial
- // number to keep in sync with the parent.
- const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "rename(%s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.rename()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- requestSerialNumber,
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- loggingOldIndex.get(),
- IDB_LOG_STRINGIFY(this));
- transaction->RenameIndex(mObjectStore, indexId, aName);
- }
- bool
- IDBIndex::Unique() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->unique();
- }
- bool
- IDBIndex::MultiEntry() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->multiEntry();
- }
- bool
- IDBIndex::LocaleAware() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->locale().IsEmpty();
- }
- const indexedDB::KeyPath&
- IDBIndex::GetKeyPath() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->keyPath();
- }
- void
- IDBIndex::GetLocale(nsString& aLocale) const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- if (mMetadata->locale().IsEmpty()) {
- SetDOMStringToNull(aLocale);
- } else {
- aLocale.AssignWithConversion(mMetadata->locale());
- }
- }
- const nsCString&
- IDBIndex::Locale() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->locale();
- }
- bool
- IDBIndex::IsAutoLocale() const
- {
- AssertIsOnOwningThread();
- MOZ_ASSERT(mMetadata);
- return mMetadata->autoLocale();
- }
- nsPIDOMWindowInner*
- IDBIndex::GetParentObject() const
- {
- AssertIsOnOwningThread();
- return mObjectStore->GetParentObject();
- }
- void
- IDBIndex::GetKeyPath(JSContext* aCx,
- JS::MutableHandle<JS::Value> aResult,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (!mCachedKeyPath.isUndefined()) {
- MOZ_ASSERT(mRooted);
- aResult.set(mCachedKeyPath);
- return;
- }
- MOZ_ASSERT(!mRooted);
- aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
- if (NS_WARN_IF(aRv.Failed())) {
- return;
- }
- if (mCachedKeyPath.isGCThing()) {
- mozilla::HoldJSObjects(this);
- mRooted = true;
- }
- aResult.set(mCachedKeyPath);
- }
- already_AddRefed<IDBRequest>
- IDBIndex::GetInternal(bool aKeyOnly,
- JSContext* aCx,
- JS::Handle<JS::Value> aKey,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (mDeletedMetadata) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
- return nullptr;
- }
- IDBTransaction* transaction = mObjectStore->Transaction();
- if (!transaction->IsOpen()) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
- return nullptr;
- }
- RefPtr<IDBKeyRange> keyRange;
- aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
- if (!keyRange) {
- // Must specify a key or keyRange for get() and getKey().
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
- return nullptr;
- }
- const int64_t objectStoreId = mObjectStore->Id();
- const int64_t indexId = Id();
- SerializedKeyRange serializedKeyRange;
- keyRange->ToSerialized(serializedKeyRange);
- RequestParams params;
- if (aKeyOnly) {
- params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange);
- } else {
- params = IndexGetParams(objectStoreId, indexId, serializedKeyRange);
- }
- RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
- MOZ_ASSERT(request);
- if (aKeyOnly) {
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "getKey(%s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getKey()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange));
- } else {
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "get(%s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.get()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange));
- }
- transaction->StartRequest(request, params);
- return request.forget();
- }
- already_AddRefed<IDBRequest>
- IDBIndex::GetAllInternal(bool aKeysOnly,
- JSContext* aCx,
- JS::Handle<JS::Value> aKey,
- const Optional<uint32_t>& aLimit,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (mDeletedMetadata) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
- return nullptr;
- }
- IDBTransaction* transaction = mObjectStore->Transaction();
- if (!transaction->IsOpen()) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
- return nullptr;
- }
- RefPtr<IDBKeyRange> keyRange;
- aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
- const int64_t objectStoreId = mObjectStore->Id();
- const int64_t indexId = Id();
- OptionalKeyRange optionalKeyRange;
- if (keyRange) {
- SerializedKeyRange serializedKeyRange;
- keyRange->ToSerialized(serializedKeyRange);
- optionalKeyRange = serializedKeyRange;
- } else {
- optionalKeyRange = void_t();
- }
- const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0;
- RequestParams params;
- if (aKeysOnly) {
- params = IndexGetAllKeysParams(objectStoreId, indexId, optionalKeyRange,
- limit);
- } else {
- params = IndexGetAllParams(objectStoreId, indexId, optionalKeyRange, limit);
- }
- RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
- MOZ_ASSERT(request);
- if (aKeysOnly) {
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "getAllKeys(%s, %s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAllKeys()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange),
- IDB_LOG_STRINGIFY(aLimit));
- } else {
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "getAll(%s, %s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAll()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange),
- IDB_LOG_STRINGIFY(aLimit));
- }
- transaction->StartRequest(request, params);
- return request.forget();
- }
- already_AddRefed<IDBRequest>
- IDBIndex::OpenCursorInternal(bool aKeysOnly,
- JSContext* aCx,
- JS::Handle<JS::Value> aRange,
- IDBCursorDirection aDirection,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (mDeletedMetadata) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
- return nullptr;
- }
- IDBTransaction* transaction = mObjectStore->Transaction();
- if (!transaction->IsOpen()) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
- return nullptr;
- }
- RefPtr<IDBKeyRange> keyRange;
- aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
- int64_t objectStoreId = mObjectStore->Id();
- int64_t indexId = Id();
- OptionalKeyRange optionalKeyRange;
- if (keyRange) {
- SerializedKeyRange serializedKeyRange;
- keyRange->ToSerialized(serializedKeyRange);
- optionalKeyRange = Move(serializedKeyRange);
- } else {
- optionalKeyRange = void_t();
- }
- IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
- OpenCursorParams params;
- if (aKeysOnly) {
- IndexOpenKeyCursorParams openParams;
- openParams.objectStoreId() = objectStoreId;
- openParams.indexId() = indexId;
- openParams.optionalKeyRange() = Move(optionalKeyRange);
- openParams.direction() = direction;
- params = Move(openParams);
- } else {
- IndexOpenCursorParams openParams;
- openParams.objectStoreId() = objectStoreId;
- openParams.indexId() = indexId;
- openParams.optionalKeyRange() = Move(optionalKeyRange);
- openParams.direction() = direction;
- params = Move(openParams);
- }
- RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
- MOZ_ASSERT(request);
- if (aKeysOnly) {
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "openKeyCursor(%s, %s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.openKeyCursor()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange),
- IDB_LOG_STRINGIFY(direction));
- } else {
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "openCursor(%s, %s)",
- "IndexedDB %s: C T[%lld] R[%llu]: "
- "IDBObjectStore.openKeyCursor()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange),
- IDB_LOG_STRINGIFY(direction));
- }
- BackgroundCursorChild* actor =
- new BackgroundCursorChild(request, this, direction);
- mObjectStore->Transaction()->OpenCursor(actor, params);
- return request.forget();
- }
- already_AddRefed<IDBRequest>
- IDBIndex::Count(JSContext* aCx,
- JS::Handle<JS::Value> aKey,
- ErrorResult& aRv)
- {
- AssertIsOnOwningThread();
- if (mDeletedMetadata) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
- return nullptr;
- }
- IDBTransaction* transaction = mObjectStore->Transaction();
- if (!transaction->IsOpen()) {
- aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
- return nullptr;
- }
- RefPtr<IDBKeyRange> keyRange;
- aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
- if (aRv.Failed()) {
- return nullptr;
- }
- IndexCountParams params;
- params.objectStoreId() = mObjectStore->Id();
- params.indexId() = Id();
- if (keyRange) {
- SerializedKeyRange serializedKeyRange;
- keyRange->ToSerialized(serializedKeyRange);
- params.optionalKeyRange() = serializedKeyRange;
- } else {
- params.optionalKeyRange() = void_t();
- }
- RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
- MOZ_ASSERT(request);
- IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
- "database(%s).transaction(%s).objectStore(%s).index(%s)."
- "count(%s)",
- "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
- IDB_LOG_ID_STRING(),
- transaction->LoggingSerialNumber(),
- request->LoggingSerialNumber(),
- IDB_LOG_STRINGIFY(transaction->Database()),
- IDB_LOG_STRINGIFY(transaction),
- IDB_LOG_STRINGIFY(mObjectStore),
- IDB_LOG_STRINGIFY(this),
- IDB_LOG_STRINGIFY(keyRange));
- transaction->StartRequest(request, params);
- return request.forget();
- }
- NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex)
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex)
- NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
- NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex)
- NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
- NS_IMPL_CYCLE_COLLECTION_TRACE_END
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex)
- NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
- // Don't unlink mObjectStore!
- tmp->mCachedKeyPath.setUndefined();
- if (tmp->mRooted) {
- mozilla::DropJSObjects(tmp);
- tmp->mRooted = false;
- }
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- JSObject*
- IDBIndex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return IDBIndexBinding::Wrap(aCx, this, aGivenProto);
- }
- } // namespace dom
- } // namespace mozilla
|