diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 04ff83b70cc7..2c575918bcf2 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -296,6 +296,20 @@ static uint32_t CountNewlinesInNativeLength(nsIContent* aContent, } #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) diff --git a/dom/events/ContentEventHandler.h b/dom/events/ContentEventHandler.h index 1fedc29ca819..f10818c57f43 100644 --- a/dom/events/ContentEventHandler.h +++ b/dom/events/ContentEventHandler.h @@ -85,6 +85,12 @@ public: 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); diff --git a/dom/events/IMEContentObserver.cpp b/dom/events/IMEContentObserver.cpp index b312c6925fb7..0d7dd9ffb727 100644 --- a/dom/events/IMEContentObserver.cpp +++ b/dom/events/IMEContentObserver.cpp @@ -82,6 +82,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver) IMEContentObserver::IMEContentObserver() : mESM(nullptr) + , mPreCharacterDataChangeLength(-1) , mIsEditorInTransaction(false) , mIsSelectionChangeEventPending(false) , mSelectionChangeCausedOnlyByComposition(false) @@ -641,12 +642,15 @@ IMEContentObserver::StoreTextChangeData(const TextChangeData& aTextChangeData) } void -IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument, - nsIContent* aContent, - CharacterDataChangeInfo* aInfo) +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(); @@ -657,6 +661,38 @@ IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument, 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 = @@ -666,8 +702,13 @@ IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument, 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(removedLength); + uint32_t newEnd = offset + newLength; TextChangeData data(offset, oldEnd, newEnd, causedByComposition); MaybeNotifyIMEOfTextChange(data); diff --git a/dom/events/IMEContentObserver.h b/dom/events/IMEContentObserver.h index da93c29949c1..50220e7adab5 100644 --- a/dom/events/IMEContentObserver.h +++ b/dom/events/IMEContentObserver.h @@ -46,6 +46,7 @@ public: nsISelectionListener) NS_DECL_NSIEDITOROBSERVER NS_DECL_NSISELECTIONLISTENER + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED @@ -212,6 +213,7 @@ private: nsIMEUpdatePreference mUpdatePreference; uint32_t mPreAttrChangeLength; + int64_t mPreCharacterDataChangeLength; bool mIsEditorInTransaction; bool mIsSelectionChangeEventPending;