From dd277f3277c4d2810fb78e2ddb85c287cd1a409c Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 28 Jan 2015 15:27:31 +0900 Subject: [PATCH] Bug 917322 part.7 TextEventDispatcher should manage if it has composition r=smaug --- dom/events/TextComposition.cpp | 37 ++++++---------------------- widget/PuppetWidget.cpp | 4 +-- widget/PuppetWidget.h | 4 ++- widget/TextEventDispatcher.cpp | 33 +++++++++++++++++++++++++ widget/TextEventDispatcher.h | 15 +++++++++++ widget/android/nsWindow.cpp | 4 +-- widget/android/nsWindow.h | 4 ++- widget/cocoa/nsChildView.h | 4 ++- widget/cocoa/nsChildView.mm | 4 +-- widget/cocoa/nsCocoaWindow.h | 4 ++- widget/cocoa/nsCocoaWindow.mm | 4 +-- widget/gtk/nsWindow.cpp | 4 +-- widget/gtk/nsWindow.h | 5 +++- widget/nsBaseWidget.cpp | 20 +++++++++++++++ widget/nsBaseWidget.h | 5 +++- widget/windows/nsWindow.cpp | 4 +-- widget/windows/nsWindow.h | 4 ++- widget/windows/winrt/MetroWidget.cpp | 4 +-- widget/windows/winrt/MetroWidget.h | 4 ++- 19 files changed, 116 insertions(+), 51 deletions(-) diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index cff46b3bc5df..352f37d89296 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -340,35 +340,14 @@ TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard) mIsRequestingCancel = false; mIsRequestingCommit = true; } - if (!mIsSynthesizedForTests) { - // FYI: CompositionEvents caused by a call of NotifyIME() may be - // discarded by PresShell if it's not safe to dispatch the event. - nsresult rv = - aWidget->NotifyIME(IMENotification(aDiscard ? - REQUEST_TO_CANCEL_COMPOSITION : - REQUEST_TO_COMMIT_COMPOSITION)); - if (rv == NS_ERROR_NOT_IMPLEMENTED) { - return rv; - } - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } else { - // Emulates to commit or cancel the composition - // FYI: These events may be discarded by PresShell if it's not safe to - // dispatch the event. - nsCOMPtr widget(aWidget); - nsAutoString commitData(aDiscard ? EmptyString() : lastData); - bool isChanging = commitData != mLastData; - uint32_t message = - isChanging ? NS_COMPOSITION_COMMIT : NS_COMPOSITION_COMMIT_AS_IS; - WidgetCompositionEvent commitEvent(true, message, widget); - if (commitEvent.message == NS_COMPOSITION_COMMIT) { - commitEvent.mData = commitData; - } - commitEvent.mFlags.mIsSynthesizedForTests = true; - nsEventStatus status = nsEventStatus_eIgnore; - widget->DispatchEvent(&commitEvent, status); + // FYI: CompositionEvents caused by a call of NotifyIME() may be + // discarded by PresShell if it's not safe to dispatch the event. + nsresult rv = + aWidget->NotifyIME(IMENotification(aDiscard ? + REQUEST_TO_CANCEL_COMPOSITION : + REQUEST_TO_COMMIT_COMPOSITION)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } } diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index b4e9fcaafbd4..4a211dac6273 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -428,8 +428,8 @@ PuppetWidget::IMEEndComposition(bool aCancel) return NS_OK; } -NS_IMETHODIMP -PuppetWidget::NotifyIME(const IMENotification& aIMENotification) +nsresult +PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification) { switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: diff --git a/widget/PuppetWidget.h b/widget/PuppetWidget.h index 793fd598b3b5..3df336cb7e0b 100644 --- a/widget/PuppetWidget.h +++ b/widget/PuppetWidget.h @@ -163,7 +163,6 @@ public: LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, bool* aAllowRetaining = nullptr) MOZ_OVERRIDE; - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction) MOZ_OVERRIDE; NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE; @@ -204,6 +203,9 @@ protected: bool mEnabled; bool mVisible; + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + private: nsresult Paint(); diff --git a/widget/TextEventDispatcher.cpp b/widget/TextEventDispatcher.cpp index c0928db416e9..dc675f0bb4fe 100644 --- a/widget/TextEventDispatcher.cpp +++ b/widget/TextEventDispatcher.cpp @@ -23,6 +23,7 @@ TextEventDispatcher::TextEventDispatcher(nsIWidget* aWidget) : mWidget(aWidget) , mInitialized(false) , mForTests(false) + , mIsComposing(false) { MOZ_RELEASE_ASSERT(mWidget, "aWidget must not be nullptr"); } @@ -33,6 +34,7 @@ TextEventDispatcher::Init() if (mInitialized) { return NS_ERROR_ALREADY_INITIALIZED; } + MOZ_ASSERT(!mIsComposing, "There should not be active composition"); mInitialized = true; mForTests = false; return NS_OK; @@ -44,6 +46,7 @@ TextEventDispatcher::InitForTests() if (mInitialized) { return NS_ERROR_ALREADY_INITIALIZED; } + MOZ_ASSERT(!mIsComposing, "There should not be active composition"); mInitialized = true; mForTests = true; return NS_OK; @@ -85,6 +88,11 @@ TextEventDispatcher::StartComposition(nsEventStatus& aStatus) return rv; } + if (NS_WARN_IF(mIsComposing)) { + return NS_ERROR_FAILURE; + } + + mIsComposing = true; nsCOMPtr widget(mWidget); WidgetCompositionEvent compositionStartEvent(true, NS_COMPOSITION_START, widget); @@ -108,6 +116,10 @@ TextEventDispatcher::CommitComposition(nsEventStatus& aStatus, return rv; } + // End current composition and make this free for other IMEs. + mIsComposing = false; + mInitialized = false; + nsCOMPtr widget(mWidget); uint32_t message = aCommitString ? NS_COMPOSITION_COMMIT : NS_COMPOSITION_COMMIT_AS_IS; @@ -124,6 +136,27 @@ TextEventDispatcher::CommitComposition(nsEventStatus& aStatus, return NS_OK; } +nsresult +TextEventDispatcher::NotifyIME(const IMENotification& aIMENotification) +{ + switch (aIMENotification.mMessage) { + case REQUEST_TO_COMMIT_COMPOSITION: { + NS_ASSERTION(mIsComposing, "Why is this requested without composition?"); + nsEventStatus status = nsEventStatus_eIgnore; + CommitComposition(status); + return NS_OK; + } + case REQUEST_TO_CANCEL_COMPOSITION: { + NS_ASSERTION(mIsComposing, "Why is this requested without composition?"); + nsEventStatus status = nsEventStatus_eIgnore; + CommitComposition(status, &EmptyString()); + return NS_OK; + } + default: + return NS_ERROR_NOT_IMPLEMENTED; + } +} + /****************************************************************************** * TextEventDispatcher::PendingComposition *****************************************************************************/ diff --git a/widget/TextEventDispatcher.h b/widget/TextEventDispatcher.h index a5e258ba3c60..63629ca7567a 100644 --- a/widget/TextEventDispatcher.h +++ b/widget/TextEventDispatcher.h @@ -17,6 +17,8 @@ class nsIWidget; namespace mozilla { namespace widget { +struct IMENotification; + /** * TextEventDispatcher is a helper class for dispatching widget events defined * in TextEvents.h. Currently, this is a helper for dispatching @@ -63,6 +65,12 @@ public: */ nsresult GetState() const; + /** + * IsComposing() returns true after calling StartComposition() and before + * calling CommitComposition(). + */ + bool IsComposing() const { return mIsComposing; } + /** * StartComposition() starts composition explicitly. */ @@ -135,6 +143,11 @@ public: return mPendingComposition.Flush(this, aStatus); } + /** + * @see nsIWidget::NotifyIME() + */ + nsresult NotifyIME(const IMENotification& aIMENotification); + private: // mWidget is owner of the instance. When this is created, this is set. // And when mWidget is released, this is cleared by OnDestroyWidget(). @@ -168,6 +181,8 @@ private: bool mInitialized; bool mForTests; + // See IsComposing(). + bool mIsComposing; /** * InitEvent() initializes aEvent. This must be called before dispatching diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 1479a8de20ff..19e386245fe3 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2047,8 +2047,8 @@ nsWindow::UserActivity() } } -NS_IMETHODIMP -nsWindow::NotifyIME(const IMENotification& aIMENotification) +nsresult +nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 59d72f1a25dc..97dd2b7d7377 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -132,7 +132,6 @@ public: return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction); NS_IMETHOD_(InputContext) GetInputContext(); @@ -228,6 +227,9 @@ protected: InputContext mInputContext; + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + static void DumpWindows(); static void DumpWindows(const nsTArray& wins, int indent = 0); static void LogWindow(nsWindow *win, int index, int indent); diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index f1111dc76f69..65aaef78f2ff 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -425,7 +425,6 @@ public: NS_IMETHOD ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE; NS_IMETHOD ForceUpdateNativeMenuAt(const nsAString& indexString) MOZ_OVERRIDE; - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction) MOZ_OVERRIDE; NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE; @@ -568,6 +567,9 @@ protected: nsIWidget* GetWidgetForListenerEvents(); + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + protected: NSView* mView; // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG] diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 9ac6fc0a0939..2bbf250b33e8 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -1579,8 +1579,8 @@ bool nsChildView::HasPendingInputEvent() #pragma mark - -NS_IMETHODIMP -nsChildView::NotifyIME(const IMENotification& aIMENotification) +nsresult +nsChildView::NotifyIMEInternal(const IMENotification& aIMENotification) { switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index acae40374120..814cd73b0198 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -330,7 +330,6 @@ public: void SetMenuBar(nsMenuBarX* aMenuBar); nsMenuBarX *GetMenuBar(); - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD_(void) SetInputContext( const InputContext& aContext, const InputContextAction& aAction) MOZ_OVERRIDE; @@ -381,6 +380,9 @@ protected: return widget.forget(); } + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + nsIWidget* mParent; // if we're a popup, this is our parent [WEAK] BaseWindow* mWindow; // our cocoa window [STRONG] WindowDelegate* mDelegate; // our delegate for processing window msgs [STRONG] diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm index d7bacf40765c..c2ca5819591d 100644 --- a/widget/cocoa/nsCocoaWindow.mm +++ b/widget/cocoa/nsCocoaWindow.mm @@ -2111,8 +2111,8 @@ void nsCocoaWindow::SetPopupWindowLevel() } } -NS_IMETHODIMP -nsCocoaWindow::NotifyIME(const IMENotification& aIMENotification) +nsresult +nsCocoaWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { switch (aIMENotification.mMessage) { case NOTIFY_IME_OF_FOCUS: diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 0766fc4e1c0b..ac60972ef09a 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -5977,8 +5977,8 @@ nsChildWindow::~nsChildWindow() { } -NS_IMETHODIMP -nsWindow::NotifyIME(const IMENotification& aIMENotification) +nsresult +nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { if (MOZ_UNLIKELY(!mIMModule)) { return NS_ERROR_NOT_AVAILABLE; diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index eeee01b10f76..4c6ac8639da6 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -260,7 +260,6 @@ public: bool DispatchKeyDownEvent(GdkEventKey *aEvent, bool *aIsCancelled); - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction) MOZ_OVERRIDE; NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE; @@ -318,6 +317,10 @@ protected: GtkWidget* aNewContainer, GdkWindow* aNewParentWindow, GtkWidget* aOldContainer); + + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + nsCOMPtr mParent; // Is this a toplevel window? bool mIsTopLevel; diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 11dd7e12443f..878c11bc2358 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -73,6 +73,7 @@ nsIRollupListener* nsBaseWidget::gRollupListener = nullptr; using namespace mozilla::layers; using namespace mozilla::ipc; +using namespace mozilla::widget; using namespace mozilla; using base::Thread; @@ -1585,6 +1586,25 @@ nsBaseWidget::NotifyUIStateChanged(UIStateChangeType aShowAccelerators, } } +NS_IMETHODIMP +nsBaseWidget::NotifyIME(const IMENotification& aIMENotification) +{ + switch (aIMENotification.mMessage) { + case REQUEST_TO_COMMIT_COMPOSITION: + case REQUEST_TO_CANCEL_COMPOSITION: + // Currently, if native IME handler doesn't use TextEventDispatcher, + // the request may be notified to mTextEventDispatcher or native IME + // directly. Therefore, if mTextEventDispatcher has a composition, + // the request should be handled by the mTextEventDispatcher. + if (mTextEventDispatcher && mTextEventDispatcher->IsComposing()) { + return mTextEventDispatcher->NotifyIME(aIMENotification); + } + // Otherwise, call NotifyIMEInternal() for native IME handlers. + default: + return NotifyIMEInternal(aIMENotification); + } +} + NS_IMETHODIMP_(nsIWidget::TextEventDispatcher*) nsBaseWidget::GetTextEventDispatcher() { diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index e9ad21a448b7..082f8b741a53 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -195,7 +195,7 @@ public: NS_IMETHOD BeginMoveDrag(mozilla::WidgetMouseEvent* aEvent) MOZ_OVERRIDE; virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE MOZ_FINAL; NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD_(bool) ExecuteNativeKeyBinding( NativeKeyBindingsType aType, @@ -358,6 +358,9 @@ protected: uint32_t aPointerOrientation) MOZ_OVERRIDE { return NS_ERROR_UNEXPECTED; } + virtual nsresult NotifyIMEInternal(const IMENotification& aIMENotification) + { return NS_ERROR_NOT_IMPLEMENTED; } + protected: // Stores the clip rectangles in aRects into mClipRects. Returns true // if the new rectangles are different from the old rectangles. diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index f47c945ac1cf..e364e51949bf 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -6703,8 +6703,8 @@ nsWindow::OnSysColorChanged() ************************************************************** **************************************************************/ -NS_IMETHODIMP -nsWindow::NotifyIME(const IMENotification& aIMENotification) +nsresult +nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification) { return IMEHandler::NotifyIME(this, aIMENotification); } diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index efc0e2247fee..e580254debe0 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -175,7 +175,6 @@ public: double aDeltaZ, uint32_t aModifierFlags, uint32_t aAdditionalFlags); - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction); NS_IMETHOD_(InputContext) GetInputContext(); @@ -282,6 +281,9 @@ protected: virtual void WindowUsesOMTC() MOZ_OVERRIDE; + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + // A magic number to identify the FAKETRACKPOINTSCROLLABLE window created // when the trackpoint hack is enabled. enum { eFakeTrackPointScrollableID = 0x46545053 }; diff --git a/widget/windows/winrt/MetroWidget.cpp b/widget/windows/winrt/MetroWidget.cpp index 23e66225bc94..2c4ad6e06035 100644 --- a/widget/windows/winrt/MetroWidget.cpp +++ b/widget/windows/winrt/MetroWidget.cpp @@ -1527,8 +1527,8 @@ MetroWidget::GetInputContext() return mInputContext; } -NS_IMETHODIMP -MetroWidget::NotifyIME(const IMENotification& aIMENotification) +nsresult +MetroWidget::NotifyIMEInternal(const IMENotification& aIMENotification) { switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: diff --git a/widget/windows/winrt/MetroWidget.h b/widget/windows/winrt/MetroWidget.h index d0bc8c8f435b..74742d98705a 100644 --- a/widget/windows/winrt/MetroWidget.h +++ b/widget/windows/winrt/MetroWidget.h @@ -160,7 +160,6 @@ public: NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction); NS_IMETHOD_(nsIWidget::InputContext) GetInputContext(); - NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE; NS_IMETHOD GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState); virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE; @@ -252,6 +251,9 @@ protected: void RemoveSubclass(); nsIWidgetListener* GetPaintListener(); + virtual nsresult NotifyIMEInternal( + const IMENotification& aIMENotification) MOZ_OVERRIDE; + // Async event dispatching void DispatchAsyncScrollEvent(DispatchMsg* aEvent); void DeliverNextScrollEvent();