Bug 1043182 Removed and inserted text length which are notified by CharacterDataWillChange() and CharacterDataChanged() should be converted to the length with native new lines in IMEContentObserver r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Thu, 31 Jul 2014 13:38:01 +0900
changeset 196975 2cb0971fc597e19415ff0985ab9be756dedfa209
parent 196974 20f6847ad2d900b6f45e79fa8f4bed5f7e18ec59
child 196976 9245b2bb1ecb61b0588d43f9cba6224082117c4c
push id47016
push usermasayuki@d-toybox.com
push dateThu, 31 Jul 2014 04:38:12 +0000
treeherdermozilla-inbound@2cb0971fc597 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1043182
milestone34.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 1043182 Removed and inserted text length which are notified by CharacterDataWillChange() and CharacterDataChanged() should be converted to the length with native new lines in IMEContentObserver r=smaug
dom/events/ContentEventHandler.cpp
dom/events/ContentEventHandler.h
dom/events/IMEContentObserver.cpp
dom/events/IMEContentObserver.h
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -293,16 +293,30 @@ static uint32_t CountNewlinesInNativeLen
     }
   }
   return newlines;
 }
 #endif
 
 /* static */ uint32_t
 ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
+                                         uint32_t aStartOffset,
+                                         uint32_t aEndOffset)
+{
+  MOZ_ASSERT(aEndOffset >= aStartOffset,
+             "aEndOffset must be equals or larger than aStartOffset");
+  if (aStartOffset == aEndOffset) {
+    return 0;
+  }
+  return GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aEndOffset) -
+           GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aStartOffset);
+}
+
+/* static */ uint32_t
+ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
                                          uint32_t aMaxLength)
 {
   return GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aMaxLength);
 }
 
 /* static */ uint32_t
 ContentEventHandler::GetTextLength(nsIContent* aContent,
                                    LineBreakType aLineBreakType,
--- a/dom/events/ContentEventHandler.h
+++ b/dom/events/ContentEventHandler.h
@@ -80,16 +80,22 @@ public:
                                            nsINode* aNode,
                                            int32_t aNodeOffset,
                                            uint32_t* aOffset,
                                            LineBreakType aLineBreakType);
   static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
                                            nsRange* aRange,
                                            uint32_t* aOffset,
                                            LineBreakType aLineBreakType);
+  // Computes the native text length between aStartOffset and aEndOffset of
+  // aContent.  Currently, this method supports only text node or br element
+  // for aContent.
+  static uint32_t GetNativeTextLength(nsIContent* aContent,
+                                      uint32_t aStartOffset,
+                                      uint32_t aEndOffset);
   // Get the native text length of a content node excluding any children
   static uint32_t GetNativeTextLength(nsIContent* aContent,
                                       uint32_t aMaxLength = UINT32_MAX);
 protected:
   static uint32_t GetTextLength(nsIContent* aContent,
                                 LineBreakType aLineBreakType,
                                 uint32_t aMaxLength = UINT32_MAX);
   static LineBreakType GetLineBreakType(WidgetQueryContentEvent* aEvent);
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -77,16 +77,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelectionListener)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
 
 IMEContentObserver::IMEContentObserver()
   : mESM(nullptr)
+  , mPreCharacterDataChangeLength(-1)
   , mIsEditorInTransaction(false)
   , mIsSelectionChangeEventPending(false)
   , mSelectionChangeCausedOnlyByComposition(false)
   , mIsPositionChangeEventPending(false)
 {
 #ifdef DEBUG
   TestMergingTextChangeData();
 #endif
@@ -636,43 +637,83 @@ IMEContentObserver::StoreTextChangeData(
   // The end of added text should be adjusted with the new difference.
   uint32_t oldAddedEndOffsetInNewText =
     oldData.mAddedEndOffset + newData.Difference();
   mTextChangeData.mAddedEndOffset =
     std::max(newData.mAddedEndOffset, oldAddedEndOffsetInNewText);
 }
 
 void
+IMEContentObserver::CharacterDataWillChange(nsIDocument* aDocument,
+                                            nsIContent* aContent,
+                                            CharacterDataChangeInfo* aInfo)
+{
+  NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
+               "character data changed for non-text node");
+  MOZ_ASSERT(mPreCharacterDataChangeLength < 0,
+             "CharacterDataChanged() should've reset "
+             "mPreCharacterDataChangeLength");
+
+  mEndOfAddedTextCache.Clear();
+  mStartOfRemovingTextRangeCache.Clear();
+
+  bool causedByComposition = IsEditorHandlingEventForComposition();
+  if (!mTextChangeData.mStored && causedByComposition &&
+      !mUpdatePreference.WantChangesCausedByComposition()) {
+    return;
+  }
+
+  mPreCharacterDataChangeLength =
+    ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart,
+                                             aInfo->mChangeEnd);
+  MOZ_ASSERT(mPreCharacterDataChangeLength >=
+               aInfo->mChangeEnd - aInfo->mChangeStart,
+             "The computed length must be same as or larger than XP length");
+}
+
+void
 IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
                                          nsIContent* aContent,
                                          CharacterDataChangeInfo* aInfo)
 {
   NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
                "character data changed for non-text node");
 
   mEndOfAddedTextCache.Clear();
   mStartOfRemovingTextRangeCache.Clear();
 
+  int64_t removedLength = mPreCharacterDataChangeLength;
+  mPreCharacterDataChangeLength = -1;
+
   bool causedByComposition = IsEditorHandlingEventForComposition();
   if (!mTextChangeData.mStored && causedByComposition &&
       !mUpdatePreference.WantChangesCausedByComposition()) {
     return;
   }
 
+  MOZ_ASSERT(removedLength >= 0,
+             "mPreCharacterDataChangeLength should've been set by "
+             "CharacterDataWillChange()");
+
   uint32_t offset = 0;
   // get offsets of change and fire notification
   nsresult rv =
     ContentEventHandler::GetFlatTextOffsetOfRange(mRootContent, aContent,
                                                   aInfo->mChangeStart,
                                                   &offset,
                                                   LINE_BREAK_TYPE_NATIVE);
   NS_ENSURE_SUCCESS_VOID(rv);
 
-  uint32_t oldEnd = offset + aInfo->mChangeEnd - aInfo->mChangeStart;
-  uint32_t newEnd = offset + aInfo->mReplaceLength;
+  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);
   MaybeNotifyIMEOfTextChange(data);
 }
 
 void
 IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
                                        int32_t aStartIndex,
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -41,16 +41,17 @@ class IMEContentObserver MOZ_FINAL : pub
 public:
   IMEContentObserver();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IMEContentObserver,
                                            nsISelectionListener)
   NS_DECL_NSIEDITOROBSERVER
   NS_DECL_NSISELECTIONLISTENER
+  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIREFLOWOBSERVER
 
@@ -207,16 +208,17 @@ private:
   FlatTextCache mStartOfRemovingTextRangeCache;
 
   TextChangeData mTextChangeData;
 
   EventStateManager* mESM;
 
   nsIMEUpdatePreference mUpdatePreference;
   uint32_t mPreAttrChangeLength;
+  int64_t mPreCharacterDataChangeLength;
 
   bool mIsEditorInTransaction;
   bool mIsSelectionChangeEventPending;
   bool mSelectionChangeCausedOnlyByComposition;
   bool mIsPositionChangeEventPending;
 };
 
 } // namespace mozilla