From d5aafd2cdcdb6eaa2d3e67f37849e643f2edd55c Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 26 Sep 2014 09:05:12 +0900 Subject: [PATCH] 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 --- dom/events/IMEStateManager.cpp | 41 +++++++++++++++++++++++++++++++++- dom/events/IMEStateManager.h | 6 +++++ dom/events/TextComposition.cpp | 23 +++++++++++++++++++ dom/events/TextComposition.h | 21 +++++++++++++++++ layout/base/nsPresShell.cpp | 4 ++++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp index d3780a65f25..4731a16116d 100644 --- a/dom/events/IMEStateManager.cpp +++ b/dom/events/IMEStateManager.cpp @@ -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 composition = + sTextCompositions->GetCompositionFor(GUIEvent->widget); + composition->OnCompositionEventDiscarded(GUIEvent); +} + // static nsresult IMEStateManager::NotifyIME(IMEMessage aMessage, diff --git a/dom/events/IMEStateManager.h b/dom/events/IMEStateManager.h index 9502803e5bc..0a1b3fd0e71 100644 --- a/dom/events/IMEStateManager.h +++ b/dom/events/IMEStateManager.h @@ -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. */ diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 1affb9a9f6f..9f1911ee5ea 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -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, diff --git a/dom/events/TextComposition.h b/dom/events/TextComposition.h index 013a22be7d4..911810de212 100644 --- a/dom/events/TextComposition.h +++ b/dom/events/TextComposition.h @@ -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 */ diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 000830355cd..60d777d2943 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -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);