Bug 975387 Notify TextComposition instance of that nsIMEStateManager stops managing it r=smaug, sec-a=abillings
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 25 Feb 2014 15:59:28 +0900
changeset 170685 f2fcc1dea68868d8b86aa5825cd474f3543c88f6
parent 170684 c5dc06a580e17a33353be1025e8620aa468eb697
child 170686 8c1eb349d342d617e50e44d50e75b4f041613fe8
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssmaug
bugs975387
milestone30.0a1
Bug 975387 Notify TextComposition instance of that nsIMEStateManager stops managing it r=smaug, sec-a=abillings
dom/events/TextComposition.cpp
dom/events/TextComposition.h
dom/events/nsIMEStateManager.cpp
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -30,16 +30,25 @@ TextComposition::TextComposition(nsPresC
   mPresContext(aPresContext), mNode(aNode),
   mNativeContext(aEvent->widget->GetInputContext().mNativeIMEContext),
   mCompositionStartOffset(0), mCompositionTargetOffset(0),
   mIsSynthesizedForTests(aEvent->mFlags.mIsSynthesizedForTests),
   mIsComposing(false)
 {
 }
 
+void
+TextComposition::Destroy()
+{
+  mPresContext = nullptr;
+  mNode = 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;
 }
 
 void
 TextComposition::DispatchEvent(WidgetGUIEvent* aEvent,
@@ -48,16 +57,20 @@ TextComposition::DispatchEvent(WidgetGUI
 {
   if (aEvent->message == NS_COMPOSITION_UPDATE) {
     mLastData = aEvent->AsCompositionEvent()->data;
   }
 
   nsEventDispatcher::Dispatch(mNode, mPresContext,
                               aEvent, nullptr, aStatus, aCallBack);
 
+  if (!mPresContext) {
+    return;
+  }
+
   // Emulate editor behavior of text event handler if no editor handles
   // composition/text events.
   if (aEvent->message == NS_TEXT_TEXT && !HasEditor()) {
     EditorWillHandleTextEvent(aEvent->AsTextEvent());
     EditorDidHandleTextEvent();
   }
 
 #ifdef DEBUG
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -40,16 +40,17 @@ public:
                   nsINode* aNode,
                   WidgetGUIEvent* aEvent);
 
   ~TextComposition()
   {
     // WARNING: mPresContext may be destroying, so, be careful if you touch it.
   }
 
+  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; }
   // The composition string which is already handled by the focused editor.
   // I.e., this value must be same as the composition string on the focused
   // editor.  This value is modified at a call of EditorDidHandleTextEvent().
@@ -58,16 +59,21 @@ public:
   const nsString& String() const { return mString; }
   // Returns true if the composition is started with synthesized event which
   // came from nsDOMWindowUtils.
   bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
 
   bool MatchesNativeContext(nsIWidget* aWidget) const;
 
   /**
+   * This is called when nsIMEStateManager stops managing the instance.
+   */
+  void Destroy();
+
+  /**
    * SynthesizeCommit() dispatches compositionupdate, text and compositionend
    * events for emulating commit on the content.
    *
    * @param aDiscard true when committing with empty string.  Otherwise, false.
    */
   void SynthesizeCommit(bool aDiscard);
 
   /**
--- a/dom/events/nsIMEStateManager.cpp
+++ b/dom/events/nsIMEStateManager.cpp
@@ -112,16 +112,17 @@ nsIMEStateManager::OnDestroyPresContext(
   NS_ENSURE_ARG_POINTER(aPresContext);
 
   // First, if there is a composition in the aPresContext, clean up it.
   if (sTextCompositions) {
     TextCompositionArray::index_type i =
       sTextCompositions->IndexOf(aPresContext);
     if (i != TextCompositionArray::NoIndex) {
       // there should be only one composition per presContext object.
+      sTextCompositions->ElementAt(i)->Destroy();
       sTextCompositions->RemoveElementAt(i);
       MOZ_ASSERT(sTextCompositions->IndexOf(aPresContext) ==
                    TextCompositionArray::NoIndex);
     }
   }
 
   if (aPresContext != sPresContext)
     return NS_OK;
@@ -574,16 +575,17 @@ nsIMEStateManager::DispatchCompositionEv
 
   // WARNING: the |composition| might have been destroyed already.
 
   // Remove the ended composition from the array.
   if (aEvent->message == NS_COMPOSITION_END) {
     TextCompositionArray::index_type i =
       sTextCompositions->IndexOf(GUIEvent->widget);
     if (i != TextCompositionArray::NoIndex) {
+      sTextCompositions->ElementAt(i)->Destroy();
       sTextCompositions->RemoveElementAt(i);
     }
   }
 }
 
 // static
 nsresult
 nsIMEStateManager::NotifyIME(IMEMessage aMessage,