From 073357cfca13ca61032ac30c0c676e3c15fb005a Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Tue, 13 Nov 2012 13:01:26 -0800 Subject: [PATCH 01/76] Bug 809661 - Need a speedy way to construct a thread list for SMS messages. r=sicking --- dom/sms/Makefile.in | 2 +- dom/sms/interfaces/nsIDOMSmsManager.idl | 4 +- dom/sms/interfaces/nsISmsDatabaseService.idl | 4 +- dom/sms/interfaces/nsISmsRequest.idl | 14 +- dom/sms/src/SmsManager.cpp | 14 + dom/sms/src/SmsRequest.cpp | 151 ++++++++++- dom/sms/src/SmsRequest.h | 21 +- dom/sms/src/android/SmsDatabaseService.cpp | 7 + dom/sms/src/fallback/SmsDatabaseService.cpp | 7 + dom/sms/src/ipc/PSms.ipdl | 5 + dom/sms/src/ipc/PSmsRequest.ipdl | 20 ++ dom/sms/src/ipc/SmsChild.cpp | 8 + dom/sms/src/ipc/SmsIPCService.cpp | 7 + dom/sms/src/ipc/SmsParent.cpp | 17 ++ dom/sms/src/ipc/SmsParent.h | 3 + dom/sms/src/ril/SmsDatabaseService.js | 262 +++++++++++++++---- js/xpconnect/src/dictionary_helper_gen.conf | 3 +- 17 files changed, 492 insertions(+), 57 deletions(-) diff --git a/dom/sms/Makefile.in b/dom/sms/Makefile.in index 8196e39412c6..14338d78479a 100644 --- a/dom/sms/Makefile.in +++ b/dom/sms/Makefile.in @@ -11,7 +11,7 @@ relativesrcdir = @relativesrcdir@ include $(DEPTH)/config/autoconf.mk -PARALLEL_DIRS = interfaces src +DIRS = interfaces src TEST_DIRS += tests ifdef ENABLE_TESTS diff --git a/dom/sms/interfaces/nsIDOMSmsManager.idl b/dom/sms/interfaces/nsIDOMSmsManager.idl index a6ce0e457df5..36eca7954a43 100644 --- a/dom/sms/interfaces/nsIDOMSmsManager.idl +++ b/dom/sms/interfaces/nsIDOMSmsManager.idl @@ -8,7 +8,7 @@ interface nsIDOMEventListener; interface nsIDOMMozSmsRequest; interface nsIDOMMozSmsFilter; -[scriptable, builtinclass, uuid(1bee1224-56a2-4935-af7b-0011746306cb)] +[scriptable, builtinclass, uuid(caaf5c38-a730-4dbb-a0f0-12384bfac8e3)] interface nsIDOMMozSmsManager : nsIDOMEventTarget { unsigned short getNumberOfMessagesForText(in DOMString text); @@ -29,6 +29,8 @@ interface nsIDOMMozSmsManager : nsIDOMEventTarget nsIDOMMozSmsRequest markMessageRead(in long id, in boolean aValue); + nsIDOMMozSmsRequest getThreadList(); + [implicit_jscontext] attribute jsval onreceived; [implicit_jscontext] attribute jsval onsent; [implicit_jscontext] attribute jsval ondeliverysuccess; diff --git a/dom/sms/interfaces/nsISmsDatabaseService.idl b/dom/sms/interfaces/nsISmsDatabaseService.idl index 157f0462c13a..cff1a6d8550d 100644 --- a/dom/sms/interfaces/nsISmsDatabaseService.idl +++ b/dom/sms/interfaces/nsISmsDatabaseService.idl @@ -14,7 +14,7 @@ interface nsIDOMMozSmsFilter; interface nsISmsRequest; -[scriptable, uuid(6ad55465-6937-4491-93ca-29dad9775d46)] +[scriptable, uuid(c2cb2af7-6b96-4915-bcc8-54ad705d6110)] interface nsISmsDatabaseService : nsISupports { // Takes some information required to save the message and returns its id. @@ -30,4 +30,6 @@ interface nsISmsDatabaseService : nsISupports void getNextMessageInList(in long listId, in nsISmsRequest request); void clearMessageList(in long listId); void markMessageRead(in long messageId, in boolean value, in nsISmsRequest request); + + void getThreadList(in nsISmsRequest request); }; diff --git a/dom/sms/interfaces/nsISmsRequest.idl b/dom/sms/interfaces/nsISmsRequest.idl index 8ce490fcf6a9..993cb43ae2a1 100644 --- a/dom/sms/interfaces/nsISmsRequest.idl +++ b/dom/sms/interfaces/nsISmsRequest.idl @@ -6,7 +6,15 @@ interface nsIDOMMozSmsMessage; -[scriptable, builtinclass, uuid(97067327-64b9-4e26-848b-59e443c55db9)] +dictionary SmsThreadListItem +{ + DOMString senderOrReceiver; + unsigned long long timestamp; + DOMString body; + unsigned long long unreadCount; +}; + +[scriptable, builtinclass, uuid(82a6d16d-cf33-4745-8662-8b5d441f512f)] interface nsISmsRequest : nsISupports { /** @@ -37,4 +45,8 @@ interface nsISmsRequest : nsISupports void notifyMessageMarkedRead(in boolean read); void notifyMarkMessageReadFailed(in long error); + + [implicit_jscontext] + void notifyThreadList(in jsval threadList); + void notifyThreadListFailed(in long error); }; diff --git a/dom/sms/src/SmsManager.cpp b/dom/sms/src/SmsManager.cpp index 40493d00aebf..d022cc680fb2 100644 --- a/dom/sms/src/SmsManager.cpp +++ b/dom/sms/src/SmsManager.cpp @@ -303,6 +303,20 @@ SmsManager::MarkMessageRead(int32_t aId, bool aValue, return NS_OK; } +NS_IMETHODIMP +SmsManager::GetThreadList(nsIDOMMozSmsRequest** aRequest) +{ + nsCOMPtr req = SmsRequest::Create(this); + nsCOMPtr smsDBService = + do_GetService(SMS_DATABASE_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE); + nsCOMPtr forwarder = + new SmsRequestForwarder(static_cast(req.get())); + smsDBService->GetThreadList(forwarder); + req.forget(aRequest); + return NS_OK; +} + nsresult SmsManager::DispatchTrustedSmsEventToSelf(const nsAString& aEventName, nsIDOMMozSmsMessage* aMessage) { diff --git a/dom/sms/src/SmsRequest.cpp b/dom/sms/src/SmsRequest.cpp index 2630e499c65c..6ca0f6de3a70 100644 --- a/dom/sms/src/SmsRequest.cpp +++ b/dom/sms/src/SmsRequest.cpp @@ -9,11 +9,16 @@ #include "nsDOMString.h" #include "nsContentUtils.h" #include "nsIDOMSmsMessage.h" +#include "nsIScriptGlobalObject.h" +#include "nsPIDOMWindow.h" #include "SmsCursor.h" #include "SmsMessage.h" #include "SmsManager.h" #include "mozilla/dom/DOMError.h" #include "SmsParent.h" +#include "jsapi.h" +#include "DictionaryHelpers.h" +#include "xpcpublic.h" #define SUCCESS_EVENT_NAME NS_LITERAL_STRING("success") #define ERROR_EVENT_NAME NS_LITERAL_STRING("error") @@ -145,12 +150,7 @@ SmsRequest::SetSuccess(nsIDOMMozSmsMessage* aMessage) void SmsRequest::SetSuccess(bool aResult) { - NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!"); - NS_PRECONDITION(!mError, "mError shouldn't have been set!"); - NS_PRECONDITION(mResult == JSVAL_NULL, "mResult shouldn't have been set!"); - - mResult.setBoolean(aResult); - mDone = true; + SetSuccess(aResult ? JSVAL_TRUE : JSVAL_FALSE); } void @@ -168,6 +168,17 @@ SmsRequest::SetSuccess(nsIDOMMozSmsCursor* aCursor) } } +void +SmsRequest::SetSuccess(const jsval& aResult) +{ + NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!"); + NS_PRECONDITION(!mError, "mError shouldn't have been set!"); + NS_PRECONDITION(JSVAL_IS_VOID(mResult), "mResult shouldn't have been set!"); + + mResult = aResult; + mDone = true; +} + bool SmsRequest::SetSuccessInternal(nsISupports* aObject) { @@ -445,6 +456,134 @@ SmsRequest::NotifyMarkMessageReadFailed(int32_t aError) return NotifyError(aError); } +NS_IMETHODIMP +SmsRequest::NotifyThreadList(const jsval& aThreadList, JSContext* aCx) +{ + MOZ_ASSERT(aThreadList.isObject()); + + if (mParent) { + JSObject* array = const_cast(&aThreadList.toObject()); + + uint32_t length; + bool ok = JS_GetArrayLength(aCx, array, &length); + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + + ReplyThreadList reply; + InfallibleTArray& ipcItems = reply.items(); + + if (length) { + ipcItems.SetCapacity(length); + + for (uint32_t i = 0; i < length; i++) { + jsval arrayEntry; + ok = JS_GetElement(aCx, array, i, &arrayEntry); + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + + MOZ_ASSERT(arrayEntry.isObject()); + + SmsThreadListItem item; + nsresult rv = item.Init(aCx, &arrayEntry); + NS_ENSURE_SUCCESS(rv, rv); + + ThreadListItem* ipcItem = ipcItems.AppendElement(); + ipcItem->senderOrReceiver() = item.senderOrReceiver; + ipcItem->timestamp() = item.timestamp; + ipcItem->body() = item.body; + ipcItem->unreadCount() = item.unreadCount; + } + } + + return SendMessageReply(reply); + } + + return NotifySuccess(aThreadList); +} + +NS_IMETHODIMP +SmsRequest::NotifyThreadListFailed(int32_t aError) +{ + if (mParent) { + return SendMessageReply(MessageReply(ReplyThreadListFail(aError))); + } + return NotifyError(aError); +} + +void +SmsRequest::NotifyThreadList(const InfallibleTArray& aItems) +{ + MOZ_ASSERT(!mParent); + MOZ_ASSERT(GetOwner()); + + nsresult rv; + nsIScriptContext* sc = GetContextForEventHandlers(&rv); + NS_ENSURE_SUCCESS_VOID(rv); + NS_ENSURE_TRUE_VOID(sc); + + JSContext* cx = sc->GetNativeContext(); + MOZ_ASSERT(cx); + + nsCOMPtr sgo = do_QueryInterface(GetOwner()); + + JSObject* ownerObj = sgo->GetGlobalJSObject(); + NS_ENSURE_TRUE_VOID(ownerObj); + + nsCxPusher pusher; + NS_ENSURE_TRUE_VOID(pusher.Push(cx, false)); + + JSAutoRequest ar(cx); + JSAutoCompartment ac(cx, ownerObj); + + JSObject* array = JS_NewArrayObject(cx, aItems.Length(), nullptr); + NS_ENSURE_TRUE_VOID(array); + + bool ok; + + for (uint32_t i = 0; i < aItems.Length(); i++) { + const ThreadListItem& source = aItems[i]; + + nsString temp = source.senderOrReceiver(); + + jsval senderOrReceiver; + ok = xpc::StringToJsval(cx, temp, &senderOrReceiver); + NS_ENSURE_TRUE_VOID(ok); + + JSObject* timestampObj = JS_NewDateObjectMsec(cx, source.timestamp()); + NS_ENSURE_TRUE_VOID(timestampObj); + + jsval timestamp = OBJECT_TO_JSVAL(timestampObj); + + temp = source.body(); + + jsval body; + ok = xpc::StringToJsval(cx, temp, &body); + NS_ENSURE_TRUE_VOID(ok); + + jsval unreadCount = JS_NumberValue(double(source.unreadCount())); + + JSObject* elementObj = JS_NewObject(cx, nullptr, nullptr, nullptr); + NS_ENSURE_TRUE_VOID(elementObj); + + ok = JS_SetProperty(cx, elementObj, "senderOrReceiver", &senderOrReceiver); + NS_ENSURE_TRUE_VOID(ok); + + ok = JS_SetProperty(cx, elementObj, "timestamp", ×tamp); + NS_ENSURE_TRUE_VOID(ok); + + ok = JS_SetProperty(cx, elementObj, "body", &body); + NS_ENSURE_TRUE_VOID(ok); + + ok = JS_SetProperty(cx, elementObj, "unreadCount", &unreadCount); + NS_ENSURE_TRUE_VOID(ok); + + jsval element = OBJECT_TO_JSVAL(elementObj); + + ok = JS_SetElement(cx, array, i, &element); + NS_ENSURE_TRUE_VOID(ok); + } + + NotifyThreadList(OBJECT_TO_JSVAL(array), cx); +} + } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/SmsRequest.h b/dom/sms/src/SmsRequest.h index e27cf80b005a..7abe4b1b9809 100644 --- a/dom/sms/src/SmsRequest.h +++ b/dom/sms/src/SmsRequest.h @@ -17,24 +17,33 @@ namespace mozilla { namespace dom { namespace sms { +class SmsRequestChild; class SmsRequestParent; class MessageReply; +class ThreadListItem; // We need this forwarder to avoid a QI to nsIClassInfo. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=775997#c51 class SmsRequestForwarder : public nsISmsRequest { - NS_FORWARD_NSISMSREQUEST(mRealRequest->) + friend class SmsRequestChild; +public: NS_DECL_ISUPPORTS + NS_FORWARD_NSISMSREQUEST(mRealRequest->) SmsRequestForwarder(nsISmsRequest* aRealRequest) { mRealRequest = aRealRequest; } + +private: virtual ~SmsRequestForwarder() {} -private: + nsISmsRequest* GetRealRequest() { + return mRealRequest; + } + nsCOMPtr mRealRequest; }; @@ -66,6 +75,9 @@ public: mParentAlive = false; } + void + NotifyThreadList(const InfallibleTArray& aItems); + private: SmsRequest() MOZ_DELETE; @@ -100,6 +112,11 @@ private: */ void SetSuccess(nsIDOMMozSmsCursor* aCursor); + /** + * Set the object in a success state with the result being the given jsval. + */ + void SetSuccess(const jsval& aVal); + /** * Set the object in an error state with the error type being aError. */ diff --git a/dom/sms/src/android/SmsDatabaseService.cpp b/dom/sms/src/android/SmsDatabaseService.cpp index b68ad3233c77..bcf527f1e868 100644 --- a/dom/sms/src/android/SmsDatabaseService.cpp +++ b/dom/sms/src/android/SmsDatabaseService.cpp @@ -112,6 +112,13 @@ SmsDatabaseService::MarkMessageRead(int32_t aMessageId, bool aValue, return NS_OK; } +NS_IMETHODIMP +SmsDatabaseService::GetThreadList(nsISmsRequest* aRequest) +{ + NS_NOTYETIMPLEMENTED("Implement me!"); + return NS_ERROR_NOT_IMPLEMENTED; +} + } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/fallback/SmsDatabaseService.cpp b/dom/sms/src/fallback/SmsDatabaseService.cpp index cb66dbf36432..35b0e69095e4 100644 --- a/dom/sms/src/fallback/SmsDatabaseService.cpp +++ b/dom/sms/src/fallback/SmsDatabaseService.cpp @@ -90,6 +90,13 @@ SmsDatabaseService::MarkMessageRead(int32_t aMessageId, return NS_OK; } +NS_IMETHODIMP +SmsDatabaseService::GetThreadList(nsISmsRequest* aRequest) +{ + NS_ERROR("We should not be here!"); + return NS_OK; +} + } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/ipc/PSms.ipdl b/dom/sms/src/ipc/PSms.ipdl index 9059832425c1..139d8b75d3c3 100644 --- a/dom/sms/src/ipc/PSms.ipdl +++ b/dom/sms/src/ipc/PSms.ipdl @@ -53,6 +53,10 @@ struct MarkMessageReadRequest bool value; }; +struct GetThreadListRequest +{ +}; + union IPCSmsRequest { SendMessageRequest; @@ -61,6 +65,7 @@ union IPCSmsRequest CreateMessageListRequest; GetNextMessageInListRequest; MarkMessageReadRequest; + GetThreadListRequest; }; sync protocol PSms { diff --git a/dom/sms/src/ipc/PSmsRequest.ipdl b/dom/sms/src/ipc/PSmsRequest.ipdl index ef4b9b40d83e..6949eea9b473 100644 --- a/dom/sms/src/ipc/PSmsRequest.ipdl +++ b/dom/sms/src/ipc/PSmsRequest.ipdl @@ -85,6 +85,24 @@ struct ReplyNoMessageInList { }; +struct ThreadListItem +{ + nsString senderOrReceiver; + uint64_t timestamp; + nsString body; + uint64_t unreadCount; +}; + +struct ReplyThreadList +{ + ThreadListItem[] items; +}; + +struct ReplyThreadListFail +{ + int32_t error; +}; + union MessageReply { ReplyMessageSend; @@ -99,6 +117,8 @@ union MessageReply ReplyGetNextMessage; ReplyMarkeMessageRead; ReplyMarkeMessageReadFail; + ReplyThreadList; + ReplyThreadListFail; }; } // namespace sms diff --git a/dom/sms/src/ipc/SmsChild.cpp b/dom/sms/src/ipc/SmsChild.cpp index 1314267001c0..ada82e852e86 100644 --- a/dom/sms/src/ipc/SmsChild.cpp +++ b/dom/sms/src/ipc/SmsChild.cpp @@ -161,6 +161,14 @@ SmsRequestChild::Recv__delete__(const MessageReply& aReply) case MessageReply::TReplyMarkeMessageReadFail: mReplyRequest->NotifyMarkMessageReadFailed(aReply.get_ReplyMarkeMessageReadFail().error()); break; + case MessageReply::TReplyThreadList: { + SmsRequestForwarder* forwarder = static_cast(mReplyRequest.get()); + SmsRequest* request = static_cast(forwarder->GetRealRequest()); + request->NotifyThreadList(aReply.get_ReplyThreadList().items()); + } break; + case MessageReply::TReplyThreadListFail: + mReplyRequest->NotifyThreadListFailed(aReply.get_ReplyThreadListFail().error()); + break; default: MOZ_NOT_REACHED("Received invalid response parameters!"); return false; diff --git a/dom/sms/src/ipc/SmsIPCService.cpp b/dom/sms/src/ipc/SmsIPCService.cpp index a700669acc42..b1b2cde7691a 100644 --- a/dom/sms/src/ipc/SmsIPCService.cpp +++ b/dom/sms/src/ipc/SmsIPCService.cpp @@ -179,6 +179,13 @@ SmsIPCService::MarkMessageRead(int32_t aMessageId, return NS_OK; } +NS_IMETHODIMP +SmsIPCService::GetThreadList(nsISmsRequest* aRequest) +{ + SendRequest(GetThreadListRequest(), aRequest); + return NS_OK; +} + } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/ipc/SmsParent.cpp b/dom/sms/src/ipc/SmsParent.cpp index aabf3ebdd4e3..caf1d17e8361 100644 --- a/dom/sms/src/ipc/SmsParent.cpp +++ b/dom/sms/src/ipc/SmsParent.cpp @@ -203,6 +203,8 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor, return actor->DoRequest(aRequest.get_GetNextMessageInListRequest()); case IPCSmsRequest::TMarkMessageReadRequest: return actor->DoRequest(aRequest.get_MarkMessageReadRequest()); + case IPCSmsRequest::TGetThreadListRequest: + return actor->DoRequest(aRequest.get_GetThreadListRequest()); default: MOZ_NOT_REACHED("Unknown type!"); return false; @@ -347,6 +349,21 @@ SmsRequestParent::DoRequest(const MarkMessageReadRequest& aRequest) return true; } +bool +SmsRequestParent::DoRequest(const GetThreadListRequest& aRequest) +{ + nsCOMPtr smsDBService = + do_GetService(SMS_DATABASE_SERVICE_CONTRACTID); + + NS_ENSURE_TRUE(smsDBService, true); + mSmsRequest = SmsRequest::Create(this); + nsCOMPtr forwarder = new SmsRequestForwarder(mSmsRequest); + nsresult rv = smsDBService->GetThreadList(forwarder); + NS_ENSURE_SUCCESS(rv, false); + + return true; +} + } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/ipc/SmsParent.h b/dom/sms/src/ipc/SmsParent.h index d791c55560ee..82ebae78856b 100644 --- a/dom/sms/src/ipc/SmsParent.h +++ b/dom/sms/src/ipc/SmsParent.h @@ -103,6 +103,9 @@ protected: bool DoRequest(const MarkMessageReadRequest& aRequest); + + bool + DoRequest(const GetThreadListRequest& aRequest); }; } // namespace sms diff --git a/dom/sms/src/ril/SmsDatabaseService.js b/dom/sms/src/ril/SmsDatabaseService.js index 0511fd34d869..c61fb1ac798e 100644 --- a/dom/sms/src/ril/SmsDatabaseService.js +++ b/dom/sms/src/ril/SmsDatabaseService.js @@ -14,8 +14,9 @@ const RIL_SMSDATABASESERVICE_CID = Components.ID("{a1fa610c-eb6c-4ac2-878f-b005d const DEBUG = false; const DB_NAME = "sms"; -const DB_VERSION = 3; +const DB_VERSION = 4; const STORE_NAME = "sms"; +const MOST_RECENT_STORE_NAME = "most-recent"; const DELIVERY_SENT = "sent"; const DELIVERY_RECEIVED = "received"; @@ -52,6 +53,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager", const GLOBAL_SCOPE = this; +function numberFromMessage(message) { + return message.delivery == DELIVERY_SENT ? message.receiver : message.sender; +} + /** * SmsDatabaseService */ @@ -176,6 +181,10 @@ SmsDatabaseService.prototype = { objectStore = event.target.transaction.objectStore(STORE_NAME); self.upgradeSchema2(objectStore); break; + case 3: + if (DEBUG) debug("Upgrade to version 4. Add quick threads view.") + self.upgradeSchema3(event.target.transaction); + break; default: event.target.transaction.abort(); callback("Old database version: " + event.oldVersion, null); @@ -183,7 +192,7 @@ SmsDatabaseService.prototype = { } currentVersion++; } - }; + } request.onerror = function (event) { //TODO look at event.target.Code and change error constant accordingly callback("Error opening database!", null); @@ -201,15 +210,22 @@ SmsDatabaseService.prototype = { * @param callback * Function to call when the transaction is available. It will * be invoked with the transaction and the 'sms' object store. + * @param objectStores + * Function to call when the transaction is available. It will + * be invoked with the transaction and the 'sms' object store. */ - newTxn: function newTxn(txn_type, callback) { + newTxn: function newTxn(txn_type, callback, objectStores) { + if (!objectStores) { + objectStores = [STORE_NAME]; + } + if (DEBUG) debug("Opening transaction for objectStores: " + objectStores); this.ensureDB(function (error, db) { if (error) { if (DEBUG) debug("Could not open database: " + error); callback(error); return; } - let txn = db.transaction([STORE_NAME], txn_type); + let txn = db.transaction(objectStores, txn_type); if (DEBUG) debug("Started transaction " + txn + " of type " + txn_type); if (DEBUG) { txn.oncomplete = function oncomplete(event) { @@ -221,9 +237,18 @@ SmsDatabaseService.prototype = { debug("Error occurred during transaction: " + event.target.errorCode); }; } - if (DEBUG) debug("Retrieving object store", STORE_NAME); - let store = txn.objectStore(STORE_NAME); - callback(null, txn, store); + let stores; + if (objectStores.length == 1) { + if (DEBUG) debug("Retrieving object store " + objectStores[0]); + stores = txn.objectStore(objectStores[0]); + } else { + stores = []; + for each (let storeName in objectStores) { + if (DEBUG) debug("Retrieving object store " + storeName); + stores.push(txn.objectStore(storeName)); + } + } + callback(null, txn, stores); }); }, @@ -234,8 +259,8 @@ SmsDatabaseService.prototype = { * TODO full text search on body??? */ createSchema: function createSchema(db) { + // This objectStore holds the main SMS data. let objectStore = db.createObjectStore(STORE_NAME, { keyPath: "id" }); - objectStore.createIndex("id", "id", { unique: true }); objectStore.createIndex("delivery", "delivery", { unique: false }); objectStore.createIndex("sender", "sender", { unique: false }); objectStore.createIndex("receiver", "receiver", { unique: false }); @@ -247,7 +272,6 @@ SmsDatabaseService.prototype = { * Upgrade to the corresponding database schema version. */ upgradeSchema: function upgradeSchema(objectStore) { - // For now, the only possible upgrade is to version 2. objectStore.createIndex("read", "read", { unique: false }); }, @@ -266,6 +290,29 @@ SmsDatabaseService.prototype = { } }, + upgradeSchema3: function upgradeSchema2(transaction) { + // Delete redundant "id" index. + let objectStore = transaction.objectStore(STORE_NAME); + if (objectStore.indexNames.contains("id")) { + objectStore.deleteIndex("id"); + } + + /** + * This objectStore can be used to quickly construct a thread view of the + * SMS database. Each entry looks like this: + * + * { senderOrReceiver: (primary key), + * id: , + * timestamp: , + * body: , + * unreadCount: } + * + */ + objectStore = db.createObjectStore(MOST_RECENT_STORE_NAME, + { keyPath: "senderOrReceiver" }); + objectStore.createIndex("timestamp", "timestamp"); + }, + /** * Helper function to make the intersection of the partial result arrays * obtained within createMessageList. @@ -355,12 +402,43 @@ SmsDatabaseService.prototype = { this.lastKey += 1; message.id = this.lastKey; if (DEBUG) debug("Going to store " + JSON.stringify(message)); - this.newTxn(READ_WRITE, function(error, txn, store) { + this.newTxn(READ_WRITE, function(error, txn, stores) { if (error) { return; } - let request = store.put(message); - }); + // First add to main objectStore. + stores[0].put(message); + + let number = numberFromMessage(message); + + // Next update the other objectStore. + stores[1].get(number).onsuccess = function(event) { + let mostRecentEntry = event.target.result; + if (mostRecentEntry) { + let needsUpdate = false; + + if (mostRecentEntry.timestamp <= message.timestamp) { + mostRecentEntry.timestamp = message.timestamp; + mostRecentEntry.body = message.body; + needsUpdate = true; + } + + if (!message.read) { + mostRecentEntry.unreadCount++; + needsUpdate = true; + } + + if (needsUpdate) { + event.target.source.put(mostRecentEntry); + } + } else { + event.target.source.add({ senderOrReceiver: number, + timestamp: message.timestamp, + body: message.body, + unreadCount: message.read ? 0 : 1 }); + } + } + }, [STORE_NAME, MOST_RECENT_STORE_NAME]); // We return the key that we expect to store in the db return message.id; }, @@ -500,33 +578,103 @@ SmsDatabaseService.prototype = { deleteMessage: function deleteMessage(messageId, aRequest) { let deleted = false; let self = this; - this.newTxn(READ_WRITE, function (error, txn, store) { + this.newTxn(READ_WRITE, function (error, txn, stores) { if (error) { aRequest.notifyDeleteMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR); return; } - let request = store.count(messageId); - - request.onsuccess = function onsuccess(event) { - let count = event.target.result; - if (DEBUG) debug("Count for messageId " + messageId + ": " + count); - deleted = (count == 1); - if (deleted) { - store.delete(messageId); - } + txn.onerror = function onerror(event) { + if (DEBUG) debug("Caught error on transaction", event.target.errorCode); + //TODO look at event.target.errorCode, pick appropriate error constant + aRequest.notifyDeleteMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR); }; + const smsStore = stores[0]; + const mruStore = stores[1]; + + let deleted = false; + txn.oncomplete = function oncomplete(event) { if (DEBUG) debug("Transaction " + txn + " completed."); aRequest.notifyMessageDeleted(deleted); }; - txn.onerror = function onerror(event) { - if (DEBUG) debug("Caught error on transaction", event.target.errorCode); - //TODO look at event.target.errorCode, pick appropriate error constant - aRequest.notifyDeleteMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR); + smsStore.get(messageId).onsuccess = function(event) { + let message = event.target.result; + if (message) { + if (DEBUG) debug("Deleting message id " + messageId); + + // First actually delete the message. + event.target.source.delete(messageId).onsuccess = function(event) { + deleted = true; + + // Then update unread count and most recent message. + let number = numberFromMessage(message); + + mruStore.get(number).onsuccess = function(event) { + // This must exist. + let mostRecentEntry = event.target.result; + + if (!message.read) { + mostRecentEntry.unreadCount--; + } + + if (mostRecentEntry.id == messageId) { + // This sucks, we have to find a new most-recent message. + message = null; + + // Check most recent sender. + smsStore.index("sender").openCursor(number, "prev").onsuccess = function(event) { + let cursor = event.target.result; + if (cursor) { + message = cursor.value; + } + }; + + // Check most recent receiver. + smsStore.index("receiver").openCursor(number, "prev").onsuccess = function(event) { + let cursor = event.target.result; + if (cursor) { + if (!message || cursor.value.timeStamp > message.timestamp) { + message = cursor.value; + } + } + + // If we found a new message then we need to update the data + // in the most-recent store. Otherwise we can delete it. + if (message) { + mostRecentEntry.id = message.id; + mostRecentEntry.timestamp = message.timestamp; + mostRecentEntry.body = message.body; + if (DEBUG) { + debug("Updating mru entry: " + + JSON.stringify(mostRecentEntry)); + } + mruStore.put(mostRecentEntry); + } + else { + if (DEBUG) { + debug("Deleting mru entry for number '" + number + "'"); + } + mruStore.delete(number); + } + }; + } else if (!message.read) { + // Shortcut, just update the unread count. + if (DEBUG) { + debug("Updating unread count for number '" + number + "': " + + (mostRecentEntry.unreadCount + 1) + " -> " + + mostRecentEntry.unreadCount); + } + mruStore.put(mostRecentEntry); + } + }; + }; + } else if (DEBUG) { + debug("Message id " + messageId + " does not exist"); + } }; - }); + }, [STORE_NAME, MOST_RECENT_STORE_NAME]); }, createMessageList: function createMessageList(filter, reverse, aRequest) { @@ -557,7 +705,7 @@ SmsDatabaseService.prototype = { if (DEBUG) { debug("These messages match the " + filter + " filter: " + filteredKeys[filter]); - } + } return; } // The cursor primaryKey is stored in its corresponding partial array @@ -727,18 +875,20 @@ SmsDatabaseService.prototype = { markMessageRead: function markMessageRead(messageId, value, aRequest) { if (DEBUG) debug("Setting message " + messageId + " read to " + value); - this.newTxn(READ_WRITE, function (error, txn, store) { + this.newTxn(READ_WRITE, function (error, txn, stores) { if (error) { if (DEBUG) debug(error); aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR); return; } - let getRequest = store.get(messageId); - - getRequest.onsuccess = function onsuccess(event) { + txn.onerror = function onerror(event) { + if (DEBUG) debug("Caught error on transaction ", event.target.errorCode); + aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR); + }; + stores[0].get(messageId).onsuccess = function onsuccess(event) { let message = event.target.result; - if (DEBUG) debug("Message ID " + messageId + " not found"); if (!message) { + if (DEBUG) debug("Message ID " + messageId + " not found"); aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR); return; } @@ -759,26 +909,50 @@ SmsDatabaseService.prototype = { } message.read = value ? FILTER_READ_READ : FILTER_READ_UNREAD; if (DEBUG) debug("Message.read set to: " + value); - let putRequest = store.put(message); - putRequest.onsuccess = function onsuccess(event) { + event.target.source.put(message).onsuccess = function onsuccess(event) { if (DEBUG) { debug("Update successfully completed. Message: " + JSON.stringify(event.target.result)); } - let checkRequest = store.get(message.id); - checkRequest.onsuccess = function onsuccess(event) { - aRequest.notifyMessageMarkedRead(event.target.result.read); - }; - } - }; + // Now update the unread count. + let number = numberFromMessage(message); + + stores[1].get(number).onsuccess = function(event) { + let mostRecentEntry = event.target.result; + mostRecentEntry.unreadCount += value ? -1 : 1; + if (DEBUG) { + debug("Updating unreadCount for '" + number + "': " + + (value ? + mostRecentEntry.unreadCount + 1 : + mostRecentEntry.unreadCount - 1) + + " -> " + mostRecentEntry.unreadCount); + } + event.target.source.put(mostRecentEntry).onsuccess = function(event) { + aRequest.notifyMessageMarkedRead(message.read); + }; + }; + }; + }; + }, [STORE_NAME, MOST_RECENT_STORE_NAME]); + }, + getThreadList: function getThreadList(aRequest) { + if (DEBUG) debug("Getting thread list"); + this.newTxn(READ_ONLY, function (error, txn, store) { + if (error) { + if (DEBUG) debug(error); + aRequest.notifyThreadListFailed(Ci.nsISmsRequest.INTERNAL_ERROR); + return; + } txn.onerror = function onerror(event) { if (DEBUG) debug("Caught error on transaction ", event.target.errorCode); - aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR); + aRequest.notifyThreadListFailed(Ci.nsISmsRequest.INTERNAL_ERROR); }; - }); + store.index("timestamp").mozGetAll().onsuccess = function(event) { + aRequest.notifyThreadList(event.target.result); + }; + }, [MOST_RECENT_STORE_NAME]); } - }; XPCOMUtils.defineLazyGetter(SmsDatabaseService.prototype, "mRIL", function () { diff --git a/js/xpconnect/src/dictionary_helper_gen.conf b/js/xpconnect/src/dictionary_helper_gen.conf index ebb095ecd113..82103fd64697 100644 --- a/js/xpconnect/src/dictionary_helper_gen.conf +++ b/js/xpconnect/src/dictionary_helper_gen.conf @@ -21,7 +21,8 @@ dictionaries = [ [ 'CameraSelector', 'nsIDOMCameraManager.idl' ], [ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ], [ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ], - [ 'ArchiveReaderOptions', 'nsIDOMArchiveReader.idl' ] + [ 'ArchiveReaderOptions', 'nsIDOMArchiveReader.idl' ], + [ 'SmsThreadListItem', 'nsISmsRequest.idl' ] ] # include file names From 44257757b56c1559a8a296e93882ba7622763bb2 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Tue, 13 Nov 2012 16:03:49 -0500 Subject: [PATCH 02/76] Bug 811120 - negative download times in stub installer pings. r=rstrong --- browser/installer/windows/nsis/defines.nsi.in | 2 +- browser/installer/windows/nsis/stub.nsi | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/browser/installer/windows/nsis/defines.nsi.in b/browser/installer/windows/nsis/defines.nsi.in index 0209bf45de76..01cc03baeb19 100644 --- a/browser/installer/windows/nsis/defines.nsi.in +++ b/browser/installer/windows/nsis/defines.nsi.in @@ -35,7 +35,7 @@ !define BETA_UPDATE_CHANNEL !endif -!define BaseURLStubPing "http://download-stats.mozilla.org/stub/v1/" +!define BaseURLStubPing "http://download-stats.mozilla.org/stub/v2/" # NO_INSTDIR_FROM_REG is defined for pre-releases which have a PreReleaseSuffix # (e.g. Alpha X, Beta X, etc.) to prevent finding a non-default installation diff --git a/browser/installer/windows/nsis/stub.nsi b/browser/installer/windows/nsis/stub.nsi index 71cf1c812bd4..f77023427e1e 100644 --- a/browser/installer/windows/nsis/stub.nsi +++ b/browser/installer/windows/nsis/stub.nsi @@ -68,6 +68,7 @@ Var TmpVal Var InstallCounterStep Var ExitCode +Var DownloadStartTime Var SecondsToDownload Var ExistingProfile Var ExistingInstall @@ -892,7 +893,7 @@ Function createInstall System::Int64Op $1 * 0x100000000 Pop $1 System::Int64Op $1 + $0 - Pop $SecondsToDownload + Pop $DownloadStartTime ${NSD_CreateTimer} StartDownload ${DownloadIntervalMS} @@ -910,10 +911,8 @@ Function leaveInstall # Need a ping? FunctionEnd -; This function is not idempotent. It calculates the amount of time between now -; and $SecondsToDownload and stores the results back into $SecondsToDownload. -; For that reason it should only be called once for the purpose of determining -; the number of elapsed seconds to download. +; GetSecondsToDownload calculates the amount of time between $DownloadStartTime +; and now, and stores the results into $SecondsToDownload. Function GetSecondsToDownload GetTempFileName $2 GetFileTime $2 $1 $0 @@ -922,9 +921,9 @@ Function GetSecondsToDownload Pop $1 System::Int64Op $1 + $0 Pop $0 - System::Int64Op $0 - $SecondsToDownload - Pop $SecondsToDownload - System::Int64Op $SecondsToDownload / 10000000 + System::Int64Op $0 - $DownloadStartTime + Pop $4 + System::Int64Op $4 / 10000000 Pop $SecondsToDownload FunctionEnd From 478ddb2b2d83438be897fdd7c2606a04a0fff30a Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 13 Nov 2012 15:51:08 -0500 Subject: [PATCH 03/76] Bug 810959 - Reset text and selection before focus notification; r=cpeterson --- widget/android/nsWindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index af00d466df9a..9c64b17fdd28 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2163,14 +2163,14 @@ nsWindow::OnIMEFocusChange(bool aFocus) { ALOGIME("IME: OnIMEFocusChange: f=%d", aFocus); - AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_FOCUSCHANGE, - int(aFocus)); - if (aFocus) { OnIMETextChange(0, INT32_MAX, INT32_MAX); OnIMESelectionChange(); } + AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_FOCUSCHANGE, + int(aFocus)); + return NS_OK; } From 0eaf14c15c1743abc3bad56b3dd371923869bf95 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 13 Nov 2012 15:54:14 -0500 Subject: [PATCH 04/76] Bug 761287 - Follow-up to fix TableTicker.cpp bustage; r=ehsan --- tools/profiler/TableTicker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/profiler/TableTicker.cpp b/tools/profiler/TableTicker.cpp index 2ad3448e20ba..79adfc0ffd42 100644 --- a/tools/profiler/TableTicker.cpp +++ b/tools/profiler/TableTicker.cpp @@ -834,7 +834,7 @@ void TableTicker::doBacktrace(ThreadProfile &aProfile, TickSample* aSample) // handle it correctly. unw_tdep_context_t *unw_ctx = reinterpret_cast (&uc); mcontext_t& mcontext = reinterpret_cast (aSample->context)->uc_mcontext; -#define REPLACE_REG(num) unw_ctx->regs[num] = mcontext.gregs[R##num] +#define REPLACE_REG(num) unw_ctx->regs[num] = (&mcontext.arm_r0)[num] REPLACE_REG(0); REPLACE_REG(1); REPLACE_REG(2); From 60d882dbc279cd4e2b240d1ed3e9993b1665fb28 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 13 Nov 2012 13:28:22 -0800 Subject: [PATCH 05/76] No bug: Correct comment on type of argument to DebuggerTransport constructor. DONTBUILD r=dcamp on IRC --- toolkit/devtools/debugger/dbg-transport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/devtools/debugger/dbg-transport.js b/toolkit/devtools/debugger/dbg-transport.js index 713379a8b373..9dcc20030620 100644 --- a/toolkit/devtools/debugger/dbg-transport.js +++ b/toolkit/devtools/debugger/dbg-transport.js @@ -14,7 +14,7 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm"); * * @param aInput nsIInputStream * The input stream. - * @param aOutput nsIOutputStream + * @param aOutput nsIAsyncOutputStream * The output stream. * * Given a DebuggerTransport instance dt: From ee58d7edd67fed10da09072243aa753767b51768 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Tue, 13 Nov 2012 16:55:02 -0500 Subject: [PATCH 06/76] Bug 801227: Patch v2 (unbitrotted) r=anant a=abillings --- dom/media/MediaManager.cpp | 58 ++++++++++++++++---------------------- dom/media/MediaManager.h | 7 +++-- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index fcd8cf47376c..0a07a084e571 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -229,7 +229,6 @@ public: GetUserMediaStreamRunnable( already_AddRefed aSuccess, already_AddRefed aError, - StreamListeners* aListeners, uint64_t aWindowID, MediaEngineSource* aAudioSource, MediaEngineSource* aVideoSource) @@ -237,7 +236,6 @@ public: , mError(aError) , mAudioSource(aAudioSource) , mVideoSource(aVideoSource) - , mListeners(aListeners) , mWindowID(aWindowID) {} ~GetUserMediaStreamRunnable() {} @@ -247,29 +245,29 @@ public: { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + // We're on main-thread, and the windowlist can only + // be invalidated from the main-thread (see OnNavigation) + StreamListeners* listeners = MediaManager::Get()->GetWindowListeners(mWindowID); + if (!listeners) { + // This window is no longer live. + return NS_OK; + } + // Create a media stream. nsRefPtr stream; uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0); hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0); stream = nsDOMLocalMediaStream::CreateSourceStream(hints); + if (!stream) { + nsCOMPtr error(mError); + LOG(("Returning error for getUserMedia() - no stream")); + error->OnError(NS_LITERAL_STRING("NO_STREAM")); + return NS_OK; + } nsPIDOMWindow *window = static_cast (nsGlobalWindow::GetInnerWindowWithId(mWindowID)); - { - if (!stream) { - if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) { - return NS_OK; - } - // This is safe since we're on main-thread, and the windowlist can only - // be invalidated from the main-thread (see OnNavigation) - nsCOMPtr error(mError); - LOG(("Returning error for getUserMedia() - no stream")); - error->OnError(NS_LITERAL_STRING("NO_STREAM")); - return NS_OK; - } - } - if (window && window->GetExtantDoc()) { stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal()); } @@ -287,7 +285,7 @@ public: stream->GetStream()->AddListener(listener); // No need for locking because we always do this in the main thread. - mListeners->AppendElement(listener); + listeners->AppendElement(listener); // Dispatch to the media thread to ask it to start the sources, // because that can take a while @@ -316,7 +314,6 @@ private: already_AddRefed mError; nsRefPtr mAudioSource; nsRefPtr mVideoSource; - StreamListeners* mListeners; uint64_t mWindowID; }; @@ -339,14 +336,12 @@ public: GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture, already_AddRefed aSuccess, already_AddRefed aError, - StreamListeners* aListeners, uint64_t aWindowID, - MediaDevice* aAudioDevice, MediaDevice* aVideoDevice) + uint64_t aWindowID, MediaDevice* aAudioDevice, MediaDevice* aVideoDevice) : mAudio(aAudio) , mVideo(aVideo) , mPicture(aPicture) , mSuccess(aSuccess) , mError(aError) - , mListeners(aListeners) , mWindowID(aWindowID) , mDeviceChosen(true) , mBackendChosen(false) @@ -362,13 +357,12 @@ public: GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture, already_AddRefed aSuccess, already_AddRefed aError, - StreamListeners* aListeners, uint64_t aWindowID) + uint64_t aWindowID) : mAudio(aAudio) , mVideo(aVideo) , mPicture(aPicture) , mSuccess(aSuccess) , mError(aError) - , mListeners(aListeners) , mWindowID(aWindowID) , mDeviceChosen(false) , mBackendChosen(false) {} @@ -380,13 +374,12 @@ public: GetUserMediaRunnable(bool aAudio, bool aVideo, already_AddRefed aSuccess, already_AddRefed aError, - StreamListeners* aListeners, uint64_t aWindowID, MediaEngine* aBackend) + uint64_t aWindowID, MediaEngine* aBackend) : mAudio(aAudio) , mVideo(aVideo) , mPicture(false) , mSuccess(aSuccess) , mError(aError) - , mListeners(aListeners) , mWindowID(aWindowID) , mDeviceChosen(false) , mBackendChosen(true) @@ -571,7 +564,7 @@ public: } NS_DispatchToMainThread(new GetUserMediaStreamRunnable( - mSuccess, mError, mListeners, mWindowID, aAudioSource, aVideoSource + mSuccess, mError, mWindowID, aAudioSource, aVideoSource )); return; } @@ -611,7 +604,6 @@ private: already_AddRefed mSuccess; already_AddRefed mError; - StreamListeners* mListeners; uint64_t mWindowID; nsRefPtr mAudioDevice; nsRefPtr mVideoDevice; @@ -824,22 +816,20 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow, if (fake) { // Fake stream from default backend. gUMRunnable = new GetUserMediaRunnable( - audio, video, onSuccess.forget(), onError.forget(), listeners, - windowID, new MediaEngineDefault() + audio, video, onSuccess.forget(), onError.forget(), windowID, + new MediaEngineDefault() ); } else if (audiodevice || videodevice) { // Stream from provided device. gUMRunnable = new GetUserMediaRunnable( - audio, video, picture, onSuccess.forget(), onError.forget(), listeners, - windowID, + audio, video, picture, onSuccess.forget(), onError.forget(), windowID, static_cast(audiodevice.get()), static_cast(videodevice.get()) ); } else { // Stream from default device from WebRTC backend. gUMRunnable = new GetUserMediaRunnable( - audio, video, picture, onSuccess.forget(), onError.forget(), listeners, - windowID + audio, video, picture, onSuccess.forget(), onError.forget(), windowID ); } @@ -948,7 +938,7 @@ MediaManager::OnNavigation(uint64_t aWindowID) // This is safe since we're on main-thread, and the windowlist can only // be added to from the main-thread (see OnNavigation) - StreamListeners* listeners = GetActiveWindows()->Get(aWindowID); + StreamListeners* listeners = GetWindowListeners(aWindowID); if (!listeners) { return; } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 6a67588d299a..286c1cec436b 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -294,10 +294,13 @@ public: NS_DECL_NSIOBSERVER MediaEngine* GetBackend(); - bool IsWindowStillActive(uint64_t aWindowId) { + StreamListeners *GetWindowListeners(uint64_t aWindowId) { NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread"); - return !!mActiveWindows.Get(aWindowId); + return mActiveWindows.Get(aWindowId); + } + bool IsWindowStillActive(uint64_t aWindowId) { + return !!GetWindowListeners(aWindowId); } nsresult GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow, From 0a85e5f5b07519a5fcef6b8577b368bff92107c9 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 13 Nov 2012 14:18:23 -0800 Subject: [PATCH 07/76] Bug 650567 - Mark 267459-2.html as passing on Android --- layout/reftests/bidi/reftest.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/bidi/reftest.list b/layout/reftests/bidi/reftest.list index 317291e1ffd9..f0347219da9a 100644 --- a/layout/reftests/bidi/reftest.list +++ b/layout/reftests/bidi/reftest.list @@ -64,7 +64,7 @@ fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azur == 263359-3.html 263359-3-ref.html == 263359-4.html 263359-4-ref.html random-if(winWidget) == 267459-1.html 267459-1-ref.html # depends on windows version, see bug 590101 -fails-if(Android) == 267459-2.html 267459-2-ref.html # bug 650567 +== 267459-2.html 267459-2-ref.html == 299065-1.html 299065-1-ref.html random-if(winWidget) == 305643-1.html 305643-1-ref.html # depends on windows version, see bug 590101 == 332655-1.html 332655-1-ref.html From 2e9353fe55249f3f34689b47b8c6d2cef430ecd5 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 13 Nov 2012 14:22:21 -0800 Subject: [PATCH 08/76] Bug 810186 - Don't unnecessarily nest inactive layers. r=roc --- layout/base/FrameLayerBuilder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index eeda339c52ec..7013c2c33024 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2052,6 +2052,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // Assign the item to a layer if (layerState == LAYER_ACTIVE_FORCE || + (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) || (!forceInactive && (layerState == LAYER_ACTIVE_EMPTY || layerState == LAYER_ACTIVE))) { @@ -2696,7 +2697,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder, gfxMatrix transform2d; bool canDraw2D = transform.CanDraw2D(&transform2d); gfxSize scale; - bool isRetained = aLayerBuilder->GetRetainingLayerManager() == aLayer->Manager(); + bool isRetained = aLayer->Manager()->IsWidgetLayerManager(); // Only fiddle with scale factors for the retaining layer manager, since // it only matters for retained layers // XXX Should we do something for 3D transforms? From 54188f6e82ac325d9ba882ab129d7038d14d8eee Mon Sep 17 00:00:00 2001 From: Gregor Wagner Date: Tue, 13 Nov 2012 14:44:18 -0800 Subject: [PATCH 09/76] Backout f2c60518351d Bug 809661 --- dom/sms/Makefile.in | 2 +- dom/sms/interfaces/nsIDOMSmsManager.idl | 4 +- dom/sms/interfaces/nsISmsDatabaseService.idl | 4 +- dom/sms/interfaces/nsISmsRequest.idl | 14 +- dom/sms/src/SmsManager.cpp | 14 - dom/sms/src/SmsRequest.cpp | 151 +---------- dom/sms/src/SmsRequest.h | 23 +- dom/sms/src/android/SmsDatabaseService.cpp | 7 - dom/sms/src/fallback/SmsDatabaseService.cpp | 7 - dom/sms/src/ipc/PSms.ipdl | 5 - dom/sms/src/ipc/PSmsRequest.ipdl | 20 -- dom/sms/src/ipc/SmsChild.cpp | 8 - dom/sms/src/ipc/SmsIPCService.cpp | 7 - dom/sms/src/ipc/SmsParent.cpp | 17 -- dom/sms/src/ipc/SmsParent.h | 3 - dom/sms/src/ril/SmsDatabaseService.js | 260 +++---------------- js/xpconnect/src/dictionary_helper_gen.conf | 3 +- 17 files changed, 57 insertions(+), 492 deletions(-) diff --git a/dom/sms/Makefile.in b/dom/sms/Makefile.in index 14338d78479a..8196e39412c6 100644 --- a/dom/sms/Makefile.in +++ b/dom/sms/Makefile.in @@ -11,7 +11,7 @@ relativesrcdir = @relativesrcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = interfaces src +PARALLEL_DIRS = interfaces src TEST_DIRS += tests ifdef ENABLE_TESTS diff --git a/dom/sms/interfaces/nsIDOMSmsManager.idl b/dom/sms/interfaces/nsIDOMSmsManager.idl index 36eca7954a43..a6ce0e457df5 100644 --- a/dom/sms/interfaces/nsIDOMSmsManager.idl +++ b/dom/sms/interfaces/nsIDOMSmsManager.idl @@ -8,7 +8,7 @@ interface nsIDOMEventListener; interface nsIDOMMozSmsRequest; interface nsIDOMMozSmsFilter; -[scriptable, builtinclass, uuid(caaf5c38-a730-4dbb-a0f0-12384bfac8e3)] +[scriptable, builtinclass, uuid(1bee1224-56a2-4935-af7b-0011746306cb)] interface nsIDOMMozSmsManager : nsIDOMEventTarget { unsigned short getNumberOfMessagesForText(in DOMString text); @@ -29,8 +29,6 @@ interface nsIDOMMozSmsManager : nsIDOMEventTarget nsIDOMMozSmsRequest markMessageRead(in long id, in boolean aValue); - nsIDOMMozSmsRequest getThreadList(); - [implicit_jscontext] attribute jsval onreceived; [implicit_jscontext] attribute jsval onsent; [implicit_jscontext] attribute jsval ondeliverysuccess; diff --git a/dom/sms/interfaces/nsISmsDatabaseService.idl b/dom/sms/interfaces/nsISmsDatabaseService.idl index cff1a6d8550d..157f0462c13a 100644 --- a/dom/sms/interfaces/nsISmsDatabaseService.idl +++ b/dom/sms/interfaces/nsISmsDatabaseService.idl @@ -14,7 +14,7 @@ interface nsIDOMMozSmsFilter; interface nsISmsRequest; -[scriptable, uuid(c2cb2af7-6b96-4915-bcc8-54ad705d6110)] +[scriptable, uuid(6ad55465-6937-4491-93ca-29dad9775d46)] interface nsISmsDatabaseService : nsISupports { // Takes some information required to save the message and returns its id. @@ -30,6 +30,4 @@ interface nsISmsDatabaseService : nsISupports void getNextMessageInList(in long listId, in nsISmsRequest request); void clearMessageList(in long listId); void markMessageRead(in long messageId, in boolean value, in nsISmsRequest request); - - void getThreadList(in nsISmsRequest request); }; diff --git a/dom/sms/interfaces/nsISmsRequest.idl b/dom/sms/interfaces/nsISmsRequest.idl index 993cb43ae2a1..8ce490fcf6a9 100644 --- a/dom/sms/interfaces/nsISmsRequest.idl +++ b/dom/sms/interfaces/nsISmsRequest.idl @@ -6,15 +6,7 @@ interface nsIDOMMozSmsMessage; -dictionary SmsThreadListItem -{ - DOMString senderOrReceiver; - unsigned long long timestamp; - DOMString body; - unsigned long long unreadCount; -}; - -[scriptable, builtinclass, uuid(82a6d16d-cf33-4745-8662-8b5d441f512f)] +[scriptable, builtinclass, uuid(97067327-64b9-4e26-848b-59e443c55db9)] interface nsISmsRequest : nsISupports { /** @@ -45,8 +37,4 @@ interface nsISmsRequest : nsISupports void notifyMessageMarkedRead(in boolean read); void notifyMarkMessageReadFailed(in long error); - - [implicit_jscontext] - void notifyThreadList(in jsval threadList); - void notifyThreadListFailed(in long error); }; diff --git a/dom/sms/src/SmsManager.cpp b/dom/sms/src/SmsManager.cpp index d022cc680fb2..40493d00aebf 100644 --- a/dom/sms/src/SmsManager.cpp +++ b/dom/sms/src/SmsManager.cpp @@ -303,20 +303,6 @@ SmsManager::MarkMessageRead(int32_t aId, bool aValue, return NS_OK; } -NS_IMETHODIMP -SmsManager::GetThreadList(nsIDOMMozSmsRequest** aRequest) -{ - nsCOMPtr req = SmsRequest::Create(this); - nsCOMPtr smsDBService = - do_GetService(SMS_DATABASE_SERVICE_CONTRACTID); - NS_ENSURE_TRUE(smsDBService, NS_ERROR_FAILURE); - nsCOMPtr forwarder = - new SmsRequestForwarder(static_cast(req.get())); - smsDBService->GetThreadList(forwarder); - req.forget(aRequest); - return NS_OK; -} - nsresult SmsManager::DispatchTrustedSmsEventToSelf(const nsAString& aEventName, nsIDOMMozSmsMessage* aMessage) { diff --git a/dom/sms/src/SmsRequest.cpp b/dom/sms/src/SmsRequest.cpp index 6ca0f6de3a70..2630e499c65c 100644 --- a/dom/sms/src/SmsRequest.cpp +++ b/dom/sms/src/SmsRequest.cpp @@ -9,16 +9,11 @@ #include "nsDOMString.h" #include "nsContentUtils.h" #include "nsIDOMSmsMessage.h" -#include "nsIScriptGlobalObject.h" -#include "nsPIDOMWindow.h" #include "SmsCursor.h" #include "SmsMessage.h" #include "SmsManager.h" #include "mozilla/dom/DOMError.h" #include "SmsParent.h" -#include "jsapi.h" -#include "DictionaryHelpers.h" -#include "xpcpublic.h" #define SUCCESS_EVENT_NAME NS_LITERAL_STRING("success") #define ERROR_EVENT_NAME NS_LITERAL_STRING("error") @@ -150,7 +145,12 @@ SmsRequest::SetSuccess(nsIDOMMozSmsMessage* aMessage) void SmsRequest::SetSuccess(bool aResult) { - SetSuccess(aResult ? JSVAL_TRUE : JSVAL_FALSE); + NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!"); + NS_PRECONDITION(!mError, "mError shouldn't have been set!"); + NS_PRECONDITION(mResult == JSVAL_NULL, "mResult shouldn't have been set!"); + + mResult.setBoolean(aResult); + mDone = true; } void @@ -168,17 +168,6 @@ SmsRequest::SetSuccess(nsIDOMMozSmsCursor* aCursor) } } -void -SmsRequest::SetSuccess(const jsval& aResult) -{ - NS_PRECONDITION(!mDone, "mDone shouldn't have been set to true already!"); - NS_PRECONDITION(!mError, "mError shouldn't have been set!"); - NS_PRECONDITION(JSVAL_IS_VOID(mResult), "mResult shouldn't have been set!"); - - mResult = aResult; - mDone = true; -} - bool SmsRequest::SetSuccessInternal(nsISupports* aObject) { @@ -456,134 +445,6 @@ SmsRequest::NotifyMarkMessageReadFailed(int32_t aError) return NotifyError(aError); } -NS_IMETHODIMP -SmsRequest::NotifyThreadList(const jsval& aThreadList, JSContext* aCx) -{ - MOZ_ASSERT(aThreadList.isObject()); - - if (mParent) { - JSObject* array = const_cast(&aThreadList.toObject()); - - uint32_t length; - bool ok = JS_GetArrayLength(aCx, array, &length); - NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - - ReplyThreadList reply; - InfallibleTArray& ipcItems = reply.items(); - - if (length) { - ipcItems.SetCapacity(length); - - for (uint32_t i = 0; i < length; i++) { - jsval arrayEntry; - ok = JS_GetElement(aCx, array, i, &arrayEntry); - NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - - MOZ_ASSERT(arrayEntry.isObject()); - - SmsThreadListItem item; - nsresult rv = item.Init(aCx, &arrayEntry); - NS_ENSURE_SUCCESS(rv, rv); - - ThreadListItem* ipcItem = ipcItems.AppendElement(); - ipcItem->senderOrReceiver() = item.senderOrReceiver; - ipcItem->timestamp() = item.timestamp; - ipcItem->body() = item.body; - ipcItem->unreadCount() = item.unreadCount; - } - } - - return SendMessageReply(reply); - } - - return NotifySuccess(aThreadList); -} - -NS_IMETHODIMP -SmsRequest::NotifyThreadListFailed(int32_t aError) -{ - if (mParent) { - return SendMessageReply(MessageReply(ReplyThreadListFail(aError))); - } - return NotifyError(aError); -} - -void -SmsRequest::NotifyThreadList(const InfallibleTArray& aItems) -{ - MOZ_ASSERT(!mParent); - MOZ_ASSERT(GetOwner()); - - nsresult rv; - nsIScriptContext* sc = GetContextForEventHandlers(&rv); - NS_ENSURE_SUCCESS_VOID(rv); - NS_ENSURE_TRUE_VOID(sc); - - JSContext* cx = sc->GetNativeContext(); - MOZ_ASSERT(cx); - - nsCOMPtr sgo = do_QueryInterface(GetOwner()); - - JSObject* ownerObj = sgo->GetGlobalJSObject(); - NS_ENSURE_TRUE_VOID(ownerObj); - - nsCxPusher pusher; - NS_ENSURE_TRUE_VOID(pusher.Push(cx, false)); - - JSAutoRequest ar(cx); - JSAutoCompartment ac(cx, ownerObj); - - JSObject* array = JS_NewArrayObject(cx, aItems.Length(), nullptr); - NS_ENSURE_TRUE_VOID(array); - - bool ok; - - for (uint32_t i = 0; i < aItems.Length(); i++) { - const ThreadListItem& source = aItems[i]; - - nsString temp = source.senderOrReceiver(); - - jsval senderOrReceiver; - ok = xpc::StringToJsval(cx, temp, &senderOrReceiver); - NS_ENSURE_TRUE_VOID(ok); - - JSObject* timestampObj = JS_NewDateObjectMsec(cx, source.timestamp()); - NS_ENSURE_TRUE_VOID(timestampObj); - - jsval timestamp = OBJECT_TO_JSVAL(timestampObj); - - temp = source.body(); - - jsval body; - ok = xpc::StringToJsval(cx, temp, &body); - NS_ENSURE_TRUE_VOID(ok); - - jsval unreadCount = JS_NumberValue(double(source.unreadCount())); - - JSObject* elementObj = JS_NewObject(cx, nullptr, nullptr, nullptr); - NS_ENSURE_TRUE_VOID(elementObj); - - ok = JS_SetProperty(cx, elementObj, "senderOrReceiver", &senderOrReceiver); - NS_ENSURE_TRUE_VOID(ok); - - ok = JS_SetProperty(cx, elementObj, "timestamp", ×tamp); - NS_ENSURE_TRUE_VOID(ok); - - ok = JS_SetProperty(cx, elementObj, "body", &body); - NS_ENSURE_TRUE_VOID(ok); - - ok = JS_SetProperty(cx, elementObj, "unreadCount", &unreadCount); - NS_ENSURE_TRUE_VOID(ok); - - jsval element = OBJECT_TO_JSVAL(elementObj); - - ok = JS_SetElement(cx, array, i, &element); - NS_ENSURE_TRUE_VOID(ok); - } - - NotifyThreadList(OBJECT_TO_JSVAL(array), cx); -} - } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/SmsRequest.h b/dom/sms/src/SmsRequest.h index 7abe4b1b9809..e27cf80b005a 100644 --- a/dom/sms/src/SmsRequest.h +++ b/dom/sms/src/SmsRequest.h @@ -17,33 +17,24 @@ namespace mozilla { namespace dom { namespace sms { -class SmsRequestChild; class SmsRequestParent; class MessageReply; -class ThreadListItem; // We need this forwarder to avoid a QI to nsIClassInfo. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=775997#c51 class SmsRequestForwarder : public nsISmsRequest { - friend class SmsRequestChild; - -public: - NS_DECL_ISUPPORTS NS_FORWARD_NSISMSREQUEST(mRealRequest->) + NS_DECL_ISUPPORTS + SmsRequestForwarder(nsISmsRequest* aRealRequest) { mRealRequest = aRealRequest; } - -private: virtual ~SmsRequestForwarder() {} - nsISmsRequest* GetRealRequest() { - return mRealRequest; - } - +private: nsCOMPtr mRealRequest; }; @@ -75,9 +66,6 @@ public: mParentAlive = false; } - void - NotifyThreadList(const InfallibleTArray& aItems); - private: SmsRequest() MOZ_DELETE; @@ -112,11 +100,6 @@ private: */ void SetSuccess(nsIDOMMozSmsCursor* aCursor); - /** - * Set the object in a success state with the result being the given jsval. - */ - void SetSuccess(const jsval& aVal); - /** * Set the object in an error state with the error type being aError. */ diff --git a/dom/sms/src/android/SmsDatabaseService.cpp b/dom/sms/src/android/SmsDatabaseService.cpp index bcf527f1e868..b68ad3233c77 100644 --- a/dom/sms/src/android/SmsDatabaseService.cpp +++ b/dom/sms/src/android/SmsDatabaseService.cpp @@ -112,13 +112,6 @@ SmsDatabaseService::MarkMessageRead(int32_t aMessageId, bool aValue, return NS_OK; } -NS_IMETHODIMP -SmsDatabaseService::GetThreadList(nsISmsRequest* aRequest) -{ - NS_NOTYETIMPLEMENTED("Implement me!"); - return NS_ERROR_NOT_IMPLEMENTED; -} - } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/fallback/SmsDatabaseService.cpp b/dom/sms/src/fallback/SmsDatabaseService.cpp index 35b0e69095e4..cb66dbf36432 100644 --- a/dom/sms/src/fallback/SmsDatabaseService.cpp +++ b/dom/sms/src/fallback/SmsDatabaseService.cpp @@ -90,13 +90,6 @@ SmsDatabaseService::MarkMessageRead(int32_t aMessageId, return NS_OK; } -NS_IMETHODIMP -SmsDatabaseService::GetThreadList(nsISmsRequest* aRequest) -{ - NS_ERROR("We should not be here!"); - return NS_OK; -} - } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/ipc/PSms.ipdl b/dom/sms/src/ipc/PSms.ipdl index 139d8b75d3c3..9059832425c1 100644 --- a/dom/sms/src/ipc/PSms.ipdl +++ b/dom/sms/src/ipc/PSms.ipdl @@ -53,10 +53,6 @@ struct MarkMessageReadRequest bool value; }; -struct GetThreadListRequest -{ -}; - union IPCSmsRequest { SendMessageRequest; @@ -65,7 +61,6 @@ union IPCSmsRequest CreateMessageListRequest; GetNextMessageInListRequest; MarkMessageReadRequest; - GetThreadListRequest; }; sync protocol PSms { diff --git a/dom/sms/src/ipc/PSmsRequest.ipdl b/dom/sms/src/ipc/PSmsRequest.ipdl index 6949eea9b473..ef4b9b40d83e 100644 --- a/dom/sms/src/ipc/PSmsRequest.ipdl +++ b/dom/sms/src/ipc/PSmsRequest.ipdl @@ -85,24 +85,6 @@ struct ReplyNoMessageInList { }; -struct ThreadListItem -{ - nsString senderOrReceiver; - uint64_t timestamp; - nsString body; - uint64_t unreadCount; -}; - -struct ReplyThreadList -{ - ThreadListItem[] items; -}; - -struct ReplyThreadListFail -{ - int32_t error; -}; - union MessageReply { ReplyMessageSend; @@ -117,8 +99,6 @@ union MessageReply ReplyGetNextMessage; ReplyMarkeMessageRead; ReplyMarkeMessageReadFail; - ReplyThreadList; - ReplyThreadListFail; }; } // namespace sms diff --git a/dom/sms/src/ipc/SmsChild.cpp b/dom/sms/src/ipc/SmsChild.cpp index ada82e852e86..1314267001c0 100644 --- a/dom/sms/src/ipc/SmsChild.cpp +++ b/dom/sms/src/ipc/SmsChild.cpp @@ -161,14 +161,6 @@ SmsRequestChild::Recv__delete__(const MessageReply& aReply) case MessageReply::TReplyMarkeMessageReadFail: mReplyRequest->NotifyMarkMessageReadFailed(aReply.get_ReplyMarkeMessageReadFail().error()); break; - case MessageReply::TReplyThreadList: { - SmsRequestForwarder* forwarder = static_cast(mReplyRequest.get()); - SmsRequest* request = static_cast(forwarder->GetRealRequest()); - request->NotifyThreadList(aReply.get_ReplyThreadList().items()); - } break; - case MessageReply::TReplyThreadListFail: - mReplyRequest->NotifyThreadListFailed(aReply.get_ReplyThreadListFail().error()); - break; default: MOZ_NOT_REACHED("Received invalid response parameters!"); return false; diff --git a/dom/sms/src/ipc/SmsIPCService.cpp b/dom/sms/src/ipc/SmsIPCService.cpp index b1b2cde7691a..a700669acc42 100644 --- a/dom/sms/src/ipc/SmsIPCService.cpp +++ b/dom/sms/src/ipc/SmsIPCService.cpp @@ -179,13 +179,6 @@ SmsIPCService::MarkMessageRead(int32_t aMessageId, return NS_OK; } -NS_IMETHODIMP -SmsIPCService::GetThreadList(nsISmsRequest* aRequest) -{ - SendRequest(GetThreadListRequest(), aRequest); - return NS_OK; -} - } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/ipc/SmsParent.cpp b/dom/sms/src/ipc/SmsParent.cpp index caf1d17e8361..aabf3ebdd4e3 100644 --- a/dom/sms/src/ipc/SmsParent.cpp +++ b/dom/sms/src/ipc/SmsParent.cpp @@ -203,8 +203,6 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor, return actor->DoRequest(aRequest.get_GetNextMessageInListRequest()); case IPCSmsRequest::TMarkMessageReadRequest: return actor->DoRequest(aRequest.get_MarkMessageReadRequest()); - case IPCSmsRequest::TGetThreadListRequest: - return actor->DoRequest(aRequest.get_GetThreadListRequest()); default: MOZ_NOT_REACHED("Unknown type!"); return false; @@ -349,21 +347,6 @@ SmsRequestParent::DoRequest(const MarkMessageReadRequest& aRequest) return true; } -bool -SmsRequestParent::DoRequest(const GetThreadListRequest& aRequest) -{ - nsCOMPtr smsDBService = - do_GetService(SMS_DATABASE_SERVICE_CONTRACTID); - - NS_ENSURE_TRUE(smsDBService, true); - mSmsRequest = SmsRequest::Create(this); - nsCOMPtr forwarder = new SmsRequestForwarder(mSmsRequest); - nsresult rv = smsDBService->GetThreadList(forwarder); - NS_ENSURE_SUCCESS(rv, false); - - return true; -} - } // namespace sms } // namespace dom } // namespace mozilla diff --git a/dom/sms/src/ipc/SmsParent.h b/dom/sms/src/ipc/SmsParent.h index 82ebae78856b..d791c55560ee 100644 --- a/dom/sms/src/ipc/SmsParent.h +++ b/dom/sms/src/ipc/SmsParent.h @@ -103,9 +103,6 @@ protected: bool DoRequest(const MarkMessageReadRequest& aRequest); - - bool - DoRequest(const GetThreadListRequest& aRequest); }; } // namespace sms diff --git a/dom/sms/src/ril/SmsDatabaseService.js b/dom/sms/src/ril/SmsDatabaseService.js index c61fb1ac798e..0511fd34d869 100644 --- a/dom/sms/src/ril/SmsDatabaseService.js +++ b/dom/sms/src/ril/SmsDatabaseService.js @@ -14,9 +14,8 @@ const RIL_SMSDATABASESERVICE_CID = Components.ID("{a1fa610c-eb6c-4ac2-878f-b005d const DEBUG = false; const DB_NAME = "sms"; -const DB_VERSION = 4; +const DB_VERSION = 3; const STORE_NAME = "sms"; -const MOST_RECENT_STORE_NAME = "most-recent"; const DELIVERY_SENT = "sent"; const DELIVERY_RECEIVED = "received"; @@ -53,10 +52,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager", const GLOBAL_SCOPE = this; -function numberFromMessage(message) { - return message.delivery == DELIVERY_SENT ? message.receiver : message.sender; -} - /** * SmsDatabaseService */ @@ -181,10 +176,6 @@ SmsDatabaseService.prototype = { objectStore = event.target.transaction.objectStore(STORE_NAME); self.upgradeSchema2(objectStore); break; - case 3: - if (DEBUG) debug("Upgrade to version 4. Add quick threads view.") - self.upgradeSchema3(event.target.transaction); - break; default: event.target.transaction.abort(); callback("Old database version: " + event.oldVersion, null); @@ -192,7 +183,7 @@ SmsDatabaseService.prototype = { } currentVersion++; } - } + }; request.onerror = function (event) { //TODO look at event.target.Code and change error constant accordingly callback("Error opening database!", null); @@ -210,22 +201,15 @@ SmsDatabaseService.prototype = { * @param callback * Function to call when the transaction is available. It will * be invoked with the transaction and the 'sms' object store. - * @param objectStores - * Function to call when the transaction is available. It will - * be invoked with the transaction and the 'sms' object store. */ - newTxn: function newTxn(txn_type, callback, objectStores) { - if (!objectStores) { - objectStores = [STORE_NAME]; - } - if (DEBUG) debug("Opening transaction for objectStores: " + objectStores); + newTxn: function newTxn(txn_type, callback) { this.ensureDB(function (error, db) { if (error) { if (DEBUG) debug("Could not open database: " + error); callback(error); return; } - let txn = db.transaction(objectStores, txn_type); + let txn = db.transaction([STORE_NAME], txn_type); if (DEBUG) debug("Started transaction " + txn + " of type " + txn_type); if (DEBUG) { txn.oncomplete = function oncomplete(event) { @@ -237,18 +221,9 @@ SmsDatabaseService.prototype = { debug("Error occurred during transaction: " + event.target.errorCode); }; } - let stores; - if (objectStores.length == 1) { - if (DEBUG) debug("Retrieving object store " + objectStores[0]); - stores = txn.objectStore(objectStores[0]); - } else { - stores = []; - for each (let storeName in objectStores) { - if (DEBUG) debug("Retrieving object store " + storeName); - stores.push(txn.objectStore(storeName)); - } - } - callback(null, txn, stores); + if (DEBUG) debug("Retrieving object store", STORE_NAME); + let store = txn.objectStore(STORE_NAME); + callback(null, txn, store); }); }, @@ -259,8 +234,8 @@ SmsDatabaseService.prototype = { * TODO full text search on body??? */ createSchema: function createSchema(db) { - // This objectStore holds the main SMS data. let objectStore = db.createObjectStore(STORE_NAME, { keyPath: "id" }); + objectStore.createIndex("id", "id", { unique: true }); objectStore.createIndex("delivery", "delivery", { unique: false }); objectStore.createIndex("sender", "sender", { unique: false }); objectStore.createIndex("receiver", "receiver", { unique: false }); @@ -272,6 +247,7 @@ SmsDatabaseService.prototype = { * Upgrade to the corresponding database schema version. */ upgradeSchema: function upgradeSchema(objectStore) { + // For now, the only possible upgrade is to version 2. objectStore.createIndex("read", "read", { unique: false }); }, @@ -290,29 +266,6 @@ SmsDatabaseService.prototype = { } }, - upgradeSchema3: function upgradeSchema2(transaction) { - // Delete redundant "id" index. - let objectStore = transaction.objectStore(STORE_NAME); - if (objectStore.indexNames.contains("id")) { - objectStore.deleteIndex("id"); - } - - /** - * This objectStore can be used to quickly construct a thread view of the - * SMS database. Each entry looks like this: - * - * { senderOrReceiver: (primary key), - * id: , - * timestamp: , - * body: , - * unreadCount: } - * - */ - objectStore = db.createObjectStore(MOST_RECENT_STORE_NAME, - { keyPath: "senderOrReceiver" }); - objectStore.createIndex("timestamp", "timestamp"); - }, - /** * Helper function to make the intersection of the partial result arrays * obtained within createMessageList. @@ -402,43 +355,12 @@ SmsDatabaseService.prototype = { this.lastKey += 1; message.id = this.lastKey; if (DEBUG) debug("Going to store " + JSON.stringify(message)); - this.newTxn(READ_WRITE, function(error, txn, stores) { + this.newTxn(READ_WRITE, function(error, txn, store) { if (error) { return; } - // First add to main objectStore. - stores[0].put(message); - - let number = numberFromMessage(message); - - // Next update the other objectStore. - stores[1].get(number).onsuccess = function(event) { - let mostRecentEntry = event.target.result; - if (mostRecentEntry) { - let needsUpdate = false; - - if (mostRecentEntry.timestamp <= message.timestamp) { - mostRecentEntry.timestamp = message.timestamp; - mostRecentEntry.body = message.body; - needsUpdate = true; - } - - if (!message.read) { - mostRecentEntry.unreadCount++; - needsUpdate = true; - } - - if (needsUpdate) { - event.target.source.put(mostRecentEntry); - } - } else { - event.target.source.add({ senderOrReceiver: number, - timestamp: message.timestamp, - body: message.body, - unreadCount: message.read ? 0 : 1 }); - } - } - }, [STORE_NAME, MOST_RECENT_STORE_NAME]); + let request = store.put(message); + }); // We return the key that we expect to store in the db return message.id; }, @@ -578,103 +500,33 @@ SmsDatabaseService.prototype = { deleteMessage: function deleteMessage(messageId, aRequest) { let deleted = false; let self = this; - this.newTxn(READ_WRITE, function (error, txn, stores) { + this.newTxn(READ_WRITE, function (error, txn, store) { if (error) { aRequest.notifyDeleteMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR); return; } - txn.onerror = function onerror(event) { - if (DEBUG) debug("Caught error on transaction", event.target.errorCode); - //TODO look at event.target.errorCode, pick appropriate error constant - aRequest.notifyDeleteMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR); + let request = store.count(messageId); + + request.onsuccess = function onsuccess(event) { + let count = event.target.result; + if (DEBUG) debug("Count for messageId " + messageId + ": " + count); + deleted = (count == 1); + if (deleted) { + store.delete(messageId); + } }; - const smsStore = stores[0]; - const mruStore = stores[1]; - - let deleted = false; - txn.oncomplete = function oncomplete(event) { if (DEBUG) debug("Transaction " + txn + " completed."); aRequest.notifyMessageDeleted(deleted); }; - smsStore.get(messageId).onsuccess = function(event) { - let message = event.target.result; - if (message) { - if (DEBUG) debug("Deleting message id " + messageId); - - // First actually delete the message. - event.target.source.delete(messageId).onsuccess = function(event) { - deleted = true; - - // Then update unread count and most recent message. - let number = numberFromMessage(message); - - mruStore.get(number).onsuccess = function(event) { - // This must exist. - let mostRecentEntry = event.target.result; - - if (!message.read) { - mostRecentEntry.unreadCount--; - } - - if (mostRecentEntry.id == messageId) { - // This sucks, we have to find a new most-recent message. - message = null; - - // Check most recent sender. - smsStore.index("sender").openCursor(number, "prev").onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - message = cursor.value; - } - }; - - // Check most recent receiver. - smsStore.index("receiver").openCursor(number, "prev").onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - if (!message || cursor.value.timeStamp > message.timestamp) { - message = cursor.value; - } - } - - // If we found a new message then we need to update the data - // in the most-recent store. Otherwise we can delete it. - if (message) { - mostRecentEntry.id = message.id; - mostRecentEntry.timestamp = message.timestamp; - mostRecentEntry.body = message.body; - if (DEBUG) { - debug("Updating mru entry: " + - JSON.stringify(mostRecentEntry)); - } - mruStore.put(mostRecentEntry); - } - else { - if (DEBUG) { - debug("Deleting mru entry for number '" + number + "'"); - } - mruStore.delete(number); - } - }; - } else if (!message.read) { - // Shortcut, just update the unread count. - if (DEBUG) { - debug("Updating unread count for number '" + number + "': " + - (mostRecentEntry.unreadCount + 1) + " -> " + - mostRecentEntry.unreadCount); - } - mruStore.put(mostRecentEntry); - } - }; - }; - } else if (DEBUG) { - debug("Message id " + messageId + " does not exist"); - } + txn.onerror = function onerror(event) { + if (DEBUG) debug("Caught error on transaction", event.target.errorCode); + //TODO look at event.target.errorCode, pick appropriate error constant + aRequest.notifyDeleteMessageFailed(Ci.nsISmsRequest.INTERNAL_ERROR); }; - }, [STORE_NAME, MOST_RECENT_STORE_NAME]); + }); }, createMessageList: function createMessageList(filter, reverse, aRequest) { @@ -705,7 +557,7 @@ SmsDatabaseService.prototype = { if (DEBUG) { debug("These messages match the " + filter + " filter: " + filteredKeys[filter]); - } + } return; } // The cursor primaryKey is stored in its corresponding partial array @@ -875,20 +727,18 @@ SmsDatabaseService.prototype = { markMessageRead: function markMessageRead(messageId, value, aRequest) { if (DEBUG) debug("Setting message " + messageId + " read to " + value); - this.newTxn(READ_WRITE, function (error, txn, stores) { + this.newTxn(READ_WRITE, function (error, txn, store) { if (error) { if (DEBUG) debug(error); aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR); return; } - txn.onerror = function onerror(event) { - if (DEBUG) debug("Caught error on transaction ", event.target.errorCode); - aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR); - }; - stores[0].get(messageId).onsuccess = function onsuccess(event) { + let getRequest = store.get(messageId); + + getRequest.onsuccess = function onsuccess(event) { let message = event.target.result; + if (DEBUG) debug("Message ID " + messageId + " not found"); if (!message) { - if (DEBUG) debug("Message ID " + messageId + " not found"); aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.NOT_FOUND_ERROR); return; } @@ -909,50 +759,26 @@ SmsDatabaseService.prototype = { } message.read = value ? FILTER_READ_READ : FILTER_READ_UNREAD; if (DEBUG) debug("Message.read set to: " + value); - event.target.source.put(message).onsuccess = function onsuccess(event) { + let putRequest = store.put(message); + putRequest.onsuccess = function onsuccess(event) { if (DEBUG) { debug("Update successfully completed. Message: " + JSON.stringify(event.target.result)); } - - // Now update the unread count. - let number = numberFromMessage(message); - - stores[1].get(number).onsuccess = function(event) { - let mostRecentEntry = event.target.result; - mostRecentEntry.unreadCount += value ? -1 : 1; - if (DEBUG) { - debug("Updating unreadCount for '" + number + "': " + - (value ? - mostRecentEntry.unreadCount + 1 : - mostRecentEntry.unreadCount - 1) + - " -> " + mostRecentEntry.unreadCount); - } - event.target.source.put(mostRecentEntry).onsuccess = function(event) { - aRequest.notifyMessageMarkedRead(message.read); - }; + let checkRequest = store.get(message.id); + checkRequest.onsuccess = function onsuccess(event) { + aRequest.notifyMessageMarkedRead(event.target.result.read); }; - }; + } }; - }, [STORE_NAME, MOST_RECENT_STORE_NAME]); - }, - getThreadList: function getThreadList(aRequest) { - if (DEBUG) debug("Getting thread list"); - this.newTxn(READ_ONLY, function (error, txn, store) { - if (error) { - if (DEBUG) debug(error); - aRequest.notifyThreadListFailed(Ci.nsISmsRequest.INTERNAL_ERROR); - return; - } + txn.onerror = function onerror(event) { if (DEBUG) debug("Caught error on transaction ", event.target.errorCode); - aRequest.notifyThreadListFailed(Ci.nsISmsRequest.INTERNAL_ERROR); + aRequest.notifyMarkMessageReadFailed(Ci.nsISmsRequest.INTERNAL_ERROR); }; - store.index("timestamp").mozGetAll().onsuccess = function(event) { - aRequest.notifyThreadList(event.target.result); - }; - }, [MOST_RECENT_STORE_NAME]); + }); } + }; XPCOMUtils.defineLazyGetter(SmsDatabaseService.prototype, "mRIL", function () { diff --git a/js/xpconnect/src/dictionary_helper_gen.conf b/js/xpconnect/src/dictionary_helper_gen.conf index 82103fd64697..ebb095ecd113 100644 --- a/js/xpconnect/src/dictionary_helper_gen.conf +++ b/js/xpconnect/src/dictionary_helper_gen.conf @@ -21,8 +21,7 @@ dictionaries = [ [ 'CameraSelector', 'nsIDOMCameraManager.idl' ], [ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ], [ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ], - [ 'ArchiveReaderOptions', 'nsIDOMArchiveReader.idl' ], - [ 'SmsThreadListItem', 'nsISmsRequest.idl' ] + [ 'ArchiveReaderOptions', 'nsIDOMArchiveReader.idl' ] ] # include file names From dc32f73f6d5d5c0024630738c655231bb0abef39 Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Tue, 13 Nov 2012 15:03:06 -0800 Subject: [PATCH 10/76] Bug 809758 - Ensure sGeoInitPending is set to false prior to notifying ServiceReady. r=gwagner. a=blocking-basecamp --- dom/src/geolocation/nsGeolocation.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dom/src/geolocation/nsGeolocation.cpp b/dom/src/geolocation/nsGeolocation.cpp index 59d11e0b1a45..9688d184a3c2 100644 --- a/dom/src/geolocation/nsGeolocation.cpp +++ b/dom/src/geolocation/nsGeolocation.cpp @@ -746,11 +746,10 @@ nsGeolocationService::HandleMozsettingValue(const bool aValue) } if (sGeoInitPending) { + sGeoInitPending = false; for (uint32_t i = 0, length = mGeolocators.Length(); i < length; ++i) { mGeolocators[i]->ServiceReady(); } - - sGeoInitPending = false; } } From cfce24e0609cac88d9de6411a5b212f700d773a7 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 13 Nov 2012 15:09:31 -0800 Subject: [PATCH 11/76] Bug 801918. OpenGL: Avoid doing extra invalidation when unrotating a buffer. r=mwoodrow This approach ends up calling BlitTextureImage three extra times instead of changing BlitTextureImage to support rotated buffers. Supporting rotated buffers in BlitTextureImage is somewhat tricky because of TiledTextureImage, and calling it three more times shouldn't be too bad (it should be better than having to repaint) Unfortunately, the rectangle manipulation code is a bit hairy. --HG-- extra : rebase_source : a1018a22932675b154b76533f403a1328aa29cb5 --- gfx/layers/opengl/ThebesLayerOGL.cpp | 127 ++++++++++++++++++--------- 1 file changed, 86 insertions(+), 41 deletions(-) diff --git a/gfx/layers/opengl/ThebesLayerOGL.cpp b/gfx/layers/opengl/ThebesLayerOGL.cpp index 99ea98f5036d..ed0084d50fa3 100644 --- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -587,63 +587,108 @@ BasicBufferOGL::BeginPaint(ContentType aContentType, // TEXTURE_2D. This isn't the case on some older X1600-era Radeons. if (mOGLLayer->OGLManager()->FBOTextureTarget() == LOCAL_GL_TEXTURE_2D) { nsIntRect overlap; + + // The buffer looks like: + // ______ + // |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner. + // |___|__| + // |3 |4 | + // |___|__| + // + // This is drawn to the screen as: + // ______ + // |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from + // |___|__| from the top left corner - rotationPoint. + // |2 |1 | + // |___|__| + // + + // The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles + // in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified. + + nsIntRect srcBufferSpaceBottomRight(mBufferRotation.x, mBufferRotation.y, mBufferRect.width - mBufferRotation.x, mBufferRect.height - mBufferRotation.y); + nsIntRect srcBufferSpaceTopRight(mBufferRotation.x, 0, mBufferRect.width - mBufferRotation.x, mBufferRotation.y); + nsIntRect srcBufferSpaceTopLeft(0, 0, mBufferRotation.x, mBufferRotation.y); + nsIntRect srcBufferSpaceBottomLeft(0, mBufferRotation.y, mBufferRotation.x, mBufferRect.height - mBufferRotation.y); + overlap.IntersectRect(mBufferRect, destBufferRect); nsIntRect srcRect(overlap), dstRect(overlap); srcRect.MoveBy(- mBufferRect.TopLeft() + mBufferRotation); - dstRect.MoveBy(- destBufferRect.TopLeft()); - - if (mBufferRotation != nsIntPoint(0, 0)) { - // If mBuffer is rotated, then BlitTextureImage will only be copying the bottom-right section - // of the buffer. We need to invalidate the remaining sections so that they get redrawn too. - // Alternatively we could teach BlitTextureImage to rearrange the rotated segments onto - // the new buffer. - - // When the rotated buffer is reorganised, the bottom-right section will be drawn in the top left. - // Find the point where this content ends. - nsIntPoint rotationPoint(mBufferRect.x + mBufferRect.width - mBufferRotation.x, - mBufferRect.y + mBufferRect.height - mBufferRotation.y); - // The buffer looks like: - // ______ - // |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner. - // |___|__| - // |3 |4 | - // |___|__| - // - // This is drawn to the screen as: - // ______ - // |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from - // |___|__| from the top left corner - rotationPoint. Since only quadrant 4 will actually be copied, - // |2 |1 | we need to invalidate the others. - // |___|__| - // - // Quadrants 2 and 1 - nsIntRect bottom(mBufferRect.x, rotationPoint.y, mBufferRect.width, mBufferRotation.y); - // Quadrant 3 - nsIntRect topright(rotationPoint.x, mBufferRect.y, mBufferRotation.x, rotationPoint.y - mBufferRect.y); + nsIntRect srcRectDrawTopRight(srcRect); + nsIntRect srcRectDrawTopLeft(srcRect); + nsIntRect srcRectDrawBottomLeft(srcRect); + // transform into the different quadrants + srcRectDrawTopRight .MoveBy(-nsIntPoint(0, mBufferRect.height)); + srcRectDrawTopLeft .MoveBy(-nsIntPoint(mBufferRect.width, mBufferRect.height)); + srcRectDrawBottomLeft.MoveBy(-nsIntPoint(mBufferRect.width, 0)); - if (!bottom.IsEmpty()) { - nsIntRegion temp; - temp.And(destBufferRect, bottom); - result.mRegionToDraw.Or(result.mRegionToDraw, temp); - } - if (!topright.IsEmpty()) { - nsIntRegion temp; - temp.And(destBufferRect, topright); - result.mRegionToDraw.Or(result.mRegionToDraw, temp); - } - } + // Intersect with the quadrant + srcRect = srcRect .Intersect(srcBufferSpaceBottomRight); + srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight); + srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft); + srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft); + + dstRect = srcRect; + nsIntRect dstRectDrawTopRight(srcRectDrawTopRight); + nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft); + nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft); + + // transform back to src buffer space + dstRect .MoveBy(-mBufferRotation); + dstRectDrawTopRight .MoveBy(-mBufferRotation + nsIntPoint(0, mBufferRect.height)); + dstRectDrawTopLeft .MoveBy(-mBufferRotation + nsIntPoint(mBufferRect.width, mBufferRect.height)); + dstRectDrawBottomLeft.MoveBy(-mBufferRotation + nsIntPoint(mBufferRect.width, 0)); + + // transform back to draw coordinates + dstRect .MoveBy(mBufferRect.TopLeft()); + dstRectDrawTopRight .MoveBy(mBufferRect.TopLeft()); + dstRectDrawTopLeft .MoveBy(mBufferRect.TopLeft()); + dstRectDrawBottomLeft.MoveBy(mBufferRect.TopLeft()); + + // transform to destBuffer space + dstRect .MoveBy(-destBufferRect.TopLeft()); + dstRectDrawTopRight .MoveBy(-destBufferRect.TopLeft()); + dstRectDrawTopLeft .MoveBy(-destBufferRect.TopLeft()); + dstRectDrawBottomLeft.MoveBy(-destBufferRect.TopLeft()); destBuffer->Resize(destBufferRect.Size()); gl()->BlitTextureImage(mTexImage, srcRect, destBuffer, dstRect); + if (mBufferRotation != nsIntPoint(0, 0)) { + // Draw the remaining quadrants. We call BlitTextureImage 3 extra + // times instead of doing a single draw call because supporting that + // with a tiled source is quite tricky. + if (!srcRectDrawTopRight.IsEmpty()) + gl()->BlitTextureImage(mTexImage, srcRectDrawTopRight, + destBuffer, dstRectDrawTopRight); + if (!srcRectDrawTopLeft.IsEmpty()) + gl()->BlitTextureImage(mTexImage, srcRectDrawTopLeft, + destBuffer, dstRectDrawTopLeft); + if (!srcRectDrawBottomLeft.IsEmpty()) + gl()->BlitTextureImage(mTexImage, srcRectDrawBottomLeft, + destBuffer, dstRectDrawBottomLeft); + } destBuffer->MarkValid(); if (mode == Layer::SURFACE_COMPONENT_ALPHA) { destBufferOnWhite->Resize(destBufferRect.Size()); gl()->BlitTextureImage(mTexImageOnWhite, srcRect, destBufferOnWhite, dstRect); + if (mBufferRotation != nsIntPoint(0, 0)) { + // draw the remaining quadrants + if (!srcRectDrawTopRight.IsEmpty()) + gl()->BlitTextureImage(mTexImageOnWhite, srcRectDrawTopRight, + destBufferOnWhite, dstRectDrawTopRight); + if (!srcRectDrawTopLeft.IsEmpty()) + gl()->BlitTextureImage(mTexImageOnWhite, srcRectDrawTopLeft, + destBufferOnWhite, dstRectDrawTopLeft); + if (!srcRectDrawBottomLeft.IsEmpty()) + gl()->BlitTextureImage(mTexImageOnWhite, srcRectDrawBottomLeft, + destBufferOnWhite, dstRectDrawBottomLeft); + } + destBufferOnWhite->MarkValid(); } } else { From c1723ffee1b4620e92b4ad1bc077d76717228057 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 13 Nov 2012 17:26:18 -0500 Subject: [PATCH 12/76] Bug 810170 - Properly handle extracted text notification and selection notification; r=cpeterson --- mobile/android/base/GeckoEditable.java | 18 ++++----- mobile/android/base/GeckoInputConnection.java | 38 ++++++++++++++++--- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 9e113fef4be9..746d0441ed82 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -553,14 +553,14 @@ final class GeckoEditable } } else { mText.replace(start, oldEnd, text, 0, text.length()); - geckoPostToUI(new Runnable() { - public void run() { - if (mListener != null) { - mListener.onTextChange(text, start, oldEnd, newEnd); - } - } - }); } + geckoPostToUI(new Runnable() { + public void run() { + if (mListener != null) { + mListener.onTextChange(text, start, oldEnd, newEnd); + } + } + }); } // InvocationHandler interface @@ -640,9 +640,7 @@ final class GeckoEditable } // Okay to remove immediately mText.removeSpan(what); - if (mUpdateGecko) { - mActionQueue.offer(new Action(Action.TYPE_REMOVE_SPAN)); - } + mActionQueue.offer(new Action(Action.TYPE_REMOVE_SPAN)); } @Override diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index 64aab7b59151..0155eeb79738 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -64,6 +64,8 @@ class GeckoInputConnection protected int mBatchEditCount; private ExtractedTextRequest mUpdateRequest; private final ExtractedText mUpdateExtract = new ExtractedText(); + private boolean mBatchSelectionChanged; + private boolean mBatchTextChanged; public static InputConnectionHandler create(View targetView, GeckoEditableClient editable) { @@ -94,6 +96,16 @@ class GeckoInputConnection if (mBatchEditCount > 0) { mBatchEditCount--; if (mBatchEditCount == 0) { + if (mBatchTextChanged) { + notifyTextChange(); + mBatchTextChanged = false; + } + if (mBatchSelectionChanged) { + Editable editable = getEditable(); + notifySelectionChange(Selection.getSelectionStart(editable), + Selection.getSelectionEnd(editable)); + mBatchSelectionChanged = false; + } mEditableClient.setUpdateGecko(true); } } else { @@ -191,10 +203,20 @@ class GeckoInputConnection public void onTextChange(String text, int start, int oldEnd, int newEnd) { - if (mBatchEditCount > 0 || mUpdateRequest == null) { + if (mUpdateRequest == null) { return; } + if (mBatchEditCount > 0) { + // Delay notification until after the batch edit + mBatchTextChanged = true; + return; + } + notifyTextChange(); + } + + private void notifyTextChange() { + final InputMethodManager imm = getInputMethodManager(); if (imm == null) { return; @@ -203,10 +225,9 @@ class GeckoInputConnection final Editable editable = getEditable(); mUpdateExtract.flags = 0; - // Update from (0, oldEnd) to (0, newEnd) because some IMEs - // assume that updates start at zero, according to jchen. - mUpdateExtract.partialStartOffset = 0; - mUpdateExtract.partialEndOffset = editable.length(); + // Update the entire Editable range + mUpdateExtract.partialStartOffset = -1; + mUpdateExtract.partialEndOffset = -1; mUpdateExtract.selectionStart = Selection.getSelectionStart(editable); mUpdateExtract.selectionEnd = @@ -221,8 +242,15 @@ class GeckoInputConnection public void onSelectionChange(int start, int end) { if (mBatchEditCount > 0) { + // Delay notification until after the batch edit + mBatchSelectionChanged = true; return; } + notifySelectionChange(start, end); + } + + private void notifySelectionChange(int start, int end) { + final InputMethodManager imm = getInputMethodManager(); if (imm == null) { return; From 0b59e691521612d3848c9aeffae3949cc22a5469 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 13 Nov 2012 17:27:19 -0500 Subject: [PATCH 13/76] Bug 808287 - Fix out-of-order IME events during focus change; r=cpeterson --- mobile/android/base/GeckoEditable.java | 6 ++++++ mobile/android/base/GeckoEvent.java | 1 + widget/android/AndroidJavaWrappers.h | 3 ++- widget/android/nsWindow.cpp | 21 ++++++++++++++++++++- widget/android/nsWindow.h | 1 + 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index 746d0441ed82..e9abea9f3952 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -53,6 +53,7 @@ final class GeckoEditable private static final boolean DEBUG = false; private static final String LOGTAG = "GeckoEditable"; private static final int NOTIFY_IME_REPLY_EVENT = 1; + private static final int NOTIFY_IME_FOCUSCHANGE = 3; // Filters to implement Editable's filtering functionality private InputFilter[] mFilters; @@ -464,6 +465,11 @@ final class GeckoEditable public void run() { // Make sure there are no other things going on mActionQueue.syncWithGecko(); + if (type == NOTIFY_IME_FOCUSCHANGE && state != 0) { + // Unmask events on the Gecko side + GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent( + GeckoEvent.IME_ACKNOWLEDGE_FOCUS)); + } if (mListener != null) { mListener.notifyIME(type, state); } diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 578c7c39442f..2200f6966243 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -86,6 +86,7 @@ public class GeckoEvent { public static final int IME_ADD_COMPOSITION_RANGE = 3; public static final int IME_UPDATE_COMPOSITION = 4; public static final int IME_REMOVE_COMPOSITION = 5; + public static final int IME_ACKNOWLEDGE_FOCUS = 6; public static final int IME_RANGE_CARETPOSITION = 1; public static final int IME_RANGE_RAWINPUT = 2; diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index 8742278c72a7..20a8a5c6008f 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -815,7 +815,8 @@ public: IME_SET_SELECTION = 2, IME_ADD_COMPOSITION_RANGE = 3, IME_UPDATE_COMPOSITION = 4, - IME_REMOVE_COMPOSITION = 5 + IME_REMOVE_COMPOSITION = 5, + IME_ACKNOWLEDGE_FOCUS = 6 }; }; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 9c64b17fdd28..31421048dfdd 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -163,7 +163,9 @@ nsWindow::nsWindow() : mFocus(nullptr), mIMEComposing(false), mIMEMaskSelectionUpdate(false), - mIMEMaskTextUpdate(false) + mIMEMaskTextUpdate(false), + // Mask IME events initially because there is no focused editors yet + mIMEMaskEvents(true) { } @@ -1880,6 +1882,18 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) composition through update composition events */ nsRefPtr kungFuDeathGrip(this); + + if (ae->Action() == AndroidGeckoEvent::IME_ACKNOWLEDGE_FOCUS) { + mIMEMaskEvents = false; + return; + } else if (mIMEMaskEvents) { + // Still reply to events, but don't do anything else + if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE || + ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { + AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT, 0); + } + return; + } switch (ae->Action()) { case AndroidGeckoEvent::IME_SYNCHRONIZE: { @@ -2166,6 +2180,11 @@ nsWindow::OnIMEFocusChange(bool aFocus) if (aFocus) { OnIMETextChange(0, INT32_MAX, INT32_MAX); OnIMESelectionChange(); + } else { + // Mask events because we lost focus. On the next focus event, Gecko will notify + // Java, and Java will send an acknowledge focus event back to Gecko. That is + // where we unmask event handling + mIMEMaskEvents = true; } AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_FOCUSCHANGE, diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 5e4ae6d8527c..760d8a277814 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -184,6 +184,7 @@ protected: bool mIMEComposing; bool mIMEMaskSelectionUpdate, mIMEMaskTextUpdate; + bool mIMEMaskEvents; nsString mIMEComposingText; nsAutoTArray mIMERanges; From 6a1f18041e952e02218ce1306e6bb8702c645b14 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 13 Nov 2012 17:27:26 -0500 Subject: [PATCH 14/76] Bug 808287 - Follow-up to combine IME enums, etc; r=cpeterson --- mobile/android/base/GeckoEditable.java | 18 +++++++++++++++--- mobile/android/base/GeckoInputConnection.java | 10 ---------- widget/android/nsWindow.cpp | 8 ++++---- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/mobile/android/base/GeckoEditable.java b/mobile/android/base/GeckoEditable.java index e9abea9f3952..c1ed9a4ff0ce 100644 --- a/mobile/android/base/GeckoEditable.java +++ b/mobile/android/base/GeckoEditable.java @@ -34,6 +34,20 @@ interface GeckoEditableClient { /* interface for the Editable to listen to the Gecko thread and also for the UI thread to listen to the Editable */ interface GeckoEditableListener { + // IME notification type for notifyIME() + final int NOTIFY_IME_RESETINPUTSTATE = 0; + final int NOTIFY_IME_REPLY_EVENT = 1; + final int NOTIFY_IME_CANCELCOMPOSITION = 2; + final int NOTIFY_IME_FOCUSCHANGE = 3; + // IME focus state for notifyIME(NOTIFY_IME_FOCUSCHANGE, ..) + final int IME_FOCUS_STATE_FOCUS = 1; + final int IME_FOCUS_STATE_BLUR = 0; + // IME enabled state for notifyIMEEnabled() + final int IME_STATE_DISABLED = 0; + final int IME_STATE_ENABLED = 1; + final int IME_STATE_PASSWORD = 2; + final int IME_STATE_PLUGIN = 3; + void notifyIME(int type, int state); void notifyIMEEnabled(int state, String typeHint, String modeHint, String actionHint); @@ -52,8 +66,6 @@ final class GeckoEditable private static final boolean DEBUG = false; private static final String LOGTAG = "GeckoEditable"; - private static final int NOTIFY_IME_REPLY_EVENT = 1; - private static final int NOTIFY_IME_FOCUSCHANGE = 3; // Filters to implement Editable's filtering functionality private InputFilter[] mFilters; @@ -465,7 +477,7 @@ final class GeckoEditable public void run() { // Make sure there are no other things going on mActionQueue.syncWithGecko(); - if (type == NOTIFY_IME_FOCUSCHANGE && state != 0) { + if (type == NOTIFY_IME_FOCUSCHANGE && state != IME_FOCUS_STATE_BLUR) { // Unmask events on the Gecko side GeckoAppShell.sendEventToGecko(GeckoEvent.createIMEEvent( GeckoEvent.IME_ACKNOWLEDGE_FOCUS)); diff --git a/mobile/android/base/GeckoInputConnection.java b/mobile/android/base/GeckoInputConnection.java index 0155eeb79738..36a4265825b8 100644 --- a/mobile/android/base/GeckoInputConnection.java +++ b/mobile/android/base/GeckoInputConnection.java @@ -39,16 +39,6 @@ class GeckoInputConnection private static final boolean DEBUG = false; protected static final String LOGTAG = "GeckoInputConnection"; - // IME stuff - public static final int IME_STATE_DISABLED = 0; - public static final int IME_STATE_ENABLED = 1; - public static final int IME_STATE_PASSWORD = 2; - public static final int IME_STATE_PLUGIN = 3; - - private static final int NOTIFY_IME_RESETINPUTSTATE = 0; - private static final int NOTIFY_IME_CANCELCOMPOSITION = 2; - private static final int NOTIFY_IME_FOCUSCHANGE = 3; - private static final int INLINE_IME_MIN_DISPLAY_SIZE = 480; private static final Timer mIMETimer = new Timer("GeckoInputConnection Timer"); diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 31421048dfdd..19b856918aab 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -164,8 +164,7 @@ nsWindow::nsWindow() : mIMEComposing(false), mIMEMaskSelectionUpdate(false), mIMEMaskTextUpdate(false), - // Mask IME events initially because there is no focused editors yet - mIMEMaskEvents(true) + mIMEMaskEvents(true) // Mask IME events since there's no focus yet { } @@ -1886,10 +1885,11 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae) if (ae->Action() == AndroidGeckoEvent::IME_ACKNOWLEDGE_FOCUS) { mIMEMaskEvents = false; return; - } else if (mIMEMaskEvents) { + } + if (mIMEMaskEvents) { // Still reply to events, but don't do anything else if (ae->Action() == AndroidGeckoEvent::IME_SYNCHRONIZE || - ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { + ae->Action() == AndroidGeckoEvent::IME_REPLACE_TEXT) { AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT, 0); } return; From 95dbcb905d5866ea17212afec74fe88164f29d58 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 13 Nov 2012 10:20:40 +0900 Subject: [PATCH 15/76] Bug 808287 nsTextStateManager shouldn't notify widget of selection changes and text changes after IME loses focus r=smaug --- content/events/src/nsIMEStateManager.cpp | 35 ++++++++++++------------ 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/content/events/src/nsIMEStateManager.cpp b/content/events/src/nsIMEStateManager.cpp index 44ffe8a2a389..4e0f7afc4796 100644 --- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -775,6 +775,8 @@ nsTextStateManager::Destroy(void) false, false))->RunDOMEventWhenSafe(); } mWidget->OnIMEFocusChange(false); + // Even if there are some pending notification, it'll never notify the widget. + mWidget = nullptr; if (mObserving && mSel) { nsCOMPtr selPrivate(do_QueryInterface(mSel)); if (selPrivate) @@ -786,7 +788,6 @@ nsTextStateManager::Destroy(void) } mRootContent = nullptr; mEditableNode = nullptr; - mWidget = nullptr; mObserving = false; } @@ -811,21 +812,21 @@ NS_IMPL_ISUPPORTS2(nsTextStateManager, // Helper class, used for selection change notification class SelectionChangeEvent : public nsRunnable { public: - SelectionChangeEvent(nsIWidget *widget) - : mWidget(widget) + SelectionChangeEvent(nsTextStateManager *aDispatcher) + : mDispatcher(aDispatcher) { - MOZ_ASSERT(mWidget); + MOZ_ASSERT(mDispatcher); } NS_IMETHOD Run() { - if(mWidget) { - mWidget->OnIMESelectionChange(); + if (mDispatcher->mWidget) { + mDispatcher->mWidget->OnIMESelectionChange(); } return NS_OK; } private: - nsCOMPtr mWidget; + nsRefPtr mDispatcher; }; nsresult @@ -837,7 +838,7 @@ nsTextStateManager::NotifySelectionChanged(nsIDOMDocument* aDoc, nsresult rv = aSel->GetRangeCount(&count); NS_ENSURE_SUCCESS(rv, rv); if (count > 0 && mWidget) { - nsContentUtils::AddScriptRunner(new SelectionChangeEvent(mWidget)); + nsContentUtils::AddScriptRunner(new SelectionChangeEvent(this)); } return NS_OK; } @@ -845,25 +846,25 @@ nsTextStateManager::NotifySelectionChanged(nsIDOMDocument* aDoc, // Helper class, used for text change notification class TextChangeEvent : public nsRunnable { public: - TextChangeEvent(nsIWidget *widget, + TextChangeEvent(nsTextStateManager* aDispatcher, uint32_t start, uint32_t oldEnd, uint32_t newEnd) - : mWidget(widget) + : mDispatcher(aDispatcher) , mStart(start) , mOldEnd(oldEnd) , mNewEnd(newEnd) { - MOZ_ASSERT(mWidget); + MOZ_ASSERT(mDispatcher); } NS_IMETHOD Run() { - if(mWidget) { - mWidget->OnIMETextChange(mStart, mOldEnd, mNewEnd); + if (mDispatcher->mWidget) { + mDispatcher->mWidget->OnIMETextChange(mStart, mOldEnd, mNewEnd); } return NS_OK; } private: - nsCOMPtr mWidget; + nsRefPtr mDispatcher; uint32_t mStart, mOldEnd, mNewEnd; }; @@ -885,7 +886,7 @@ nsTextStateManager::CharacterDataChanged(nsIDocument* aDocument, uint32_t newEnd = offset + aInfo->mReplaceLength; nsContentUtils::AddScriptRunner( - new TextChangeEvent(mWidget, offset, oldEnd, newEnd)); + new TextChangeEvent(this, offset, oldEnd, newEnd)); } void @@ -907,7 +908,7 @@ nsTextStateManager::NotifyContentAdded(nsINode* aContainer, // fire notification if (newOffset) nsContentUtils::AddScriptRunner( - new TextChangeEvent(mWidget, offset, offset, offset + newOffset)); + new TextChangeEvent(this, offset, offset, offset + newOffset)); } void @@ -956,7 +957,7 @@ nsTextStateManager::ContentRemoved(nsIDocument* aDocument, // fire notification if (childOffset) nsContentUtils::AddScriptRunner( - new TextChangeEvent(mWidget, offset, offset + childOffset, offset)); + new TextChangeEvent(this, offset, offset + childOffset, offset)); } bool From 32a8eee843413d6a6430ef0267d2f4eed4e0746f Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 13 Nov 2012 10:18:57 +0900 Subject: [PATCH 16/76] Bug 805766 nsFocusManager should change IME state before dispatching focus event at activating different document r=enndeakin --- dom/base/nsFocusManager.cpp | 2 ++ widget/tests/test_imestate.html | 41 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 148cd8c8293e..f6ebe3719713 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1755,6 +1755,8 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow, // if switching to a new document, first fire the focus event on the // document and then the window. if (aIsNewDocument) { + nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr, + GetFocusMoveActionCause(aFlags)); nsIDocument* doc = aWindow->GetExtantDoc(); if (doc) SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell, doc, diff --git a/widget/tests/test_imestate.html b/widget/tests/test_imestate.html index 2d8623a1eecf..7ca3833a12c2 100644 --- a/widget/tests/test_imestate.html +++ b/widget/tests/test_imestate.html @@ -160,12 +160,15 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription) } var previousFocusedElement = gFM.focusedElement; var element = document.getElementById(aTest.id); + var focusEventTarget = element; var subDocument = null; if (element.contentDocument) { + focusEventTarget = element.contentDocument; subDocument = element.contentDocument; element = element.contentDocument.documentElement; } + focusEventTarget.addEventListener("focus", aFocusEventHandler, true); document.addEventListener("MozIMEFocusIn", aFocusEventHandler, true); document.addEventListener("MozIMEFocusOut", aFocusEventHandler, true); if (subDocument) { @@ -175,6 +178,7 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription) element.focus(); + focusEventTarget.removeEventListener("focus", aFocusEventHandler, true); document.removeEventListener("MozIMEFocusIn", aFocusEventHandler, true); document.removeEventListener("MozIMEFocusOut", aFocusEventHandler, true); if (element.contentDocument) { @@ -215,6 +219,7 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription) // IME Enabled state testing var enabled = gUtils.IME_STATUS_ENABLED; if (kIMEEnabledSupported) { + var focusEventCount = 0; var mozIMEFocusInCount = 0; var mozIMEFocusOutCount = 0; var IMEHasFocus = false; @@ -222,6 +227,11 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription) function onFocus(aEvent) { switch (aEvent.type) { + case "focus": + focusEventCount++; + is(gUtils.IMEStatus, aTest.expectedEnabled, + aDescription + ": " + aTest.description + ", wrong enabled state at focus event"); + break; case "MozIMEFocusIn": mozIMEFocusInCount++; IMEHasFocus = true; @@ -245,36 +255,25 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription) if (aTest.focusable) { if (!aTest.focusEventNotFired) { + ok(focusEventCount > 0, + aDescription + ": " + aTest.description + ", focus event is never fired"); if (aTest.expectedEnabled == gUtils.IME_STATUS_ENABLED || aTest.expectedEnabled == gUtils.IME_STATUS_PASSWORD) { + ok(mozIMEFocusInCount > 0, + aDescription + ": " + aTest.description + ", MozIMEFocusIn event should be fired"); var toDesignModeEditor = (document.activeElement.contentDocument && (document.activeElement.contentDocument.designMode == "on")); - if (aInDesignMode && toDesignModeEditor) { + if (aInDesignMode && !toDesignModeEditor) { is(mozIMEFocusOutCount, 0, aDescription + ": " + aTest.description + ", MozIMEFocusOut event shouldn't be fired in designMode since focus isn't moved from another editor"); - todo(mozIMEFocusInCount > 0, - aDescription + ": " + aTest.description + ", MozIMEFocusIn event should be fired"); // bug 805766 } else { ok(mozIMEFocusOutCount > 0, aDescription + ": " + aTest.description + ", MozIMEFocusOut event should be fired for the previous focused editor"); - if (toDesignModeEditor) { - todo(mozIMEFocusInCount > 0, - aDescription + ": " + aTest.description + ", MozIMEFocusIn event should be fired"); // bug 805766 - } else { - ok(mozIMEFocusInCount > 0, - aDescription + ": " + aTest.description + ", MozIMEFocusIn event should be fired"); - } - } - if (aInDesignMode || toDesignModeEditor) { // bug 805766 - todo(IMEHasFocus, - aDescription + ": " + aTest.description + - ", The latest MozIMEFocus* event must be MozIMEFocusIn"); - } else { - ok(IMEHasFocus, - aDescription + ": " + aTest.description + - ", The latest MozIMEFocus* event must be MozIMEFocusIn"); } + ok(IMEHasFocus, + aDescription + ": " + aTest.description + + ", The latest MozIMEFocus* event must be MozIMEFocusIn"); } else { is(mozIMEFocusInCount, 0, aDescription + ": " + aTest.description + @@ -287,8 +286,8 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription) ", The latest MozIMEFocus* event must be MozIMEFocusOut"); } } else { - todo(false, aDescription + ": " + aTest.description + - ", In this case, focus event isn't fired, it's a bug, so, couldn't test it"); + todo(focusEventCount > 0, + aDescription + ": " + aTest.description + ", focus event should be fired"); } } else { is(mozIMEFocusInCount, 0, From b016c92883dc701c9d219e37c83c34b43f068d56 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Tue, 13 Nov 2012 18:25:09 -0500 Subject: [PATCH 17/76] Backed out changeset 43e4b01c0150 (bug 810186) for reftest failures. --- layout/base/FrameLayerBuilder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 7013c2c33024..eeda339c52ec 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2052,7 +2052,6 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // Assign the item to a layer if (layerState == LAYER_ACTIVE_FORCE || - (layerState == LAYER_INACTIVE && !mManager->IsWidgetLayerManager()) || (!forceInactive && (layerState == LAYER_ACTIVE_EMPTY || layerState == LAYER_ACTIVE))) { @@ -2697,7 +2696,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder, gfxMatrix transform2d; bool canDraw2D = transform.CanDraw2D(&transform2d); gfxSize scale; - bool isRetained = aLayer->Manager()->IsWidgetLayerManager(); + bool isRetained = aLayerBuilder->GetRetainingLayerManager() == aLayer->Manager(); // Only fiddle with scale factors for the retaining layer manager, since // it only matters for retained layers // XXX Should we do something for 3D transforms? From 8c41c8d21a3e2f6a51fb4dd3b9ddabb17f16f667 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Tue, 13 Nov 2012 11:44:36 -0800 Subject: [PATCH 18/76] bug 684176 - Intermittent failure in test_bug454235.xul | offscreen browser is not visible r=smaug --- docshell/test/chrome/test_bug454235.xul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docshell/test/chrome/test_bug454235.xul b/docshell/test/chrome/test_bug454235.xul index 6d8e9ddebc37..f9107a1865d1 100644 --- a/docshell/test/chrome/test_bug454235.xul +++ b/docshell/test/chrome/test_bug454235.xul @@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=454235 /** Test for Bug 454235 **/ SimpleTest.waitForExplicitFinish(); -addLoadEvent(doTest); +SimpleTest.waitForFocus(doTest); function doTest() { var shownBrowser = document.getElementById("shownBrowser"); From 7815f1867f16631944eb8aa2741c91090a73de65 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Thu, 1 Nov 2012 08:47:51 -0400 Subject: [PATCH 19/76] bug 739542 - Disable screen timeout when playing HTML5