bug 582644 - IME event remoting, patch to content r=smaug blocking-fennec=2.0a1+
authorJim Chen <nchen@mozilla.com>
Mon, 16 Aug 2010 14:48:32 -0700
changeset 50690 b967e8b3e927a013d0ed5f183de68a902dc3c2a4
parent 50689 197b54fa96a100267840593be9eac6e3aa74d46d
child 50691 6d383749eacfe5b841450d824da30289162d4634
push idunknown
push userunknown
push dateunknown
reviewerssmaug
bugs582644
milestone2.0b4pre
bug 582644 - IME event remoting, patch to content r=smaug blocking-fennec=2.0a1+
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/base/src/nsFrameLoader.cpp
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
widget/public/nsGUIEvent.h
widget/public/nsGUIEventIPC.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1671,16 +1671,33 @@ public:
   /**
    * Determine whether a content node is focused or not,
    *
    * @param aContent the content node to check
    * @return true if the content node is focused, false otherwise.
    */
   static PRBool IsFocusedContent(nsIContent *aContent);
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  static void SetActiveFrameLoader(nsFrameLoader *aFrameLoader)
+  {
+    sActiveFrameLoader = aFrameLoader;
+  }
+
+  static void ClearActiveFrameLoader(const nsFrameLoader *aFrameLoader)
+  {
+    if (sActiveFrameLoader == aFrameLoader)
+      sActiveFrameLoader = nsnull;
+  }
+
+  static already_AddRefed<nsFrameLoader> GetActiveFrameLoader();
+#endif
+#endif
+
 private:
 
   static PRBool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
 
@@ -1760,16 +1777,22 @@ private:
   static PRUint32 sRemovableScriptBlockerCount;
   static nsCOMArray<nsIRunnable>* sBlockedScriptRunners;
   static PRUint32 sRunnersCountAtFirstBlocker;
   static PRUint32 sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static PRBool sIsHandlingKeyBoardEvent;
+
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  static nsFrameLoader *sActiveFrameLoader;
+#endif
+#endif
 };
 
 #define NS_HOLD_JS_OBJECTS(obj, clazz)                                         \
   nsContentUtils::HoldJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz),        \
                                 &NS_CYCLE_COLLECTION_NAME(clazz))
 
 #define NS_DROP_JS_OBJECTS(obj, clazz)                                         \
   nsContentUtils::DropJSObjects(NS_CYCLE_COLLECTION_UPCAST(obj, clazz))
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -261,16 +261,22 @@ JSRuntime *nsAutoGCRoot::sJSScriptRuntim
 
 PRBool nsContentUtils::sIsHandlingKeyBoardEvent = PR_FALSE;
 
 PRBool nsContentUtils::sInitialized = PR_FALSE;
 
 nsRefPtrHashtable<nsPrefObserverHashKey, nsPrefOldCallback>
   *nsContentUtils::sPrefCallbackTable = nsnull;
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+nsFrameLoader *nsContentUtils::sActiveFrameLoader = nsnull;
+#endif
+#endif
+
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
 public:
   EventListenerManagerMapEntry(const void *aKey)
     : mKey(aKey)
   {
@@ -6204,16 +6210,27 @@ mozAutoRemovableBlockerRemover::~mozAuto
 PRBool
 nsContentUtils::IsFocusedContent(nsIContent* aContent)
 {
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 
   return fm && fm->GetFocusedContent() == aContent;
 }
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+// static
+already_AddRefed<nsFrameLoader>
+nsContentUtils::GetActiveFrameLoader()
+{
+  return nsCOMPtr<nsFrameLoader>(sActiveFrameLoader).forget();
+}
+#endif
+#endif
+
 void nsContentUtils::RemoveNewlines(nsString &aString)
 {
   // strip CR/LF and null
   static const char badChars[] = {'\r', '\n', 0};
   aString.StripChars(badChars);
 }
 
 void
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -1165,16 +1165,19 @@ nsFrameLoader::SwapWithOtherLoader(nsFra
   return NS_OK;
 }
 
 void
 nsFrameLoader::DestroyChild()
 {
 #ifdef MOZ_IPC
   if (mRemoteBrowser) {
+#ifdef ANDROID
+    nsContentUtils::ClearActiveFrameLoader(this);
+#endif
     mRemoteBrowser->SetOwnerElement(nsnull);
     // If this fails, it's most likely due to a content-process crash,
     // and auto-cleanup will kick in.  Otherwise, the child side will
     // destroy itself and send back __delete__().
     unused << mRemoteBrowser->SendDestroy();
     mRemoteBrowser = nsnull;
   }
 #endif
@@ -1700,16 +1703,19 @@ nsFrameLoader::GetRemoteBrowser()
 }
 #endif
 
 NS_IMETHODIMP
 nsFrameLoader::ActivateRemoteFrame() {
 #ifdef MOZ_IPC
   if (mRemoteBrowser) {
     mRemoteBrowser->Activate();
+#ifdef ANDROID
+    nsContentUtils::SetActiveFrameLoader(this);
+#endif
     return NS_OK;
   }
 #endif
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
 nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -39,16 +39,22 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+#include "mozilla/dom/PBrowserParent.h"
+#endif
+#endif
+
 #include "nsCOMPtr.h"
 #include "nsEventStateManager.h"
 #include "nsEventListenerManager.h"
 #include "nsIMEStateManager.h"
 #include "nsContentEventHandler.h"
 #include "nsIContent.h"
 #include "nsINodeInfo.h"
 #include "nsIDocument.h"
@@ -154,16 +160,22 @@
 #include "nsIController.h"
 #include "nsICommandParams.h"
 #include "mozilla/Services.h"
 
 #ifdef XP_MACOSX
 #import <ApplicationServices/ApplicationServices.h>
 #endif
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+#include "nsFrameLoader.h"
+#endif
+#endif
+
 //#define DEBUG_DOCSHELL_FOCUS
 
 #define NS_USER_INTERACTION_INTERVAL 5000 // ms
 
 static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
 
 static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
@@ -1364,16 +1376,50 @@ nsEventStateManager::PreHandleEvent(nsPr
       DoContentCommandEvent(static_cast<nsContentCommandEvent*>(aEvent));
     }
     break;
   case NS_CONTENT_COMMAND_SCROLL:
     {
       DoContentCommandScrollEvent(static_cast<nsContentCommandEvent*>(aEvent));
     }
     break;
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  case NS_TEXT_TEXT:
+    {
+      nsTextEvent *textEvent = static_cast<nsTextEvent*>(aEvent);
+      if (IsTargetCrossProcess(textEvent)) {
+        // Will not be handled locally, remote the event
+        mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+        if (remoteBrowser &&
+            remoteBrowser->SendTextEvent(*textEvent)) {
+          // Cancel local dispatching
+          *aStatus = nsEventStatus_eConsumeNoDefault;
+        }
+      }
+    }
+    break;
+  case NS_COMPOSITION_START:
+  case NS_COMPOSITION_END:
+    {
+      nsCompositionEvent *compositionEvent =
+          static_cast<nsCompositionEvent*>(aEvent);
+      if (IsTargetCrossProcess(compositionEvent)) {
+        // Will not be handled locally, remote the event
+        mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+        if (remoteBrowser &&
+            remoteBrowser->SendCompositionEvent(*compositionEvent)) {
+          // Cancel local dispatching
+          *aStatus = nsEventStatus_eConsumeNoDefault;
+        }
+      }
+    }
+    break;
+#endif
+#endif
   }
   return NS_OK;
 }
 
 static PRInt32
 GetAccessModifierMask(nsISupports* aDocShell)
 {
   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
@@ -3194,24 +3240,88 @@ nsEventStateManager::PostHandleEvent(nsP
       mCurrentTarget->GetContentForEvent(presContext, aEvent,
                                          getter_AddRefs(targetContent));
       if (!NodeAllowsClickThrough(targetContent)) {
         *aStatus = nsEventStatus_eConsumeNoDefault;
       }
     }
     break;
 #endif
+
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  case NS_QUERY_SELECTED_TEXT:
+  case NS_QUERY_TEXT_CONTENT:
+  case NS_QUERY_CARET_RECT:
+  case NS_QUERY_TEXT_RECT:
+  case NS_QUERY_EDITOR_RECT:
+  case NS_QUERY_CONTENT_STATE:
+  // We don't remote nsITransferable yet
+  //case NS_QUERY_SELECTION_AS_TRANSFERABLE:
+  case NS_QUERY_CHARACTER_AT_POINT:
+    {
+      nsQueryContentEvent *queryEvent =
+          static_cast<nsQueryContentEvent*>(aEvent);
+      // If local query failed, try remote query
+      if (queryEvent->mSucceeded)
+        break;
+
+      mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+      if (remoteBrowser &&
+          remoteBrowser->SendQueryContentEvent(*queryEvent)) {
+        queryEvent->mWasAsync = PR_TRUE;
+        queryEvent->mSucceeded = PR_TRUE;
+      }
+    }
+    break;
+  case NS_SELECTION_SET:
+    {
+      nsSelectionEvent *selectionEvent =
+          static_cast<nsSelectionEvent*>(aEvent);
+      // If local handler failed, try remoting the event
+      if (selectionEvent->mSucceeded)
+        break;
+
+      mozilla::dom::PBrowserParent *remoteBrowser = GetCrossProcessTarget();
+      if (remoteBrowser &&
+          remoteBrowser->SendSelectionEvent(*selectionEvent))
+        selectionEvent->mSucceeded = PR_TRUE;
+    }
+    break;
+#endif // ANDROID
+#endif // MOZ_IPC
   }
 
   //Reset target frame to null to avoid mistargeting after reentrant event
   mCurrentTarget = nsnull;
 
   return ret;
 }
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+mozilla::dom::PBrowserParent*
+nsEventStateManager::GetCrossProcessTarget()
+{
+  nsCOMPtr<nsFrameLoader> fl = nsContentUtils::GetActiveFrameLoader();
+  NS_ENSURE_TRUE(fl, nsnull);
+  return fl->GetRemoteBrowser();
+}
+
+PRBool
+nsEventStateManager::IsTargetCrossProcess(nsGUIEvent *aEvent)
+{
+  nsQueryContentEvent stateEvent(PR_TRUE, NS_QUERY_CONTENT_STATE, aEvent->widget);
+  nsContentEventHandler handler(mPresContext);
+  handler.OnQueryContentState(&stateEvent);
+  return !stateEvent.mSucceeded;
+}
+#endif
+#endif
+
 NS_IMETHODIMP
 nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
 {
   nsIMEStateManager::OnDestroyPresContext(aPresContext);
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -326,16 +326,23 @@ protected:
    * BeginTrackingDragGesture). aEvent->widget must be
    * mCurrentTarget->GetNearestWidget().
    */
   void FillInEventFromGestureDown(nsMouseEvent* aEvent);
 
   nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent);
   nsresult DoContentCommandScrollEvent(nsContentCommandEvent* aEvent);
 
+#ifdef MOZ_IPC
+#ifdef ANDROID
+  mozilla::dom::PBrowserParent *GetCrossProcessTarget();
+  PRBool IsTargetCrossProcess(nsGUIEvent *aEvent);
+#endif
+#endif
+
   PRInt32     mLockCursor;
 
   nsWeakFrame mCurrentTarget;
   nsCOMPtr<nsIContent> mCurrentTargetContent;
   nsWeakFrame mLastMouseOverFrame;
   nsCOMPtr<nsIContent> mLastMouseOverElement;
   nsWeakFrame mLastDragOverFrame;
 
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -1229,17 +1229,17 @@ private:
     mReply.mContentsRoot = nsnull;
     mReply.mFocusedWidget = nsnull;
   }
 #endif // MOZ_IPC
 
 public:
   nsQueryContentEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget) :
     nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_QUERY_CONTENT_EVENT),
-    mSucceeded(PR_FALSE)
+    mSucceeded(PR_FALSE), mWasAsync(PR_FALSE)
   {
   }
 
   void InitForQueryTextContent(PRUint32 aOffset, PRUint32 aLength)
   {
     NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT,
                  "wrong initializer is called");
     mInput.mOffset = aOffset;
@@ -1257,16 +1257,17 @@ public:
   {
     NS_ASSERTION(message == NS_QUERY_TEXT_RECT,
                  "wrong initializer is called");
     mInput.mOffset = aOffset;
     mInput.mLength = aLength;
   }
 
   PRBool mSucceeded;
+  PRPackedBool mWasAsync;
   struct {
     PRUint32 mOffset;
     PRUint32 mLength;
   } mInput;
   struct {
     void* mContentsRoot;
     PRUint32 mOffset;
     nsString mString;
--- a/widget/public/nsGUIEventIPC.h
+++ b/widget/public/nsGUIEventIPC.h
@@ -223,16 +223,17 @@ struct ParamTraits<nsQueryContentEvent>
     WriteParam(aMsg, aParam.mReply.mString);
     WriteParam(aMsg, aParam.mReply.mRect);
     WriteParam(aMsg, aParam.mReply.mReversed);
     WriteParam(aMsg, aParam.mReply.mHasSelection);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
+    aResult->mWasAsync = PR_TRUE;
     return ReadParam(aMsg, aIter, static_cast<nsGUIEvent*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->mSucceeded) &&
            ReadParam(aMsg, aIter, &aResult->mInput.mOffset) &&
            ReadParam(aMsg, aIter, &aResult->mInput.mLength) &&
            ReadParam(aMsg, aIter, &aResult->mReply.mOffset) &&
            ReadParam(aMsg, aIter, &aResult->mReply.mString) &&
            ReadParam(aMsg, aIter, &aResult->mReply.mRect) &&
            ReadParam(aMsg, aIter, &aResult->mReply.mReversed) &&