Bug 975383 part.1 TextComposition should dispatch compositionupdate event automatically if text event changes composition string r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 03 Oct 2014 15:33:47 +0900
changeset 231740 3c8da0709f07151e0447389ad1ff641ec28fff7f
parent 231739 16998eb738aa34b9206b8ca47ee35c7c21fd8116
child 231741 f784b7a2d71804c03c32a15516b7df6ec2f555a4
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs975383
milestone35.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 975383 part.1 TextComposition should dispatch compositionupdate event automatically if text event changes composition string r=smaug
dom/base/nsDOMWindowUtils.cpp
dom/events/IMEStateManager.cpp
dom/events/TextComposition.cpp
dom/events/TextComposition.h
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2112,17 +2112,24 @@ nsDOMWindowUtils::SendCompositionEvent(c
   }
 
   uint32_t msg;
   if (aType.EqualsLiteral("compositionstart")) {
     msg = NS_COMPOSITION_START;
   } else if (aType.EqualsLiteral("compositionend")) {
     msg = NS_COMPOSITION_END;
   } else if (aType.EqualsLiteral("compositionupdate")) {
-    msg = NS_COMPOSITION_UPDATE;
+    // Now we don't support manually dispatching composition update with this
+    // API.  compositionupdate is dispatched when text event modifies
+    // composition string automatically.  For backward compatibility, this
+    // shouldn't return error in this case.
+    NS_WARNING("Don't call nsIDOMWindowUtils.sendCompositionEvent() for "
+               "compositionupdate since it's ignored and the event is "
+               "fired automatically when it's necessary");
+    return NS_OK;
   } else {
     return NS_ERROR_FAILURE;
   }
 
   WidgetCompositionEvent compositionEvent(true, msg, widget);
   InitEvent(compositionEvent);
   if (msg != NS_COMPOSITION_START) {
     compositionEvent.data = aData;
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -903,16 +903,21 @@ IMEStateManager::DispatchCompositionEven
      GetBoolName(aIsSynthesized)));
 
   MOZ_ASSERT(aEvent->mClass == eCompositionEventClass ||
              aEvent->mClass == eTextEventClass);
   if (!aEvent->mFlags.mIsTrusted || aEvent->mFlags.mPropagationStopped) {
     return;
   }
 
+  // Temporarily, let's ignore compositionupdate event from widget.
+  if (aEvent->message == NS_COMPOSITION_UPDATE) {
+    return;
+  }
+
   EnsureTextCompositionArray();
 
   WidgetGUIEvent* GUIEvent = aEvent->AsGUIEvent();
 
   nsRefPtr<TextComposition> composition =
     sTextCompositions->GetCompositionFor(GUIEvent->widget);
   if (!composition) {
     // If synthesized event comes after delayed native composition events
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -76,26 +76,19 @@ TextComposition::MaybeDispatchCompositio
                                            aEvent->widget);
   compositionUpdate.time = aEvent->time;
   compositionUpdate.timeStamp = aEvent->timeStamp;
   compositionUpdate.data = aEvent->theText;
   compositionUpdate.mFlags.mIsSynthesizedForTests =
     aEvent->mFlags.mIsSynthesizedForTests;
 
   nsEventStatus status = nsEventStatus_eConsumeNoDefault;
-  if (aEvent->mFlags.mIsSynthesizedForTests &&
-      (mIsRequestingCommit || mIsRequestingCancel)) {
-    // At emulating commit/cancel request, compositionupdate should be
-    // dispatched via widget since it's more similar path to native event.
-    aEvent->widget->DispatchEvent(&compositionUpdate, status);
-  } else {
-    mLastData = compositionUpdate.data;
-    EventDispatcher::Dispatch(mNode, mPresContext,
-                              &compositionUpdate, nullptr, &status, nullptr);
-  }
+  mLastData = compositionUpdate.data;
+  EventDispatcher::Dispatch(mNode, mPresContext,
+                            &compositionUpdate, nullptr, &status, nullptr);
   return !Destroyed();
 }
 
 void
 TextComposition::OnCompositionEventDiscarded(const WidgetGUIEvent* aEvent)
 {
   // Note that this method is never called for synthesized events for emulating
   // commit or cancel composition.
@@ -147,17 +140,16 @@ TextComposition::DispatchEvent(WidgetGUI
   // They typically tell us an IDEOGRAPHIC SPACE or empty string as composition
   // string.  Therefore, we should hack it only when:
   // 1. committing string is empty string at requesting commit but the last
   //    data isn't IDEOGRAPHIC SPACE.
   // 2. non-empty string is committed at requesting cancel.
   if (!aIsSynthesized && (mIsRequestingCommit || mIsRequestingCancel)) {
     nsString* committingData = nullptr;
     switch (aEvent->message) {
-      case NS_COMPOSITION_UPDATE:
       case NS_COMPOSITION_END:
         committingData = &aEvent->AsCompositionEvent()->data;
         break;
       case NS_TEXT_TEXT:
         committingData = &aEvent->AsTextEvent()->theText;
         break;
       default:
         NS_WARNING("Unexpected event comes during committing or "
@@ -166,36 +158,23 @@ TextComposition::DispatchEvent(WidgetGUI
     }
     if (committingData) {
       if (mIsRequestingCommit && committingData->IsEmpty() &&
           mLastData != IDEOGRAPHIC_SPACE) {
         committingData->Assign(mLastData);
       } else if (mIsRequestingCancel && !committingData->IsEmpty()) {
         committingData->Truncate();
       }
-
-      if (aEvent->message == NS_COMPOSITION_UPDATE) {
-        // If committing string is not different from the last data,
-        // we don't need to dispatch this.
-        if (committingData->Equals(mLastData)) {
-          return;
-        }
-      } else if (aEvent->message == NS_TEXT_TEXT) {
-        // If committing string is different from the last data,
-        // we need to dispatch compositionupdate before dispatching text event.
-        if (!MaybeDispatchCompositionUpdate(aEvent->AsTextEvent())) {
-          NS_WARNING("Dispatching compositionupdate caused destroying");
-          return;
-        }
-      }
     }
   }
 
-  if (aEvent->message == NS_COMPOSITION_UPDATE) {
-    mLastData = aEvent->AsCompositionEvent()->data;
+  if (aEvent->message == NS_TEXT_TEXT) {
+    if (!MaybeDispatchCompositionUpdate(aEvent->AsTextEvent())) {
+      return;
+    }
   }
 
   EventDispatcher::Dispatch(mNode, mPresContext,
                             aEvent, nullptr, aStatus, aCallBack);
 
   if (NS_WARN_IF(Destroyed())) {
     return;
   }
@@ -336,25 +315,21 @@ TextComposition::RequestToCommit(nsIWidg
 
   // If the request is performed synchronously, this must be already destroyed.
   if (Destroyed()) {
     return NS_OK;
   }
 
   // Otherwise, synthesize the commit in content.
   nsAutoString data(aDiscard ? EmptyString() : lastData);
-  bool changingData = lastData != data;
-  if (changingData) {
-    DispatchCompositionEventRunnable(NS_COMPOSITION_UPDATE, data, true);
-  }
   // If the last composition string and new data are different, we need to
   // dispatch text event for removing IME selection.  However, if the commit
   // string is empty string and it's not changed from the last data, we don't
   // need to dispatch text event.
-  if (changingData || !data.IsEmpty()) {
+  if (lastData != data || !data.IsEmpty()) {
     DispatchCompositionEventRunnable(NS_TEXT_TEXT, data, true);
   }
   DispatchCompositionEventRunnable(NS_COMPOSITION_END, data, true);
 
   return NS_OK;
 }
 
 nsresult
@@ -463,17 +438,16 @@ TextComposition::CompositionEventDispatc
       compStart.data = selectedText.mReply.mString;
       compStart.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compStart, &status, nullptr,
                                                 mIsSynthesizedEvent);
       break;
     }
-    case NS_COMPOSITION_UPDATE:
     case NS_COMPOSITION_END: {
       WidgetCompositionEvent compEvent(true, mEventMessage, widget);
       compEvent.data = mData;
       compEvent.mFlags.mIsSynthesizedForTests =
         mTextComposition->IsSynthesizedForTests();
       IMEStateManager::DispatchCompositionEvent(mEventTarget, presContext,
                                                 &compEvent, &status, nullptr,
                                                 mIsSynthesizedEvent);
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -309,17 +309,17 @@ private:
    * DispatchCompositionEventRunnable() dispatches a composition or text event
    * to the content.  Be aware, if you use this method, nsPresShellEventCB
    * isn't used.  That means that nsIFrame::HandleEvent() is never called.
    * WARNING: The instance which is managed by IMEStateManager may be
    *          destroyed by this method call.
    *
    * @param aEventMessage       Must be one of composition event or text event.
    * @param aData               Used for data value if aEventMessage is
-   *                            NS_COMPOSITION_UPDATE or NS_COMPOSITION_END.
+   *                            NS_COMPOSITION_END.
    *                            Used for theText value if aEventMessage is
    *                            NS_TEXT_TEXT.
    * @param aIsSynthesizingCommit   true if this is called for synthesizing
    *                                commit or cancel composition.  Otherwise,
    *                                false.
    */
   void DispatchCompositionEventRunnable(uint32_t aEventMessage,
                                         const nsAString& aData,