--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -505,16 +505,17 @@ ContentCacheInChild::SetSelection(nsIWid
/*****************************************************************************
* mozilla::ContentCacheInParent
*****************************************************************************/
ContentCacheInParent::ContentCacheInParent()
: ContentCache()
, mCommitStringByRequest(nullptr)
, mPendingEventsNeedingAck(0)
+ , mPendingCompositionCount(0)
, mWidgetHasComposition(false)
{
}
void
ContentCacheInParent::AssignContent(const ContentCache& aOther,
nsIWidget* aWidget,
const IMENotification* aNotification)
@@ -1054,31 +1055,35 @@ ContentCacheInParent::GetCaretRect(uint3
bool
ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p OnCompositionEvent(aEvent={ "
"mMessage=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), "
"mPendingEventsNeedingAck=%u, mWidgetHasComposition=%s, "
- "mCommitStringByRequest=0x%p",
+ "mPendingCompositionCount=%u, mCommitStringByRequest=0x%p",
this, ToChar(aEvent.mMessage),
GetEscapedUTF8String(aEvent.mData).get(), aEvent.mData.Length(),
aEvent.mRanges ? aEvent.mRanges->Length() : 0, mPendingEventsNeedingAck,
- GetBoolName(mWidgetHasComposition), mCommitStringByRequest));
+ GetBoolName(mWidgetHasComposition), mPendingCompositionCount,
+ mCommitStringByRequest));
// We must be able to simulate the selection because
// we might not receive selection updates in time
if (!mWidgetHasComposition) {
if (aEvent.mWidget && aEvent.mWidget->PluginHasFocus()) {
// If focus is on plugin, we cannot get selection range
mCompositionStart = 0;
} else {
mCompositionStart = mSelection.StartOffset();
}
+ MOZ_ASSERT(aEvent.mMessage == eCompositionStart);
+ MOZ_RELEASE_ASSERT(mPendingCompositionCount < UINT8_MAX);
+ mPendingCompositionCount++;
}
mWidgetHasComposition = !aEvent.CausesDOMCompositionEndEvent();
if (!mWidgetHasComposition) {
mCompositionStart = UINT32_MAX;
}
@@ -1103,39 +1108,45 @@ ContentCacheInParent::OnCompositionEvent
void
ContentCacheInParent::OnSelectionEvent(
const WidgetSelectionEvent& aSelectionEvent)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p OnSelectionEvent(aEvent={ "
"mMessage=%s, mOffset=%u, mLength=%u, mReversed=%s, "
"mExpandToClusterBoundary=%s, mUseNativeLineBreak=%s }), "
- "mPendingEventsNeedingAck=%u, mWidgetHasComposition=%s",
+ "mPendingEventsNeedingAck=%u, mWidgetHasComposition=%s, "
+ "mPendingCompositionCount=%u",
this, ToChar(aSelectionEvent.mMessage),
aSelectionEvent.mOffset, aSelectionEvent.mLength,
GetBoolName(aSelectionEvent.mReversed),
GetBoolName(aSelectionEvent.mExpandToClusterBoundary),
GetBoolName(aSelectionEvent.mUseNativeLineBreak), mPendingEventsNeedingAck,
- GetBoolName(mWidgetHasComposition)));
+ GetBoolName(mWidgetHasComposition), mPendingCompositionCount));
mPendingEventsNeedingAck++;
}
void
ContentCacheInParent::OnEventNeedingAckHandled(nsIWidget* aWidget,
EventMessage aMessage)
{
// This is called when the child process receives WidgetCompositionEvent or
// WidgetSelectionEvent.
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p OnEventNeedingAckHandled(aWidget=0x%p, "
- "aMessage=%s), mPendingEventsNeedingAck=%u",
+ "aMessage=%s), mPendingEventsNeedingAck=%u, mPendingCompositionCount=%u",
this, aWidget, ToChar(aMessage), mPendingEventsNeedingAck));
+ if (WidgetCompositionEvent::IsFollowedByCompositionEnd(aMessage)) {
+ MOZ_RELEASE_ASSERT(mPendingCompositionCount > 0);
+ mPendingCompositionCount--;
+ }
+
MOZ_RELEASE_ASSERT(mPendingEventsNeedingAck > 0);
if (--mPendingEventsNeedingAck) {
return;
}
FlushPendingNotifications(aWidget);
}
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -409,17 +409,19 @@ private:
// This is not nullptr only while the instance is requesting IME to
// composition. Then, data value of dispatched composition events should
// be stored into the instance.
nsAString* mCommitStringByRequest;
// mPendingEventsNeedingAck is increased before sending a composition event or
// a selection event and decreased after they are received in the child
// process.
uint32_t mPendingEventsNeedingAck;
-
+ // mPendingCompositionCount is number of compositions which started in widget
+ // but not yet handled in the child process.
+ uint8_t mPendingCompositionCount;
// mWidgetHasComposition is true when the widget in this process thinks that
// IME has composition. So, this is set to true when eCompositionStart is
// dispatched and set to false when eCompositionCommit(AsIs) is dispatched.
bool mWidgetHasComposition;
/**
* When following methods' aRoundToExistingOffset is true, even if specified
* offset or range is out of bounds, the result is computed with the existing