mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 20:01:50 +00:00
Bug 1137561 part.3 Make IMMHandler use TextEventDispatcher r=m_kato
This commit is contained in:
parent
04597dabbb
commit
4de2cb08cc
@ -224,6 +224,15 @@ public:
|
||||
mPendingComposition.Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* GetPendingCompositionClauses() returns text ranges which was appended by
|
||||
* AppendClauseToPendingComposition() or SetPendingComposition().
|
||||
*/
|
||||
const TextRangeArray* GetPendingCompositionClauses() const
|
||||
{
|
||||
return mPendingComposition.GetClauses();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see nsIWidget::NotifyIME()
|
||||
*/
|
||||
@ -301,6 +310,7 @@ private:
|
||||
nsresult Flush(TextEventDispatcher* aDispatcher,
|
||||
nsEventStatus& aStatus,
|
||||
const WidgetEventTime* aEventTime);
|
||||
const TextRangeArray* GetClauses() const { return mClauses; }
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
|
@ -1106,6 +1106,7 @@ IMMHandler::OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
|
||||
("IMM: OnIMEStartCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s",
|
||||
aWindow->GetWindowHandle(), GetBoolName(mIsComposingOnPlugin)));
|
||||
mIsComposingOnPlugin = true;
|
||||
mDispatcher = GetTextEventDispatcherFor(aWindow);
|
||||
mComposingWindow = aWindow;
|
||||
IMEContext context(aWindow);
|
||||
SetIMERelatedWindowsPosOnPlugin(aWindow, context);
|
||||
@ -1131,11 +1132,13 @@ IMMHandler::OnIMECompositionOnPlugin(nsWindow* aWindow,
|
||||
if (IS_COMMITTING_LPARAM(lParam)) {
|
||||
mIsComposingOnPlugin = false;
|
||||
mComposingWindow = nullptr;
|
||||
mDispatcher = nullptr;
|
||||
return;
|
||||
}
|
||||
// Continue composition if there is still a string being composed.
|
||||
if (IS_COMPOSING_LPARAM(lParam)) {
|
||||
mIsComposingOnPlugin = true;
|
||||
mDispatcher = GetTextEventDispatcherFor(aWindow);
|
||||
mComposingWindow = aWindow;
|
||||
IMEContext context(aWindow);
|
||||
SetIMERelatedWindowsPosOnPlugin(aWindow, context);
|
||||
@ -1153,6 +1156,7 @@ IMMHandler::OnIMEEndCompositionOnPlugin(nsWindow* aWindow,
|
||||
|
||||
mIsComposingOnPlugin = false;
|
||||
mComposingWindow = nullptr;
|
||||
mDispatcher = nullptr;
|
||||
|
||||
if (mNativeCaretIsCreated) {
|
||||
::DestroyCaret();
|
||||
@ -1258,6 +1262,13 @@ IMMHandler::OnCharOnPlugin(nsWindow* aWindow,
|
||||
* others
|
||||
****************************************************************************/
|
||||
|
||||
TextEventDispatcher*
|
||||
IMMHandler::GetTextEventDispatcherFor(nsWindow* aWindow)
|
||||
{
|
||||
return aWindow == mComposingWindow && mDispatcher ?
|
||||
mDispatcher : aWindow->GetTextEventDispatcher();
|
||||
}
|
||||
|
||||
void
|
||||
IMMHandler::HandleStartComposition(nsWindow* aWindow,
|
||||
const IMEContext& aContext)
|
||||
@ -1278,13 +1289,27 @@ IMMHandler::HandleStartComposition(nsWindow* aWindow,
|
||||
mCompositionStart = selection.mOffset;
|
||||
mCursorPosition = NO_IME_CARET;
|
||||
|
||||
WidgetCompositionEvent event(true, eCompositionStart, aWindow);
|
||||
LayoutDeviceIntPoint point(0, 0);
|
||||
aWindow->InitEvent(event, &point);
|
||||
DispatchEvent(aWindow, event);
|
||||
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcherFor(aWindow);
|
||||
nsresult rv = dispatcher->BeginNativeInputTransaction();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: HandleStartComposition, FAILED due to "
|
||||
"TextEventDispatcher::BeginNativeInputTransaction() failure"));
|
||||
return;
|
||||
}
|
||||
WidgetEventTime eventTime = aWindow->CurrentMessageWidgetEventTime();
|
||||
nsEventStatus status;
|
||||
rv = dispatcher->StartComposition(status, &eventTime);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: HandleStartComposition, FAILED, due to "
|
||||
"TextEventDispatcher::StartComposition() failure"));
|
||||
return;
|
||||
}
|
||||
|
||||
mIsComposing = true;
|
||||
mComposingWindow = aWindow;
|
||||
mDispatcher = dispatcher;
|
||||
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: HandleStartComposition, START composition, mCompositionStart=%ld",
|
||||
@ -1547,17 +1572,27 @@ IMMHandler::HandleEndComposition(nsWindow* aWindow,
|
||||
mNativeCaretIsCreated = false;
|
||||
}
|
||||
|
||||
EventMessage message =
|
||||
aCommitString ? eCompositionCommit : eCompositionCommitAsIs;
|
||||
WidgetCompositionEvent compositionCommitEvent(true, message, aWindow);
|
||||
LayoutDeviceIntPoint point(0, 0);
|
||||
aWindow->InitEvent(compositionCommitEvent, &point);
|
||||
if (aCommitString) {
|
||||
compositionCommitEvent.mData = *aCommitString;
|
||||
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcherFor(aWindow);
|
||||
nsresult rv = dispatcher->BeginNativeInputTransaction();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: HandleEndComposition, FAILED due to "
|
||||
"TextEventDispatcher::BeginNativeInputTransaction() failure"));
|
||||
return;
|
||||
}
|
||||
WidgetEventTime eventTime = aWindow->CurrentMessageWidgetEventTime();
|
||||
nsEventStatus status;
|
||||
rv = dispatcher->CommitComposition(status, aCommitString, &eventTime);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: HandleStartComposition, FAILED, due to "
|
||||
"TextEventDispatcher::CommitComposition() failure"));
|
||||
return;
|
||||
}
|
||||
DispatchEvent(aWindow, compositionCommitEvent);
|
||||
mIsComposing = false;
|
||||
// XXX aWindow and mComposingWindow are always same??
|
||||
mComposingWindow = nullptr;
|
||||
mDispatcher = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1929,116 +1964,127 @@ IMMHandler::DispatchCompositionChangeEvent(nsWindow* aWindow,
|
||||
}
|
||||
|
||||
RefPtr<nsWindow> kungFuDeathGrip(aWindow);
|
||||
RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcherFor(aWindow);
|
||||
nsresult rv = dispatcher->BeginNativeInputTransaction();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: DispatchCompositionChangeEvent, FAILED due to "
|
||||
"TextEventDispatcher::BeginNativeInputTransaction() failure"));
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutDeviceIntPoint point(0, 0);
|
||||
// NOTE: Calling SetIMERelatedWindowsPos() from this method will be failure
|
||||
// in e10s mode. compositionchange event will notify this of
|
||||
// NOTIFY_IME_OF_COMPOSITION_UPDATE, then SetIMERelatedWindowsPos()
|
||||
// will be called.
|
||||
|
||||
WidgetCompositionEvent event(true, eCompositionChange, aWindow);
|
||||
// XXX Sogou (Simplified Chinese IME) returns contradictory values:
|
||||
// The cursor position is actual cursor position. However, other values
|
||||
// (composition string and attributes) are empty.
|
||||
|
||||
aWindow->InitEvent(event, &point);
|
||||
|
||||
event.mRanges = CreateTextRangeArray();
|
||||
event.mData = mCompositionString;
|
||||
|
||||
DispatchEvent(aWindow, event);
|
||||
|
||||
// Calling SetIMERelatedWindowsPos will be failure on e10s at this point.
|
||||
// compositionchange event will notify NOTIFY_IME_OF_COMPOSITION_UPDATE, then
|
||||
// it will call SetIMERelatedWindowsPos.
|
||||
}
|
||||
|
||||
already_AddRefed<TextRangeArray>
|
||||
IMMHandler::CreateTextRangeArray()
|
||||
{
|
||||
// Sogou (Simplified Chinese IME) returns contradictory values: The cursor
|
||||
// position is actual cursor position. However, other values (composition
|
||||
// string and attributes) are empty. So, if you want to remove following
|
||||
// assertion, be careful.
|
||||
NS_ASSERTION(ShouldDrawCompositionStringOurselves(),
|
||||
"CreateTextRangeArray is called when we don't need to fire "
|
||||
"compositionchange event");
|
||||
|
||||
RefPtr<TextRangeArray> textRangeArray = new TextRangeArray();
|
||||
|
||||
TextRange range;
|
||||
if (mCompositionString.IsEmpty()) {
|
||||
// Don't append clause information if composition string is empty.
|
||||
} else if (mClauseArray.Length() == 0) {
|
||||
} else if (mClauseArray.IsEmpty()) {
|
||||
// Some IMEs don't return clause array information, then, we assume that
|
||||
// all characters in the composition string are in one clause.
|
||||
range.mStartOffset = 0;
|
||||
range.mEndOffset = mCompositionString.Length();
|
||||
range.mRangeType = NS_TEXTRANGE_RAWINPUT;
|
||||
textRangeArray->AppendElement(range);
|
||||
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, mClauseLength=0"));
|
||||
("IMM: DispatchCompositionChangeEvent, mClauseArray.Length()=0"));
|
||||
rv =dispatcher->SetPendingComposition(mCompositionString, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: DispatchCompositionChangeEvent, FAILED due to"
|
||||
"TextEventDispatcher::SetPendingComposition() failure"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// iterate over the attributes
|
||||
rv = dispatcher->SetPendingCompositionString(mCompositionString);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: DispatchCompositionChangeEvent, FAILED due to"
|
||||
"TextEventDispatcher::SetPendingCompositionString() failure"));
|
||||
return;
|
||||
}
|
||||
uint32_t lastOffset = 0;
|
||||
for (uint32_t i = 0; i < mClauseArray.Length() - 1; i++) {
|
||||
uint32_t current = mClauseArray[i + 1];
|
||||
if (current > mCompositionString.Length()) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, mClauseArray[%ld]=%lu. "
|
||||
("IMM: DispatchCompositionChangeEvent, mClauseArray[%ld]=%lu. "
|
||||
"This is larger than mCompositionString.Length()=%lu",
|
||||
i + 1, current, mCompositionString.Length()));
|
||||
current = int32_t(mCompositionString.Length());
|
||||
}
|
||||
|
||||
range.mRangeType = PlatformToNSAttr(mAttributeArray[lastOffset]);
|
||||
range.mStartOffset = lastOffset;
|
||||
range.mEndOffset = current;
|
||||
textRangeArray->AppendElement(range);
|
||||
uint32_t length = current - lastOffset;
|
||||
uint32_t attr = PlatformToNSAttr(mAttributeArray[lastOffset]);
|
||||
rv = dispatcher->AppendClauseToPendingComposition(length, attr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: DispatchCompositionChangeEvent, FAILED due to"
|
||||
"TextEventDispatcher::AppendClauseToPendingComposition() failure"));
|
||||
return;
|
||||
}
|
||||
|
||||
lastOffset = current;
|
||||
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, index=%ld, rangeType=%s, range=[%lu-%lu]",
|
||||
i, GetRangeTypeName(range.mRangeType), range.mStartOffset,
|
||||
range.mEndOffset));
|
||||
("IMM: DispatchCompositionChangeEvent, index=%ld, rangeType=%s, "
|
||||
"range length=%lu",
|
||||
i, GetRangeTypeName(attr), length));
|
||||
}
|
||||
}
|
||||
|
||||
if (mCursorPosition == NO_IME_CARET) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, no caret"));
|
||||
return textRangeArray.forget();
|
||||
("IMM: DispatchCompositionChangeEvent, no caret"));
|
||||
} else {
|
||||
uint32_t cursor = static_cast<uint32_t>(mCursorPosition);
|
||||
if (cursor > mCompositionString.Length()) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, mCursorPosition=%ld. "
|
||||
"This is larger than mCompositionString.Length()=%lu",
|
||||
mCursorPosition, mCompositionString.Length()));
|
||||
cursor = mCompositionString.Length();
|
||||
}
|
||||
|
||||
// If caret is in the target clause, the target clause will be painted as
|
||||
// normal selection range. Since caret shouldn't be in selection range on
|
||||
// Windows, we shouldn't append caret range in such case.
|
||||
const TextRangeArray* clauses = dispatcher->GetPendingCompositionClauses();
|
||||
const TextRange* targetClause =
|
||||
clauses ? clauses->GetTargetClause() : nullptr;
|
||||
if (targetClause &&
|
||||
cursor >= targetClause->mStartOffset &&
|
||||
cursor <= targetClause->mEndOffset) {
|
||||
// Forget the caret position specified by IME since Gecko's caret position
|
||||
// will be at the end of composition string.
|
||||
mCursorPosition = NO_IME_CARET;
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, no caret due to it's in the target "
|
||||
"clause, now, mCursorPosition is NO_IME_CARET"));
|
||||
}
|
||||
|
||||
if (mCursorPosition != NO_IME_CARET) {
|
||||
rv = dispatcher->SetCaretInPendingComposition(cursor, 0);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: DispatchCompositionChangeEvent, FAILED due to"
|
||||
"TextEventDispatcher::SetCaretInPendingComposition() failure"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t cursor = static_cast<uint32_t>(mCursorPosition);
|
||||
if (cursor > mCompositionString.Length()) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, mCursorPosition=%ld. "
|
||||
"This is larger than mCompositionString.Length()=%lu",
|
||||
mCursorPosition, mCompositionString.Length()));
|
||||
cursor = mCompositionString.Length();
|
||||
WidgetEventTime eventTime = aWindow->CurrentMessageWidgetEventTime();
|
||||
nsEventStatus status;
|
||||
rv = dispatcher->FlushPendingComposition(status, &eventTime);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("IMM: DispatchCompositionChangeEvent, FAILED due to"
|
||||
"TextEventDispatcher::FlushPendingComposition() failure"));
|
||||
return;
|
||||
}
|
||||
|
||||
// If caret is in the target clause, the target clause will be painted as
|
||||
// normal selection range. Since caret shouldn't be in selection range on
|
||||
// Windows, we shouldn't append caret range in such case.
|
||||
const TextRange* targetClause = textRangeArray->GetTargetClause();
|
||||
if (targetClause &&
|
||||
cursor >= targetClause->mStartOffset &&
|
||||
cursor <= targetClause->mEndOffset) {
|
||||
// Forget the caret position specified by IME since Gecko's caret position
|
||||
// will be at the end of composition string.
|
||||
mCursorPosition = NO_IME_CARET;
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, no caret due to it's in the target clause, "
|
||||
"now, mCursorPosition is NO_IME_CARET"));
|
||||
return textRangeArray.forget();
|
||||
}
|
||||
|
||||
range.mStartOffset = range.mEndOffset = cursor;
|
||||
range.mRangeType = NS_TEXTRANGE_CARETPOSITION;
|
||||
textRangeArray->AppendElement(range);
|
||||
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("IMM: CreateTextRangeArray, caret position=%ld",
|
||||
range.mStartOffset));
|
||||
|
||||
return textRangeArray.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "nsRect.h"
|
||||
#include "WritingModes.h"
|
||||
#include "npapi.h"
|
||||
@ -374,7 +375,6 @@ protected:
|
||||
*/
|
||||
void DispatchCompositionChangeEvent(nsWindow* aWindow,
|
||||
const IMEContext& aContext);
|
||||
already_AddRefed<mozilla::TextRangeArray> CreateTextRangeArray();
|
||||
|
||||
nsresult EnsureClauseArray(int32_t aCount);
|
||||
nsresult EnsureAttributeArray(int32_t aCount);
|
||||
@ -414,7 +414,10 @@ protected:
|
||||
mPassedIMEChar.AppendElement(msg);
|
||||
}
|
||||
|
||||
TextEventDispatcher* GetTextEventDispatcherFor(nsWindow* aWindow);
|
||||
|
||||
nsWindow* mComposingWindow;
|
||||
RefPtr<TextEventDispatcher> mDispatcher;
|
||||
nsString mCompositionString;
|
||||
InfallibleTArray<uint32_t> mClauseArray;
|
||||
InfallibleTArray<uint8_t> mAttributeArray;
|
||||
|
Loading…
x
Reference in New Issue
Block a user