From affac42d194a4eada779f04a6647de040c9966a7 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Wed, 26 Sep 2012 14:47:51 +0900 Subject: [PATCH] Bug 705057 part.4 Emulate the behavior of nsIWidget::ResetInputState() and nsIWidget::CancelIMEComposition() if the composition is synthesized r=smaug+roc, sr=roc --- content/events/src/TextComposition.cpp | 5 +- content/events/src/TextComposition.h | 6 ++ content/events/src/nsIMEStateManager.cpp | 83 +++++++++++++++++++++--- dom/base/nsDOMWindowUtils.cpp | 4 ++ widget/nsIWidget.h | 9 +++ widget/windows/TaskbarPreview.cpp | 2 +- widget/xpwidgets/nsBaseWidget.cpp | 1 - widget/xpwidgets/nsBaseWidget.h | 8 --- 8 files changed, 99 insertions(+), 19 deletions(-) diff --git a/content/events/src/TextComposition.cpp b/content/events/src/TextComposition.cpp index 5c245a3adf16..65dc006bb478 100644 --- a/content/events/src/TextComposition.cpp +++ b/content/events/src/TextComposition.cpp @@ -26,7 +26,9 @@ TextComposition::TextComposition(nsPresContext* aPresContext, mPresContext(aPresContext), mNode(aNode), // temporarily, we should assume that one native IME context is per native // widget. - mNativeContext(aEvent->widget) + mNativeContext(aEvent->widget), + mIsSynthesizedForTests( + (aEvent->flags & NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT) != 0) { } @@ -36,6 +38,7 @@ TextComposition::TextComposition(const TextComposition& aOther) mPresContext = aOther.mPresContext; mNode = aOther.mNode; mLastData = aOther.mLastData; + mIsSynthesizedForTests = aOther.mIsSynthesizedForTests; } bool diff --git a/content/events/src/TextComposition.h b/content/events/src/TextComposition.h index a47de852e856..5651eba89759 100644 --- a/content/events/src/TextComposition.h +++ b/content/events/src/TextComposition.h @@ -48,6 +48,9 @@ public: nsINode* GetEventTargetNode() const { return mNode; } // The latest CompositionEvent.data value except compositionstart event. const nsString& GetLastData() const { return mLastData; } + // Returns true if the composition is started with synthesized event which + // came from nsDOMWindowUtils. + bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; } bool MatchesNativeContext(nsIWidget* aWidget) const; bool MatchesEventTarget(nsPresContext* aPresContext, @@ -83,6 +86,9 @@ private: // the compositionstart event). nsString mLastData; + // See the comment for IsSynthesizedForTests(). + bool mIsSynthesizedForTests; + // Hide the default constructor TextComposition() {} diff --git a/content/events/src/nsIMEStateManager.cpp b/content/events/src/nsIMEStateManager.cpp index dc488d3942c2..9bc10d6654e6 100644 --- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -508,16 +508,83 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, if (sTextCompositions) { composition = sTextCompositions->GetCompositionFor(aWidget); } + if (!composition || !composition->IsSynthesizedForTests()) { + switch (aNotification) { + case NOTIFY_IME_OF_CURSOR_POS_CHANGED: + return aWidget->ResetInputState(); + case REQUEST_TO_COMMIT_COMPOSITION: + return composition ? aWidget->ResetInputState() : NS_OK; + case REQUEST_TO_CANCEL_COMPOSITION: + return composition ? aWidget->CancelIMEComposition() : NS_OK; + default: + MOZ_NOT_REACHED("Unsupported notification"); + return NS_ERROR_INVALID_ARG; + } + MOZ_NOT_REACHED( + "Failed to handle the notification for non-synthesized composition"); + } + + // If the composition is synthesized events for automated tests, we should + // dispatch composition events for emulating the native composition behavior. + // NOTE: The dispatched events are discarded if it's not safe to run script. switch (aNotification) { - case NOTIFY_IME_OF_CURSOR_POS_CHANGED: - return aWidget->ResetInputState(); - case REQUEST_TO_COMMIT_COMPOSITION: - return composition ? aWidget->ResetInputState() : NS_OK; - case REQUEST_TO_CANCEL_COMPOSITION: - return composition ? aWidget->CancelIMEComposition() : NS_OK; + case REQUEST_TO_COMMIT_COMPOSITION: { + nsCOMPtr widget(aWidget); + TextComposition backup = *composition; + + nsEventStatus status = nsEventStatus_eIgnore; + if (!backup.GetLastData().IsEmpty()) { + nsTextEvent textEvent(true, NS_TEXT_TEXT, widget); + textEvent.theText = backup.GetLastData(); + textEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + widget->DispatchEvent(&textEvent, status); + if (widget->Destroyed()) { + return NS_OK; + } + } + + status = nsEventStatus_eIgnore; + nsCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); + endEvent.data = backup.GetLastData(); + endEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + widget->DispatchEvent(&endEvent, status); + + return NS_OK; + } + case REQUEST_TO_CANCEL_COMPOSITION: { + nsCOMPtr widget(aWidget); + TextComposition backup = *composition; + + nsEventStatus status = nsEventStatus_eIgnore; + if (!backup.GetLastData().IsEmpty()) { + nsCompositionEvent updateEvent(true, NS_COMPOSITION_UPDATE, widget); + updateEvent.data = backup.GetLastData(); + updateEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + widget->DispatchEvent(&updateEvent, status); + if (widget->Destroyed()) { + return NS_OK; + } + + status = nsEventStatus_eIgnore; + nsTextEvent textEvent(true, NS_TEXT_TEXT, widget); + textEvent.theText = backup.GetLastData(); + textEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + widget->DispatchEvent(&textEvent, status); + if (widget->Destroyed()) { + return NS_OK; + } + } + + status = nsEventStatus_eIgnore; + nsCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); + endEvent.data = backup.GetLastData(); + endEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + widget->DispatchEvent(&endEvent, status); + + return NS_OK; + } default: - MOZ_NOT_REACHED("Unsupported notification"); - return NS_ERROR_INVALID_ARG; + return NS_OK; } } diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 419c9708f7d3..2681d5da931d 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1598,6 +1598,8 @@ nsDOMWindowUtils::SendCompositionEvent(const nsAString& aType, compositionEvent.data = aData; } + compositionEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + nsEventStatus status; nsresult rv = widget->DispatchEvent(&compositionEvent, status); NS_ENSURE_SUCCESS(rv, rv); @@ -1675,6 +1677,8 @@ nsDOMWindowUtils::SendTextEvent(const nsAString& aCompositionString, textEvent.rangeCount = textRanges.Length(); textEvent.rangeArray = textRanges.Elements(); + textEvent.flags |= NS_EVENT_FLAG_SYNTHETIC_TEST_EVENT; + nsEventStatus status; nsresult rv = widget->DispatchEvent(&textEvent, status); NS_ENSURE_SUCCESS(rv, rv); diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 4e80f57d5c26..333132fe78da 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -409,6 +409,7 @@ class nsIWidget : public nsISupports { nsIWidget() : mLastChild(nullptr) , mPrevSibling(nullptr) + , mOnDestroyCalled(false) {} @@ -511,6 +512,12 @@ class nsIWidget : public nsISupports { NS_IMETHOD Destroy(void) = 0; + /** + * Destroyed() returns true if Destroy() has been called already. + * Otherwise, false. + */ + bool Destroyed() const { return mOnDestroyCalled; } + /** * Reparent a widget @@ -1654,6 +1661,8 @@ protected: nsIWidget* mLastChild; nsCOMPtr mNextSibling; nsIWidget* mPrevSibling; + // When Destroy() is called, the sub class should set this true. + bool mOnDestroyCalled; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIWidget, NS_IWIDGET_IID) diff --git a/widget/windows/TaskbarPreview.cpp b/widget/windows/TaskbarPreview.cpp index d0df6df71a72..3677dcc12ad3 100644 --- a/widget/windows/TaskbarPreview.cpp +++ b/widget/windows/TaskbarPreview.cpp @@ -251,7 +251,7 @@ bool TaskbarPreview::IsWindowAvailable() const { if (mWnd) { nsWindow* win = WinUtils::GetNSWindowPtr(mWnd); - if(win && !win->HasDestroyStarted()) { + if(win && !win->Destroyed()) { return true; } } diff --git a/widget/xpwidgets/nsBaseWidget.cpp b/widget/xpwidgets/nsBaseWidget.cpp index e7eddad9688f..08c25c72908f 100644 --- a/widget/xpwidgets/nsBaseWidget.cpp +++ b/widget/xpwidgets/nsBaseWidget.cpp @@ -90,7 +90,6 @@ nsBaseWidget::nsBaseWidget() , mCursor(eCursor_standard) , mWindowType(eWindowType_child) , mBorderStyle(eBorderStyle_none) -, mOnDestroyCalled(false) , mUseAcceleratedRendering(false) , mForceLayersAcceleration(false) , mTemporarilyUseBasicLayerManager(false) diff --git a/widget/xpwidgets/nsBaseWidget.h b/widget/xpwidgets/nsBaseWidget.h index 29934b313882..e7f099d10089 100644 --- a/widget/xpwidgets/nsBaseWidget.h +++ b/widget/xpwidgets/nsBaseWidget.h @@ -228,13 +228,6 @@ public: }; friend class AutoUseBasicLayerManager; - bool HasDestroyStarted() const - { - return mOnDestroyCalled; - } - - bool Destroyed() { return mOnDestroyCalled; } - nsWindowType GetWindowType() { return mWindowType; } virtual bool UseOffMainThreadCompositing(); @@ -341,7 +334,6 @@ protected: nsCursor mCursor; nsWindowType mWindowType; nsBorderStyle mBorderStyle; - bool mOnDestroyCalled; bool mUseAcceleratedRendering; bool mForceLayersAcceleration; bool mTemporarilyUseBasicLayerManager;