Bug 917322 part.7 TextEventDispatcher should manage if it has composition r=smaug

This commit is contained in:
Masayuki Nakano 2015-01-28 15:27:31 +09:00
Родитель cdcbe304ef
Коммит dd277f3277
19 изменённых файлов: 116 добавлений и 51 удалений

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

@ -340,35 +340,14 @@ TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard)
mIsRequestingCancel = false; mIsRequestingCancel = false;
mIsRequestingCommit = true; mIsRequestingCommit = true;
} }
if (!mIsSynthesizedForTests) { // FYI: CompositionEvents caused by a call of NotifyIME() may be
// FYI: CompositionEvents caused by a call of NotifyIME() may be // discarded by PresShell if it's not safe to dispatch the event.
// discarded by PresShell if it's not safe to dispatch the event. nsresult rv =
nsresult rv = aWidget->NotifyIME(IMENotification(aDiscard ?
aWidget->NotifyIME(IMENotification(aDiscard ? REQUEST_TO_CANCEL_COMPOSITION :
REQUEST_TO_CANCEL_COMPOSITION : REQUEST_TO_COMMIT_COMPOSITION));
REQUEST_TO_COMMIT_COMPOSITION)); if (NS_WARN_IF(NS_FAILED(rv))) {
if (rv == NS_ERROR_NOT_IMPLEMENTED) { return rv;
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<nsIWidget> 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);
} }
} }

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

@ -428,8 +428,8 @@ PuppetWidget::IMEEndComposition(bool aCancel)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsresult
PuppetWidget::NotifyIME(const IMENotification& aIMENotification) PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
switch (aIMENotification.mMessage) { switch (aIMENotification.mMessage) {
case REQUEST_TO_COMMIT_COMPOSITION: case REQUEST_TO_COMMIT_COMPOSITION:

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

@ -163,7 +163,6 @@ public:
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
bool* aAllowRetaining = nullptr) MOZ_OVERRIDE; bool* aAllowRetaining = nullptr) MOZ_OVERRIDE;
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) MOZ_OVERRIDE; const InputContextAction& aAction) MOZ_OVERRIDE;
NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE; NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE;
@ -204,6 +203,9 @@ protected:
bool mEnabled; bool mEnabled;
bool mVisible; bool mVisible;
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
private: private:
nsresult Paint(); nsresult Paint();

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

@ -23,6 +23,7 @@ TextEventDispatcher::TextEventDispatcher(nsIWidget* aWidget)
: mWidget(aWidget) : mWidget(aWidget)
, mInitialized(false) , mInitialized(false)
, mForTests(false) , mForTests(false)
, mIsComposing(false)
{ {
MOZ_RELEASE_ASSERT(mWidget, "aWidget must not be nullptr"); MOZ_RELEASE_ASSERT(mWidget, "aWidget must not be nullptr");
} }
@ -33,6 +34,7 @@ TextEventDispatcher::Init()
if (mInitialized) { if (mInitialized) {
return NS_ERROR_ALREADY_INITIALIZED; return NS_ERROR_ALREADY_INITIALIZED;
} }
MOZ_ASSERT(!mIsComposing, "There should not be active composition");
mInitialized = true; mInitialized = true;
mForTests = false; mForTests = false;
return NS_OK; return NS_OK;
@ -44,6 +46,7 @@ TextEventDispatcher::InitForTests()
if (mInitialized) { if (mInitialized) {
return NS_ERROR_ALREADY_INITIALIZED; return NS_ERROR_ALREADY_INITIALIZED;
} }
MOZ_ASSERT(!mIsComposing, "There should not be active composition");
mInitialized = true; mInitialized = true;
mForTests = true; mForTests = true;
return NS_OK; return NS_OK;
@ -85,6 +88,11 @@ TextEventDispatcher::StartComposition(nsEventStatus& aStatus)
return rv; return rv;
} }
if (NS_WARN_IF(mIsComposing)) {
return NS_ERROR_FAILURE;
}
mIsComposing = true;
nsCOMPtr<nsIWidget> widget(mWidget); nsCOMPtr<nsIWidget> widget(mWidget);
WidgetCompositionEvent compositionStartEvent(true, NS_COMPOSITION_START, WidgetCompositionEvent compositionStartEvent(true, NS_COMPOSITION_START,
widget); widget);
@ -108,6 +116,10 @@ TextEventDispatcher::CommitComposition(nsEventStatus& aStatus,
return rv; return rv;
} }
// End current composition and make this free for other IMEs.
mIsComposing = false;
mInitialized = false;
nsCOMPtr<nsIWidget> widget(mWidget); nsCOMPtr<nsIWidget> widget(mWidget);
uint32_t message = aCommitString ? NS_COMPOSITION_COMMIT : uint32_t message = aCommitString ? NS_COMPOSITION_COMMIT :
NS_COMPOSITION_COMMIT_AS_IS; NS_COMPOSITION_COMMIT_AS_IS;
@ -124,6 +136,27 @@ TextEventDispatcher::CommitComposition(nsEventStatus& aStatus,
return NS_OK; 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 * TextEventDispatcher::PendingComposition
*****************************************************************************/ *****************************************************************************/

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

@ -17,6 +17,8 @@ class nsIWidget;
namespace mozilla { namespace mozilla {
namespace widget { namespace widget {
struct IMENotification;
/** /**
* TextEventDispatcher is a helper class for dispatching widget events defined * TextEventDispatcher is a helper class for dispatching widget events defined
* in TextEvents.h. Currently, this is a helper for dispatching * in TextEvents.h. Currently, this is a helper for dispatching
@ -63,6 +65,12 @@ public:
*/ */
nsresult GetState() const; nsresult GetState() const;
/**
* IsComposing() returns true after calling StartComposition() and before
* calling CommitComposition().
*/
bool IsComposing() const { return mIsComposing; }
/** /**
* StartComposition() starts composition explicitly. * StartComposition() starts composition explicitly.
*/ */
@ -135,6 +143,11 @@ public:
return mPendingComposition.Flush(this, aStatus); return mPendingComposition.Flush(this, aStatus);
} }
/**
* @see nsIWidget::NotifyIME()
*/
nsresult NotifyIME(const IMENotification& aIMENotification);
private: private:
// mWidget is owner of the instance. When this is created, this is set. // mWidget is owner of the instance. When this is created, this is set.
// And when mWidget is released, this is cleared by OnDestroyWidget(). // And when mWidget is released, this is cleared by OnDestroyWidget().
@ -168,6 +181,8 @@ private:
bool mInitialized; bool mInitialized;
bool mForTests; bool mForTests;
// See IsComposing().
bool mIsComposing;
/** /**
* InitEvent() initializes aEvent. This must be called before dispatching * InitEvent() initializes aEvent. This must be called before dispatching

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

@ -2047,8 +2047,8 @@ nsWindow::UserActivity()
} }
} }
NS_IMETHODIMP nsresult
nsWindow::NotifyIME(const IMENotification& aIMENotification) nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
switch (aIMENotification.mMessage) { switch (aIMENotification.mMessage) {
case REQUEST_TO_COMMIT_COMPOSITION: case REQUEST_TO_COMMIT_COMPOSITION:

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

@ -132,7 +132,6 @@ public:
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction); const InputContextAction& aAction);
NS_IMETHOD_(InputContext) GetInputContext(); NS_IMETHOD_(InputContext) GetInputContext();
@ -228,6 +227,9 @@ protected:
InputContext mInputContext; InputContext mInputContext;
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
static void DumpWindows(); static void DumpWindows();
static void DumpWindows(const nsTArray<nsWindow*>& wins, int indent = 0); static void DumpWindows(const nsTArray<nsWindow*>& wins, int indent = 0);
static void LogWindow(nsWindow *win, int index, int indent); static void LogWindow(nsWindow *win, int index, int indent);

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

@ -425,7 +425,6 @@ public:
NS_IMETHOD ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE; NS_IMETHOD ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE;
NS_IMETHOD ForceUpdateNativeMenuAt(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, NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) MOZ_OVERRIDE; const InputContextAction& aAction) MOZ_OVERRIDE;
NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE; NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE;
@ -568,6 +567,9 @@ protected:
nsIWidget* GetWidgetForListenerEvents(); nsIWidget* GetWidgetForListenerEvents();
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
protected: protected:
NSView<mozView>* mView; // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG] NSView<mozView>* mView; // my parallel cocoa view (ChildView or NativeScrollbarView), [STRONG]

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

@ -1579,8 +1579,8 @@ bool nsChildView::HasPendingInputEvent()
#pragma mark - #pragma mark -
NS_IMETHODIMP nsresult
nsChildView::NotifyIME(const IMENotification& aIMENotification) nsChildView::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
switch (aIMENotification.mMessage) { switch (aIMENotification.mMessage) {
case REQUEST_TO_COMMIT_COMPOSITION: case REQUEST_TO_COMMIT_COMPOSITION:

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

@ -330,7 +330,6 @@ public:
void SetMenuBar(nsMenuBarX* aMenuBar); void SetMenuBar(nsMenuBarX* aMenuBar);
nsMenuBarX *GetMenuBar(); nsMenuBarX *GetMenuBar();
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
NS_IMETHOD_(void) SetInputContext( NS_IMETHOD_(void) SetInputContext(
const InputContext& aContext, const InputContext& aContext,
const InputContextAction& aAction) MOZ_OVERRIDE; const InputContextAction& aAction) MOZ_OVERRIDE;
@ -381,6 +380,9 @@ protected:
return widget.forget(); return widget.forget();
} }
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
nsIWidget* mParent; // if we're a popup, this is our parent [WEAK] nsIWidget* mParent; // if we're a popup, this is our parent [WEAK]
BaseWindow* mWindow; // our cocoa window [STRONG] BaseWindow* mWindow; // our cocoa window [STRONG]
WindowDelegate* mDelegate; // our delegate for processing window msgs [STRONG] WindowDelegate* mDelegate; // our delegate for processing window msgs [STRONG]

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

@ -2111,8 +2111,8 @@ void nsCocoaWindow::SetPopupWindowLevel()
} }
} }
NS_IMETHODIMP nsresult
nsCocoaWindow::NotifyIME(const IMENotification& aIMENotification) nsCocoaWindow::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
switch (aIMENotification.mMessage) { switch (aIMENotification.mMessage) {
case NOTIFY_IME_OF_FOCUS: case NOTIFY_IME_OF_FOCUS:

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

@ -5977,8 +5977,8 @@ nsChildWindow::~nsChildWindow()
{ {
} }
NS_IMETHODIMP nsresult
nsWindow::NotifyIME(const IMENotification& aIMENotification) nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
if (MOZ_UNLIKELY(!mIMModule)) { if (MOZ_UNLIKELY(!mIMModule)) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;

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

@ -260,7 +260,6 @@ public:
bool DispatchKeyDownEvent(GdkEventKey *aEvent, bool DispatchKeyDownEvent(GdkEventKey *aEvent,
bool *aIsCancelled); bool *aIsCancelled);
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) MOZ_OVERRIDE; const InputContextAction& aAction) MOZ_OVERRIDE;
NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE; NS_IMETHOD_(InputContext) GetInputContext() MOZ_OVERRIDE;
@ -318,6 +317,10 @@ protected:
GtkWidget* aNewContainer, GtkWidget* aNewContainer,
GdkWindow* aNewParentWindow, GdkWindow* aNewParentWindow,
GtkWidget* aOldContainer); GtkWidget* aOldContainer);
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
nsCOMPtr<nsIWidget> mParent; nsCOMPtr<nsIWidget> mParent;
// Is this a toplevel window? // Is this a toplevel window?
bool mIsTopLevel; bool mIsTopLevel;

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

@ -73,6 +73,7 @@ nsIRollupListener* nsBaseWidget::gRollupListener = nullptr;
using namespace mozilla::layers; using namespace mozilla::layers;
using namespace mozilla::ipc; using namespace mozilla::ipc;
using namespace mozilla::widget;
using namespace mozilla; using namespace mozilla;
using base::Thread; 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*) NS_IMETHODIMP_(nsIWidget::TextEventDispatcher*)
nsBaseWidget::GetTextEventDispatcher() nsBaseWidget::GetTextEventDispatcher()
{ {

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

@ -195,7 +195,7 @@ public:
NS_IMETHOD BeginMoveDrag(mozilla::WidgetMouseEvent* aEvent) MOZ_OVERRIDE; NS_IMETHOD BeginMoveDrag(mozilla::WidgetMouseEvent* aEvent) MOZ_OVERRIDE;
virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } 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; } 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 AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD_(bool) ExecuteNativeKeyBinding( NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
NativeKeyBindingsType aType, NativeKeyBindingsType aType,
@ -358,6 +358,9 @@ protected:
uint32_t aPointerOrientation) MOZ_OVERRIDE uint32_t aPointerOrientation) MOZ_OVERRIDE
{ return NS_ERROR_UNEXPECTED; } { return NS_ERROR_UNEXPECTED; }
virtual nsresult NotifyIMEInternal(const IMENotification& aIMENotification)
{ return NS_ERROR_NOT_IMPLEMENTED; }
protected: protected:
// Stores the clip rectangles in aRects into mClipRects. Returns true // Stores the clip rectangles in aRects into mClipRects. Returns true
// if the new rectangles are different from the old rectangles. // if the new rectangles are different from the old rectangles.

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

@ -6703,8 +6703,8 @@ nsWindow::OnSysColorChanged()
************************************************************** **************************************************************
**************************************************************/ **************************************************************/
NS_IMETHODIMP nsresult
nsWindow::NotifyIME(const IMENotification& aIMENotification) nsWindow::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
return IMEHandler::NotifyIME(this, aIMENotification); return IMEHandler::NotifyIME(this, aIMENotification);
} }

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

@ -175,7 +175,6 @@ public:
double aDeltaZ, double aDeltaZ,
uint32_t aModifierFlags, uint32_t aModifierFlags,
uint32_t aAdditionalFlags); uint32_t aAdditionalFlags);
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction); const InputContextAction& aAction);
NS_IMETHOD_(InputContext) GetInputContext(); NS_IMETHOD_(InputContext) GetInputContext();
@ -282,6 +281,9 @@ protected:
virtual void WindowUsesOMTC() MOZ_OVERRIDE; virtual void WindowUsesOMTC() MOZ_OVERRIDE;
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
// A magic number to identify the FAKETRACKPOINTSCROLLABLE window created // A magic number to identify the FAKETRACKPOINTSCROLLABLE window created
// when the trackpoint hack is enabled. // when the trackpoint hack is enabled.
enum { eFakeTrackPointScrollableID = 0x46545053 }; enum { eFakeTrackPointScrollableID = 0x46545053 };

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

@ -1527,8 +1527,8 @@ MetroWidget::GetInputContext()
return mInputContext; return mInputContext;
} }
NS_IMETHODIMP nsresult
MetroWidget::NotifyIME(const IMENotification& aIMENotification) MetroWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
{ {
switch (aIMENotification.mMessage) { switch (aIMENotification.mMessage) {
case REQUEST_TO_COMMIT_COMPOSITION: case REQUEST_TO_COMMIT_COMPOSITION:

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

@ -160,7 +160,6 @@ public:
NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
const InputContextAction& aAction); const InputContextAction& aAction);
NS_IMETHOD_(nsIWidget::InputContext) GetInputContext(); NS_IMETHOD_(nsIWidget::InputContext) GetInputContext();
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE;
NS_IMETHOD GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState); NS_IMETHOD GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState);
virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE; virtual nsIMEUpdatePreference GetIMEUpdatePreference() MOZ_OVERRIDE;
@ -252,6 +251,9 @@ protected:
void RemoveSubclass(); void RemoveSubclass();
nsIWidgetListener* GetPaintListener(); nsIWidgetListener* GetPaintListener();
virtual nsresult NotifyIMEInternal(
const IMENotification& aIMENotification) MOZ_OVERRIDE;
// Async event dispatching // Async event dispatching
void DispatchAsyncScrollEvent(DispatchMsg* aEvent); void DispatchAsyncScrollEvent(DispatchMsg* aEvent);
void DeliverNextScrollEvent(); void DeliverNextScrollEvent();