Bug 1137561 part.3 Make IMMHandler use TextEventDispatcher r=m_kato

This commit is contained in:
Masayuki Nakano 2016-03-16 13:47:48 +09:00
parent 04597dabbb
commit 4de2cb08cc
3 changed files with 150 additions and 91 deletions

View File

@ -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:

View File

@ -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

View File

@ -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;