Bug 1184890 part.1 SelectionChangeDataBase and TextChangeDataBase should have a flag which indicates whether the change occurred during composition or not r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 27 Oct 2015 07:21:37 +0900
changeset 303029 760b56778e5a427026377c5ac2170f56917a672c
parent 303028 d70472571f1d0313456c99d8f34e3ecbc9831cfe
child 303030 e23949bd2c042aa175f029112a26114c2ea6b558
push id5392
push userraliiev@mozilla.com
push dateMon, 14 Dec 2015 20:08:23 +0000
treeherdermozilla-beta@16ce8562a975 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1184890
milestone44.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 1184890 part.1 SelectionChangeDataBase and TextChangeDataBase should have a flag which indicates whether the change occurred during composition or not r=smaug
dom/events/IMEContentObserver.cpp
dom/events/IMEContentObserver.h
widget/IMEData.h
widget/nsBaseWidget.cpp
widget/nsGUIEventIPC.h
widget/windows/TSFTextStore.cpp
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -19,16 +19,17 @@
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
 #include "nsIAtom.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMRange.h"
+#include "nsIEditorIMESupport.h"
 #include "nsIFrame.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
 #include "nsISelectionController.h"
 #include "nsISelectionPrivate.h"
 #include "nsISupports.h"
 #include "nsIWidget.h"
 #include "nsPresContext.h"
@@ -584,16 +585,35 @@ IMEContentObserver::IsEditorHandlingEven
   RefPtr<TextComposition> composition =
     IMEStateManager::GetTextCompositionFor(mWidget);
   if (!composition) {
     return false;
   }
   return composition->IsEditorHandlingEvent();
 }
 
+bool
+IMEContentObserver::IsEditorComposing() const
+{
+  // Note that don't use TextComposition here. The important thing is,
+  // whether the editor already started to handle composition because
+  // web contents can change selection, text content and/or something from
+  // compositionstart event listener which is run before nsEditor handles it.
+  nsCOMPtr<nsIEditorIMESupport> editorIMESupport = do_QueryInterface(mEditor);
+  if (NS_WARN_IF(!editorIMESupport)) {
+    return false;
+  }
+  bool isComposing = false;
+  nsresult rv = editorIMESupport->GetComposing(&isComposing);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+  return isComposing;
+}
+
 nsresult
 IMEContentObserver::GetSelectionAndRoot(nsISelection** aSelection,
                                         nsIContent** aRootContent) const
 {
   if (!mEditableNode || !mSelection) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
@@ -609,18 +629,20 @@ IMEContentObserver::NotifySelectionChang
                                            int16_t aReason)
 {
   int32_t count = 0;
   nsresult rv = aSelection->GetRangeCount(&count);
   NS_ENSURE_SUCCESS(rv, rv);
   if (count > 0 && mWidget) {
     bool causedByComposition = IsEditorHandlingEventForComposition();
     bool causedBySelectionEvent = TextComposition::IsHandlingSelectionEvent();
+    bool duringComposition = IsEditorComposing();
     MaybeNotifyIMEOfSelectionChange(causedByComposition,
-                                    causedBySelectionEvent);
+                                    causedBySelectionEvent,
+                                    duringComposition);
   }
   return NS_OK;
 }
 
 void
 IMEContentObserver::ScrollPositionChanged()
 {
   MaybeNotifyIMEOfPositionChange();
@@ -820,17 +842,18 @@ IMEContentObserver::CharacterDataChanged
   uint32_t newLength =
     ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart,
                                              aInfo->mChangeStart +
                                                aInfo->mReplaceLength);
 
   uint32_t oldEnd = offset + static_cast<uint32_t>(removedLength);
   uint32_t newEnd = offset + newLength;
 
-  TextChangeData data(offset, oldEnd, newEnd, causedByComposition);
+  TextChangeData data(offset, oldEnd, newEnd, causedByComposition,
+                      IsEditorComposing());
   MaybeNotifyIMEOfTextChange(data);
 }
 
 void
 IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
                                        int32_t aStartIndex,
                                        int32_t aEndIndex)
 {
@@ -873,17 +896,17 @@ IMEContentObserver::NotifyContentAdded(n
   // before of it.
   mEndOfAddedTextCache.Cache(aContainer, aEndIndex, offset + addingLength);
 
   if (!addingLength) {
     return;
   }
 
   TextChangeData data(offset, offset, offset + addingLength,
-                      causedByComposition);
+                      causedByComposition, IsEditorComposing());
   MaybeNotifyIMEOfTextChange(data);
 }
 
 void
 IMEContentObserver::ContentAppended(nsIDocument* aDocument,
                                     nsIContent* aContainer,
                                     nsIContent* aFirstNewContent,
                                     int32_t aNewIndexInContainer)
@@ -950,17 +973,18 @@ IMEContentObserver::ContentRemoved(nsIDo
     mStartOfRemovingTextRangeCache.Clear();
     return;
   }
 
   if (!textLength) {
     return;
   }
 
-  TextChangeData data(offset, offset + textLength, offset, causedByComposition);
+  TextChangeData data(offset, offset + textLength, offset,
+                      causedByComposition, IsEditorComposing());
   MaybeNotifyIMEOfTextChange(data);
 }
 
 static nsIContent*
 GetContentBR(dom::Element* aElement)
 {
   if (!aElement->IsNodeOfType(nsINode::eCONTENT)) {
     return nullptr;
@@ -1012,17 +1036,18 @@ IMEContentObserver::AttributeChanged(nsI
   uint32_t start;
   nsresult rv =
     ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, content,
                                                   0, &start,
                                                   LINE_BREAK_TYPE_NATIVE);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   TextChangeData data(start, start + mPreAttrChangeLength,
-                      start + postAttrChangeLength, causedByComposition);
+                      start + postAttrChangeLength, causedByComposition,
+                      IsEditorComposing());
   MaybeNotifyIMEOfTextChange(data);
 }
 
 void
 IMEContentObserver::SuppressNotifyingIME()
 {
   mSuppressNotifications++;
 
@@ -1135,25 +1160,28 @@ IMEContentObserver::MaybeNotifyIMEOfText
   mTextChangeData += aTextChangeData;
   PostTextChangeNotification();
   FlushMergeableNotifications();
 }
 
 void
 IMEContentObserver::MaybeNotifyIMEOfSelectionChange(
                       bool aCausedByComposition,
-                      bool aCausedBySelectionEvent)
+                      bool aCausedBySelectionEvent,
+                      bool aOccurredDuringComposition)
 {
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
     ("IMECO: 0x%p IMEContentObserver::MaybeNotifyIMEOfSelectionChange("
-     "aCausedByComposition=%s, aCausedBySelectionEvent=%s)",
+     "aCausedByComposition=%s, aCausedBySelectionEvent=%s, "
+     "aOccurredDuringComposition)",
      this, ToChar(aCausedByComposition), ToChar(aCausedBySelectionEvent)));
 
   mSelectionData.AssignReason(aCausedByComposition,
-                              aCausedBySelectionEvent);
+                              aCausedBySelectionEvent,
+                              aOccurredDuringComposition);
   PostSelectionChangeNotification();
   FlushMergeableNotifications();
 }
 
 void
 IMEContentObserver::MaybeNotifyIMEOfPositionChange()
 {
   MOZ_LOG(sIMECOLog, LogLevel::Debug,
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -117,24 +117,26 @@ private:
                       nsIEditor* aEditor);
   bool InitWithPlugin(nsPresContext* aPresContext, nsIContent* aContent);
   bool IsInitializedWithPlugin() const { return !mEditor; }
   void Clear();
   bool IsObservingContent(nsPresContext* aPresContext,
                           nsIContent* aContent) const;
   bool IsReflowLocked() const;
   bool IsSafeToNotifyIME() const;
+  bool IsEditorComposing() const;
 
   void PostFocusSetNotification();
   void MaybeNotifyIMEOfFocusSet();
   void PostTextChangeNotification();
   void MaybeNotifyIMEOfTextChange(const TextChangeDataBase& aTextChangeData);
   void PostSelectionChangeNotification();
   void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition,
-                                       bool aCausedBySelectionEvent);
+                                       bool aCausedBySelectionEvent,
+                                       bool aOccurredDuringComposition);
   void PostPositionChangeNotification();
   void MaybeNotifyIMEOfPositionChange();
 
   void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
   void ObserveEditableNode();
   /**
    *  NotifyIMEOfBlur() notifies IME of blur.
    */
--- a/widget/IMEData.h
+++ b/widget/IMEData.h
@@ -549,16 +549,17 @@ struct IMENotification final
     nsString* mString;
 
     // Writing mode at the selection.
     uint8_t mWritingMode;
 
     bool mReversed;
     bool mCausedByComposition;
     bool mCausedBySelectionEvent;
+    bool mOccurredDuringComposition;
 
     void SetWritingMode(const WritingMode& aWritingMode);
     WritingMode GetWritingMode() const;
 
     uint32_t StartOffset() const
     {
       return mOffset + (mReversed ? Length() : 0);
     }
@@ -589,35 +590,39 @@ struct IMENotification final
       mWritingMode = 0;
       mReversed = false;
     }
     void Clear()
     {
       ClearSelectionData();
       mCausedByComposition = false;
       mCausedBySelectionEvent = false;
+      mOccurredDuringComposition = false;
     }
     bool IsValid() const
     {
       return mOffset != UINT32_MAX;
     }
     void Assign(const SelectionChangeDataBase& aOther)
     {
       mOffset = aOther.mOffset;
       *mString = aOther.String();
       mWritingMode = aOther.mWritingMode;
       mReversed = aOther.mReversed;
       AssignReason(aOther.mCausedByComposition,
-                   aOther.mCausedBySelectionEvent);
+                   aOther.mCausedBySelectionEvent,
+                   aOther.mOccurredDuringComposition);
     }
     void AssignReason(bool aCausedByComposition,
-                      bool aCausedBySelectionEvent)
+                      bool aCausedBySelectionEvent,
+                      bool aOccurredDuringComposition)
     {
       mCausedByComposition = aCausedByComposition;
       mCausedBySelectionEvent = aCausedBySelectionEvent;
+      mOccurredDuringComposition = aOccurredDuringComposition;
     }
   };
 
   // SelectionChangeDataBase cannot have constructors because it's used in
   // the union.  Therefore, SelectionChangeData should only implement
   // constructors.  In other words, add other members to
   // SelectionChangeDataBase.
   struct SelectionChangeData final : public SelectionChangeDataBase
@@ -665,16 +670,17 @@ struct IMENotification final
     // original content.  If the value is same as mStartOffset, no text hasn't
     // been removed yet.
     uint32_t mRemovedEndOffset;
     // mAddedEndOffset is the end offset of inserted text or same as
     // mStartOffset if just removed.  The vlaue is offset in the new content.
     uint32_t mAddedEndOffset;
 
     bool mCausedByComposition;
+    bool mOccurredDuringComposition;
 
     uint32_t OldLength() const
     {
       MOZ_ASSERT(IsValid());
       return mRemovedEndOffset - mStartOffset;
     }
     uint32_t NewLength() const
     {
@@ -725,26 +731,28 @@ struct IMENotification final
   // words, add other members to TextChangeDataBase.
   struct TextChangeData : public TextChangeDataBase
   {
     TextChangeData() { Clear(); }
 
     TextChangeData(uint32_t aStartOffset,
                    uint32_t aRemovedEndOffset,
                    uint32_t aAddedEndOffset,
-                   bool aCausedByComposition)
+                   bool aCausedByComposition,
+                   bool aOccurredDuringComposition)
     {
       MOZ_ASSERT(aRemovedEndOffset >= aStartOffset,
                  "removed end offset must not be smaller than start offset");
       MOZ_ASSERT(aAddedEndOffset >= aStartOffset,
                  "added end offset must not be smaller than start offset");
       mStartOffset = aStartOffset;
       mRemovedEndOffset = aRemovedEndOffset;
       mAddedEndOffset = aAddedEndOffset;
       mCausedByComposition = aCausedByComposition;
+      mOccurredDuringComposition = aOccurredDuringComposition;
     }
   };
 
   struct MouseButtonEventData
   {
     // The value of WidgetEvent::mMessage
     EventMessage mEventMessage;
     // Character offset from the start of the focused editor under the cursor
@@ -790,14 +798,26 @@ struct IMENotification final
       case NOTIFY_IME_OF_SELECTION_CHANGE:
         return mSelectionChangeData.mCausedByComposition;
       case NOTIFY_IME_OF_TEXT_CHANGE:
         return mTextChangeData.mCausedByComposition;
       default:
         return false;
     }
   }
+
+  bool OccurredDuringComposition() const
+  {
+    switch (mMessage) {
+      case NOTIFY_IME_OF_SELECTION_CHANGE:
+        return mSelectionChangeData.mOccurredDuringComposition;
+      case NOTIFY_IME_OF_TEXT_CHANGE:
+        return mTextChangeData.mOccurredDuringComposition;
+      default:
+        return false;
+    }
+  }
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // #ifndef mozilla_widget_IMEData_h_
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -2026,18 +2026,24 @@ IMENotification::TextChangeDataBase::Mer
   // adjusted to be in same text.  The |oldData.mAddedEndOffset| should be
   // computed as in the new text because |mAddedEndOffset| indicates the end
   // offset of inserted text in the new text but |oldData.mAddedEndOffset|
   // doesn't include any changes of the text before |newData.mAddedEndOffset|.
 
   const TextChangeDataBase& newData = aOther;
   const TextChangeDataBase oldData = *this;
 
+  // mCausedByComposition should be true only when all changes are caused by
+  // composition.
   mCausedByComposition =
     newData.mCausedByComposition && oldData.mCausedByComposition;
+  // mOccurredDuringComposition should be true only when all changes occurred
+  // during composition.
+  mOccurredDuringComposition =
+    newData.mOccurredDuringComposition && oldData.mOccurredDuringComposition;
 
   if (newData.mStartOffset >= oldData.mAddedEndOffset) {
     // Case 1:
     // If new start is after old end offset of added text, it means that text
     // after the modified range is modified.  Like:
     // added range of old change:             +----------+
     // removed range of new change:                           +----------+
     // So, the old start offset is always the smaller offset.
@@ -2183,437 +2189,437 @@ IMENotification::TextChangeDataBase::Tes
   }
   gTestTextChangeEvent = false;
 
   /****************************************************************************
    * Case 1
    ****************************************************************************/
 
   // Appending text
-  MergeWith(TextChangeData(10, 10, 20, false));
-  MergeWith(TextChangeData(20, 20, 35, false));
+  MergeWith(TextChangeData(10, 10, 20, false, false));
+  MergeWith(TextChangeData(20, 20, 35, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 1-1-1: mStartOffset should be the first offset");
   MOZ_ASSERT(mRemovedEndOffset == 10, // 20 - (20 - 10)
     "Test 1-1-2: mRemovedEndOffset should be the first end of removed text");
   MOZ_ASSERT(mAddedEndOffset == 35,
     "Test 1-1-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Removing text (longer line -> shorter line)
-  MergeWith(TextChangeData(10, 20, 10, false));
-  MergeWith(TextChangeData(10, 30, 10, false));
+  MergeWith(TextChangeData(10, 20, 10, false, false));
+  MergeWith(TextChangeData(10, 30, 10, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 1-2-1: mStartOffset should be the first offset");
   MOZ_ASSERT(mRemovedEndOffset == 40, // 30 + (10 - 20)
     "Test 1-2-2: mRemovedEndOffset should be the the last end of removed text "
     "with already removed length");
   MOZ_ASSERT(mAddedEndOffset == 10,
     "Test 1-2-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Removing text (shorter line -> longer line)
-  MergeWith(TextChangeData(10, 20, 10, false));
-  MergeWith(TextChangeData(10, 15, 10, false));
+  MergeWith(TextChangeData(10, 20, 10, false, false));
+  MergeWith(TextChangeData(10, 15, 10, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 1-3-1: mStartOffset should be the first offset");
   MOZ_ASSERT(mRemovedEndOffset == 25, // 15 + (10 - 20)
     "Test 1-3-2: mRemovedEndOffset should be the the last end of removed text "
     "with already removed length");
   MOZ_ASSERT(mAddedEndOffset == 10,
     "Test 1-3-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Appending text at different point (not sure if actually occurs)
-  MergeWith(TextChangeData(10, 10, 20, false));
-  MergeWith(TextChangeData(55, 55, 60, false));
+  MergeWith(TextChangeData(10, 10, 20, false, false));
+  MergeWith(TextChangeData(55, 55, 60, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 1-4-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 45, // 55 - (10 - 20)
     "Test 1-4-2: mRemovedEndOffset should be the the largest end of removed "
     "text without already added length");
   MOZ_ASSERT(mAddedEndOffset == 60,
     "Test 1-4-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Removing text at different point (not sure if actually occurs)
-  MergeWith(TextChangeData(10, 20, 10, false));
-  MergeWith(TextChangeData(55, 68, 55, false));
+  MergeWith(TextChangeData(10, 20, 10, false, false));
+  MergeWith(TextChangeData(55, 68, 55, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 1-5-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 78, // 68 - (10 - 20)
     "Test 1-5-2: mRemovedEndOffset should be the the largest end of removed "
     "text with already removed length");
   MOZ_ASSERT(mAddedEndOffset == 55,
     "Test 1-5-3: mAddedEndOffset should be the largest end of added text");
   Clear();
 
   // Replacing text and append text (becomes longer)
-  MergeWith(TextChangeData(30, 35, 32, false));
-  MergeWith(TextChangeData(32, 32, 40, false));
+  MergeWith(TextChangeData(30, 35, 32, false, false));
+  MergeWith(TextChangeData(32, 32, 40, false, false));
   MOZ_ASSERT(mStartOffset == 30,
     "Test 1-6-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 35, // 32 - (32 - 35)
     "Test 1-6-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 40,
     "Test 1-6-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text and append text (becomes shorter)
-  MergeWith(TextChangeData(30, 35, 32, false));
-  MergeWith(TextChangeData(32, 32, 33, false));
+  MergeWith(TextChangeData(30, 35, 32, false, false));
+  MergeWith(TextChangeData(32, 32, 33, false, false));
   MOZ_ASSERT(mStartOffset == 30,
     "Test 1-7-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 35, // 32 - (32 - 35)
     "Test 1-7-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 33,
     "Test 1-7-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Removing text and replacing text after first range (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(30, 35, 30, false));
-  MergeWith(TextChangeData(32, 34, 48, false));
+  MergeWith(TextChangeData(30, 35, 30, false, false));
+  MergeWith(TextChangeData(32, 34, 48, false, false));
   MOZ_ASSERT(mStartOffset == 30,
     "Test 1-8-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 39, // 34 - (30 - 35)
     "Test 1-8-2: mRemovedEndOffset should be the the first end of removed text "
     "without already removed text");
   MOZ_ASSERT(mAddedEndOffset == 48,
     "Test 1-8-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Removing text and replacing text after first range (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(30, 35, 30, false));
-  MergeWith(TextChangeData(32, 38, 36, false));
+  MergeWith(TextChangeData(30, 35, 30, false, false));
+  MergeWith(TextChangeData(32, 38, 36, false, false));
   MOZ_ASSERT(mStartOffset == 30,
     "Test 1-9-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 43, // 38 - (30 - 35)
     "Test 1-9-2: mRemovedEndOffset should be the the first end of removed text "
     "without already removed text");
   MOZ_ASSERT(mAddedEndOffset == 36,
     "Test 1-9-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   /****************************************************************************
    * Case 2
    ****************************************************************************/
 
   // Replacing text in around end of added text (becomes shorter) (not sure
   // if actually occurs)
-  MergeWith(TextChangeData(50, 50, 55, false));
-  MergeWith(TextChangeData(53, 60, 54, false));
+  MergeWith(TextChangeData(50, 50, 55, false, false));
+  MergeWith(TextChangeData(53, 60, 54, false, false));
   MOZ_ASSERT(mStartOffset == 50,
     "Test 2-1-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 55, // 60 - (55 - 50)
     "Test 2-1-2: mRemovedEndOffset should be the the last end of removed text "
     "without already added text length");
   MOZ_ASSERT(mAddedEndOffset == 54,
     "Test 2-1-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text around end of added text (becomes longer) (not sure
   // if actually occurs)
-  MergeWith(TextChangeData(50, 50, 55, false));
-  MergeWith(TextChangeData(54, 62, 68, false));
+  MergeWith(TextChangeData(50, 50, 55, false, false));
+  MergeWith(TextChangeData(54, 62, 68, false, false));
   MOZ_ASSERT(mStartOffset == 50,
     "Test 2-2-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 57, // 62 - (55 - 50)
     "Test 2-2-2: mRemovedEndOffset should be the the last end of removed text "
     "without already added text length");
   MOZ_ASSERT(mAddedEndOffset == 68,
     "Test 2-2-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text around end of replaced text (became shorter) (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(36, 48, 45, false));
-  MergeWith(TextChangeData(43, 50, 49, false));
+  MergeWith(TextChangeData(36, 48, 45, false, false));
+  MergeWith(TextChangeData(43, 50, 49, false, false));
   MOZ_ASSERT(mStartOffset == 36,
     "Test 2-3-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 53, // 50 - (45 - 48)
     "Test 2-3-2: mRemovedEndOffset should be the the last end of removed text "
     "without already removed text length");
   MOZ_ASSERT(mAddedEndOffset == 49,
     "Test 2-3-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text around end of replaced text (became longer) (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(36, 52, 53, false));
-  MergeWith(TextChangeData(43, 68, 61, false));
+  MergeWith(TextChangeData(36, 52, 53, false, false));
+  MergeWith(TextChangeData(43, 68, 61, false, false));
   MOZ_ASSERT(mStartOffset == 36,
     "Test 2-4-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 67, // 68 - (53 - 52)
     "Test 2-4-2: mRemovedEndOffset should be the the last end of removed text "
     "without already added text length");
   MOZ_ASSERT(mAddedEndOffset == 61,
     "Test 2-4-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   /****************************************************************************
    * Case 3
    ****************************************************************************/
 
   // Appending text in already added text (not sure if actually occurs)
-  MergeWith(TextChangeData(10, 10, 20, false));
-  MergeWith(TextChangeData(15, 15, 30, false));
+  MergeWith(TextChangeData(10, 10, 20, false, false));
+  MergeWith(TextChangeData(15, 15, 30, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 3-1-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 10,
     "Test 3-1-2: mRemovedEndOffset should be the the first end of removed text");
   MOZ_ASSERT(mAddedEndOffset == 35, // 20 + (30 - 15)
     "Test 3-1-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Replacing text in added text (not sure if actually occurs)
-  MergeWith(TextChangeData(50, 50, 55, false));
-  MergeWith(TextChangeData(52, 53, 56, false));
+  MergeWith(TextChangeData(50, 50, 55, false, false));
+  MergeWith(TextChangeData(52, 53, 56, false, false));
   MOZ_ASSERT(mStartOffset == 50,
     "Test 3-2-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 50,
     "Test 3-2-2: mRemovedEndOffset should be the the first end of removed text");
   MOZ_ASSERT(mAddedEndOffset == 58, // 55 + (56 - 53)
     "Test 3-2-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Replacing text in replaced text (became shorter) (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(36, 48, 45, false));
-  MergeWith(TextChangeData(37, 38, 50, false));
+  MergeWith(TextChangeData(36, 48, 45, false, false));
+  MergeWith(TextChangeData(37, 38, 50, false, false));
   MOZ_ASSERT(mStartOffset == 36,
     "Test 3-3-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 48,
     "Test 3-3-2: mRemovedEndOffset should be the the first end of removed text");
   MOZ_ASSERT(mAddedEndOffset == 57, // 45 + (50 - 38)
     "Test 3-3-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Replacing text in replaced text (became longer) (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(32, 48, 53, false));
-  MergeWith(TextChangeData(43, 50, 52, false));
+  MergeWith(TextChangeData(32, 48, 53, false, false));
+  MergeWith(TextChangeData(43, 50, 52, false, false));
   MOZ_ASSERT(mStartOffset == 32,
     "Test 3-4-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 48,
     "Test 3-4-2: mRemovedEndOffset should be the the last end of removed text "
     "without already added text length");
   MOZ_ASSERT(mAddedEndOffset == 55, // 53 + (52 - 50)
     "Test 3-4-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Replacing text in replaced text (became shorter) (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(36, 48, 50, false));
-  MergeWith(TextChangeData(37, 49, 47, false));
+  MergeWith(TextChangeData(36, 48, 50, false, false));
+  MergeWith(TextChangeData(37, 49, 47, false, false));
   MOZ_ASSERT(mStartOffset == 36,
     "Test 3-5-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 48,
     "Test 3-5-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 48, // 50 + (47 - 49)
     "Test 3-5-3: mAddedEndOffset should be the first end of added text without "
     "removed text length by the new change");
   Clear();
 
   // Replacing text in replaced text (became longer) (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(32, 48, 53, false));
-  MergeWith(TextChangeData(43, 50, 47, false));
+  MergeWith(TextChangeData(32, 48, 53, false, false));
+  MergeWith(TextChangeData(43, 50, 47, false, false));
   MOZ_ASSERT(mStartOffset == 32,
     "Test 3-6-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 48,
     "Test 3-6-2: mRemovedEndOffset should be the the last end of removed text "
     "without already added text length");
   MOZ_ASSERT(mAddedEndOffset == 50, // 53 + (47 - 50)
     "Test 3-6-3: mAddedEndOffset should be the first end of added text without "
     "removed text length by the new change");
   Clear();
 
   /****************************************************************************
    * Case 4
    ****************************************************************************/
 
   // Replacing text all of already append text (not sure if actually occurs)
-  MergeWith(TextChangeData(50, 50, 55, false));
-  MergeWith(TextChangeData(44, 66, 68, false));
+  MergeWith(TextChangeData(50, 50, 55, false, false));
+  MergeWith(TextChangeData(44, 66, 68, false, false));
   MOZ_ASSERT(mStartOffset == 44,
     "Test 4-1-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 61, // 66 - (55 - 50)
     "Test 4-1-2: mRemovedEndOffset should be the the last end of removed text "
     "without already added text length");
   MOZ_ASSERT(mAddedEndOffset == 68,
     "Test 4-1-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text around a point in which text was removed (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(50, 62, 50, false));
-  MergeWith(TextChangeData(44, 66, 68, false));
+  MergeWith(TextChangeData(50, 62, 50, false, false));
+  MergeWith(TextChangeData(44, 66, 68, false, false));
   MOZ_ASSERT(mStartOffset == 44,
     "Test 4-2-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 78, // 66 - (50 - 62)
     "Test 4-2-2: mRemovedEndOffset should be the the last end of removed text "
     "without already removed text length");
   MOZ_ASSERT(mAddedEndOffset == 68,
     "Test 4-2-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text all replaced text (became shorter) (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(50, 62, 60, false));
-  MergeWith(TextChangeData(49, 128, 130, false));
+  MergeWith(TextChangeData(50, 62, 60, false, false));
+  MergeWith(TextChangeData(49, 128, 130, false, false));
   MOZ_ASSERT(mStartOffset == 49,
     "Test 4-3-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 130, // 128 - (60 - 62)
     "Test 4-3-2: mRemovedEndOffset should be the the last end of removed text "
     "without already removed text length");
   MOZ_ASSERT(mAddedEndOffset == 130,
     "Test 4-3-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   // Replacing text all replaced text (became longer) (not sure if actually
   // occurs)
-  MergeWith(TextChangeData(50, 61, 73, false));
-  MergeWith(TextChangeData(44, 100, 50, false));
+  MergeWith(TextChangeData(50, 61, 73, false, false));
+  MergeWith(TextChangeData(44, 100, 50, false, false));
   MOZ_ASSERT(mStartOffset == 44,
     "Test 4-4-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 88, // 100 - (73 - 61)
     "Test 4-4-2: mRemovedEndOffset should be the the last end of removed text "
     "with already added text length");
   MOZ_ASSERT(mAddedEndOffset == 50,
     "Test 4-4-3: mAddedEndOffset should be the last end of added text");
   Clear();
 
   /****************************************************************************
    * Case 5
    ****************************************************************************/
 
   // Replacing text around start of added text (not sure if actually occurs)
-  MergeWith(TextChangeData(50, 50, 55, false));
-  MergeWith(TextChangeData(48, 52, 49, false));
+  MergeWith(TextChangeData(50, 50, 55, false, false));
+  MergeWith(TextChangeData(48, 52, 49, false, false));
   MOZ_ASSERT(mStartOffset == 48,
     "Test 5-1-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 50,
     "Test 5-1-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 52, // 55 + (52 - 49)
     "Test 5-1-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Replacing text around start of replaced text (became shorter) (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(50, 60, 58, false));
-  MergeWith(TextChangeData(43, 50, 48, false));
+  MergeWith(TextChangeData(50, 60, 58, false, false));
+  MergeWith(TextChangeData(43, 50, 48, false, false));
   MOZ_ASSERT(mStartOffset == 43,
     "Test 5-2-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 60,
     "Test 5-2-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 56, // 58 + (48 - 50)
     "Test 5-2-3: mAddedEndOffset should be the first end of added text without "
     "removed text length by the new change");
   Clear();
 
   // Replacing text around start of replaced text (became longer) (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(50, 60, 68, false));
-  MergeWith(TextChangeData(43, 55, 53, false));
+  MergeWith(TextChangeData(50, 60, 68, false, false));
+  MergeWith(TextChangeData(43, 55, 53, false, false));
   MOZ_ASSERT(mStartOffset == 43,
     "Test 5-3-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 60,
     "Test 5-3-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 66, // 68 + (53 - 55)
     "Test 5-3-3: mAddedEndOffset should be the first end of added text without "
     "removed text length by the new change");
   Clear();
 
   // Replacing text around start of replaced text (became shorter) (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(50, 60, 58, false));
-  MergeWith(TextChangeData(43, 50, 128, false));
+  MergeWith(TextChangeData(50, 60, 58, false, false));
+  MergeWith(TextChangeData(43, 50, 128, false, false));
   MOZ_ASSERT(mStartOffset == 43,
     "Test 5-4-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 60,
     "Test 5-4-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 136, // 58 + (128 - 50)
     "Test 5-4-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Replacing text around start of replaced text (became longer) (not sure if
   // actually occurs)
-  MergeWith(TextChangeData(50, 60, 68, false));
-  MergeWith(TextChangeData(43, 55, 65, false));
+  MergeWith(TextChangeData(50, 60, 68, false, false));
+  MergeWith(TextChangeData(43, 55, 65, false, false));
   MOZ_ASSERT(mStartOffset == 43,
     "Test 5-5-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 60,
     "Test 5-5-2: mRemovedEndOffset should be the the first end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 78, // 68 + (65 - 55)
     "Test 5-5-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   /****************************************************************************
    * Case 6
    ****************************************************************************/
 
   // Appending text before already added text (not sure if actually occurs)
-  MergeWith(TextChangeData(30, 30, 45, false));
-  MergeWith(TextChangeData(10, 10, 20, false));
+  MergeWith(TextChangeData(30, 30, 45, false, false));
+  MergeWith(TextChangeData(10, 10, 20, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 6-1-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 30,
     "Test 6-1-2: mRemovedEndOffset should be the the largest end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 55, // 45 + (20 - 10)
     "Test 6-1-3: mAddedEndOffset should be the first end of added text with "
     "added text length by the new change");
   Clear();
 
   // Removing text before already removed text (not sure if actually occurs)
-  MergeWith(TextChangeData(30, 35, 30, false));
-  MergeWith(TextChangeData(10, 25, 10, false));
+  MergeWith(TextChangeData(30, 35, 30, false, false));
+  MergeWith(TextChangeData(10, 25, 10, false, false));
   MOZ_ASSERT(mStartOffset == 10,
     "Test 6-2-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 35,
     "Test 6-2-2: mRemovedEndOffset should be the the largest end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 15, // 30 - (25 - 10)
     "Test 6-2-3: mAddedEndOffset should be the first end of added text with "
     "removed text length by the new change");
   Clear();
 
   // Replacing text before already replaced text (not sure if actually occurs)
-  MergeWith(TextChangeData(50, 65, 70, false));
-  MergeWith(TextChangeData(13, 24, 15, false));
+  MergeWith(TextChangeData(50, 65, 70, false, false));
+  MergeWith(TextChangeData(13, 24, 15, false, false));
   MOZ_ASSERT(mStartOffset == 13,
     "Test 6-3-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 65,
     "Test 6-3-2: mRemovedEndOffset should be the the largest end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 61, // 70 + (15 - 24)
     "Test 6-3-3: mAddedEndOffset should be the first end of added text without "
     "removed text length by the new change");
   Clear();
 
   // Replacing text before already replaced text (not sure if actually occurs)
-  MergeWith(TextChangeData(50, 65, 70, false));
-  MergeWith(TextChangeData(13, 24, 36, false));
+  MergeWith(TextChangeData(50, 65, 70, false, false));
+  MergeWith(TextChangeData(13, 24, 36, false, false));
   MOZ_ASSERT(mStartOffset == 13,
     "Test 6-4-1: mStartOffset should be the smallest offset");
   MOZ_ASSERT(mRemovedEndOffset == 65,
     "Test 6-4-2: mRemovedEndOffset should be the the largest end of removed "
     "text");
   MOZ_ASSERT(mAddedEndOffset == 82, // 70 + (36 - 24)
     "Test 6-4-3: mAddedEndOffset should be the first end of added text without "
     "removed text length by the new change");
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -730,49 +730,53 @@ struct ParamTraits<mozilla::widget::IMEN
   {
     MOZ_RELEASE_ASSERT(aParam.mString);
     WriteParam(aMsg, aParam.mOffset);
     WriteParam(aMsg, *aParam.mString);
     WriteParam(aMsg, aParam.mWritingMode);
     WriteParam(aMsg, aParam.mReversed);
     WriteParam(aMsg, aParam.mCausedByComposition);
     WriteParam(aMsg, aParam.mCausedBySelectionEvent);
+    WriteParam(aMsg, aParam.mOccurredDuringComposition);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     aResult->mString = new nsString();
     return ReadParam(aMsg, aIter, &aResult->mOffset) &&
            ReadParam(aMsg, aIter, aResult->mString) &&
            ReadParam(aMsg, aIter, &aResult->mWritingMode) &&
            ReadParam(aMsg, aIter, &aResult->mReversed) &&
            ReadParam(aMsg, aIter, &aResult->mCausedByComposition) &&
-           ReadParam(aMsg, aIter, &aResult->mCausedBySelectionEvent);
+           ReadParam(aMsg, aIter, &aResult->mCausedBySelectionEvent) &&
+           ReadParam(aMsg, aIter, &aResult->mOccurredDuringComposition);
   }
 };
 
 template<>
 struct ParamTraits<mozilla::widget::IMENotification::TextChangeDataBase>
 {
   typedef mozilla::widget::IMENotification::TextChangeDataBase paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mStartOffset);
     WriteParam(aMsg, aParam.mRemovedEndOffset);
     WriteParam(aMsg, aParam.mAddedEndOffset);
     WriteParam(aMsg, aParam.mCausedByComposition);
+    WriteParam(aMsg, aParam.mOccurredDuringComposition);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mStartOffset) &&
            ReadParam(aMsg, aIter, &aResult->mRemovedEndOffset) &&
            ReadParam(aMsg, aIter, &aResult->mAddedEndOffset) &&
-           ReadParam(aMsg, aIter, &aResult->mCausedByComposition);
+           ReadParam(aMsg, aIter, &aResult->mCausedByComposition) &&
+           ReadParam(aMsg, aIter, &aResult->mOccurredDuringComposition);
   }
 };
 
 template<>
 struct ParamTraits<mozilla::widget::IMENotification::MouseButtonEventData>
 {
   typedef mozilla::widget::IMENotification::MouseButtonEventData paramType;
 
--- a/widget/windows/TSFTextStore.cpp
+++ b/widget/windows/TSFTextStore.cpp
@@ -4543,25 +4543,32 @@ TSFTextStore::GetIMEUpdatePreference()
     }
   }
   return nsIMEUpdatePreference();
 }
 
 nsresult
 TSFTextStore::OnTextChangeInternal(const IMENotification& aIMENotification)
 {
+  const IMENotification::TextChangeDataBase& textChangeData =
+    aIMENotification.mTextChangeData;
+
   MOZ_LOG(sTextStoreLog, LogLevel::Debug,
          ("TSF: 0x%p   TSFTextStore::OnTextChangeInternal(aIMENotification={ "
           "mMessage=0x%08X, mTextChangeData={ mStartOffset=%lu, "
-          "mRemovedEndOffset=%lu, mAddedEndOffset=%lu}), mSink=0x%p, "
-          "mSinkMask=%s, mComposition.IsComposing()=%s",
+          "mRemovedEndOffset=%lu, mAddedEndOffset=%lu, "
+          "mCausedByComposition=%s, mOccurredDuringComposition=%s }), "
+          "mSink=0x%p, mSinkMask=%s, mComposition.IsComposing()=%s",
           this, aIMENotification.mMessage,
-          aIMENotification.mTextChangeData.mStartOffset,
-          aIMENotification.mTextChangeData.mRemovedEndOffset,
-          aIMENotification.mTextChangeData.mAddedEndOffset, mSink.get(),
+          textChangeData.mStartOffset,
+          textChangeData.mRemovedEndOffset,
+          textChangeData.mAddedEndOffset,
+          GetBoolName(textChangeData.mCausedByComposition),
+          GetBoolName(textChangeData.mOccurredDuringComposition),
+          mSink.get(),
           GetSinkMaskNameStr(mSinkMask).get(),
           GetBoolName(mComposition.IsComposing())));
 
   mDeferNotifyingTSF = false;
 
   if (IsReadLocked()) {
     // XXX If text change occurs during the document is locked, it must be
     //     modified by Javascript.  In such case, we should notify merged
@@ -4572,22 +4579,19 @@ TSFTextStore::OnTextChangeInternal(const
   mSelection.MarkDirty();
 
   if (!mSink || !(mSinkMask & TS_AS_TEXT_CHANGE)) {
     return NS_OK;
   }
 
   if (aIMENotification.mTextChangeData.IsInInt32Range()) {
     TS_TEXTCHANGE textChange;
-    textChange.acpStart =
-      static_cast<LONG>(aIMENotification.mTextChangeData.mStartOffset);
-    textChange.acpOldEnd =
-      static_cast<LONG>(aIMENotification.mTextChangeData.mRemovedEndOffset);
-    textChange.acpNewEnd =
-      static_cast<LONG>(aIMENotification.mTextChangeData.mAddedEndOffset);
+    textChange.acpStart = static_cast<LONG>(textChangeData.mStartOffset);
+    textChange.acpOldEnd = static_cast<LONG>(textChangeData.mRemovedEndOffset);
+    textChange.acpNewEnd = static_cast<LONG>(textChangeData.mAddedEndOffset);
     NotifyTSFOfTextChange(textChange);
   } else {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
            ("TSF: 0x%p   TSFTextStore::NotifyTSFOfTextChange() FAILED due to "
             "offset is too big for calling "
             "ITextStoreACPSink::OnTextChange()...",
             this));
   }
@@ -4630,24 +4634,26 @@ nsresult
 TSFTextStore::OnSelectionChangeInternal(const IMENotification& aIMENotification)
 {
   const IMENotification::SelectionChangeDataBase& selectionChangeData =
     aIMENotification.mSelectionChangeData;
   MOZ_LOG(sTextStoreLog, LogLevel::Debug,
          ("TSF: 0x%p   TSFTextStore::OnSelectionChangeInternal("
           "aIMENotification={ mSelectionChangeData={ mOffset=%lu, "
           "Length()=%lu, mReversed=%s, mWritingMode=%s, "
-          "mCausedByComposition=%s, mCausedBySelectionEvent=%s } }), "
+          "mCausedByComposition=%s, mCausedBySelectionEvent=%s, "
+          "mOccurredDuringComposition=%s } }), "
           "mSink=0x%p, mSinkMask=%s, mIsRecordingActionsWithoutLock=%s, "
           "mComposition.IsComposing()=%s",
           this, selectionChangeData.mOffset, selectionChangeData.Length(),
           GetBoolName(selectionChangeData.mReversed),
           GetWritingModeName(selectionChangeData.GetWritingMode()).get(),
           GetBoolName(selectionChangeData.mCausedByComposition),
           GetBoolName(selectionChangeData.mCausedBySelectionEvent),
+          GetBoolName(selectionChangeData.mOccurredDuringComposition),
           mSink.get(), GetSinkMaskNameStr(mSinkMask).get(),
           GetBoolName(mIsRecordingActionsWithoutLock),
           GetBoolName(mComposition.IsComposing())));
 
   mDeferNotifyingTSF = false;
 
   if (IsReadLocked()) {
     // XXX Why don't we mark mPendingOnSelectionChange as true here?