Bug 917322 part.8 TextEventDispatcher should start composition automatically even if StartComposition() isn't called explicitly r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 28 Jan 2015 15:27:31 +0900
changeset 226214 a80685d0ff6f1766090a9dc3aa995b4f0cc7847f
parent 226213 994fee1e166c6a7a9ba0a8b33366b886067f47d1
child 226215 0458d8e6291e3f2c4039fa02f874fba357f1637b
push id28187
push usercbook@mozilla.com
push dateWed, 28 Jan 2015 13:20:48 +0000
treeherdermozilla-central@fc21937ca612 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs917322
milestone38.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 917322 part.8 TextEventDispatcher should start composition automatically even if StartComposition() isn't called explicitly r=smaug
widget/TextEventDispatcher.cpp
widget/TextEventDispatcher.h
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -101,31 +101,74 @@ TextEventDispatcher::StartComposition(ns
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
+TextEventDispatcher::StartCompositionAutomaticallyIfNecessary(
+                       nsEventStatus& aStatus)
+{
+  if (IsComposing()) {
+    return NS_OK;
+  }
+
+  nsresult rv = StartComposition(aStatus);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // If started composition has already been committed, we shouldn't dispatch
+  // the compositionchange event.
+  if (!IsComposing()) {
+    aStatus = nsEventStatus_eConsumeNoDefault;
+    return NS_OK;
+  }
+
+  // Note that the widget might be destroyed during a call of
+  // StartComposition().  In such case, we shouldn't keep dispatching next
+  // event.
+  rv = GetState();
+  if (NS_FAILED(rv)) {
+    MOZ_ASSERT(rv != NS_ERROR_NOT_INITIALIZED,
+               "aDispatcher must still be initialized in this case");
+    aStatus = nsEventStatus_eConsumeNoDefault;
+    return NS_OK; // Don't throw exception in this case
+  }
+
+  aStatus = nsEventStatus_eIgnore;
+  return NS_OK;
+}
+
+nsresult
 TextEventDispatcher::CommitComposition(nsEventStatus& aStatus,
                                        const nsAString* aCommitString)
 {
   aStatus = nsEventStatus_eIgnore;
 
   nsresult rv = GetState();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  nsCOMPtr<nsIWidget> widget(mWidget);
+  rv = StartCompositionAutomaticallyIfNecessary(aStatus);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (aStatus == nsEventStatus_eConsumeNoDefault) {
+    return NS_OK;
+  }
+
   // End current composition and make this free for other IMEs.
   mIsComposing = false;
   mInitialized = false;
 
-  nsCOMPtr<nsIWidget> widget(mWidget);
   uint32_t message = aCommitString ? NS_COMPOSITION_COMMIT :
                                      NS_COMPOSITION_COMMIT_AS_IS;
   WidgetCompositionEvent compositionCommitEvent(true, message, widget);
   InitEvent(compositionCommitEvent);
   if (message == NS_COMPOSITION_COMMIT) {
     compositionCommitEvent.mData = *aCommitString;
   }
   rv = widget->DispatchEvent(&compositionCommitEvent, aStatus);
@@ -223,19 +266,18 @@ TextEventDispatcher::PendingComposition:
 {
   mCaret.mStartOffset = aOffset;
   mCaret.mEndOffset = mCaret.mStartOffset + aLength;
   mCaret.mRangeType = NS_TEXTRANGE_CARETPOSITION;
   return NS_OK;
 }
 
 nsresult
-TextEventDispatcher::PendingComposition::Flush(
-                       const TextEventDispatcher* aDispatcher,
-                       nsEventStatus& aStatus)
+TextEventDispatcher::PendingComposition::Flush(TextEventDispatcher* aDispatcher,
+                                               nsEventStatus& aStatus)
 {
   aStatus = nsEventStatus_eIgnore;
 
   nsresult rv = aDispatcher->GetState();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -265,16 +307,24 @@ TextEventDispatcher::PendingComposition:
                "mClauses must be non-empty array when it's not nullptr");
     compChangeEvent.mRanges = mClauses;
   }
 
   // While this method dispatches a composition event, some other event handler
   // cause more clauses to be added.  So, we should clear pending composition
   // before dispatching the event.
   Clear();
+
+  rv = aDispatcher->StartCompositionAutomaticallyIfNecessary(aStatus);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (aStatus == nsEventStatus_eConsumeNoDefault) {
+    return NS_OK;
+  }
   rv = widget->DispatchEvent(&compChangeEvent, aStatus);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   return NS_OK;
 }
 
--- a/widget/TextEventDispatcher.h
+++ b/widget/TextEventDispatcher.h
@@ -161,18 +161,17 @@ private:
   // automatically.
   class PendingComposition
   {
   public:
     PendingComposition();
     nsresult SetString(const nsAString& aString);
     nsresult AppendClause(uint32_t aLength, uint32_t aAttribute);
     nsresult SetCaret(uint32_t aOffset, uint32_t aLength);
-    nsresult Flush(const TextEventDispatcher* aDispatcher,
-                   nsEventStatus& aStatus);
+    nsresult Flush(TextEventDispatcher* aDispatcher, nsEventStatus& aStatus);
     void Clear();
 
   private:
     nsAutoString mString;
     nsRefPtr<TextRangeArray> mClauses;
     TextRange mCaret;
 
     void EnsureClauseArray();
@@ -184,14 +183,30 @@ private:
   // See IsComposing().
   bool mIsComposing;
 
   /**
    * InitEvent() initializes aEvent.  This must be called before dispatching
    * the event.
    */
   void InitEvent(WidgetCompositionEvent& aEvent) const;
+
+  /**
+   * StartCompositionAutomaticallyIfNecessary() starts composition if it hasn't
+   * been started it yet.
+   *
+   * @param aStatus         If it succeeded to start composition normally, this
+   *                        returns nsEventStatus_eIgnore.  Otherwise, e.g.,
+   *                        the composition is canceled during dispatching
+   *                        compositionstart event, this returns
+   *                        nsEventStatus_eConsumeNoDefault.  In this case,
+   *                        the caller shouldn't keep doing its job.
+   * @return                Only when something unexpected occurs, this returns
+   *                        an error.  Otherwise, returns NS_OK even if aStatus
+   *                        is nsEventStatus_eConsumeNoDefault.
+   */
+  nsresult StartCompositionAutomaticallyIfNecessary(nsEventStatus& aStatus);
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // #ifndef mozilla_widget_textcompositionsynthesizer_h_