dom/indexedDB/IDBKeyRange.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "base/basictypes.h"
     9 #include "IDBKeyRange.h"
    11 #include "nsIXPConnect.h"
    13 #include "nsJSUtils.h"
    14 #include "nsThreadUtils.h"
    15 #include "nsContentUtils.h"
    16 #include "nsDOMClassInfoID.h"
    17 #include "Key.h"
    19 #include "mozilla/dom/IDBKeyRangeBinding.h"
    20 #include "mozilla/dom/indexedDB/PIndexedDBIndex.h"
    21 #include "mozilla/dom/indexedDB/PIndexedDBObjectStore.h"
    23 using namespace mozilla;
    24 using namespace mozilla::dom;
    25 USING_INDEXEDDB_NAMESPACE
    26 using namespace mozilla::dom::indexedDB::ipc;
    28 namespace {
    30 inline nsresult
    31 GetKeyFromJSVal(JSContext* aCx,
    32                 JS::Handle<JS::Value> aVal,
    33                 Key& aKey,
    34                 bool aAllowUnset = false)
    35 {
    36   nsresult rv = aKey.SetFromJSVal(aCx, aVal);
    37   if (NS_FAILED(rv)) {
    38     NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB,
    39                  "Bad error code!");
    40     return rv;
    41   }
    43   if (aKey.IsUnset() && !aAllowUnset) {
    44     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    45   }
    47   return NS_OK;
    48 }
    50 } // anonymous namespace
    52 // static
    53 nsresult
    54 IDBKeyRange::FromJSVal(JSContext* aCx,
    55                        JS::Handle<JS::Value> aVal,
    56                        IDBKeyRange** aKeyRange)
    57 {
    58   nsRefPtr<IDBKeyRange> keyRange;
    60   if (aVal.isNullOrUndefined()) {
    61     // undefined and null returns no IDBKeyRange.
    62     keyRange.forget(aKeyRange);
    63     return NS_OK;
    64   }
    66   JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
    67   if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) ||
    68       JS_ObjectIsDate(aCx, obj)) {
    69     // A valid key returns an 'only' IDBKeyRange.
    70     keyRange = new IDBKeyRange(nullptr, false, false, true);
    72     nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
    73     if (NS_FAILED(rv)) {
    74       return rv;
    75     }
    76   }
    77   else {
    78     MOZ_ASSERT(aVal.isObject());
    79     // An object is not permitted unless it's another IDBKeyRange.
    80     if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) {
    81       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    82     }
    83   }
    85   keyRange.forget(aKeyRange);
    86   return NS_OK;
    87 }
    89 // static
    90 template <class T>
    91 already_AddRefed<IDBKeyRange>
    92 IDBKeyRange::FromSerializedKeyRange(const T& aKeyRange)
    93 {
    94   nsRefPtr<IDBKeyRange> keyRange =
    95     new IDBKeyRange(nullptr, aKeyRange.lowerOpen(), aKeyRange.upperOpen(),
    96                     aKeyRange.isOnly());
    97   keyRange->Lower() = aKeyRange.lower();
    98   if (!keyRange->IsOnly()) {
    99     keyRange->Upper() = aKeyRange.upper();
   100   }
   101   return keyRange.forget();
   102 }
   104 template <class T>
   105 void
   106 IDBKeyRange::ToSerializedKeyRange(T& aKeyRange)
   107 {
   108   aKeyRange.lowerOpen() = IsLowerOpen();
   109   aKeyRange.upperOpen() = IsUpperOpen();
   110   aKeyRange.isOnly() = IsOnly();
   112   aKeyRange.lower() = Lower();
   113   if (!IsOnly()) {
   114     aKeyRange.upper() = Upper();
   115   }
   116 }
   118 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
   120 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
   121   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
   122   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   123 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   125 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
   126   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal)
   127   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal)
   128 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   130 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
   131   NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
   132   tmp->DropJSObjects();
   133 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   135 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
   136   NS_INTERFACE_MAP_ENTRY(nsISupports)
   137 NS_INTERFACE_MAP_END
   139 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
   140 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
   142 void
   143 IDBKeyRange::DropJSObjects()
   144 {
   145   if (!mRooted) {
   146     return;
   147   }
   148   mCachedLowerVal = JS::UndefinedValue();
   149   mCachedUpperVal = JS::UndefinedValue();
   150   mHaveCachedLowerVal = false;
   151   mHaveCachedUpperVal = false;
   152   mRooted = false;
   153   mozilla::DropJSObjects(this);
   154 }
   156 IDBKeyRange::~IDBKeyRange()
   157 {
   158   DropJSObjects();
   159 }
   161 JSObject*
   162 IDBKeyRange::WrapObject(JSContext* aCx)
   163 {
   164   return IDBKeyRangeBinding::Wrap(aCx, this);
   165 }
   167 void
   168 IDBKeyRange::GetLower(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   169                       ErrorResult& aRv)
   170 {
   171   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   173   if (!mHaveCachedLowerVal) {
   174     if (!mRooted) {
   175       mozilla::HoldJSObjects(this);
   176       mRooted = true;
   177     }
   179     aRv = Lower().ToJSVal(aCx, mCachedLowerVal);
   180     if (aRv.Failed()) {
   181       return;
   182     }
   184     mHaveCachedLowerVal = true;
   185   }
   187   JS::ExposeValueToActiveJS(mCachedLowerVal);
   188   aResult.set(mCachedLowerVal);
   189 }
   191 void
   192 IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   193                       ErrorResult& aRv)
   194 {
   195   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   197   if (!mHaveCachedUpperVal) {
   198     if (!mRooted) {
   199       mozilla::HoldJSObjects(this);
   200       mRooted = true;
   201     }
   203     aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
   204     if (aRv.Failed()) {
   205       return;
   206     }
   208     mHaveCachedUpperVal = true;
   209   }
   211   JS::ExposeValueToActiveJS(mCachedUpperVal);
   212   aResult.set(mCachedUpperVal);
   213 }
   215 // static
   216 already_AddRefed<IDBKeyRange>
   217 IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx,
   218                   JS::Handle<JS::Value> aValue, ErrorResult& aRv)
   219 {
   220   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   222   nsRefPtr<IDBKeyRange> keyRange =
   223     new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true);
   225   aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
   226   if (aRv.Failed()) {
   227     return nullptr;
   228   }
   230   return keyRange.forget();
   231 }
   233 // static
   234 already_AddRefed<IDBKeyRange>
   235 IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx,
   236                         JS::Handle<JS::Value> aValue, bool aOpen,
   237                         ErrorResult& aRv)
   238 {
   239   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   241   nsRefPtr<IDBKeyRange> keyRange =
   242     new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false);
   244   aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower());
   245   if (aRv.Failed()) {
   246     return nullptr;
   247   }
   249   return keyRange.forget();
   250 }
   252 // static
   253 already_AddRefed<IDBKeyRange>
   254 IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx,
   255                         JS::Handle<JS::Value> aValue, bool aOpen,
   256                         ErrorResult& aRv)
   257 {
   258   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   260   nsRefPtr<IDBKeyRange> keyRange =
   261     new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false);
   263   aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Upper());
   264   if (aRv.Failed()) {
   265     return nullptr;
   266   }
   268   return keyRange.forget();
   269 }
   271 // static
   272 already_AddRefed<IDBKeyRange>
   273 IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx,
   274                    JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper,
   275                    bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv)
   276 {
   277   MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
   279   nsRefPtr<IDBKeyRange> keyRange =
   280     new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false);
   282   aRv = GetKeyFromJSVal(aCx, aLower, keyRange->Lower());
   283   if (aRv.Failed()) {
   284     return nullptr;
   285   }
   287   aRv = GetKeyFromJSVal(aCx, aUpper, keyRange->Upper());
   288   if (aRv.Failed()) {
   289     return nullptr;
   290   }
   292   if (keyRange->Lower() > keyRange->Upper() ||
   293       (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) {
   294     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
   295     return nullptr;
   296   }
   298   return keyRange.forget();
   299 }
   301 // Explicitly instantiate for all our key range types... Grumble.
   302 template already_AddRefed<IDBKeyRange>
   303 IDBKeyRange::FromSerializedKeyRange<KeyRange> (const KeyRange& aKeyRange);
   305 template void
   306 IDBKeyRange::ToSerializedKeyRange<KeyRange> (KeyRange& aKeyRange);

mercurial