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 208525 3c8da0709f07151e0447389ad1ff641ec28fff7f
parent 208524 16998eb738aa34b9206b8ca47ee35c7c21fd8116
child 208526 f784b7a2d71804c03c32a15516b7df6ec2f555a4
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerssmaug
bugs975383
milestone35.0a1
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,