mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1176954 part.3 Don't send selection change, text change nor composition update notification to IME from TabParent until all events sent to the child process is received by it r=smaug
This commit is contained in:
parent
0f6acb8281
commit
db82a01967
@ -1996,7 +1996,7 @@ TabParent::RecvNotifyIMETextChange(const ContentCache& aContentCache,
|
||||
notification.mTextChangeData.mCausedByComposition = aCausedByComposition;
|
||||
|
||||
mContentCache.AssignContent(aContentCache, ¬ification);
|
||||
IMEStateManager::NotifyIME(notification, widget, true);
|
||||
mContentCache.MaybeNotifyIME(widget, notification);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2011,8 +2011,7 @@ TabParent::RecvNotifyIMESelectedCompositionRect(
|
||||
|
||||
IMENotification notification(NOTIFY_IME_OF_COMPOSITION_UPDATE);
|
||||
mContentCache.AssignContent(aContentCache, ¬ification);
|
||||
|
||||
IMEStateManager::NotifyIME(notification, widget, true);
|
||||
mContentCache.MaybeNotifyIME(widget, notification);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2032,10 +2031,9 @@ TabParent::RecvNotifyIMESelection(const ContentCache& aContentCache,
|
||||
if (updatePreference.WantSelectionChange() &&
|
||||
(updatePreference.WantChangesCausedByComposition() ||
|
||||
!aCausedByComposition)) {
|
||||
mContentCache.InitNotification(notification);
|
||||
notification.mSelectionChangeData.mCausedByComposition =
|
||||
aCausedByComposition;
|
||||
IMEStateManager::NotifyIME(notification, widget, true);
|
||||
mContentCache.MaybeNotifyIME(widget, notification);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2092,7 +2090,15 @@ TabParent::RecvOnEventNeedingAckReceived()
|
||||
{
|
||||
// This is called when the child process receives WidgetCompositionEvent or
|
||||
// WidgetSelectionEvent.
|
||||
mContentCache.OnEventNeedingAckReceived();
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// While calling OnEventNeedingAckReceived(), TabParent *might* be destroyed
|
||||
// since it may send notifications to IME.
|
||||
nsRefPtr<TabParent> kungFuDeathGrip(this);
|
||||
mContentCache.OnEventNeedingAckReceived(widget);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -914,15 +914,22 @@ ContentCacheInParent::OnSelectionEvent(
|
||||
}
|
||||
|
||||
void
|
||||
ContentCacheInParent::OnEventNeedingAckReceived()
|
||||
ContentCacheInParent::OnEventNeedingAckReceived(nsIWidget* aWidget)
|
||||
{
|
||||
// This is called when the child process receives WidgetCompositionEvent or
|
||||
// WidgetSelectionEvent.
|
||||
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("ContentCacheInParent: 0x%p OnEventNeedingAckReceived(), "
|
||||
("ContentCacheInParent: 0x%p OnEventNeedingAckReceived(aWidget=0x%p), "
|
||||
"mPendingEventsNeedingAck=%u",
|
||||
this, mPendingEventsNeedingAck));
|
||||
this, aWidget, mPendingEventsNeedingAck));
|
||||
|
||||
MOZ_RELEASE_ASSERT(mPendingEventsNeedingAck > 0);
|
||||
mPendingEventsNeedingAck--;
|
||||
if (--mPendingEventsNeedingAck) {
|
||||
return;
|
||||
}
|
||||
|
||||
FlushPendingNotifications(aWidget);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@ -951,17 +958,85 @@ ContentCacheInParent::RequestToCommitComposition(nsIWidget* aWidget,
|
||||
}
|
||||
|
||||
void
|
||||
ContentCacheInParent::InitNotification(IMENotification& aNotification) const
|
||||
ContentCacheInParent::MaybeNotifyIME(nsIWidget* aWidget,
|
||||
IMENotification& aNotification)
|
||||
{
|
||||
if (NS_WARN_IF(aNotification.mMessage != NOTIFY_IME_OF_SELECTION_CHANGE)) {
|
||||
return;
|
||||
}
|
||||
if (aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE) {
|
||||
aNotification.mSelectionChangeData.mOffset = mSelection.StartOffset();
|
||||
aNotification.mSelectionChangeData.mLength = mSelection.Length();
|
||||
aNotification.mSelectionChangeData.mReversed = mSelection.Reversed();
|
||||
aNotification.mSelectionChangeData.SetWritingMode(mSelection.mWritingMode);
|
||||
}
|
||||
|
||||
if (!mPendingEventsNeedingAck) {
|
||||
IMEStateManager::NotifyIME(aNotification, aWidget, true);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aNotification.mMessage) {
|
||||
case NOTIFY_IME_OF_SELECTION_CHANGE:
|
||||
mPendingSelectionChange.MergeWith(aNotification);
|
||||
break;
|
||||
case NOTIFY_IME_OF_TEXT_CHANGE:
|
||||
mPendingTextChange.MergeWith(aNotification);
|
||||
break;
|
||||
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
|
||||
mPendingCompositionUpdate.MergeWith(aNotification);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unsupported notification");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentCacheInParent::FlushPendingNotifications(nsIWidget* aWidget)
|
||||
{
|
||||
MOZ_ASSERT(!mPendingEventsNeedingAck);
|
||||
|
||||
// New notifications which are notified during flushing pending notifications
|
||||
// should be merged again.
|
||||
mPendingEventsNeedingAck++;
|
||||
|
||||
nsCOMPtr<nsIWidget> kungFuDeathGrip(aWidget);
|
||||
|
||||
// First, text change notification should be sent because selection change
|
||||
// notification notifies IME of current selection range in the latest content.
|
||||
// So, IME may need the latest content before that.
|
||||
if (mPendingTextChange.HasNotification()) {
|
||||
IMENotification notification(mPendingTextChange);
|
||||
if (!aWidget->Destroyed()) {
|
||||
mPendingTextChange.Clear();
|
||||
IMEStateManager::NotifyIME(notification, aWidget, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (mPendingSelectionChange.HasNotification()) {
|
||||
IMENotification notification(mPendingSelectionChange);
|
||||
if (!aWidget->Destroyed()) {
|
||||
mPendingSelectionChange.Clear();
|
||||
IMEStateManager::NotifyIME(notification, aWidget, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, send composition update notification because it notifies IME of
|
||||
// finishing handling whole sending events.
|
||||
if (mPendingCompositionUpdate.HasNotification()) {
|
||||
IMENotification notification(mPendingCompositionUpdate);
|
||||
if (!aWidget->Destroyed()) {
|
||||
mPendingCompositionUpdate.Clear();
|
||||
IMEStateManager::NotifyIME(notification, aWidget, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!--mPendingEventsNeedingAck && !aWidget->Destroyed() &&
|
||||
(mPendingTextChange.HasNotification() ||
|
||||
mPendingSelectionChange.HasNotification() ||
|
||||
mPendingCompositionUpdate.HasNotification())) {
|
||||
FlushPendingNotifications(aWidget);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* mozilla::ContentCache::TextRectArray
|
||||
*****************************************************************************/
|
||||
|
@ -14,18 +14,13 @@
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "Units.h"
|
||||
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace widget {
|
||||
struct IMENotification;
|
||||
}
|
||||
|
||||
class ContentCacheInParent;
|
||||
|
||||
/**
|
||||
@ -322,8 +317,12 @@ public:
|
||||
/**
|
||||
* OnEventNeedingAckReceived() should be called when the child process
|
||||
* receives a sent event which needs acknowledging.
|
||||
*
|
||||
* WARNING: This may send notifications to IME. That might cause destroying
|
||||
* TabParent or aWidget. Therefore, the caller must not destroy
|
||||
* this instance during a call of this method.
|
||||
*/
|
||||
void OnEventNeedingAckReceived();
|
||||
void OnEventNeedingAckReceived(nsIWidget* aWidget);
|
||||
|
||||
/**
|
||||
* RequestToCommitComposition() requests to commit or cancel composition to
|
||||
@ -344,13 +343,18 @@ public:
|
||||
nsAString& aLastString);
|
||||
|
||||
/**
|
||||
* InitNotification() initializes aNotification with stored data.
|
||||
*
|
||||
* @param aNotification Must be NOTIFY_IME_OF_SELECTION_CHANGE.
|
||||
* MaybeNotifyIME() may notify IME of the notification. If child process
|
||||
* hasn't been handled all sending events yet, this stores the notification
|
||||
* and flush it later.
|
||||
*/
|
||||
void InitNotification(IMENotification& aNotification) const;
|
||||
void MaybeNotifyIME(nsIWidget* aWidget,
|
||||
IMENotification& aNotification);
|
||||
|
||||
private:
|
||||
IMENotification mPendingSelectionChange;
|
||||
IMENotification mPendingTextChange;
|
||||
IMENotification mPendingCompositionUpdate;
|
||||
|
||||
// This is commit string which is caused by our request.
|
||||
nsString mCommitStringByRequest;
|
||||
// Start offset of the composition string.
|
||||
@ -373,6 +377,7 @@ private:
|
||||
uint32_t aLength,
|
||||
LayoutDeviceIntRect& aUnionTextRect) const;
|
||||
|
||||
void FlushPendingNotifications(nsIWidget* aWidget);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -573,8 +573,11 @@ struct SizeConstraints {
|
||||
typedef int8_t IMEMessageType;
|
||||
enum IMEMessage : IMEMessageType
|
||||
{
|
||||
// This is used by IMENotification internally. This means that the instance
|
||||
// hasn't been initialized yet.
|
||||
NOTIFY_IME_OF_NOTHING,
|
||||
// An editable content is getting focus
|
||||
NOTIFY_IME_OF_FOCUS = 1,
|
||||
NOTIFY_IME_OF_FOCUS,
|
||||
// An editable content is losing focus
|
||||
NOTIFY_IME_OF_BLUR,
|
||||
// Selection in the focused editable content is changed
|
||||
@ -598,7 +601,7 @@ enum IMEMessage : IMEMessageType
|
||||
struct IMENotification
|
||||
{
|
||||
IMENotification()
|
||||
: mMessage(static_cast<IMEMessage>(-1))
|
||||
: mMessage(NOTIFY_IME_OF_NOTHING)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT IMENotification(IMEMessage aMessage)
|
||||
@ -631,6 +634,59 @@ struct IMENotification
|
||||
}
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
mMessage = NOTIFY_IME_OF_NOTHING;
|
||||
}
|
||||
|
||||
bool HasNotification() const
|
||||
{
|
||||
return mMessage != NOTIFY_IME_OF_NOTHING;
|
||||
}
|
||||
|
||||
void MergeWith(const IMENotification& aNotification)
|
||||
{
|
||||
switch (mMessage) {
|
||||
case NOTIFY_IME_OF_NOTHING:
|
||||
MOZ_ASSERT(aNotification.mMessage != NOTIFY_IME_OF_NOTHING);
|
||||
*this = aNotification;
|
||||
break;
|
||||
case NOTIFY_IME_OF_SELECTION_CHANGE:
|
||||
MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE);
|
||||
mSelectionChangeData.mOffset =
|
||||
aNotification.mSelectionChangeData.mOffset;
|
||||
mSelectionChangeData.mLength =
|
||||
aNotification.mSelectionChangeData.mLength;
|
||||
mSelectionChangeData.mWritingMode =
|
||||
aNotification.mSelectionChangeData.mWritingMode;
|
||||
mSelectionChangeData.mReversed =
|
||||
aNotification.mSelectionChangeData.mReversed;
|
||||
mSelectionChangeData.mCausedByComposition =
|
||||
mSelectionChangeData.mCausedByComposition &&
|
||||
aNotification.mSelectionChangeData.mCausedByComposition;
|
||||
break;
|
||||
case NOTIFY_IME_OF_TEXT_CHANGE:
|
||||
MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE);
|
||||
// TODO: Needs to merge the ranges rather than overwriting.
|
||||
mTextChangeData.mStartOffset =
|
||||
aNotification.mTextChangeData.mStartOffset;
|
||||
mTextChangeData.mOldEndOffset =
|
||||
aNotification.mTextChangeData.mOldEndOffset;
|
||||
mTextChangeData.mNewEndOffset =
|
||||
aNotification.mTextChangeData.mNewEndOffset;
|
||||
mTextChangeData.mCausedByComposition =
|
||||
mTextChangeData.mCausedByComposition &&
|
||||
aNotification.mTextChangeData.mCausedByComposition;
|
||||
break;
|
||||
case NOTIFY_IME_OF_COMPOSITION_UPDATE:
|
||||
MOZ_ASSERT(aNotification.mMessage == NOTIFY_IME_OF_COMPOSITION_UPDATE);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Merging notification isn't supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IMEMessage mMessage;
|
||||
|
||||
// NOTIFY_IME_OF_SELECTION_CHANGE specific data
|
||||
|
Loading…
Reference in New Issue
Block a user