Bug 949325 - C++ wrapper to support DataStore API on the worker (part 1, C++ stubs for DataStore and DataStoreCursor). r=baku,ehsan

--HG--
rename : dom/datastore/DataStoreCursor.jsm => dom/datastore/DataStoreCursorImpl.jsm
rename : dom/datastore/DataStore.jsm => dom/datastore/DataStoreImpl.jsm
This commit is contained in:
Gene Lian 2013-12-20 16:17:49 +08:00
parent f274d1d8dd
commit f232e3218e
12 changed files with 569 additions and 25 deletions

View File

@ -288,6 +288,10 @@ DOMInterfaces = {
'nativeType': 'nsDOMDataChannel',
},
'DataStoreCursor': {
'wrapperCache': False,
},
'DedicatedWorkerGlobalScope': {
'headerFile': 'mozilla/dom/WorkerScope.h',
'workers': True,

188
dom/datastore/DataStore.cpp Normal file
View File

@ -0,0 +1,188 @@
/* 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 "mozilla/dom/DataStore.h"
#include "mozilla/dom/DataStoreCursor.h"
#include "mozilla/dom/DataStoreBinding.h"
#include "mozilla/dom/DataStoreImplBinding.h"
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Preferences.h"
#include "AccessCheck.h"
namespace mozilla {
namespace dom {
NS_IMPL_ADDREF_INHERITED(DataStore, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(DataStore, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DataStore)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_1(DataStore, mStore)
DataStore::DataStore(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
{
}
already_AddRefed<DataStore>
DataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<DataStore> store = new DataStore(window);
return store.forget();
}
JSObject*
DataStore::WrapObject(JSContext* aCx)
{
return DataStoreBinding::Wrap(aCx, this);
}
/*static*/ bool
DataStore::EnabledForScope(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
// Only expose the interface when it is:
// 1. enabled by the preference and
// 2. accessed by the chrome codes in Gecko.
return (Navigator::HasDataStoreSupport(aCx, aObj) &&
nsContentUtils::ThreadsafeIsCallerChrome());
}
void
DataStore::GetName(nsAString& aName, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
nsAutoString name;
mStore->GetName(name, aRv);
aName.Assign(name);
}
void
DataStore::GetOwner(nsAString& aOwner, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
nsAutoString owner;
mStore->GetOwner(owner, aRv);
aOwner.Assign(owner);
}
bool
DataStore::GetReadOnly(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->GetReadOnly(aRv);
}
already_AddRefed<Promise>
DataStore::Get(const Sequence<OwningStringOrUnsignedLong>& aId,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->Get(aId, aRv);
}
already_AddRefed<Promise>
DataStore::Put(JSContext* aCx,
JS::Handle<JS::Value> aObj,
const StringOrUnsignedLong& aId,
const nsAString& aRevisionId,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->Put(aObj, aId, aRevisionId, aRv);
}
already_AddRefed<Promise>
DataStore::Add(JSContext* aCx,
JS::Handle<JS::Value> aObj,
const Optional<StringOrUnsignedLong>& aId,
const nsAString& aRevisionId,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->Add(aObj, aId, aRevisionId, aRv);
}
already_AddRefed<Promise>
DataStore::Remove(const StringOrUnsignedLong& aId,
const nsAString& aRevisionId,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->Remove(aId, aRevisionId, aRv);
}
already_AddRefed<Promise>
DataStore::Clear(const nsAString& aRevisionId, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->Clear(aRevisionId, aRv);
}
void
DataStore::GetRevisionId(nsAString& aRevisionId, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
nsAutoString revisionId;
mStore->GetRevisionId(revisionId, aRv);
aRevisionId.Assign(revisionId);
}
already_AddRefed<Promise>
DataStore::GetLength(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->GetLength(aRv);
}
already_AddRefed<DataStoreCursor>
DataStore::Sync(const nsAString& aRevisionId, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mStore);
return mStore->Sync(aRevisionId, aRv);
}
void
DataStore::SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mStore);
mStore = &aStore;
mStore->SetEventTarget(*this, aRv);
}
} //namespace dom
} //namespace mozilla

95
dom/datastore/DataStore.h Normal file
View File

@ -0,0 +1,95 @@
/* 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/. */
#ifndef mozilla_dom_DataStore_h
#define mozilla_dom_DataStore_h
#include "mozilla/DOMEventTargetHelper.h"
namespace mozilla {
class ErrorResult;
namespace dom {
class Promise;
class DataStoreCursor;
class DataStoreImpl;
class StringOrUnsignedLong;
class OwningStringOrUnsignedLong;
class DataStore MOZ_FINAL : public DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DataStore,
DOMEventTargetHelper)
explicit DataStore(nsPIDOMWindow* aWindow);
// WebIDL (internal functions)
static already_AddRefed<DataStore> Constructor(GlobalObject& aGlobal,
ErrorResult& aRv);
virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
static bool EnabledForScope(JSContext* aCx, JS::Handle<JSObject*> aObj);
// WebIDL (public APIs)
void GetName(nsAString& aName, ErrorResult& aRv);
void GetOwner(nsAString& aOwner, ErrorResult& aRv);
bool GetReadOnly(ErrorResult& aRv);
already_AddRefed<Promise> Get(const Sequence<OwningStringOrUnsignedLong>& aId,
ErrorResult& aRv);
already_AddRefed<Promise> Put(JSContext* aCx,
JS::Handle<JS::Value> aObj,
const StringOrUnsignedLong& aId,
const nsAString& aRevisionId,
ErrorResult& aRv);
already_AddRefed<Promise> Add(JSContext* aCx,
JS::Handle<JS::Value> aObj,
const Optional<StringOrUnsignedLong>& aId,
const nsAString& aRevisionId,
ErrorResult& aRv);
already_AddRefed<Promise> Remove(const StringOrUnsignedLong& aId,
const nsAString& aRevisionId,
ErrorResult& aRv);
already_AddRefed<Promise> Clear(const nsAString& aRevisionId,
ErrorResult& aRv);
void GetRevisionId(nsAString& aRevisionId, ErrorResult& aRv);
already_AddRefed<Promise> GetLength(ErrorResult& aRv);
already_AddRefed<DataStoreCursor> Sync(const nsAString& aRevisionId,
ErrorResult& aRv);
IMPL_EVENT_HANDLER(change)
// This internal function (ChromeOnly) is aimed to make the DataStore keep a
// reference to the DataStoreImpl which really implements the API's logic in
// JS. We also need to let the DataStoreImpl implementation keep the event
// target of DataStore, so that it can know where to fire the events.
void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv);
protected:
virtual ~DataStore() {}
private:
nsRefPtr<DataStoreImpl> mStore;
};
} //namespace dom
} //namespace mozilla
#endif

View File

@ -0,0 +1,71 @@
/* 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 "mozilla/dom/DataStore.h"
#include "mozilla/dom/DataStoreCursor.h"
#include "mozilla/dom/DataStoreBinding.h"
#include "mozilla/dom/DataStoreImplBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/ErrorResult.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DataStoreCursor, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DataStoreCursor, Release)
NS_IMPL_CYCLE_COLLECTION_1(DataStoreCursor, mCursor)
already_AddRefed<DataStoreCursor>
DataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
{
nsRefPtr<DataStoreCursor> cursor = new DataStoreCursor();
return cursor.forget();
}
JSObject*
DataStoreCursor::WrapObject(JSContext* aCx)
{
return DataStoreCursorBinding::Wrap(aCx, this);
}
already_AddRefed<DataStore>
DataStoreCursor::GetStore(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mCursor);
return mCursor->GetStore(aRv);
}
already_AddRefed<Promise>
DataStoreCursor::Next(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mCursor);
return mCursor->Next(aRv);
}
void
DataStoreCursor::Close(ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mCursor);
mCursor->Close(aRv);
}
void
DataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mCursor);
mCursor = &aCursor;
}
} //namespace dom
} //namespace mozilla

View File

@ -0,0 +1,61 @@
/* 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/. */
#ifndef mozilla_dom_DataStoreCursor_h
#define mozilla_dom_DataStoreCursor_h
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
class nsPIDOMWindow;
namespace mozilla {
class ErrorResult;
namespace dom {
class Promise;
class DataStore;
class GlobalObject;
class DataStoreCursorImpl;
class DataStoreCursor MOZ_FINAL
{
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DataStoreCursor)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(DataStoreCursor)
// WebIDL (internal functions)
static already_AddRefed<DataStoreCursor> Constructor(GlobalObject& aGlobal,
ErrorResult& aRv);
JSObject* WrapObject(JSContext *aCx);
// WebIDL (public APIs)
already_AddRefed<DataStore> GetStore(ErrorResult& aRv);
already_AddRefed<Promise> Next(ErrorResult& aRv);
void Close(ErrorResult& aRv);
// This internal function (ChromeOnly) is aimed to make the DataStoreCursor
// keep a reference to the DataStoreCursorImpl which really implements the
// API's logic in JS.
void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor);
protected:
virtual ~DataStoreCursor() {}
private:
nsRefPtr<DataStoreCursorImpl> mCursor;
};
} //namespace dom
} //namespace mozilla
#endif

View File

@ -77,13 +77,14 @@ function createDOMError(aWindow, aEvent) {
/* DataStoreCursor object */
this.DataStoreCursor = function(aWindow, aDataStore, aRevisionId) {
debug("DataStoreCursor created");
this.init(aWindow, aDataStore, aRevisionId);
}
this.DataStoreCursor.prototype = {
classDescription: 'DataStoreCursor XPCOM Component',
classID: Components.ID('{b6d14349-1eab-46b8-8513-584a7328a26b}'),
contractID: '@mozilla.org/dom/datastore-cursor;1',
contractID: '@mozilla.org/dom/datastore-cursor-impl;1',
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
_window: null,

View File

@ -23,7 +23,7 @@ const REVISION_VOID = "void";
// and yet we don't know if it's too low or too high.
const MAX_REQUESTS = 25;
Cu.import("resource://gre/modules/DataStoreCursor.jsm");
Cu.import("resource://gre/modules/DataStoreCursorImpl.jsm");
Cu.import("resource://gre/modules/DataStoreDB.jsm");
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
@ -67,7 +67,7 @@ this.DataStore = function(aWindow, aName, aOwner, aReadOnly) {
this.DataStore.prototype = {
classDescription: "DataStore XPCOM Component",
classID: Components.ID("{db5c9602-030f-4bff-a3de-881a8de370f2}"),
contractID: "@mozilla.org/dom/datastore;1",
contractID: "@mozilla.org/dom/datastore-impl;1",
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports,
Components.interfaces.nsIObserver]),
@ -81,6 +81,7 @@ this.DataStore.prototype = {
_exposedObject: null,
_cursor: null,
_shuttingdown: false,
_eventTarget: null,
init: function(aWindow, aName, aOwner, aReadOnly) {
debug("DataStore init");
@ -116,6 +117,10 @@ this.DataStore.prototype = {
}
},
setEventTarget: function(aEventTarget) {
this._eventTarget = aEventTarget;
},
newDBPromise: function(aTxnType, aFunction) {
let self = this;
return new this._window.Promise(function(aResolve, aReject) {
@ -365,7 +370,7 @@ this.DataStore.prototype = {
let event = new self._window.DataStoreChangeEvent('change',
aMessage.data.message);
self.__DOM_IMPL__.dispatchEvent(event);
self._eventTarget.dispatchEvent(event);
}
);
},
@ -519,19 +524,15 @@ this.DataStore.prototype = {
);
},
set onchange(aCallback) {
debug("Set OnChange");
this.__DOM_IMPL__.setEventHandler("onchange", aCallback);
},
get onchange() {
debug("Get OnChange");
return this.__DOM_IMPL__.getEventHandler("onchange");
},
sync: function(aRevisionId) {
debug("Sync");
this._cursor = new DataStoreCursor(this._window, this, aRevisionId);
return this._window.DataStoreCursor._create(this._window, this._cursor);
let cursorImpl = this._window.DataStoreCursorImpl.
_create(this._window, this._cursor);
let exposedCursor = new this._window.DataStoreCursor();
exposedCursor.setDataStoreCursorImpl(cursorImpl);
return exposedCursor;
}
};

View File

@ -16,7 +16,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/DataStore.jsm');
Cu.import('resource://gre/modules/DataStoreImpl.jsm');
Cu.import("resource://gre/modules/DataStoreDB.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
@ -352,10 +352,15 @@ DataStoreService.prototype = {
for (let i = 0; i < aStores.length; ++i) {
let obj = new DataStore(aWindow, aStores[i].name,
aStores[i].owner, aStores[i].readOnly);
let exposedObj = aWindow.DataStore._create(aWindow, obj);
obj.exposedObject = exposedObj;
results.push(exposedObj);
let storeImpl = aWindow.DataStoreImpl._create(aWindow, obj);
let exposedStore = new aWindow.DataStore();
exposedStore.setDataStoreImpl(storeImpl);
obj.exposedObject = exposedStore;
results.push(exposedStore);
obj.retrieveRevisionId(
function() {

View File

@ -10,17 +10,33 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'dom_datastore'
EXPORTS.mozilla.dom += [
'DataStore.h',
'DataStoreCursor.h',
]
SOURCES += [
'DataStore.cpp',
'DataStoreCursor.cpp',
]
LOCAL_INCLUDES += [
'/js/xpconnect/wrappers',
]
EXTRA_COMPONENTS += [
'DataStore.manifest',
'DataStoreService.js',
]
EXTRA_JS_MODULES += [
'DataStore.jsm',
'DataStoreChangeNotifier.jsm',
'DataStoreCursor.jsm',
'DataStoreCursorImpl.jsm',
'DataStoreDB.jsm',
'DataStoreImpl.jsm',
'DataStoreServiceInternal.jsm',
]
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
FINAL_LIBRARY = 'xul'

View File

@ -6,58 +6,91 @@
typedef (DOMString or unsigned long) DataStoreKey;
// TODO Bug 957086 - The constructor and the setDataStoreImpl(...) will be
// removed once the DataStore API is fully rewritten in C++,
// which currently plays a role of C++ proxy directing to the
// JS codes implemented by the DataStoreImpl WebIDL.
[Func="Navigator::HasDataStoreSupport",
JSImplementation="@mozilla.org/dom/datastore;1"]
ChromeConstructor]
interface DataStore : EventTarget {
// Returns the label of the DataSource.
[GetterThrows]
readonly attribute DOMString name;
// Returns the origin of the DataSource (e.g., 'facebook.com').
// This value is the manifest URL of the owner app.
[GetterThrows]
readonly attribute DOMString owner;
// is readOnly a F(current_app, datastore) function? yes
[GetterThrows]
readonly attribute boolean readOnly;
// Promise<any>
[Throws]
Promise get(DataStoreKey... id);
// Promise<void>
[Throws]
Promise put(any obj, DataStoreKey id, optional DOMString revisionId = "");
// Promise<DataStoreKey>
[Throws]
Promise add(any obj, optional DataStoreKey id,
optional DOMString revisionId = "");
// Promise<boolean>
[Throws]
Promise remove(DataStoreKey id, optional DOMString revisionId = "");
// Promise<void>
[Throws]
Promise clear(optional DOMString revisionId = "");
[GetterThrows]
readonly attribute DOMString revisionId;
attribute EventHandler onchange;
// Promise<unsigned long>
[Throws]
Promise getLength();
[NewObject, Throws]
DataStoreCursor sync(optional DOMString revisionId = "");
};
[Pref="dom.datastore.enabled",
JSImplementation="@mozilla.org/dom/datastore-cursor;1"]
interface DataStoreCursor {
partial interface DataStore {
[ChromeOnly, Throws]
void setDataStoreImpl(DataStoreImpl store);
};
// TODO Bug 957086 - The constructor and the setDataStoreCursorImpl(...) will be
// removed once the DataStore API is fully rewritten in C++,
// which currently plays a role of C++ proxy directing to the
// JS codes implemented by the DataStoreCursorImpl WebIDL.
[Pref="dom.datastore.enabled",
ChromeConstructor]
interface DataStoreCursor {
// the DataStore
[GetterThrows]
readonly attribute DataStore store;
// Promise<DataStoreTask>
[Throws]
Promise next();
[Throws]
void close();
};
partial interface DataStoreCursor {
[ChromeOnly]
void setDataStoreCursorImpl(DataStoreCursorImpl cursor);
};
enum DataStoreOperation {
"add",
"update",

View File

@ -0,0 +1,68 @@
/* -*- Mode: IDL; tab-width: 2; 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/.
*/
// TODO Bug 957086 - The DataStoreImpl WebIDL will be removed once the
// DataStore API is fully rewritten in C++ (i.e. should be
// directly implemented by the DataStore WebIDL).
[HeaderFile="mozilla/dom/DataStore.h",
Func="mozilla::dom::DataStore::EnabledForScope",
JSImplementation="@mozilla.org/dom/datastore-impl;1"]
interface DataStoreImpl {
void setEventTarget(EventTarget eventTarget);
// Returns the label of the DataSource.
readonly attribute DOMString name;
// Returns the origin of the DataSource (e.g., 'facebook.com').
// This value is the manifest URL of the owner app.
readonly attribute DOMString owner;
// is readOnly a F(current_app, datastore) function? yes
readonly attribute boolean readOnly;
// Promise<any>
Promise get(DataStoreKey... id);
// Promise<void>
Promise put(any obj, DataStoreKey id, optional DOMString revisionId = "");
// Promise<DataStoreKey>
Promise add(any obj, optional DataStoreKey id,
optional DOMString revisionId = "");
// Promise<boolean>
Promise remove(DataStoreKey id, optional DOMString revisionId = "");
// Promise<void>
Promise clear(optional DOMString revisionId = "");
readonly attribute DOMString revisionId;
// Promise<unsigned long>
Promise getLength();
[NewObject]
DataStoreCursor sync(optional DOMString revisionId = "");
};
// TODO Bug 957086 - The DataStoreCursorImpl WebIDL will be removed once the
// DataStore API is fully rewritten in C++ (i.e. should be
// directly implemented by the DataStoreCursor WebIDL).
[HeaderFile="mozilla/dom/DataStore.h",
Func="mozilla::dom::DataStore::EnabledForScope",
JSImplementation="@mozilla.org/dom/datastore-cursor-impl;1"]
interface DataStoreCursorImpl {
// the DataStore
readonly attribute DataStore store;
// Promise<DataStoreTask>
Promise next();
void close();
};

View File

@ -68,6 +68,7 @@ WEBIDL_FILES = [
'CSSValueList.webidl',
'DataContainerEvent.webidl',
'DataStore.webidl',
'DataStoreImpl.webidl',
'DataTransfer.webidl',
'DedicatedWorkerGlobalScope.webidl',
'DelayNode.webidl',