Bug 1057915 - 1/2: [MobileMessage] Ability to return multiple entries in getMessages/getThreads cursor.result. DOM & IPDL changes. r=smaug

This commit is contained in:
Vicamo Yang 2014-09-04 11:15:41 +08:00
parent 05b67b7329
commit f1f889e5f0
10 changed files with 264 additions and 61 deletions

View File

@ -8,11 +8,94 @@
#include "nsIDOMDOMRequest.h"
#include "nsIDOMMozSmsMessage.h"
#include "nsIMobileMessageCallback.h"
#include "DOMCursor.h"
#include "nsServiceManagerUtils.h" // for do_GetService
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(MobileMessageCursor, DOMCursor,
mPendingResults)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MobileMessageCursor)
NS_INTERFACE_MAP_END_INHERITING(DOMCursor)
NS_IMPL_ADDREF_INHERITED(MobileMessageCursor, DOMCursor)
NS_IMPL_RELEASE_INHERITED(MobileMessageCursor, DOMCursor)
MobileMessageCursor::MobileMessageCursor(nsPIDOMWindow* aWindow,
nsICursorContinueCallback* aCallback)
: DOMCursor(aWindow, aCallback)
{
}
NS_IMETHODIMP
MobileMessageCursor::Continue()
{
// We have originally:
//
// DOMCursor::Continue()
// +-> DOMCursor::Continue(ErrorResult& aRv)
//
// Now it becomes:
//
// MobileMessageCursor::Continue()
// +-> DOMCursor::Continue()
// +-> MobileMessageCursor::Continue(ErrorResult& aRv)
// o-> DOMCursor::Continue(ErrorResult& aRv)
return DOMCursor::Continue();
}
void
MobileMessageCursor::Continue(ErrorResult& aRv)
{
// An ordinary DOMCursor works in following flow:
//
// DOMCursor::Continue()
// +-> DOMCursor::Reset()
// +-> nsICursorContinueCallback::HandleContinue()
// +-> nsIMobileMessageCursorCallback::NotifyCursorResult()
// +-> DOMCursor::FireSuccess()
//
// With no pending result, we call to |DOMCursor::Continue()| as usual.
if (!mPendingResults.Length()) {
DOMCursor::Continue(aRv);
return;
}
// Otherwise, reset current result and fire a success event with the last
// pending one.
Reset();
nsresult rv = FireSuccessWithNextPendingResult();
if (NS_FAILED(rv)) {
aRv.Throw(rv);
}
}
nsresult
MobileMessageCursor::FireSuccessWithNextPendingResult()
{
// We're going to pop the last element from mPendingResults, so it must not
// be empty.
MOZ_ASSERT(mPendingResults.Length());
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> val(cx);
nsresult rv =
nsContentUtils::WrapNative(cx, mPendingResults.LastElement(), &val);
NS_ENSURE_SUCCESS(rv, rv);
mPendingResults.RemoveElementAt(mPendingResults.Length() - 1);
FireSuccess(val);
return NS_OK;
}
namespace mobilemessage {
NS_IMPL_CYCLE_COLLECTION(MobileMessageCursorCallback, mDOMCursor)
@ -55,21 +138,29 @@ MobileMessageCursorCallback::NotifyCursorError(int32_t aError)
}
NS_IMETHODIMP
MobileMessageCursorCallback::NotifyCursorResult(nsISupports* aResult)
MobileMessageCursorCallback::NotifyCursorResult(nsISupports** aResults,
uint32_t aSize)
{
MOZ_ASSERT(mDOMCursor);
// We should only be notified with valid results. Or, either
// |NotifyCursorDone()| or |NotifyCursorError()| should be called instead.
MOZ_ASSERT(aResults && *aResults && aSize);
// There shouldn't be unexpected notifications before |Continue()| is called.
nsTArray<nsCOMPtr<nsISupports>>& pending = mDOMCursor->mPendingResults;
MOZ_ASSERT(pending.Length() == 0);
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(mDOMCursor->GetOwner()))) {
return NS_ERROR_FAILURE;
// Push pending results in reversed order.
pending.SetCapacity(pending.Length() + aSize);
while (aSize) {
--aSize;
pending.AppendElement(aResults[aSize]);
}
JSContext* cx = jsapi.cx();
JS::Rooted<JS::Value> wrappedResult(cx);
nsresult rv = nsContentUtils::WrapNative(cx, aResult, &wrappedResult);
NS_ENSURE_SUCCESS(rv, rv);
nsresult rv = mDOMCursor->FireSuccessWithNextPendingResult();
if (NS_FAILED(rv)) {
NotifyCursorError(nsIMobileMessageCallback::INTERNAL_ERROR);
}
mDOMCursor->FireSuccess(wrappedResult);
return NS_OK;
}

View File

@ -6,6 +6,8 @@
#ifndef mozilla_dom_mobilemessage_MobileMessageCursorCallback_h
#define mozilla_dom_mobilemessage_MobileMessageCursorCallback_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/DOMCursor.h"
#include "nsIMobileMessageCursorCallback.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
@ -16,12 +18,46 @@ class nsICursorContinueCallback;
namespace mozilla {
namespace dom {
class DOMCursor;
class MobileMessageManager;
namespace mobilemessage {
class MobileMessageCursorCallback;
} // namespace mobilemessage
class MobileMessageCursorCallback : public nsIMobileMessageCursorCallback
class MobileMessageCursor MOZ_FINAL : public DOMCursor
{
friend class mobilemessage::MobileMessageCursorCallback;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MobileMessageCursor, DOMCursor)
MobileMessageCursor(nsPIDOMWindow* aWindow,
nsICursorContinueCallback* aCallback);
// Override XPIDL continue function to suppress -Werror,-Woverloaded-virtual.
NS_IMETHOD
Continue(void) MOZ_OVERRIDE;
virtual void
Continue(ErrorResult& aRv) MOZ_OVERRIDE;
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~MobileMessageCursor() {}
private:
// List of read-ahead results in reversed order.
nsTArray<nsCOMPtr<nsISupports>> mPendingResults;
nsresult
FireSuccessWithNextPendingResult();
};
namespace mobilemessage {
class MobileMessageCursorCallback MOZ_FINAL : public nsIMobileMessageCursorCallback
{
friend class mozilla::dom::MobileMessageManager;
@ -37,12 +73,13 @@ public:
}
private:
virtual ~MobileMessageCursorCallback()
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~MobileMessageCursorCallback()
{
MOZ_COUNT_DTOR(MobileMessageCursorCallback);
}
nsRefPtr<DOMCursor> mDOMCursor;
nsRefPtr<MobileMessageCursor> mDOMCursor;
};
} // namespace mobilemessage

View File

@ -439,9 +439,10 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter,
return nullptr;
}
cursorCallback->mDOMCursor = new DOMCursor(GetOwner(), continueCallback);
cursorCallback->mDOMCursor =
new MobileMessageCursor(GetOwner(), continueCallback);
nsRefPtr<DOMCursor> cursor = cursorCallback->mDOMCursor;
nsRefPtr<DOMCursor> cursor(cursorCallback->mDOMCursor);
return cursor.forget();
}
@ -491,9 +492,10 @@ MobileMessageManager::GetThreads(ErrorResult& aRv)
return nullptr;
}
cursorCallback->mDOMCursor = new DOMCursor(GetOwner(), continueCallback);
cursorCallback->mDOMCursor =
new MobileMessageCursor(GetOwner(), continueCallback);
nsRefPtr<DOMCursor> cursor = cursorCallback->mDOMCursor;
nsRefPtr<DOMCursor> cursor(cursorCallback->mDOMCursor);
return cursor.forget();
}

View File

@ -3807,7 +3807,7 @@ GetMessagesCursor.prototype = {
}
let domMessage =
self.mmdb.createDomMessageFromRecord(event.target.result);
self.callback.notifyCursorResult(domMessage);
self.callback.notifyCursorResult([domMessage], 1);
};
getRequest.onerror = function(event) {
if (DEBUG) {
@ -3888,7 +3888,7 @@ GetThreadsCursor.prototype = {
threadRecord.body,
threadRecord.unreadCount,
threadRecord.lastMessageType);
self.callback.notifyCursorResult(thread);
self.callback.notifyCursorResult([thread], 1);
};
getRequest.onerror = function(event) {
if (DEBUG) {

View File

@ -4,10 +4,11 @@
#include "nsISupports.idl"
[scriptable, builtinclass, uuid(8fd0dba2-032e-4190-a751-07cc3782e93e)]
[scriptable, builtinclass, uuid(134a6958-543b-46e2-b419-4631a2314164)]
interface nsIMobileMessageCursorCallback : nsISupports
{
void notifyCursorError(in long error);
void notifyCursorResult(in nsISupports result);
void notifyCursorResult([array, size_is(size)] in nsISupports results,
in uint32_t size);
void notifyCursorDone();
};

View File

@ -293,22 +293,17 @@ MobileMessageCursorChild::RecvNotifyResult(const MobileMessageCursorData& aData)
{
MOZ_ASSERT(mCursorCallback);
nsCOMPtr<nsISupports> result;
switch(aData.type()) {
case MobileMessageCursorData::TMmsMessageData:
result = new MmsMessage(aData.get_MmsMessageData());
case MobileMessageCursorData::TMobileMessageArrayData:
DoNotifyResult(aData.get_MobileMessageArrayData().messages());
break;
case MobileMessageCursorData::TSmsMessageData:
result = new SmsMessage(aData.get_SmsMessageData());
break;
case MobileMessageCursorData::TThreadData:
result = new MobileMessageThread(aData.get_ThreadData());
case MobileMessageCursorData::TThreadArrayData:
DoNotifyResult(aData.get_ThreadArrayData().threads());
break;
default:
MOZ_CRASH("Received invalid response parameters!");
}
mCursorCallback->NotifyCursorResult(result);
return true;
}
@ -338,6 +333,48 @@ MobileMessageCursorChild::HandleContinue()
return NS_OK;
}
void
MobileMessageCursorChild::DoNotifyResult(const nsTArray<MobileMessageData>& aDataArray)
{
const uint32_t length = aDataArray.Length();
MOZ_ASSERT(length);
AutoFallibleTArray<nsISupports*, 1> autoArray;
NS_ENSURE_TRUE_VOID(autoArray.SetCapacity(length));
AutoFallibleTArray<nsCOMPtr<nsISupports>, 1> messages;
NS_ENSURE_TRUE_VOID(messages.SetCapacity(length));
for (uint32_t i = 0; i < length; i++) {
nsCOMPtr<nsISupports> message = CreateMessageFromMessageData(aDataArray[i]);
NS_ENSURE_TRUE_VOID(messages.AppendElement(message));
NS_ENSURE_TRUE_VOID(autoArray.AppendElement(message.get()));
}
mCursorCallback->NotifyCursorResult(autoArray.Elements(), length);
}
void
MobileMessageCursorChild::DoNotifyResult(const nsTArray<ThreadData>& aDataArray)
{
const uint32_t length = aDataArray.Length();
MOZ_ASSERT(length);
AutoFallibleTArray<nsISupports*, 1> autoArray;
NS_ENSURE_TRUE_VOID(autoArray.SetCapacity(length));
AutoFallibleTArray<nsCOMPtr<nsISupports>, 1> threads;
NS_ENSURE_TRUE_VOID(threads.SetCapacity(length));
for (uint32_t i = 0; i < length; i++) {
nsCOMPtr<nsISupports> thread = new MobileMessageThread(aDataArray[i]);
NS_ENSURE_TRUE_VOID(threads.AppendElement(thread));
NS_ENSURE_TRUE_VOID(autoArray.AppendElement(thread.get()));
}
mCursorCallback->NotifyCursorResult(autoArray.Elements(), length);
}
} // namespace mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -129,6 +129,13 @@ protected:
virtual bool
Recv__delete__(const int32_t& aError) MOZ_OVERRIDE;
private:
void
DoNotifyResult(const nsTArray<MobileMessageData>& aData);
void
DoNotifyResult(const nsTArray<ThreadData>& aData);
};
} // namespace mobilemessage

View File

@ -843,40 +843,59 @@ MobileMessageCursorParent::NotifyCursorError(int32_t aError)
}
NS_IMETHODIMP
MobileMessageCursorParent::NotifyCursorResult(nsISupports* aResult)
MobileMessageCursorParent::NotifyCursorResult(nsISupports** aResults,
uint32_t aSize)
{
MOZ_ASSERT(aResults && *aResults && aSize);
// The child process could die before this asynchronous notification, in which
// case ActorDestroy() was called and mContinueCallback is now null. Return an
// error here to avoid sending a message to the dead process.
NS_ENSURE_TRUE(mContinueCallback, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMMozSmsMessage> iSms = do_QueryInterface(aResult);
if (iSms) {
SmsMessage* message = static_cast<SmsMessage*>(aResult);
return SendNotifyResult(MobileMessageCursorData(message->GetData()))
? NS_OK : NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMMozMmsMessage> iMms = do_QueryInterface(aResult);
if (iMms) {
MmsMessage* message = static_cast<MmsMessage*>(aResult);
ContentParent* parent = static_cast<ContentParent*>(Manager()->Manager());
MmsMessageData data;
if (!message->GetData(parent, data)) {
return NS_ERROR_FAILURE;
}
return SendNotifyResult(MobileMessageCursorData(data))
? NS_OK : NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMMozMobileMessageThread> iThread = do_QueryInterface(aResult);
nsCOMPtr<nsIDOMMozMobileMessageThread> iThread =
do_QueryInterface(aResults[0]);
if (iThread) {
MobileMessageThread* thread = static_cast<MobileMessageThread*>(aResult);
return SendNotifyResult(MobileMessageCursorData(thread->GetData()))
nsTArray<ThreadData> threads;
for (uint32_t i = 0; i < aSize; i++) {
nsCOMPtr<nsIDOMMozMobileMessageThread> iThread =
do_QueryInterface(aResults[i]);
NS_ENSURE_TRUE(iThread, NS_ERROR_FAILURE);
MobileMessageThread* thread =
static_cast<MobileMessageThread*>(iThread.get());
threads.AppendElement(thread->GetData());
}
return SendNotifyResult(MobileMessageCursorData(ThreadArrayData(threads)))
? NS_OK : NS_ERROR_FAILURE;
}
MOZ_CRASH("Received invalid response parameters!");
ContentParent* parent = static_cast<ContentParent*>(Manager()->Manager());
nsTArray<MobileMessageData> messages;
for (uint32_t i = 0; i < aSize; i++) {
nsCOMPtr<nsIDOMMozSmsMessage> iSms = do_QueryInterface(aResults[i]);
if (iSms) {
SmsMessage* sms = static_cast<SmsMessage*>(iSms.get());
messages.AppendElement(sms->GetData());
continue;
}
nsCOMPtr<nsIDOMMozMmsMessage> iMms = do_QueryInterface(aResults[i]);
if (iMms) {
MmsMessage* mms = static_cast<MmsMessage*>(iMms.get());
MmsMessageData mmsData;
NS_ENSURE_TRUE(mms->GetData(parent, mmsData), NS_ERROR_FAILURE);
messages.AppendElement(mmsData);
continue;
}
return NS_ERROR_FAILURE;
}
return SendNotifyResult(MobileMessageCursorData(MobileMessageArrayData(messages)))
? NS_OK : NS_ERROR_FAILURE;
}
NS_IMETHODIMP

View File

@ -99,11 +99,20 @@ struct ThreadData
MessageType lastMessageType;
};
struct MobileMessageArrayData
{
MobileMessageData[] messages;
};
struct ThreadArrayData
{
ThreadData[] threads;
};
union MobileMessageCursorData
{
MmsMessageData;
SmsMessageData;
ThreadData;
MobileMessageArrayData;
ThreadArrayData;
};
struct DeletedMessageInfoData

View File

@ -303,9 +303,9 @@ function createMmdbCursor(aMmdb, aMethodName) {
deferred.reject([aRv, results]);
},
notifyCursorResult: function(aResult) {
ok(true, "notifyCursorResult: " + aResult.id);
results.push(aResult);
notifyCursorResult: function(aResults, aSize) {
ok(true, "notifyCursorResult: " + aResults.map(function(aElement) { return aElement.id; }));
results = results.concat(aResults);
cursor.handleContinue();
},