зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
fa0ffa186e
Коммит
552423e58f
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче