Bug 1065835 part.4 Destroy TextComposition instance after handling synthesized compositionend event when synthesized events for a request to commit or cancel is caused by PresShell discarding native compositionend event r=smaug

This commit is contained in:
Masayuki Nakano 2014-09-26 09:05:12 +09:00
parent 66be0a9376
commit d5aafd2cdc
5 changed files with 94 additions and 1 deletions

View File

@ -945,7 +945,14 @@ IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
// emulating a commit, the instance shouldn't be removed from the array
// because IME may perform it later. Then, we need to ignore the
// following commit events in TextComposition::DispatchEvent().
if (!aIsSynthesized && aEvent->message == NS_COMPOSITION_END) {
// However, if commit or cancel for a request is performed synchronously
// during not safe to dispatch events, PresShell must have discarded
// compositionend event. Then, the synthesized compositionend event is
// the last event for the composition. In this case, we need to
// destroy the TextComposition with synthesized compositionend event.
if ((!aIsSynthesized ||
composition->WasNativeCompositionEndEventDiscarded()) &&
aEvent->message == NS_COMPOSITION_END) {
TextCompositionArray::index_type i =
sTextCompositions->IndexOf(GUIEvent->widget);
if (i != TextCompositionArray::NoIndex) {
@ -959,6 +966,38 @@ IMEStateManager::DispatchCompositionEvent(nsINode* aEventTargetNode,
}
}
// static
void
IMEStateManager::OnCompositionEventDiscarded(WidgetEvent* aEvent)
{
// Note that this method is never called for synthesized events for emulating
// commit or cancel composition.
PR_LOG(sISMLog, PR_LOG_ALWAYS,
("ISM: IMEStateManager::OnCompositionEventDiscarded(aEvent={ mClass=%s, "
"message=%s, mFlags={ mIsTrusted=%s } })",
GetEventClassIDName(aEvent->mClass),
GetEventMessageName(aEvent->message),
GetBoolName(aEvent->mFlags.mIsTrusted)));
MOZ_ASSERT(aEvent->mClass == eCompositionEventClass ||
aEvent->mClass == eTextEventClass);
if (!aEvent->mFlags.mIsTrusted) {
return;
}
// Ignore compositionstart for now because sTextCompositions may not have
// been created yet.
if (aEvent->message == NS_COMPOSITION_START) {
return;
}
WidgetGUIEvent* GUIEvent = aEvent->AsGUIEvent();
nsRefPtr<TextComposition> composition =
sTextCompositions->GetCompositionFor(GUIEvent->widget);
composition->OnCompositionEventDiscarded(GUIEvent);
}
// static
nsresult
IMEStateManager::NotifyIME(IMEMessage aMessage,

View File

@ -105,6 +105,12 @@ public:
EventDispatchingCallback* aCallBack,
bool aIsSynthesized = false);
/**
* This is called when PresShell ignores composition event or text event due
* to not safe to dispatch events.
*/
static void OnCompositionEventDiscarded(WidgetEvent* aEvent);
/**
* Get TextComposition from widget.
*/

View File

@ -41,6 +41,7 @@ TextComposition::TextComposition(nsPresContext* aPresContext,
, mIsRequestingCommit(false)
, mIsRequestingCancel(false)
, mRequestedToCommitOrCancel(false)
, mWasNativeCompositionEndEventDiscarded(false)
{
}
@ -93,6 +94,28 @@ TextComposition::MaybeDispatchCompositionUpdate(const WidgetTextEvent* aEvent)
return !Destroyed();
}
void
TextComposition::OnCompositionEventDiscarded(const WidgetGUIEvent* aEvent)
{
// Note that this method is never called for synthesized events for emulating
// commit or cancel composition.
MOZ_ASSERT(aEvent->mFlags.mIsTrusted,
"Shouldn't be called with untrusted event");
MOZ_ASSERT(aEvent->mClass == eCompositionEventClass ||
aEvent->mClass == eTextEventClass);
// XXX If composition events are discarded, should we dispatch them with
// runnable event? However, even if we do so, it might make native IME
// confused due to async modification. Especially when native IME is
// TSF.
if (aEvent->message != NS_COMPOSITION_END) {
return;
}
mWasNativeCompositionEndEventDiscarded = true;
}
void
TextComposition::DispatchEvent(WidgetGUIEvent* aEvent,
nsEventStatus* aStatus,

View File

@ -211,6 +211,11 @@ private:
// mIsRequestingCancel are set false.
bool mRequestedToCommitOrCancel;
// mWasNativeCompositionEndEventDiscarded is true if this composition was
// requested commit or cancel itself but native compositionend event is
// discarded by PresShell due to not safe to dispatch events.
bool mWasNativeCompositionEndEventDiscarded;
// Hide the default constructor and copy constructor.
TextComposition() {}
TextComposition(const TextComposition& aOther);
@ -255,6 +260,22 @@ private:
*/
bool MaybeDispatchCompositionUpdate(const WidgetTextEvent* aEvent);
/**
* If IME has already dispatched compositionend event but it was discarded
* by PresShell due to not safe to dispatch, this returns true.
*/
bool WasNativeCompositionEndEventDiscarded() const
{
return mWasNativeCompositionEndEventDiscarded;
}
/**
* OnCompositionEventDiscarded() is called when PresShell discards
* compositionupdate, compositionend or text event due to not safe to
* dispatch event.
*/
void OnCompositionEventDiscarded(const WidgetGUIEvent* aEvent);
/**
* Calculate composition offset then notify composition update to widget
*/

View File

@ -6942,6 +6942,10 @@ PresShell::HandleEvent(nsIFrame* aFrame,
if (!nsContentUtils::IsSafeToRunScript() &&
aEvent->IsAllowedToDispatchDOMEvent()) {
if (aEvent->mClass == eCompositionEventClass ||
aEvent->mClass == eTextEventClass) {
IMEStateManager::OnCompositionEventDiscarded(aEvent);
}
#ifdef DEBUG
if (aEvent->IsIMERelatedEvent()) {
nsPrintfCString warning("%d event is discarded", aEvent->message);