Bug 1167022 part.1 Make IMEContentObserver possible to restart to observe editor root node r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 26 May 2015 16:45:26 +0900
changeset 277996 d4a4025d966e9142b1f74bbe95a8eddedbb05e55
parent 277995 0ecd4281ab79b5e9c32d366fe1b2476a238a6b40
child 277997 59a6bef031e2bf00635ba955f13d580f78cf3626
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1167022
milestone41.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 1167022 part.1 Make IMEContentObserver possible to restart to observe editor root node r=smaug
dom/events/IMEContentObserver.cpp
dom/events/IMEContentObserver.h
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -38,17 +38,18 @@ namespace mozilla {
 
 using namespace widget;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
   nsAutoScriptBlocker scriptBlocker;
 
-  tmp->UnregisterObservers(true);
+  tmp->NotifyIMEOfBlur(true);
+  tmp->UnregisterObservers();
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mWidget)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelection)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootContent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditableNode)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditor)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndOfAddedTextCache.mContainerNode)
@@ -99,21 +100,36 @@ IMEContentObserver::IMEContentObserver()
 void
 IMEContentObserver::Init(nsIWidget* aWidget,
                          nsPresContext* aPresContext,
                          nsIContent* aContent,
                          nsIEditor* aEditor)
 {
   MOZ_ASSERT(aEditor, "aEditor must not be null");
 
+  bool firstInitialization =
+    !(mRootContent && !mRootContent->IsInComposedDoc());
+  if (!firstInitialization) {
+    // If this is now trying to initialize with new contents, all observers
+    // should be registered again for simpler implementation.
+    UnregisterObservers();
+    // Clear members which may not be initialized again.
+    mRootContent = nullptr;
+    mEditor = nullptr;
+    mSelection = nullptr;
+    mDocShell = nullptr;
+  }
+
   mESM = aPresContext->EventStateManager();
   mESM->OnStartToObserveContent(this);
 
   mWidget = aWidget;
-  mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
+
+  mEditableNode =
+    IMEStateManager::GetRootEditableNode(aPresContext, aContent);
   if (!mEditableNode) {
     return;
   }
 
   mEditor = aEditor;
   mEditor->AddEditorObserver(this);
 
   nsIPresShell* presShell = aPresContext->PresShell();
@@ -149,29 +165,31 @@ IMEContentObserver::Init(nsIWidget* aWid
   }
   if (!mRootContent && mEditableNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // The document node is editable, but there are no contents, this document
     // is not editable.
     return;
   }
   NS_ENSURE_TRUE_VOID(mRootContent);
 
-  if (IMEStateManager::IsTestingIME()) {
-    nsIDocument* doc = aPresContext->Document();
-    (new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusIn"),
-                              false, false))->RunDOMEventWhenSafe();
-  }
+  if (firstInitialization) {
+    if (IMEStateManager::IsTestingIME()) {
+      nsIDocument* doc = aPresContext->Document();
+      (new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusIn"),
+                                false, false))->RunDOMEventWhenSafe();
+    }
 
-  aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
+    aWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS));
 
-  // NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
-  // instance via IMEStateManager::UpdateIMEState().  So, this
-  // instance might already have been destroyed, check it.
-  if (!mRootContent) {
-    return;
+    // NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
+    // instance via IMEStateManager::UpdateIMEState().  So, this
+    // instance might already have been destroyed, check it.
+    if (!mRootContent) {
+      return;
+    }
   }
 
   mDocShell = aPresContext->GetDocShell();
 
   ObserveEditableNode();
 }
 
 void
@@ -198,44 +216,50 @@ IMEContentObserver::ObserveEditableNode(
     // Add scroll position listener and reflow observer to detect position and
     // size changes
     mDocShell->AddWeakScrollObserver(this);
     mDocShell->AddWeakReflowObserver(this);
   }
 }
 
 void
-IMEContentObserver::UnregisterObservers(bool aPostEvent)
+IMEContentObserver::NotifyIMEOfBlur(bool aPostEvent)
+{
+  // If this failed to initialize, mRootContent may be null, then, we
+  // should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
+  if (!mRootContent || !mWidget) {
+    return;
+  }
+
+  if (IMEStateManager::IsTestingIME() && mEditableNode) {
+    nsIDocument* doc = mEditableNode->OwnerDoc();
+    if (doc) {
+      nsRefPtr<AsyncEventDispatcher> dispatcher =
+        new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusOut"),
+                                 false, false);
+      if (aPostEvent) {
+        dispatcher->PostDOMEvent();
+      } else {
+        dispatcher->RunDOMEventWhenSafe();
+      }
+    }
+  }
+  // A test event handler might destroy the widget.
+  if (mWidget) {
+    mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
+  }
+}
+
+void
+IMEContentObserver::UnregisterObservers()
 {
   if (mEditor) {
     mEditor->RemoveEditorObserver(this);
   }
 
-  // If CreateTextStateManager failed, mRootContent will be null, then, we
-  // should not call NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR))
-  if (mRootContent && mWidget) {
-    if (IMEStateManager::IsTestingIME() && mEditableNode) {
-      nsIDocument* doc = mEditableNode->OwnerDoc();
-      if (doc) {
-        nsRefPtr<AsyncEventDispatcher> dispatcher =
-          new AsyncEventDispatcher(doc, NS_LITERAL_STRING("MozIMEFocusOut"),
-                                   false, false);
-        if (aPostEvent) {
-          dispatcher->PostDOMEvent();
-        } else {
-          dispatcher->RunDOMEventWhenSafe();
-        }
-      }
-    }
-    // A test event handler might destroy the widget.
-    if (mWidget) {
-      mWidget->NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR));
-    }
-  }
-
   if (mUpdatePreference.WantSelectionChange() && mSelection) {
     nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
     if (selPrivate) {
       selPrivate->RemoveSelectionListener(this);
     }
   }
 
   if (mUpdatePreference.WantTextChange() && mRootContent) {
@@ -254,17 +278,18 @@ IMEContentObserver::GetPresContext() con
   return mESM ? mESM->GetPresContext() : nullptr;
 }
 
 void
 IMEContentObserver::Destroy()
 {
   // WARNING: When you change this method, you have to check Unlink() too.
 
-  UnregisterObservers(false);
+  NotifyIMEOfBlur(false);
+  UnregisterObservers();
 
   mEditor = nullptr;
   // Even if there are some pending notification, it'll never notify the widget.
   mWidget = nullptr;
   mSelection = nullptr;
   mRootContent = nullptr;
   mEditableNode = nullptr;
   mDocShell = nullptr;
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -135,21 +135,25 @@ private:
 
   void MaybeNotifyIMEOfTextChange(const TextChangeData& aTextChangeData);
   void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition);
   void MaybeNotifyIMEOfPositionChange();
 
   void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
   void ObserveEditableNode();
   /**
-   *  UnregisterObservers() unresiters all listeners and observers.
+   *  NotifyIMEOfBlur() notifies IME of blur.
    *  @param aPostEvent     When true, DOM event will be posted to the thread.
    *                        Otherwise, dispatched when safe.
    */
-  void UnregisterObservers(bool aPostEvent);
+  void NotifyIMEOfBlur(bool aPostEvent);
+  /**
+   *  UnregisterObservers() unregisters all listeners and observers.
+   */
+  void UnregisterObservers();
   void StoreTextChangeData(const TextChangeData& aTextChangeData);
   void FlushMergeableNotifications();
 
 #ifdef DEBUG
   void TestMergingTextChangeData();
 #endif
 
   nsCOMPtr<nsIWidget> mWidget;