From b43a480e00b9ee3f6dd9b6f41df42c9986bbbe35 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 12 Feb 2014 22:02:56 +0900 Subject: [PATCH] Bug 960866 part.4 Remove nsEditor::mIMEBufferLength r=ehsan+smaug --- dom/events/TextComposition.cpp | 10 ++++++++++ dom/events/TextComposition.h | 19 ++++++++++++++++++- dom/events/nsIMEStateManager.cpp | 14 +++++++------- editor/libeditor/base/nsEditor.cpp | 14 ++++++-------- editor/libeditor/base/nsEditor.h | 6 ++++-- editor/libeditor/text/nsPlaintextEditor.cpp | 3 ++- editor/libeditor/text/nsTextEditRules.cpp | 4 +++- .../file_autocomplete_with_composition.js | 2 +- 8 files changed, 51 insertions(+), 21 deletions(-) diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 3ea9362f341..8456981f305 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -130,6 +130,16 @@ void TextComposition::EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent) { mIsComposing = aTextEvent->IsComposing(); + + MOZ_ASSERT(mLastData == aTextEvent->theText, + "The text of a text event must be same as previous data attribute value " + "of the latest compositionupdate event"); +} + +void +TextComposition::EditorDidHandleTextEvent() +{ + mString = mLastData; } /****************************************************************************** diff --git a/dom/events/TextComposition.h b/dom/events/TextComposition.h index c7174bd8985..ce81fd7bfd3 100644 --- a/dom/events/TextComposition.h +++ b/dom/events/TextComposition.h @@ -47,7 +47,14 @@ public: nsPresContext* GetPresContext() const { return mPresContext; } nsINode* GetEventTargetNode() const { return mNode; } // The latest CompositionEvent.data value except compositionstart event. - const nsString& GetLastData() const { return mLastData; } + // This value is modified at dispatching compositionupdate. + const nsString& LastData() const { return mLastData; } + // The composition string which is already handled by the focused editor. + // I.e., this value must be same as the composition string on the focused + // editor. This value is modified at a call of EditorDidHandleTextEvent(). + // Note that mString and mLastData are different between dispatcing + // compositionupdate and text event handled by focused editor. + const nsString& String() const { return mString; } // Returns true if the composition is started with synthesized event which // came from nsDOMWindowUtils. bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; } @@ -85,6 +92,12 @@ public: */ void EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent); + /** + * EditorDidHandleTextEvent() must be called after the focused editor handles + * a text event. + */ + void EditorDidHandleTextEvent(); + private: // This class holds nsPresContext weak. This instance shouldn't block // destroying it. When the presContext is being destroyed, it's notified to @@ -101,6 +114,10 @@ private: // the compositionstart event). nsString mLastData; + // mString stores the composition text which has been handled by the focused + // editor. + nsString mString; + // Offset of the composition string from start of the editor uint32_t mCompositionStartOffset; // Offset of the selected clause of the composition string from start of the diff --git a/dom/events/nsIMEStateManager.cpp b/dom/events/nsIMEStateManager.cpp index ca3cecf8d8b..41bb5ec8a6e 100644 --- a/dom/events/nsIMEStateManager.cpp +++ b/dom/events/nsIMEStateManager.cpp @@ -617,9 +617,9 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, case REQUEST_TO_COMMIT_COMPOSITION: { nsCOMPtr widget(aWidget); nsEventStatus status = nsEventStatus_eIgnore; - if (!composition->GetLastData().IsEmpty()) { + if (!composition->LastData().IsEmpty()) { WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget); - textEvent.theText = composition->GetLastData(); + textEvent.theText = composition->LastData(); textEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&textEvent, status); if (widget->Destroyed()) { @@ -629,7 +629,7 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, status = nsEventStatus_eIgnore; WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); - endEvent.data = composition->GetLastData(); + endEvent.data = composition->LastData(); endEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&endEvent, status); @@ -638,9 +638,9 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, case REQUEST_TO_CANCEL_COMPOSITION: { nsCOMPtr widget(aWidget); nsEventStatus status = nsEventStatus_eIgnore; - if (!composition->GetLastData().IsEmpty()) { + if (!composition->LastData().IsEmpty()) { WidgetCompositionEvent updateEvent(true, NS_COMPOSITION_UPDATE, widget); - updateEvent.data = composition->GetLastData(); + updateEvent.data = composition->LastData(); updateEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&updateEvent, status); if (widget->Destroyed()) { @@ -649,7 +649,7 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, status = nsEventStatus_eIgnore; WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget); - textEvent.theText = composition->GetLastData(); + textEvent.theText = composition->LastData(); textEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&textEvent, status); if (widget->Destroyed()) { @@ -659,7 +659,7 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, status = nsEventStatus_eIgnore; WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); - endEvent.data = composition->GetLastData(); + endEvent.data = composition->LastData(); endEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&endEvent, status); diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 37359d0a7f7..10e2204aabe 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -140,7 +140,6 @@ nsEditor::nsEditor() , mPlaceHolderBatch(0) , mAction(EditAction::none) , mIMETextOffset(0) -, mIMEBufferLength(0) , mDirection(eNone) , mDocDirtyState(-1) , mSpellcheckCheckboxState(eTriUnset) @@ -247,8 +246,6 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController * /* initialize IME stuff */ mIMETextNode = nullptr; mIMETextOffset = 0; - mIMEBufferLength = 0; - /* Show the caret */ selCon->SetCaretReadOnly(false); selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); @@ -2056,7 +2053,6 @@ nsEditor::EndIMEComposition() /* reset the data we need to construct a transaction */ mIMETextNode = nullptr; mIMETextOffset = 0; - mIMEBufferLength = 0; mComposition = nullptr; // notify editor observers of action @@ -4193,10 +4189,10 @@ nsEditor::DeleteSelectionAndCreateNode(const nsAString& aTag, /* Non-interface, protected methods */ -int32_t -nsEditor::GetIMEBufferLength() +TextComposition* +nsEditor::GetComposition() const { - return mIMEBufferLength; + return mComposition; } bool @@ -4399,7 +4395,9 @@ nsEditor::CreateTxnForIMEText(const nsAString& aStringToInsert, nsRefPtr txn = new IMETextTxn(); - nsresult rv = txn->Init(mIMETextNode, mIMETextOffset, mIMEBufferLength, + // During handling IME composition, mComposition must have been initialized. + nsresult rv = txn->Init(mIMETextNode, mIMETextOffset, + mComposition->String().Length(), mIMETextRangeList, aStringToInsert, this); if (NS_SUCCEEDED(rv)) { diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index 65f161c6357..237bc7f4430 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -599,7 +599,10 @@ public: /** Find the deep first and last children. */ nsINode* GetFirstEditableNode(nsINode* aRoot); - int32_t GetIMEBufferLength(); + /** + * Returns current composition. + */ + mozilla::TextComposition* GetComposition() const; /** * Returns true if there is composition string and not fixed. */ @@ -860,7 +863,6 @@ protected: EditAction mAction; // the current editor action uint32_t mIMETextOffset; // offset in text node where IME comp string begins - uint32_t mIMEBufferLength; // current length of IME comp string EDirection mDirection; // the current direction of editor action int8_t mDocDirtyState; // -1 = not initialized diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/text/nsPlaintextEditor.cpp index 1c0c216a616..d819fa23554 100644 --- a/editor/libeditor/text/nsPlaintextEditor.cpp +++ b/editor/libeditor/text/nsPlaintextEditor.cpp @@ -866,7 +866,8 @@ nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) rv = InsertText(widgetTextEvent->theText); - mIMEBufferLength = widgetTextEvent->theText.Length(); + // XXX This approach is ugly, we should sort out the text event handling. + mComposition->EditorDidHandleTextEvent(); if (caretP) { caretP->SetCaretDOMSelection(selection); diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index 740ffb4f754..18f296d1ec5 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TextComposition.h" #include "mozilla/Assertions.h" #include "mozilla/LookAndFeel.h" #include "mozilla/Preferences.h" @@ -1208,7 +1209,8 @@ nsTextEditRules::TruncateInsertionIfNeeded(Selection* aSelection, nsContentUtils::GetSelectionInTextControl(aSelection, mEditor->GetRoot(), start, end); - int32_t oldCompStrLength = mEditor->GetIMEBufferLength(); + TextComposition* composition = mEditor->GetComposition(); + int32_t oldCompStrLength = composition ? composition->String().Length() : 0; const int32_t selectionLength = end - start; const int32_t resultingDocLength = docLength - selectionLength - oldCompStrLength; diff --git a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js index 3acb744d2a5..25bac79365d 100644 --- a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js +++ b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js @@ -280,7 +280,7 @@ nsDoTestsForAutoCompleteWithComposition.prototype = { { description: "compositionupdate shouldn't reopen the popup", completeDefaultIndex: false, execute: function (aWindow) { - synthesizeComposition({ type: "compositionupdate", data: "ll" }, aWindow); + synthesizeComposition({ type: "compositionupdate", data: "zi" }, aWindow); synthesizeText( { "composition": { "string": "zi",