Bug 1388647 - part2: Make IMEInputHandler of Cocoa widget handle request to commit/cancel composition synchronously r=m_kato

When Gecko started to support Cocoa widget, we needed to use NSInputManager.
That allowed applications to access only focused IME context.  Therefore, commit
composition request handler for Cocoa is designed as handling asynchronosly if
it's requested when the window is not active or is being inactivated.

Additionally, the asynchronous handling isn't perfect.  We hit some MOZ_ASSERT()
now in some places.  E.g., in SelectedRange(), it doesn't assume that it's
called during deactive.

On the other hand, NSInputManager was alreay obsolete and we already stopped using it
(bug 810225).  Instead, we're using NSTextInputContext and it allows applications
to access IME anytime.  Therefore, if we make IMEInputHandler handles commit/cancel
composition requests synchronsly, that behaves same as the other platforms.  So, we
can get rid of macOS specific issue completely.

MozReview-Commit-ID: X7aWmGq95x

--HG--
extra : rebase_source : a472a03e3ef6f424fe73c2d438b8326bed80278d
This commit is contained in:
Masayuki Nakano 2017-08-09 18:41:19 +09:00
Родитель 9467d56cf9
Коммит 5345065a53
2 изменённых файлов: 12 добавлений и 85 удалений

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

@ -917,14 +917,6 @@ public:
bool IsASCIICapableOnly() { return mIsASCIICapableOnly; }
bool IgnoreIMECommit() { return mIgnoreIMECommit; }
bool IgnoreIMEComposition()
{
// Ignore the IME composition events when we're pending to discard the
// composition and we are not to handle the IME composition now.
return (mPendingMethods & kDiscardIMEComposition) &&
(mIsInFocusProcessing || !IsFocused());
}
void CommitIMEComposition();
void CancelIMEComposition();
@ -951,8 +943,7 @@ protected:
nsCOMPtr<nsITimer> mTimer;
enum {
kNotifyIMEOfFocusChangeInGecko = 1,
kDiscardIMEComposition = 2,
kSyncASCIICapableOnly = 4
kSyncASCIICapableOnly = 2
};
uint32_t mPendingMethods;
@ -990,11 +981,6 @@ private:
bool mIsIMEEnabled;
bool mIsASCIICapableOnly;
bool mIgnoreIMECommit;
// This flag is enabled by OnFocusChangeInGecko, and will be cleared by
// ExecutePendingMethods. When this is true, IsFocus() returns TRUE. At
// that time, the focus processing in Gecko might not be finished yet. So,
// you cannot use WidgetQueryContentEvent or something.
bool mIsInFocusProcessing;
bool mIMEHasFocus;
void KillIMEComposition();
@ -1003,7 +989,6 @@ private:
// Pending methods
void NotifyIMEOfFocusChangeInGecko();
void DiscardIMEComposition();
void SyncASCIICapableOnly();
static bool sStaticMembersInitialized;

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

@ -2185,13 +2185,13 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::InsertText, aAttrString=\"%s\", "
"aReplacementRange=%p { location=%lu, length=%lu }, "
"IsIMEComposing()=%s, IgnoreIMEComposition()=%s, "
"IsIMEComposing()=%s, "
"keyevent=%p, keydownHandled=%s, keypressDispatched=%s, "
"causedOtherKeyEvents=%s, compositionDispatched=%s",
this, GetCharacters([aAttrString string]), aReplacementRange,
static_cast<unsigned long>(aReplacementRange ? aReplacementRange->location : 0),
static_cast<unsigned long>(aReplacementRange ? aReplacementRange->length : 0),
TrueOrFalse(IsIMEComposing()), TrueOrFalse(IgnoreIMEComposition()),
TrueOrFalse(IsIMEComposing()),
currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownHandled) : "N/A",
@ -2202,10 +2202,6 @@ TextInputHandler::InsertText(NSAttributedString* aAttrString,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mCompositionDispatched) : "N/A"));
if (IgnoreIMEComposition()) {
return;
}
InputContext context = mWidget->GetInputContext();
bool isEditable = (context.mIMEState.mEnabled == IMEState::ENABLED ||
context.mIMEState.mEnabled == IMEState::PASSWORD);
@ -2367,10 +2363,10 @@ TextInputHandler::InsertNewline()
MOZ_LOG(gLog, LogLevel::Info,
("%p TextInputHandler::InsertNewline, "
"IsIMEComposing()=%s, IgnoreIMEComposition()=%s, "
"IsIMEComposing()=%s, "
"keyevent=%p, keydownHandled=%s, keypressDispatched=%s, "
"causedOtherKeyEvents=%s, compositionDispatched=%s",
this, TrueOrFalse(IsIMEComposing()), TrueOrFalse(IgnoreIMEComposition()),
this, TrueOrFalse(IsIMEComposing()),
currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr,
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mKeyDownHandled) : "N/A",
@ -2381,10 +2377,6 @@ TextInputHandler::InsertNewline()
currentKeyEvent ?
TrueOrFalse(currentKeyEvent->mCompositionDispatched) : "N/A"));
if (IgnoreIMEComposition()) {
return;
}
// If "insertNewline:" command shouldn't be handled, let's ignore it.
if (currentKeyEvent && !currentKeyEvent->CanHandleCommand()) {
return;
@ -2870,37 +2862,6 @@ IMEInputHandler::NotifyIMEOfFocusChangeInGecko()
NS_OBJC_END_TRY_ABORT_BLOCK;
}
void
IMEInputHandler::DiscardIMEComposition()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::DiscardIMEComposition, "
"Destroyed()=%s, IsFocused()=%s, mView=%p, inputContext=%p",
this, TrueOrFalse(Destroyed()), TrueOrFalse(IsFocused()),
mView, mView ? [mView inputContext] : nullptr));
if (Destroyed()) {
return;
}
if (!IsFocused()) {
// retry at next focus event
mPendingMethods |= kDiscardIMEComposition;
return;
}
NS_ENSURE_TRUE_VOID(mView);
NSTextInputContext* inputContext = [mView inputContext];
NS_ENSURE_TRUE_VOID(inputContext);
mIgnoreIMECommit = true;
[inputContext discardMarkedText];
mIgnoreIMECommit = false;
NS_OBJC_END_TRY_ABORT_BLOCK
}
void
IMEInputHandler::SyncASCIICapableOnly()
{
@ -2974,7 +2935,6 @@ IMEInputHandler::ExecutePendingMethods()
}
if (![[NSApplication sharedApplication] isActive]) {
mIsInFocusProcessing = false;
// If we're not active, we should retry at focus event
return;
}
@ -2984,16 +2944,12 @@ IMEInputHandler::ExecutePendingMethods()
// run now, they can reentry to the pending flags by theirselves.
mPendingMethods = 0;
if (pendingMethods & kDiscardIMEComposition)
DiscardIMEComposition();
if (pendingMethods & kSyncASCIICapableOnly)
SyncASCIICapableOnly();
if (pendingMethods & kNotifyIMEOfFocusChangeInGecko) {
NotifyIMEOfFocusChangeInGecko();
}
mIsInFocusProcessing = false;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
@ -3417,7 +3373,7 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
("%p IMEInputHandler::SetMarkedText, "
"aAttrString=\"%s\", aSelectedRange={ location=%lu, length=%lu }, "
"aReplacementRange=%p { location=%lu, length=%lu }, "
"Destroyed()=%s, IgnoreIMEComposition()=%s, IsIMEComposing()=%s, "
"Destroyed()=%s, IsIMEComposing()=%s, "
"mMarkedRange={ location=%lu, length=%lu }, keyevent=%p, "
"keydownHandled=%s, keypressDispatched=%s, causedOtherKeyEvents=%s, "
"compositionDispatched=%s",
@ -3426,8 +3382,7 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
static_cast<unsigned long>(aSelectedRange.length), aReplacementRange,
static_cast<unsigned long>(aReplacementRange ? aReplacementRange->location : 0),
static_cast<unsigned long>(aReplacementRange ? aReplacementRange->length : 0),
TrueOrFalse(Destroyed()), TrueOrFalse(IgnoreIMEComposition()),
TrueOrFalse(IsIMEComposing()),
TrueOrFalse(Destroyed()), TrueOrFalse(IsIMEComposing()),
static_cast<unsigned long>(mMarkedRange.location),
static_cast<unsigned long>(mMarkedRange.length),
currentKeyEvent ? currentKeyEvent->mKeyEvent : nullptr,
@ -3447,7 +3402,7 @@ IMEInputHandler::SetMarkedText(NSAttributedString* aAttrString,
currentKeyEvent->mCompositionDispatched = true;
}
if (Destroyed() || IgnoreIMEComposition()) {
if (Destroyed()) {
return;
}
@ -3912,7 +3867,6 @@ IMEInputHandler::IMEInputHandler(nsChildView* aWidget,
, mIsIMEEnabled(true)
, mIsASCIICapableOnly(false)
, mIgnoreIMECommit(false)
, mIsInFocusProcessing(false)
, mIMEHasFocus(false)
{
InitStaticMembers();
@ -3958,7 +3912,6 @@ IMEInputHandler::OnFocusChangeInGecko(bool aFocus)
}
sFocusedIMEHandler = this;
mIsInFocusProcessing = true;
// We need to notify IME of focus change in Gecko as native focus change
// because the window level of the focused element in Gecko may be changed.
@ -4051,26 +4004,15 @@ IMEInputHandler::KillIMEComposition()
TrueOrFalse(mIsIMEComposing), TrueOrFalse(Destroyed()),
TrueOrFalse(IsFocused())));
if (Destroyed()) {
if (Destroyed() || NS_WARN_IF(!mView)) {
return;
}
if (IsFocused()) {
NS_ENSURE_TRUE_VOID(mView);
NSTextInputContext* inputContext = [mView inputContext];
NS_ENSURE_TRUE_VOID(inputContext);
[inputContext discardMarkedText];
NSTextInputContext* inputContext = [mView inputContext];
if (NS_WARN_IF(!inputContext)) {
return;
}
MOZ_LOG(gLog, LogLevel::Info,
("%p IMEInputHandler::KillIMEComposition, Pending...", this));
// Commit the composition internally.
SendCommittedText(mIMECompositionString);
NS_ASSERTION(!mIsIMEComposing, "We're still in a composition");
// The pending method will be fired by the next focus event.
mPendingMethods |= kDiscardIMEComposition;
[inputContext discardMarkedText];
NS_OBJC_END_TRY_ABORT_BLOCK;
}