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 245653 d4a4025d966e9142b1f74bbe95a8eddedbb05e55
parent 245652 0ecd4281ab79b5e9c32d366fe1b2476a238a6b40
child 245654 59a6bef031e2bf00635ba955f13d580f78cf3626
push id13177
push userkwierso@gmail.com
push dateTue, 26 May 2015 23:26:28 +0000
treeherderfx-team@b991cd5a0ad1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1167022
milestone41.0a1
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;