Bug 1179122 TextComposition should manage a composition which is even in a child process r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 03 Jul 2015 11:49:36 +0900
changeset 251279 6d96d03b8b202c75d099393387a06317330aa8f8
parent 251278 3586a2f369588e9717ce0d3b27b4807b3f9d5516
child 251280 0bb107d007f27392e332a49b69c62109ec0af9e8
push id61811
push usermasayuki@d-toybox.com
push dateFri, 03 Jul 2015 02:49:41 +0000
treeherdermozilla-inbound@6d96d03b8b20 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1179122
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1179122 TextComposition should manage a composition which is even in a child process r=smaug
dom/events/EventStateManager.cpp
dom/events/IMEStateManager.cpp
dom/events/IMEStateManager.h
dom/events/TextComposition.cpp
dom/events/TextComposition.h
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -837,31 +837,16 @@ EventStateManager::PreHandleEvent(nsPres
       // composition event.
       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
       WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT,
                                            compositionEvent->widget);
       DoQuerySelectedText(&selectedText);
       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
       compositionEvent->mData = selectedText.mReply.mString;
     }
-    // through to compositionend handling
-  case NS_COMPOSITION_END:
-  case NS_COMPOSITION_CHANGE:
-  case NS_COMPOSITION_COMMIT_AS_IS:
-  case NS_COMPOSITION_COMMIT:
-    {
-      WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
-      if (IsTargetCrossProcess(compositionEvent)) {
-        // Will not be handled locally, remote the event
-        if (GetCrossProcessTarget()->SendCompositionEvent(*compositionEvent)) {
-          // Cancel local dispatching
-          aEvent->mFlags.mPropagationStopped = true;
-        }
-      }
-    }
     break;
   }
   return NS_OK;
 }
 
 // static
 int32_t
 EventStateManager::GetAccessModifierMaskFor(nsISupports* aDocShell)
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1120,26 +1120,30 @@ void
 IMEStateManager::DispatchCompositionEvent(
                    nsINode* aEventTargetNode,
                    nsPresContext* aPresContext,
                    WidgetCompositionEvent* aCompositionEvent,
                    nsEventStatus* aStatus,
                    EventDispatchingCallback* aCallBack,
                    bool aIsSynthesized)
 {
+  nsRefPtr<TabParent> tabParent =
+    aEventTargetNode->IsContent() ?
+      TabParent::GetFrom(aEventTargetNode->AsContent()) : nullptr;
+
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
      "aPresContext=0x%p, aCompositionEvent={ message=%s, "
      "mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
-     "aIsSynthesized=%s)",
+     "aIsSynthesized=%s), tabParent=%p",
      aEventTargetNode, aPresContext,
      GetEventMessageName(aCompositionEvent->message),
      GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
      GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
-     GetBoolName(aIsSynthesized)));
+     GetBoolName(aIsSynthesized), tabParent.get()));
 
   if (!aCompositionEvent->mFlags.mIsTrusted ||
       aCompositionEvent->mFlags.mPropagationStopped) {
     return;
   }
 
   MOZ_ASSERT(aCompositionEvent->message != NS_COMPOSITION_UPDATE,
              "compositionupdate event shouldn't be dispatched manually");
@@ -1154,17 +1158,18 @@ IMEStateManager::DispatchCompositionEven
     if (NS_WARN_IF(aIsSynthesized)) {
       return;
     }
     MOZ_LOG(sISMLog, LogLevel::Debug,
       ("ISM:   IMEStateManager::DispatchCompositionEvent(), "
        "adding new TextComposition to the array"));
     MOZ_ASSERT(aCompositionEvent->message == NS_COMPOSITION_START);
     composition =
-      new TextComposition(aPresContext, aEventTargetNode, aCompositionEvent);
+      new TextComposition(aPresContext, aEventTargetNode, tabParent,
+                          aCompositionEvent);
     sTextCompositions->AppendElement(composition);
   }
 #ifdef DEBUG
   else {
     MOZ_ASSERT(aCompositionEvent->message != NS_COMPOSITION_START);
   }
 #endif // #ifdef DEBUG
 
@@ -1198,17 +1203,17 @@ IMEStateManager::DispatchCompositionEven
       sTextCompositions->RemoveElementAt(i);
     }
   }
 }
 
 // static
 void
 IMEStateManager::OnCompositionEventDiscarded(
-                   const WidgetCompositionEvent* aCompositionEvent)
+                   WidgetCompositionEvent* aCompositionEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
 
   MOZ_LOG(sISMLog, LogLevel::Info,
     ("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ "
      "message=%s, mFlags={ mIsTrusted=%s } })",
      GetEventMessageName(aCompositionEvent->message),
--- a/dom/events/IMEStateManager.h
+++ b/dom/events/IMEStateManager.h
@@ -152,17 +152,17 @@ public:
                 EventDispatchingCallback* aCallBack,
                 bool aIsSynthesized = false);
 
   /**
    * This is called when PresShell ignores a composition event due to not safe
    * to dispatch events.
    */
   static void OnCompositionEventDiscarded(
-                const WidgetCompositionEvent* aCompositionEvent);
+                WidgetCompositionEvent* aCompositionEvent);
 
   /**
    * Get TextComposition from widget.
    */
   static already_AddRefed<TextComposition>
     GetTextCompositionFor(nsIWidget* aWidget);
 
   /**
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -12,32 +12,36 @@
 #include "nsPresContext.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
+#include "mozilla/unused.h"
+#include "mozilla/dom/TabParent.h"
 
 using namespace mozilla::widget;
 
 namespace mozilla {
 
 #define IDEOGRAPHIC_SPACE (NS_LITERAL_STRING("\x3000"))
 
 /******************************************************************************
  * TextComposition
  ******************************************************************************/
 
 TextComposition::TextComposition(nsPresContext* aPresContext,
                                  nsINode* aNode,
+                                 TabParent* aTabParent,
                                  WidgetCompositionEvent* aCompositionEvent)
   : mPresContext(aPresContext)
   , mNode(aNode)
+  , mTabParent(aTabParent)
   , mNativeContext(
       aCompositionEvent->widget->GetInputContext().mNativeIMEContext)
   , mCompositionStartOffset(0)
   , mCompositionTargetOffset(0)
   , mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
   , mIsComposing(false)
   , mIsEditorHandlingEvent(false)
   , mIsRequestingCommit(false)
@@ -50,16 +54,17 @@ TextComposition::TextComposition(nsPresC
 {
 }
 
 void
 TextComposition::Destroy()
 {
   mPresContext = nullptr;
   mNode = nullptr;
+  mTabParent = nullptr;
   // TODO: If the editor is still alive and this is held by it, we should tell
   //       this being destroyed for cleaning up the stuff.
 }
 
 bool
 TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
 {
   return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
@@ -72,16 +77,18 @@ TextComposition::IsValidStateForComposit
          mPresContext->GetPresShell() &&
          !mPresContext->GetPresShell()->IsDestroying();
 }
 
 bool
 TextComposition::MaybeDispatchCompositionUpdate(
                    const WidgetCompositionEvent* aCompositionEvent)
 {
+  MOZ_RELEASE_ASSERT(!mTabParent);
+
   if (!IsValidStateForComposition(aCompositionEvent->widget)) {
     return false;
   }
 
   if (mLastData == aCompositionEvent->mData) {
     return true;
   }
   CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_UPDATE);
@@ -90,16 +97,18 @@ TextComposition::MaybeDispatchCompositio
 
 BaseEventFlags
 TextComposition::CloneAndDispatchAs(
                    const WidgetCompositionEvent* aCompositionEvent,
                    uint32_t aMessage,
                    nsEventStatus* aStatus,
                    EventDispatchingCallback* aCallBack)
 {
+  MOZ_RELEASE_ASSERT(!mTabParent);
+
   MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
              "Should be called only when it's safe to dispatch an event");
 
   WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted,
                                           aMessage, aCompositionEvent->widget);
   compositionEvent.time = aCompositionEvent->time;
   compositionEvent.timeStamp = aCompositionEvent->timeStamp;
   compositionEvent.mData = aCompositionEvent->mData;
@@ -113,24 +122,29 @@ TextComposition::CloneAndDispatchAs(
   }
   EventDispatcher::Dispatch(mNode, mPresContext,
                             &compositionEvent, nullptr, status, aCallBack);
   return compositionEvent.mFlags;
 }
 
 void
 TextComposition::OnCompositionEventDiscarded(
-                   const WidgetCompositionEvent* aCompositionEvent)
+                   WidgetCompositionEvent* aCompositionEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
 
   MOZ_ASSERT(aCompositionEvent->mFlags.mIsTrusted,
              "Shouldn't be called with untrusted event");
 
+  if (mTabParent) {
+    // The composition event should be discarded in the child process too.
+    unused << mTabParent->SendCompositionEvent(*aCompositionEvent);
+  }
+
   // XXX If composition events are discarded, should we dispatch them with
   //     runnable event?  However, even if we do so, it might make native IME
   //     confused due to async modification.  Especially when native IME is
   //     TSF.
   if (!aCompositionEvent->CausesDOMCompositionEndEvent()) {
     return;
   }
 
@@ -193,16 +207,31 @@ RemoveControlCharactersFrom(nsAString& a
 
 void
 TextComposition::DispatchCompositionEvent(
                    WidgetCompositionEvent* aCompositionEvent,
                    nsEventStatus* aStatus,
                    EventDispatchingCallback* aCallBack,
                    bool aIsSynthesized)
 {
+  // If the content is a container of TabParent, composition should be in the
+  // remote process.
+  if (mTabParent) {
+    unused << mTabParent->SendCompositionEvent(*aCompositionEvent);
+    aCompositionEvent->mFlags.mPropagationStopped = true;
+    if (aCompositionEvent->CausesDOMTextEvent()) {
+      mLastData = aCompositionEvent->mData;
+      // Although, the composition event hasn't been actually handled yet,
+      // emulate an editor to be handling the composition event.
+      EditorWillHandleCompositionChangeEvent(aCompositionEvent);
+      EditorDidHandleCompositionChangeEvent();
+    }
+    return;
+  }
+
   if (!mAllowControlCharacters) {
     RemoveControlCharactersFrom(aCompositionEvent->mData,
                                 aCompositionEvent->mRanges);
   }
   if (aCompositionEvent->message == NS_COMPOSITION_COMMIT_AS_IS) {
     NS_ASSERTION(!aCompositionEvent->mRanges,
                  "mRanges of NS_COMPOSITION_COMMIT_AS_IS should be null");
     aCompositionEvent->mRanges = nullptr;
@@ -344,16 +373,18 @@ TextComposition::DispatchCompositionEven
   // Notify composition update to widget if possible
   NotityUpdateComposition(aCompositionEvent);
 }
 
 void
 TextComposition::NotityUpdateComposition(
                    const WidgetCompositionEvent* aCompositionEvent)
 {
+  MOZ_RELEASE_ASSERT(!mTabParent);
+
   nsEventStatus status;
 
   // When compositon start, notify the rect of first offset character.
   // When not compositon start, notify the rect of selected composition
   // string if compositionchange event.
   if (aCompositionEvent->message == NS_COMPOSITION_START) {
     nsCOMPtr<nsIWidget> widget = mPresContext->GetRootWidget();
     // Update composition start offset
@@ -460,16 +491,18 @@ TextComposition::EditorWillHandleComposi
   MOZ_ASSERT(mLastData == aCompositionChangeEvent->mData,
     "The text of a compositionchange event must be same as previous data "
     "attribute value of the latest compositionupdate event");
 }
 
 void
 TextComposition::OnEditorDestroyed()
 {
+  MOZ_RELEASE_ASSERT(!mTabParent);
+
   MOZ_ASSERT(!mIsEditorHandlingEvent,
              "The editor should have stopped listening events");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (NS_WARN_IF(!widget)) {
     // XXX If this could happen, how do we notify IME of destroying the editor?
     return;
   }
 
@@ -482,23 +515,27 @@ TextComposition::EditorDidHandleComposit
 {
   mString = mLastData;
   mIsEditorHandlingEvent = false;
 }
 
 void
 TextComposition::StartHandlingComposition(nsIEditor* aEditor)
 {
+  MOZ_RELEASE_ASSERT(!mTabParent);
+
   MOZ_ASSERT(!HasEditor(), "There is a handling editor already");
   mEditorWeak = do_GetWeakReference(aEditor);
 }
 
 void
 TextComposition::EndHandlingComposition(nsIEditor* aEditor)
 {
+  MOZ_RELEASE_ASSERT(!mTabParent);
+
 #ifdef DEBUG
   nsCOMPtr<nsIEditor> editor = GetEditor();
   MOZ_ASSERT(editor == aEditor, "Another editor handled the composition?");
 #endif // #ifdef DEBUG
   mEditorWeak = nullptr;
 }
 
 already_AddRefed<nsIEditor>
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -12,16 +12,17 @@
 #include "nsIWeakReference.h"
 #include "nsIWidget.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 #include "nsPresContext.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/TextRange.h"
+#include "mozilla/dom/TabParent.h"
 
 class nsIEditor;
 
 namespace mozilla {
 
 class EventDispatchingCallback;
 class IMEStateManager;
 
@@ -33,18 +34,21 @@ class IMEStateManager;
 
 class TextComposition final
 {
   friend class IMEStateManager;
 
   NS_INLINE_DECL_REFCOUNTING(TextComposition)
 
 public:
+  typedef dom::TabParent TabParent;
+
   TextComposition(nsPresContext* aPresContext,
                   nsINode* aNode,
+                  TabParent* aTabParent,
                   WidgetCompositionEvent* aCompositionEvent);
 
   bool Destroyed() const { return !mPresContext; }
   nsPresContext* GetPresContext() const { return mPresContext; }
   nsINode* GetEventTargetNode() const { return mNode; }
   // The latest CompositionEvent.data value except compositionstart event.
   // This value is modified at dispatching compositionupdate.
   const nsString& LastData() const { return mLastData; }
@@ -168,16 +172,17 @@ private:
   }
 
   // This class holds nsPresContext weak.  This instance shouldn't block
   // destroying it.  When the presContext is being destroyed, it's notified to
   // IMEStateManager::OnDestroyPresContext(), and then, it destroy
   // this instance.
   nsPresContext* mPresContext;
   nsCOMPtr<nsINode> mNode;
+  nsRefPtr<TabParent> mTabParent;
 
   // This is the clause and caret range information which is managed by
   // the focused editor.  This may be null if there is no clauses or caret.
   nsRefPtr<TextRangeArray> mRanges;
 
   // mNativeContext stores a opaque pointer.  This works as the "ID" for this
   // composition.  Don't access the instance, it may not be available.
   void* mNativeContext;
@@ -309,18 +314,17 @@ private:
     return mWasNativeCompositionEndEventDiscarded;
   }
 
   /**
    * OnCompositionEventDiscarded() is called when PresShell discards
    * compositionupdate, compositionend or compositionchange event due to not
    * safe to dispatch event.
    */
-  void OnCompositionEventDiscarded(
-         const WidgetCompositionEvent* aCompositionEvent);
+  void OnCompositionEventDiscarded(WidgetCompositionEvent* aCompositionEvent);
 
   /**
    * Calculate composition offset then notify composition update to widget
    */
   void NotityUpdateComposition(const WidgetCompositionEvent* aCompositionEvent);
 
   /**
    * CompositionEventDispatcher dispatches the specified composition (or text)