Bug 960866 part.1 nsEditor should store a pointer of TextComposition while composition r=ehsan
--- a/dom/events/nsIMEStateManager.cpp
+++ b/dom/events/nsIMEStateManager.cpp
@@ -1121,14 +1121,28 @@ nsIMEStateManager::GetFocusSelectionAndR
NS_ASSERTION(sTextStateObserver->mSel && sTextStateObserver->mRootContent,
"uninitialized text state observer");
NS_ADDREF(*aSel = sTextStateObserver->mSel);
NS_ADDREF(*aRoot = sTextStateObserver->mRootContent);
return NS_OK;
}
-TextComposition*
+// static
+already_AddRefed<TextComposition>
nsIMEStateManager::GetTextCompositionFor(nsIWidget* aWidget)
{
- return sTextCompositions ?
- sTextCompositions->GetCompositionFor(aWidget) : nullptr;
+ if (!sTextCompositions) {
+ return nullptr;
+ }
+ nsRefPtr<TextComposition> textComposition =
+ sTextCompositions->GetCompositionFor(aWidget);
+ return textComposition.forget();
}
+
+// static
+already_AddRefed<TextComposition>
+nsIMEStateManager::GetTextCompositionFor(WidgetGUIEvent* aEvent)
+{
+ MOZ_ASSERT(aEvent->AsCompositionEvent() || aEvent->AsTextEvent(),
+ "aEvent has to be WidgetCompositionEvent or WidgetTextEvent");
+ return GetTextCompositionFor(aEvent->widget);
+}
--- a/dom/events/nsIMEStateManager.h
+++ b/dom/events/nsIMEStateManager.h
@@ -93,17 +93,27 @@ public:
nsPresContext* aPresContext,
mozilla::WidgetEvent* aEvent,
nsEventStatus* aStatus,
nsDispatchingCallback* aCallBack);
/**
* Get TextComposition from widget.
*/
- static mozilla::TextComposition* GetTextCompositionFor(nsIWidget* aWidget);
+ static already_AddRefed<mozilla::TextComposition>
+ GetTextCompositionFor(nsIWidget* aWidget);
+
+ /**
+ * Returns TextComposition instance for the event.
+ *
+ * @param aEvent Should be a composition event or a text event which is
+ * being dispatched.
+ */
+ static already_AddRefed<mozilla::TextComposition>
+ GetTextCompositionFor(mozilla::WidgetGUIEvent* aEvent);
/**
* Send a notification to IME. It depends on the IME or platform spec what
* will occur (or not occur).
*/
static nsresult NotifyIME(mozilla::widget::NotificationToIME aNotification,
nsIWidget* aWidget);
static nsresult NotifyIME(mozilla::widget::NotificationToIME aNotification,
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -16,16 +16,17 @@
#include "EditAggregateTxn.h" // for EditAggregateTxn
#include "EditTxn.h" // for EditTxn
#include "IMETextTxn.h" // for IMETextTxn
#include "InsertElementTxn.h" // for InsertElementTxn
#include "InsertTextTxn.h" // for InsertTextTxn
#include "JoinElementTxn.h" // for JoinElementTxn
#include "PlaceholderTxn.h" // for PlaceholderTxn
#include "SplitElementTxn.h" // for SplitElementTxn
+#include "TextComposition.h" // for TextComposition
#include "mozFlushType.h" // for mozFlushType::Flush_Frames
#include "mozISpellCheckingEngine.h"
#include "mozInlineSpellChecker.h" // for mozInlineSpellChecker
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/Selection.h" // for Selection, etc
#include "mozilla/Services.h" // for GetObserverService
#include "mozilla/TextEvents.h"
#include "mozilla/dom/Element.h" // for Element, nsINode::AsElement
@@ -2005,20 +2006,35 @@ nsEditor::RestorePreservedSelection(nsIS
void
nsEditor::StopPreservingSelection()
{
mRangeUpdater.DropSelectionState(mSavedSel);
mSavedSel.MakeEmpty();
}
+void
+nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent)
+{
+ if (mComposition) {
+ return;
+ }
+ // The compositionstart event must cause creating new TextComposition
+ // instance at being dispatched by nsIMEStateManager.
+ mComposition = nsIMEStateManager::GetTextCompositionFor(aEvent);
+ if (!mComposition) {
+ MOZ_CRASH("nsIMEStateManager doesn't return proper composition");
+ }
+}
nsresult
-nsEditor::BeginIMEComposition()
-{
+nsEditor::BeginIMEComposition(WidgetCompositionEvent* aCompositionEvent)
+{
+ MOZ_ASSERT(!mComposition, "There is composition already");
+ EnsureComposition(aCompositionEvent);
mInIMEMode = true;
if (mPhonetic) {
mPhonetic->Truncate(0);
}
return NS_OK;
}
void
@@ -2039,16 +2055,17 @@ nsEditor::EndIMEComposition()
}
/* reset the data we need to construct a transaction */
mIMETextNode = nullptr;
mIMETextOffset = 0;
mIMEBufferLength = 0;
mInIMEMode = false;
mIsIMEComposing = false;
+ mComposition = nullptr;
// notify editor observers of action
NotifyEditorObservers();
}
NS_IMETHODIMP
nsEditor::GetPhonetic(nsAString& aPhonetic)
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -64,16 +64,17 @@ class nsISupports;
class nsITransaction;
class nsIWidget;
class nsRange;
class nsString;
class nsTransactionManager;
namespace mozilla {
class Selection;
+class TextComposition;
namespace dom {
class Element;
class EventTarget;
} // namespace dom
} // namespace mozilla
namespace mozilla {
@@ -237,19 +238,18 @@ public:
Arguments:
nsString& aTag - tag you want
nsIContent** aContent - returned Content that was created with above namespace.
*/
nsresult CreateHTMLContent(const nsAString& aTag,
mozilla::dom::Element** aContent);
// IME event handlers
- virtual nsresult BeginIMEComposition();
- virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
- nsIPrivateTextRangeList *aTextRange)=0;
+ virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent);
+ virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0;
void EndIMEComposition();
void SwitchTextDirectionTo(uint32_t aDirection);
protected:
nsresult DetermineCurrentDirection();
void FireInputEvent();
@@ -408,16 +408,23 @@ protected:
bool CanEnableSpellCheck()
{
// Check for password/readonly/disabled, which are not spellchecked
// regardless of DOM. Also, check to see if spell check should be skipped or not.
return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() && !ShouldSkipSpellCheck();
}
+ /**
+ * EnsureComposition() should be composition event handlers or text event
+ * handler. This tries to get the composition for the event and set it to
+ * mComposition.
+ */
+ void EnsureComposition(mozilla::WidgetGUIEvent* aEvent);
+
public:
/** All editor operations which alter the doc should be prefaced
* with a call to StartOperation, naming the action and direction */
NS_IMETHOD StartOperation(EditAction opID,
nsIEditor::EDirection aDirection);
/** All editor operations which alter the doc should be followed
@@ -825,16 +832,19 @@ protected:
nsCOMPtr<mozilla::dom::EventTarget> mEventTarget; // The form field as an event receiver
nsCOMPtr<nsIDOMEventListener> mEventListener;
nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController
nsWeakPtr mPlaceHolderTxn; // weak reference to placeholder for begin/end batch purposes
nsWeakPtr mDocWeak; // weak reference to the nsIDOMDocument
nsIAtom *mPlaceHolderName; // name of placeholder transaction
nsSelectionState *mSelState; // saved selection state for placeholder txn batching
nsString *mPhonetic;
+ // IME composition this is not null between compositionstart and
+ // compositionend.
+ nsRefPtr<mozilla::TextComposition> mComposition;
// various listeners
nsCOMArray<nsIEditActionListener> mActionListeners; // listens to all low level actions on the doc
nsCOMArray<nsIEditorObserver> mEditorObservers; // just notify once per high level change
nsCOMArray<nsIDocumentStateListener> mDocStateListeners;// listen to overall doc state (dirty or not, just created, etc)
nsSelectionState mSavedSel; // cached selection for nsAutoSelectionReset
nsRangeUpdater mRangeUpdater; // utility class object for maintaining preserved ranges
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -1,15 +1,16 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=4 sw=2 et tw=78: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Preferences.h" // for Preferences
+#include "mozilla/TextEvents.h" // for WidgetCompositionEvent
#include "mozilla/dom/Element.h" // for Element
#include "mozilla/dom/EventTarget.h" // for EventTarget
#include "nsAString.h"
#include "nsCaret.h" // for nsCaret
#include "nsDebug.h" // for NS_ENSURE_TRUE, etc
#include "nsEditor.h" // for nsEditor, etc
#include "nsEditorEventListener.h"
#include "nsEventListenerManager.h" // for nsEventListenerManager
@@ -37,18 +38,16 @@
#include "nsIFocusManager.h" // for nsIFocusManager
#include "nsIFormControl.h" // for nsIFormControl, etc
#include "nsIHTMLEditor.h" // for nsIHTMLEditor
#include "nsIMEStateManager.h" // for nsIMEStateManager
#include "nsINativeKeyBindings.h" // for nsINativeKeyBindings
#include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
#include "nsIPresShell.h" // for nsIPresShell
-#include "nsIPrivateTextEvent.h" // for nsIPrivateTextEvent
-#include "nsIPrivateTextRange.h" // for nsIPrivateTextRangeList
#include "nsISelection.h" // for nsISelection
#include "nsISelectionController.h" // for nsISelectionController, etc
#include "nsISelectionPrivate.h" // for nsISelectionPrivate
#include "nsITransferable.h" // for kFileMime, kHTMLMime, etc
#include "nsLiteralString.h" // for NS_LITERAL_STRING
#include "nsPIWindowRoot.h" // for nsPIWindowRoot
#include "nsServiceManagerUtils.h" // for do_GetService
#include "nsString.h" // for nsAutoString
@@ -656,34 +655,22 @@ NS_IMETHODIMP
nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
if (!mEditor->IsAcceptableInputEvent(aTextEvent)) {
return NS_OK;
}
- nsCOMPtr<nsIPrivateTextEvent> textEvent = do_QueryInterface(aTextEvent);
- if (!textEvent) {
- //non-ui event passed in. bad things.
- return NS_OK;
- }
-
- nsAutoString composedText;
- nsCOMPtr<nsIPrivateTextRangeList> textRangeList;
-
- textEvent->GetText(composedText);
- textRangeList = textEvent->GetInputRange();
-
// if we are readonly or disabled, then do nothing.
if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
return NS_OK;
}
- return mEditor->UpdateIMEComposition(composedText, textRangeList);
+ return mEditor->UpdateIMEComposition(aTextEvent);
}
/**
* Drag event implementation
*/
nsresult
nsEditorEventListener::DragEnter(nsIDOMDragEvent* aDragEvent)
@@ -900,17 +887,19 @@ nsEditorEventListener::CanDrop(nsIDOMDra
NS_IMETHODIMP
nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
{
NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
return NS_OK;
}
- return mEditor->BeginIMEComposition();
+ WidgetCompositionEvent* compositionStart =
+ aCompositionEvent->GetInternalNSEvent()->AsCompositionEvent();
+ return mEditor->BeginIMEComposition(compositionStart);
}
void
nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
{
MOZ_ASSERT(mEditor);
if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) {
return;
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -34,16 +34,17 @@
#include "nsIDOMKeyEvent.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIDocumentEncoder.h"
#include "nsIEditorIMESupport.h"
#include "nsINameSpaceManager.h"
#include "nsINode.h"
#include "nsIPresShell.h"
+#include "nsIPrivateTextEvent.h"
#include "nsIPrivateTextRange.h"
#include "nsISelection.h"
#include "nsISelectionController.h"
#include "nsISelectionPrivate.h"
#include "nsISupportsPrimitives.h"
#include "nsITransferable.h"
#include "nsIWeakReferenceUtils.h"
#include "nsInternetCiter.h"
@@ -806,61 +807,71 @@ NS_IMETHODIMP nsPlaintextEditor::InsertL
// post-process, always called if WillInsertBreak didn't return cancel==true
res = mRules->DidDoAction(selection, &ruleInfo, res);
}
return res;
}
nsresult
-nsPlaintextEditor::BeginIMEComposition()
+nsPlaintextEditor::BeginIMEComposition(WidgetCompositionEvent* aEvent)
{
NS_ENSURE_TRUE(!mInIMEMode, NS_OK);
if (IsPasswordEditor()) {
NS_ENSURE_TRUE(mRules, NS_ERROR_NULL_POINTER);
// Protect the edit rules object from dying
nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
nsTextEditRules *textEditRules =
static_cast<nsTextEditRules*>(mRules.get());
textEditRules->ResetIMETextPWBuf();
}
- return nsEditor::BeginIMEComposition();
+ return nsEditor::BeginIMEComposition(aEvent);
}
nsresult
-nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString,
- nsIPrivateTextRangeList* aTextRangeList)
+nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
{
- NS_ABORT_IF_FALSE(aTextRangeList, "aTextRangeList must not be nullptr");
+ NS_ABORT_IF_FALSE(aDOMTextEvent, "aDOMTextEvent must not be nullptr");
+
+ WidgetTextEvent* widgetTextEvent =
+ aDOMTextEvent->GetInternalNSEvent()->AsTextEvent();
+ NS_ENSURE_TRUE(widgetTextEvent, NS_ERROR_INVALID_ARG);
+
+ EnsureComposition(widgetTextEvent);
+ mInIMEMode = true;
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsISelection> selection;
nsresult rv = GetSelection(getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<nsCaret> caretP = ps->GetCaret();
// Update information of clauses in the new composition string.
// This will be refered by followed methods.
- mIMETextRangeList = aTextRangeList;
+ nsCOMPtr<nsIPrivateTextEvent> privateTextEvent =
+ do_QueryInterface(aDOMTextEvent);
+ NS_ENSURE_TRUE(privateTextEvent, NS_ERROR_INVALID_ARG);
+ mIMETextRangeList = privateTextEvent->GetInputRange();
+ NS_ABORT_IF_FALSE(mIMETextRangeList, "mIMETextRangeList must not be nullptr");
// We set mIsIMEComposing properly.
SetIsIMEComposing();
{
nsAutoPlaceHolderBatch batch(this, nsGkAtoms::IMETxnName);
- rv = InsertText(aCompositionString);
+ rv = InsertText(widgetTextEvent->theText);
- mIMEBufferLength = aCompositionString.Length();
+ mIMEBufferLength = widgetTextEvent->theText.Length();
if (caretP) {
caretP->SetCaretDOMSelection(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
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -117,19 +117,18 @@ public:
/** make the given selection span the entire document */
NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget();
- virtual nsresult BeginIMEComposition();
- virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
- nsIPrivateTextRangeList *aTextRange);
+ virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent);
+ virtual nsresult UpdateIMEComposition(nsIDOMEvent* aTextEvent) MOZ_OVERRIDE;
virtual already_AddRefed<nsIContent> GetInputEventTargetContent();
/* ------------ Utility Routines, not part of public API -------------- */
NS_IMETHOD TypedText(const nsAString& aString, ETypingAction aAction);
nsresult InsertTextAt(const nsAString &aStringToInsert,
nsIDOMNode *aDestinationNode,