Bug 1456377 - Move composition event handlers from EditorBase to TextEditor r=m_kato

Currently, EditorBase handles most composition events.  However, only
eCompositionChange event handler is in TextEditor and it's the main event
of handling composition.  Therefore, we should make all composition event
handlers in one place for easier to read, and make them non-virtual.

MozReview-Commit-ID: BYDhiPyGKvo

--HG--
extra : rebase_source : ed9db0f49d7ae268c85359e48015e86584f9c999
This commit is contained in:
Masayuki Nakano 2018-04-19 00:31:51 +09:00
Родитель fa0ffa186e
Коммит 552423e58f
5 изменённых файлов: 147 добавлений и 126 удалений

Просмотреть файл

@ -2335,65 +2335,6 @@ EditorBase::StopPreservingSelection()
mSavedSel.MakeEmpty();
}
bool
EditorBase::EnsureComposition(WidgetCompositionEvent* aCompositionEvent)
{
if (mComposition) {
return true;
}
// The compositionstart event must cause creating new TextComposition
// instance at being dispatched by IMEStateManager.
mComposition = IMEStateManager::GetTextCompositionFor(aCompositionEvent);
if (!mComposition) {
// However, TextComposition may be committed before the composition
// event comes here.
return false;
}
mComposition->StartHandlingComposition(this);
return true;
}
nsresult
EditorBase::BeginIMEComposition(WidgetCompositionEvent* aCompositionEvent)
{
MOZ_ASSERT(!mComposition, "There is composition already");
if (!EnsureComposition(aCompositionEvent)) {
return NS_OK;
}
return NS_OK;
}
void
EditorBase::EndIMEComposition()
{
NS_ENSURE_TRUE_VOID(mComposition); // nothing to do
// commit the IME transaction..we can get at it via the transaction mgr.
// Note that this means IME won't work without an undo stack!
if (mTransactionManager) {
nsCOMPtr<nsITransaction> txn = mTransactionManager->PeekUndoStack();
nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
if (plcTxn) {
DebugOnly<nsresult> rv = plcTxn->Commit();
NS_ASSERTION(NS_SUCCEEDED(rv),
"nsIAbsorbingTransaction::Commit() failed");
}
}
// Composition string may have hidden the caret. Therefore, we need to
// cancel it here.
HideCaret(false);
// FYI: mComposition still keeps storing container text node of committed
// string, its offset and length. However, they will be invalidated
// soon since its Destroy() will be called by IMEStateManager.
mComposition->EndHandlingComposition(this);
mComposition = nullptr;
// notify editor observers of action
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
}
NS_IMETHODIMP
EditorBase::ForceCompositionEnd()
{

Просмотреть файл

@ -657,14 +657,6 @@ public:
static already_AddRefed<nsTextNode> CreateTextNode(nsIDocument& aDocument,
const nsAString& aData);
/**
* IME event handlers.
*/
virtual nsresult BeginIMEComposition(WidgetCompositionEvent* aEvent);
virtual nsresult UpdateIMEComposition(
WidgetCompositionEvent* aCompositionChangeEvet) = 0;
void EndIMEComposition();
/**
* Get preferred IME status of current widget.
*/
@ -944,18 +936,6 @@ protected:
!ShouldSkipSpellCheck();
}
/**
* EnsureComposition() should be called by composition event handlers. This
* tries to get the composition for the event and set it to mComposition.
* However, this may fail because the composition may be committed before
* the event comes to the editor.
*
* @return true if there is a composition. Otherwise, for example,
* a composition event handler in web contents moved focus
* for committing the composition, returns false.
*/
bool EnsureComposition(WidgetCompositionEvent* aCompositionEvent);
nsresult GetSelection(SelectionType aSelectionType,
nsISelection** aSelection);

Просмотреть файл

@ -762,26 +762,6 @@ EditorEventListener::MouseDown(MouseEvent* aMouseEvent)
return NS_OK;
}
nsresult
EditorEventListener::HandleChangeComposition(
WidgetCompositionEvent* aCompositionChangeEvent)
{
MOZ_ASSERT(!aCompositionChangeEvent->DefaultPrevented(),
"eCompositionChange event shouldn't be cancelable");
RefPtr<EditorBase> editorBase(mEditorBase);
if (DetachedFromEditor() ||
!editorBase->IsAcceptableInputEvent(aCompositionChangeEvent)) {
return NS_OK;
}
// if we are readonly or disabled, then do nothing.
if (editorBase->IsReadonly() || editorBase->IsDisabled()) {
return NS_OK;
}
return editorBase->UpdateIMEComposition(aCompositionChangeEvent);
}
/**
* Drag event implementation
*/
@ -1018,6 +998,9 @@ nsresult
EditorEventListener::HandleStartComposition(
WidgetCompositionEvent* aCompositionStartEvent)
{
if (NS_WARN_IF(!aCompositionStartEvent)) {
return NS_ERROR_FAILURE;
}
RefPtr<EditorBase> editorBase(mEditorBase);
if (DetachedFromEditor() ||
!editorBase->IsAcceptableInputEvent(aCompositionStartEvent)) {
@ -1027,13 +1010,41 @@ EditorEventListener::HandleStartComposition(
// eCompositionStart event coming from widget is not cancelable.
MOZ_ASSERT(!aCompositionStartEvent->DefaultPrevented(),
"eCompositionStart shouldn't be cancelable");
return editorBase->BeginIMEComposition(aCompositionStartEvent);
TextEditor* textEditor = editorBase->AsTextEditor();
return textEditor->OnCompositionStart(*aCompositionStartEvent);
}
nsresult
EditorEventListener::HandleChangeComposition(
WidgetCompositionEvent* aCompositionChangeEvent)
{
if (NS_WARN_IF(!aCompositionChangeEvent)) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(!aCompositionChangeEvent->DefaultPrevented(),
"eCompositionChange event shouldn't be cancelable");
RefPtr<EditorBase> editorBase(mEditorBase);
if (DetachedFromEditor() ||
!editorBase->IsAcceptableInputEvent(aCompositionChangeEvent)) {
return NS_OK;
}
// if we are readonly or disabled, then do nothing.
if (editorBase->IsReadonly() || editorBase->IsDisabled()) {
return NS_OK;
}
TextEditor* textEditor = editorBase->AsTextEditor();
return textEditor->OnCompositionChange(*aCompositionChangeEvent);
}
void
EditorEventListener::HandleEndComposition(
WidgetCompositionEvent* aCompositionEndEvent)
{
if (NS_WARN_IF(!aCompositionEndEvent)) {
return;
}
RefPtr<EditorBase> editorBase(mEditorBase);
if (DetachedFromEditor() ||
!editorBase->IsAcceptableInputEvent(aCompositionEndEvent)) {
@ -1041,7 +1052,9 @@ EditorEventListener::HandleEndComposition(
}
MOZ_ASSERT(!aCompositionEndEvent->DefaultPrevented(),
"eCompositionEnd shouldn't be cancelable");
editorBase->EndIMEComposition();
TextEditor* textEditor = editorBase->AsTextEditor();
textEditor->OnCompositionEnd(*aCompositionEndEvent);
}
nsresult

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/EditorUtils.h" // AutoPlaceholderBatch, AutoRules
#include "mozilla/HTMLEditor.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/mozalloc.h"
#include "mozilla/Preferences.h"
#include "mozilla/TextEditRules.h"
@ -36,6 +37,7 @@
#include "nsDependentSubstring.h"
#include "nsError.h"
#include "nsGkAtoms.h"
#include "nsIAbsorbingTransaction.h"
#include "nsIClipboard.h"
#include "nsIContent.h"
#include "nsIContentIterator.h"
@ -1135,43 +1137,64 @@ TextEditor::SetText(const nsAString& aString)
return rules->DidDoAction(selection, &ruleInfo, rv);
}
nsresult
TextEditor::BeginIMEComposition(WidgetCompositionEvent* aEvent)
bool
TextEditor::EnsureComposition(WidgetCompositionEvent& aCompositionEvent)
{
NS_ENSURE_TRUE(!mComposition, NS_OK);
if (mComposition) {
return true;
}
// The compositionstart event must cause creating new TextComposition
// instance at being dispatched by IMEStateManager.
mComposition = IMEStateManager::GetTextCompositionFor(&aCompositionEvent);
if (!mComposition) {
// However, TextComposition may be committed before the composition
// event comes here.
return false;
}
mComposition->StartHandlingComposition(this);
return true;
}
nsresult
TextEditor::OnCompositionStart(WidgetCompositionEvent& aCompositionStartEvent)
{
if (NS_WARN_IF(mComposition)) {
return NS_OK;
}
if (IsPasswordEditor()) {
NS_ENSURE_TRUE(mRules, NS_ERROR_NULL_POINTER);
if (NS_WARN_IF(!mRules)) {
return NS_ERROR_FAILURE;
}
// Protect the edit rules object from dying
RefPtr<TextEditRules> rules(mRules);
rules->ResetIMETextPWBuf();
}
return EditorBase::BeginIMEComposition(aEvent);
EnsureComposition(aCompositionStartEvent);
NS_WARNING_ASSERTION(mComposition, "Failed to get TextComposition instance?");
return NS_OK;
}
nsresult
TextEditor::UpdateIMEComposition(WidgetCompositionEvent* aCompsitionChangeEvent)
TextEditor::OnCompositionChange(WidgetCompositionEvent& aCompsitionChangeEvent)
{
MOZ_ASSERT(aCompsitionChangeEvent,
"aCompsitionChangeEvent must not be nullptr");
if (NS_WARN_IF(!aCompsitionChangeEvent)) {
return NS_ERROR_INVALID_ARG;
}
MOZ_ASSERT(aCompsitionChangeEvent->mMessage == eCompositionChange,
MOZ_ASSERT(aCompsitionChangeEvent.mMessage == eCompositionChange,
"The event should be eCompositionChange");
if (!EnsureComposition(aCompsitionChangeEvent)) {
return NS_OK;
}
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
nsIPresShell* presShell = GetPresShell();
if (NS_WARN_IF(!presShell)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<Selection> selection = GetSelection();
NS_ENSURE_STATE(selection);
if (NS_WARN_IF(!selection)) {
return NS_ERROR_FAILURE;
}
// NOTE: TextComposition should receive selection change notification before
// CompositionChangeEventHandlingMarker notifies TextComposition of the
@ -1184,9 +1207,9 @@ TextEditor::UpdateIMEComposition(WidgetCompositionEvent* aCompsitionChangeEvent)
MOZ_ASSERT(!mPlaceholderBatch,
"UpdateIMEComposition() must be called without place holder batch");
TextComposition::CompositionChangeEventHandlingMarker
compositionChangeEventHandlingMarker(mComposition, aCompsitionChangeEvent);
compositionChangeEventHandlingMarker(mComposition, &aCompsitionChangeEvent);
RefPtr<nsCaret> caretP = ps->GetCaret();
RefPtr<nsCaret> caretP = presShell->GetCaret();
nsresult rv;
{
@ -1194,7 +1217,7 @@ TextEditor::UpdateIMEComposition(WidgetCompositionEvent* aCompsitionChangeEvent)
MOZ_ASSERT(mIsInEditAction,
"AutoPlaceholderBatch should've notified the observes of before-edit");
rv = InsertTextAsAction(aCompsitionChangeEvent->mData);
rv = InsertTextAsAction(aCompsitionChangeEvent.mData);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to insert new composition string");
@ -1208,13 +1231,46 @@ TextEditor::UpdateIMEComposition(WidgetCompositionEvent* aCompsitionChangeEvent)
// compositionend event, we don't need to notify editor observes of this
// change.
// NOTE: We must notify after the auto batch will be gone.
if (!aCompsitionChangeEvent->IsFollowedByCompositionEnd()) {
if (!aCompsitionChangeEvent.IsFollowedByCompositionEnd()) {
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
}
return rv;
}
void
TextEditor::OnCompositionEnd(WidgetCompositionEvent& aCompositionEndEvent)
{
if (NS_WARN_IF(!mComposition)) {
return;
}
// commit the IME transaction..we can get at it via the transaction mgr.
// Note that this means IME won't work without an undo stack!
if (mTransactionManager) {
nsCOMPtr<nsITransaction> txn = mTransactionManager->PeekUndoStack();
nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
if (plcTxn) {
DebugOnly<nsresult> rv = plcTxn->Commit();
NS_ASSERTION(NS_SUCCEEDED(rv),
"nsIAbsorbingTransaction::Commit() failed");
}
}
// Composition string may have hidden the caret. Therefore, we need to
// cancel it here.
HideCaret(false);
// FYI: mComposition still keeps storing container text node of committed
// string, its offset and length. However, they will be invalidated
// soon since its Destroy() will be called by IMEStateManager.
mComposition->EndHandlingComposition(this);
mComposition = nullptr;
// notify editor observers of action
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
}
already_AddRefed<nsIContent>
TextEditor::GetInputEventTargetContent()
{

Просмотреть файл

@ -121,10 +121,6 @@ public:
virtual dom::EventTarget* GetDOMEventTarget() override;
virtual nsresult BeginIMEComposition(WidgetCompositionEvent* aEvent) override;
virtual nsresult UpdateIMEComposition(
WidgetCompositionEvent* aCompositionChangeEvet) override;
virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
/**
@ -229,6 +225,29 @@ public:
*/
nsresult SetText(const nsAString& aString);
/**
* OnCompositionStart() is called when editor receives eCompositionStart
* event which should be handled in this editor.
*/
nsresult OnCompositionStart(WidgetCompositionEvent& aCompositionStartEvent);
/**
* OnCompositionChange() is called when editor receives an eCompositioChange
* event which should be handled in this editor.
*
* @param aCompositionChangeEvent eCompositionChange event which should
* be handled in this editor.
*/
nsresult
OnCompositionChange(WidgetCompositionEvent& aCompositionChangeEvent);
/**
* OnCompositionEnd() is called when editor receives an eCompositionChange
* event and it's followed by eCompositionEnd event and after
* OnCompositionChange() is called.
*/
void OnCompositionEnd(WidgetCompositionEvent& aCompositionEndEvent);
protected:
virtual ~TextEditor();
@ -309,6 +328,18 @@ protected:
bool UpdateMetaCharset(nsIDocument& aDocument,
const nsACString& aCharacterSet);
/**
* EnsureComposition() should be called by composition event handlers. This
* tries to get the composition for the event and set it to mComposition.
* However, this may fail because the composition may be committed before
* the event comes to the editor.
*
* @return true if there is a composition. Otherwise, for example,
* a composition event handler in web contents moved focus
* for committing the composition, returns false.
*/
bool EnsureComposition(WidgetCompositionEvent& aCompositionEvent);
protected:
nsCOMPtr<nsIDocumentEncoder> mCachedDocumentEncoder;
nsString mCachedDocumentEncoderType;