1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/indexedDB/IDBKeyRange.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,306 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "base/basictypes.h" 1.11 + 1.12 +#include "IDBKeyRange.h" 1.13 + 1.14 +#include "nsIXPConnect.h" 1.15 + 1.16 +#include "nsJSUtils.h" 1.17 +#include "nsThreadUtils.h" 1.18 +#include "nsContentUtils.h" 1.19 +#include "nsDOMClassInfoID.h" 1.20 +#include "Key.h" 1.21 + 1.22 +#include "mozilla/dom/IDBKeyRangeBinding.h" 1.23 +#include "mozilla/dom/indexedDB/PIndexedDBIndex.h" 1.24 +#include "mozilla/dom/indexedDB/PIndexedDBObjectStore.h" 1.25 + 1.26 +using namespace mozilla; 1.27 +using namespace mozilla::dom; 1.28 +USING_INDEXEDDB_NAMESPACE 1.29 +using namespace mozilla::dom::indexedDB::ipc; 1.30 + 1.31 +namespace { 1.32 + 1.33 +inline nsresult 1.34 +GetKeyFromJSVal(JSContext* aCx, 1.35 + JS::Handle<JS::Value> aVal, 1.36 + Key& aKey, 1.37 + bool aAllowUnset = false) 1.38 +{ 1.39 + nsresult rv = aKey.SetFromJSVal(aCx, aVal); 1.40 + if (NS_FAILED(rv)) { 1.41 + NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB, 1.42 + "Bad error code!"); 1.43 + return rv; 1.44 + } 1.45 + 1.46 + if (aKey.IsUnset() && !aAllowUnset) { 1.47 + return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; 1.48 + } 1.49 + 1.50 + return NS_OK; 1.51 +} 1.52 + 1.53 +} // anonymous namespace 1.54 + 1.55 +// static 1.56 +nsresult 1.57 +IDBKeyRange::FromJSVal(JSContext* aCx, 1.58 + JS::Handle<JS::Value> aVal, 1.59 + IDBKeyRange** aKeyRange) 1.60 +{ 1.61 + nsRefPtr<IDBKeyRange> keyRange; 1.62 + 1.63 + if (aVal.isNullOrUndefined()) { 1.64 + // undefined and null returns no IDBKeyRange. 1.65 + keyRange.forget(aKeyRange); 1.66 + return NS_OK; 1.67 + } 1.68 + 1.69 + JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr); 1.70 + if (aVal.isPrimitive() || JS_IsArrayObject(aCx, obj) || 1.71 + JS_ObjectIsDate(aCx, obj)) { 1.72 + // A valid key returns an 'only' IDBKeyRange. 1.73 + keyRange = new IDBKeyRange(nullptr, false, false, true); 1.74 + 1.75 + nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower()); 1.76 + if (NS_FAILED(rv)) { 1.77 + return rv; 1.78 + } 1.79 + } 1.80 + else { 1.81 + MOZ_ASSERT(aVal.isObject()); 1.82 + // An object is not permitted unless it's another IDBKeyRange. 1.83 + if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) { 1.84 + return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; 1.85 + } 1.86 + } 1.87 + 1.88 + keyRange.forget(aKeyRange); 1.89 + return NS_OK; 1.90 +} 1.91 + 1.92 +// static 1.93 +template <class T> 1.94 +already_AddRefed<IDBKeyRange> 1.95 +IDBKeyRange::FromSerializedKeyRange(const T& aKeyRange) 1.96 +{ 1.97 + nsRefPtr<IDBKeyRange> keyRange = 1.98 + new IDBKeyRange(nullptr, aKeyRange.lowerOpen(), aKeyRange.upperOpen(), 1.99 + aKeyRange.isOnly()); 1.100 + keyRange->Lower() = aKeyRange.lower(); 1.101 + if (!keyRange->IsOnly()) { 1.102 + keyRange->Upper() = aKeyRange.upper(); 1.103 + } 1.104 + return keyRange.forget(); 1.105 +} 1.106 + 1.107 +template <class T> 1.108 +void 1.109 +IDBKeyRange::ToSerializedKeyRange(T& aKeyRange) 1.110 +{ 1.111 + aKeyRange.lowerOpen() = IsLowerOpen(); 1.112 + aKeyRange.upperOpen() = IsUpperOpen(); 1.113 + aKeyRange.isOnly() = IsOnly(); 1.114 + 1.115 + aKeyRange.lower() = Lower(); 1.116 + if (!IsOnly()) { 1.117 + aKeyRange.upper() = Upper(); 1.118 + } 1.119 +} 1.120 + 1.121 +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange) 1.122 + 1.123 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange) 1.124 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) 1.125 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.126 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.127 + 1.128 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange) 1.129 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedLowerVal) 1.130 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedUpperVal) 1.131 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.132 + 1.133 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange) 1.134 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal) 1.135 + tmp->DropJSObjects(); 1.136 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.137 + 1.138 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange) 1.139 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.140 +NS_INTERFACE_MAP_END 1.141 + 1.142 +NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange) 1.143 +NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange) 1.144 + 1.145 +void 1.146 +IDBKeyRange::DropJSObjects() 1.147 +{ 1.148 + if (!mRooted) { 1.149 + return; 1.150 + } 1.151 + mCachedLowerVal = JS::UndefinedValue(); 1.152 + mCachedUpperVal = JS::UndefinedValue(); 1.153 + mHaveCachedLowerVal = false; 1.154 + mHaveCachedUpperVal = false; 1.155 + mRooted = false; 1.156 + mozilla::DropJSObjects(this); 1.157 +} 1.158 + 1.159 +IDBKeyRange::~IDBKeyRange() 1.160 +{ 1.161 + DropJSObjects(); 1.162 +} 1.163 + 1.164 +JSObject* 1.165 +IDBKeyRange::WrapObject(JSContext* aCx) 1.166 +{ 1.167 + return IDBKeyRangeBinding::Wrap(aCx, this); 1.168 +} 1.169 + 1.170 +void 1.171 +IDBKeyRange::GetLower(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 1.172 + ErrorResult& aRv) 1.173 +{ 1.174 + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); 1.175 + 1.176 + if (!mHaveCachedLowerVal) { 1.177 + if (!mRooted) { 1.178 + mozilla::HoldJSObjects(this); 1.179 + mRooted = true; 1.180 + } 1.181 + 1.182 + aRv = Lower().ToJSVal(aCx, mCachedLowerVal); 1.183 + if (aRv.Failed()) { 1.184 + return; 1.185 + } 1.186 + 1.187 + mHaveCachedLowerVal = true; 1.188 + } 1.189 + 1.190 + JS::ExposeValueToActiveJS(mCachedLowerVal); 1.191 + aResult.set(mCachedLowerVal); 1.192 +} 1.193 + 1.194 +void 1.195 +IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 1.196 + ErrorResult& aRv) 1.197 +{ 1.198 + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); 1.199 + 1.200 + if (!mHaveCachedUpperVal) { 1.201 + if (!mRooted) { 1.202 + mozilla::HoldJSObjects(this); 1.203 + mRooted = true; 1.204 + } 1.205 + 1.206 + aRv = Upper().ToJSVal(aCx, mCachedUpperVal); 1.207 + if (aRv.Failed()) { 1.208 + return; 1.209 + } 1.210 + 1.211 + mHaveCachedUpperVal = true; 1.212 + } 1.213 + 1.214 + JS::ExposeValueToActiveJS(mCachedUpperVal); 1.215 + aResult.set(mCachedUpperVal); 1.216 +} 1.217 + 1.218 +// static 1.219 +already_AddRefed<IDBKeyRange> 1.220 +IDBKeyRange::Only(const GlobalObject& aGlobal, JSContext* aCx, 1.221 + JS::Handle<JS::Value> aValue, ErrorResult& aRv) 1.222 +{ 1.223 + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); 1.224 + 1.225 + nsRefPtr<IDBKeyRange> keyRange = 1.226 + new IDBKeyRange(aGlobal.GetAsSupports(), false, false, true); 1.227 + 1.228 + aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower()); 1.229 + if (aRv.Failed()) { 1.230 + return nullptr; 1.231 + } 1.232 + 1.233 + return keyRange.forget(); 1.234 +} 1.235 + 1.236 +// static 1.237 +already_AddRefed<IDBKeyRange> 1.238 +IDBKeyRange::LowerBound(const GlobalObject& aGlobal, JSContext* aCx, 1.239 + JS::Handle<JS::Value> aValue, bool aOpen, 1.240 + ErrorResult& aRv) 1.241 +{ 1.242 + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); 1.243 + 1.244 + nsRefPtr<IDBKeyRange> keyRange = 1.245 + new IDBKeyRange(aGlobal.GetAsSupports(), aOpen, true, false); 1.246 + 1.247 + aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Lower()); 1.248 + if (aRv.Failed()) { 1.249 + return nullptr; 1.250 + } 1.251 + 1.252 + return keyRange.forget(); 1.253 +} 1.254 + 1.255 +// static 1.256 +already_AddRefed<IDBKeyRange> 1.257 +IDBKeyRange::UpperBound(const GlobalObject& aGlobal, JSContext* aCx, 1.258 + JS::Handle<JS::Value> aValue, bool aOpen, 1.259 + ErrorResult& aRv) 1.260 +{ 1.261 + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); 1.262 + 1.263 + nsRefPtr<IDBKeyRange> keyRange = 1.264 + new IDBKeyRange(aGlobal.GetAsSupports(), true, aOpen, false); 1.265 + 1.266 + aRv = GetKeyFromJSVal(aCx, aValue, keyRange->Upper()); 1.267 + if (aRv.Failed()) { 1.268 + return nullptr; 1.269 + } 1.270 + 1.271 + return keyRange.forget(); 1.272 +} 1.273 + 1.274 +// static 1.275 +already_AddRefed<IDBKeyRange> 1.276 +IDBKeyRange::Bound(const GlobalObject& aGlobal, JSContext* aCx, 1.277 + JS::Handle<JS::Value> aLower, JS::Handle<JS::Value> aUpper, 1.278 + bool aLowerOpen, bool aUpperOpen, ErrorResult& aRv) 1.279 +{ 1.280 + MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!"); 1.281 + 1.282 + nsRefPtr<IDBKeyRange> keyRange = 1.283 + new IDBKeyRange(aGlobal.GetAsSupports(), aLowerOpen, aUpperOpen, false); 1.284 + 1.285 + aRv = GetKeyFromJSVal(aCx, aLower, keyRange->Lower()); 1.286 + if (aRv.Failed()) { 1.287 + return nullptr; 1.288 + } 1.289 + 1.290 + aRv = GetKeyFromJSVal(aCx, aUpper, keyRange->Upper()); 1.291 + if (aRv.Failed()) { 1.292 + return nullptr; 1.293 + } 1.294 + 1.295 + if (keyRange->Lower() > keyRange->Upper() || 1.296 + (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) { 1.297 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 1.298 + return nullptr; 1.299 + } 1.300 + 1.301 + return keyRange.forget(); 1.302 +} 1.303 + 1.304 +// Explicitly instantiate for all our key range types... Grumble. 1.305 +template already_AddRefed<IDBKeyRange> 1.306 +IDBKeyRange::FromSerializedKeyRange<KeyRange> (const KeyRange& aKeyRange); 1.307 + 1.308 +template void 1.309 +IDBKeyRange::ToSerializedKeyRange<KeyRange> (KeyRange& aKeyRange);