Bug 1200980 part.4 nsPlaintextEditor should notify editor observers of the end of edit action when NS_COMPOSITION_CHANGE isn't followed by NS_COMPOSITION_END r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 08 Sep 2015 12:54:14 +0900
changeset 261268 48fe95399f05dae43cad3559f25dd2bfbdaa1dbb
parent 261267 62a79bc9cf9eb720a0f9cadf797a0186a54c253b
child 261269 cc22943628f46797ebb085567ed293f1cdf7018d
push id29339
push usercbook@mozilla.com
push dateTue, 08 Sep 2015 13:37:23 +0000
treeherdermozilla-central@b23b2fa33a9d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1200980
milestone43.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 1200980 part.4 nsPlaintextEditor should notify editor observers of the end of edit action when NS_COMPOSITION_CHANGE isn't followed by NS_COMPOSITION_END r=smaug
dom/events/TextComposition.cpp
editor/libeditor/nsEditor.cpp
editor/libeditor/nsPlaintextEditor.cpp
widget/TextEvents.h
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -109,16 +109,17 @@ TextComposition::CloneAndDispatchAs(
   MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
              "Should be called only when it's safe to dispatch an event");
 
   WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted,
                                           aMessage, aCompositionEvent->widget);
   compositionEvent.time = aCompositionEvent->time;
   compositionEvent.timeStamp = aCompositionEvent->timeStamp;
   compositionEvent.mData = aCompositionEvent->mData;
+  compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
   compositionEvent.mFlags.mIsSynthesizedForTests =
     aCompositionEvent->mFlags.mIsSynthesizedForTests;
 
   nsEventStatus dummyStatus = nsEventStatus_eConsumeNoDefault;
   nsEventStatus* status = aStatus ? aStatus : &dummyStatus;
   if (aMessage == NS_COMPOSITION_UPDATE) {
     mLastData = compositionEvent.mData;
   }
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -1852,16 +1852,19 @@ nsEditor::NotifyEditorObservers(Notifica
 
       if (!mDispatchInputEvent) {
         return;
       }
 
       FireInputEvent();
       break;
     case eNotifyEditorObserversOfBefore:
+      if (NS_WARN_IF(mIsInEditAction)) {
+        break;
+      }
       mIsInEditAction = true;
       for (auto& observer : observers) {
         observer->BeforeEditAction();
       }
       break;
     case eNotifyEditorObserversOfCancel:
       mIsInEditAction = false;
       for (auto& observer : observers) {
--- a/editor/libeditor/nsPlaintextEditor.cpp
+++ b/editor/libeditor/nsPlaintextEditor.cpp
@@ -880,20 +880,21 @@ nsPlaintextEditor::UpdateIMEComposition(
     rv = InsertText(compositionChangeEvent->mData);
 
     if (caretP) {
       caretP->SetSelection(selection);
     }
   }
 
   // If still composing, we should fire input event via observer.
-  // Note that if committed, we don't need to notify it since it will be
-  // notified at followed compositionend event.
+  // Note that if the composition will be committed by the following
+  // compositionend event, we don't need to notify editor observes of this
+  // change.
   // NOTE: We must notify after the auto batch will be gone.
-  if (IsIMEComposing()) {
+  if (!compositionChangeEvent->IsFollowedByCompositionEnd()) {
     NotifyEditorObservers(eNotifyEditorObserversOfEnd);
   }
 
   return rv;
 }
 
 already_AddRefed<nsIContent>
 nsPlaintextEditor::GetInputEventTargetContent()
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -360,16 +360,17 @@ public:
   virtual WidgetCompositionEvent* AsCompositionEvent() override
   {
     return this;
   }
 
   WidgetCompositionEvent(bool aIsTrusted, EventMessage aMessage,
                          nsIWidget* aWidget)
     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eCompositionEventClass)
+    , mOriginalMessage(eVoidEvent)
   {
     // XXX compositionstart is cancelable in draft of DOM3 Events.
     //     However, it doesn't make sense for us, we cannot cancel composition
     //     when we send compositionstart event.
     mFlags.mCancelable = false;
   }
 
   virtual WidgetEvent* Duplicate() const override
@@ -386,22 +387,27 @@ public:
 
   // The composition string or the commit string.  If the instance is a
   // compositionstart event, this is initialized with selected text by
   // TextComposition automatically.
   nsString mData;
 
   nsRefPtr<TextRangeArray> mRanges;
 
+  // If the instance is a clone of another event, mOriginalMessage stores
+  // the another event's mMessage.
+  EventMessage mOriginalMessage;
+
   void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
                                   bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
 
     mData = aEvent.mData;
+    mOriginalMessage = aEvent.mOriginalMessage;
 
     // Currently, we don't need to copy the other members because they are
     // for internal use only (not available from JS).
   }
 
   bool IsComposing() const
   {
     return mRanges && mRanges->IsComposing();
@@ -434,16 +440,22 @@ public:
   }
 
   bool CausesDOMCompositionEndEvent() const
   {
     return mMessage == NS_COMPOSITION_END ||
            mMessage == NS_COMPOSITION_COMMIT ||
            mMessage == NS_COMPOSITION_COMMIT_AS_IS;
   }
+
+  bool IsFollowedByCompositionEnd() const
+  {
+    return mOriginalMessage == NS_COMPOSITION_COMMIT ||
+           mOriginalMessage == NS_COMPOSITION_COMMIT_AS_IS;
+  }
 };
 
 /******************************************************************************
  * mozilla::WidgetQueryContentEvent
  ******************************************************************************/
 
 class WidgetQueryContentEvent : public WidgetGUIEvent
 {