--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -343,17 +343,20 @@ ContentCacheInChild::CacheTextRects(nsIW
IMEStateManager::GetTextCompositionFor(aWidget);
if (textComposition) {
// mCompositionStart may be updated by some composition event handlers.
// So, let's update it with the latest information.
mCompositionStart = textComposition->NativeOffsetOfStartComposition();
// Note that TextComposition::String() may not be modified here because
// it's modified after all edit action listeners are performed but this
// is called while some of them are performed.
- uint32_t length = textComposition->LastData().Length();
+ // FYI: For supporting IME which commits composition and restart new
+ // composition immediately, we should cache next character of current
+ // composition too.
+ uint32_t length = textComposition->LastData().Length() + 1;
mTextRectArray.mStart = mCompositionStart;
if (NS_WARN_IF(!QueryCharRectArray(aWidget, mTextRectArray.mStart, length,
mTextRectArray.mRects))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p CacheTextRects(), FAILED, "
"couldn't retrieve text rect array of the composition string", this));
}
}
@@ -540,47 +543,53 @@ ContentCacheInParent::AssignContent(cons
// When the widget has composition, we should set mCompositionStart to
// *current* composition start offset. Note that, in strictly speaking,
// widget should not use WidgetQueryContentEvent if there are some pending
// compositions (i.e., when mPendingCompositionCount is 2 or more).
mCompositionStartInChild = aOther.mCompositionStart;
if (mWidgetHasComposition) {
if (aOther.mCompositionStart != UINT32_MAX) {
- mCompositionStart = aOther.mCompositionStart;
- } else {
+ if (mCompositionStart != aOther.mCompositionStart) {
+ mCompositionStart = aOther.mCompositionStart;
+ mPendingCommitLength = 0;
+ }
+ } else if (mCompositionStart != mSelection.StartOffset()) {
mCompositionStart = mSelection.StartOffset();
+ mPendingCommitLength = 0;
NS_WARNING_ASSERTION(mCompositionStart != UINT32_MAX,
"mCompositionStart shouldn't be invalid offset when "
"the widget has composition");
}
- } else {
+ } else if (mCompositionStart != UINT32_MAX) {
mCompositionStart = UINT32_MAX;
+ mPendingCommitLength = 0;
}
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p AssignContent(aNotification=%s), "
"Succeeded, mText.Length()=%u, mSelection={ mAnchor=%u, mFocus=%u, "
"mWritingMode=%s, mAnchorCharRects[eNextCharRect]=%s, "
"mAnchorCharRects[ePrevCharRect]=%s, mFocusCharRects[eNextCharRect]=%s, "
"mFocusCharRects[ePrevCharRect]=%s, mRect=%s }, "
"mFirstCharRect=%s, mCaret={ mOffset=%u, mRect=%s }, mTextRectArray={ "
"mStart=%u, mRects.Length()=%" PRIuSIZE " }, mWidgetHasComposition=%s, "
- "mPendingCompositionCount=%u, mCompositionStart=%u, mEditorRect=%s",
+ "mPendingCompositionCount=%u, mCompositionStart=%u, "
+ "mPendingCommitLength=%u, mEditorRect=%s",
this, GetNotificationName(aNotification),
mText.Length(), mSelection.mAnchor, mSelection.mFocus,
GetWritingModeName(mSelection.mWritingMode).get(),
GetRectText(mSelection.mAnchorCharRects[eNextCharRect]).get(),
GetRectText(mSelection.mAnchorCharRects[ePrevCharRect]).get(),
GetRectText(mSelection.mFocusCharRects[eNextCharRect]).get(),
GetRectText(mSelection.mFocusCharRects[ePrevCharRect]).get(),
GetRectText(mSelection.mRect).get(), GetRectText(mFirstCharRect).get(),
mCaret.mOffset, GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), GetBoolName(mWidgetHasComposition),
- mPendingCompositionCount, mCompositionStart,
+ mPendingCompositionCount, mCompositionStart, mPendingCommitLength,
GetRectText(mEditorRect).get()));
}
bool
ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
nsIWidget* aWidget) const
{
MOZ_ASSERT(aWidget);
@@ -620,41 +629,49 @@ ContentCacheInParent::HandleQueryContent
("0x%p HandleQueryContentEvent(), FAILED due to "
"aEvent.mInput.MakeOffsetAbsolute(0) failure, aEvent={ mMessage=%s, "
"mInput={ mOffset=%" PRId64 ", mLength=%" PRIu32 " } }",
this, ToChar(aEvent.mMessage), aEvent.mInput.mOffset,
aEvent.mInput.mLength));
return false;
}
} else if (mWidgetHasComposition) {
- if (NS_WARN_IF(!aEvent.mInput.MakeOffsetAbsolute(mCompositionStart))) {
+ if (NS_WARN_IF(!aEvent.mInput.MakeOffsetAbsolute(
+ mCompositionStart +
+ mPendingCommitLength))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p HandleQueryContentEvent(), FAILED due to "
- "aEvent.mInput.MakeOffsetAbsolute(mCompositionStart) failure, "
- "mCompositionStart=%d, aEvent={ mMessage=%s, "
- "mInput={ mOffset=%" PRId64 ", mLength=%" PRIu32 " } }",
- this, mCompositionStart, ToChar(aEvent.mMessage),
- aEvent.mInput.mOffset, aEvent.mInput.mLength));
+ "aEvent.mInput.MakeOffsetAbsolute(mCompositionStart + "
+ "mPendingCommitLength) failure, "
+ "mCompositionStart=%" PRIu32 ", mPendingCommitLength=%" PRIu32 ", "
+ "aEvent={ mMessage=%s, mInput={ mOffset=%" PRId64
+ ", mLength=%" PRIu32 " } }",
+ this, mCompositionStart, mPendingCommitLength,
+ ToChar(aEvent.mMessage), aEvent.mInput.mOffset,
+ aEvent.mInput.mLength));
return false;
}
} else if (NS_WARN_IF(!mSelection.IsValid())) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p HandleQueryContentEvent(), FAILED due to mSelection is invalid",
this));
return false;
} else if (NS_WARN_IF(!aEvent.mInput.MakeOffsetAbsolute(
- mSelection.StartOffset()))) {
+ mSelection.StartOffset() +
+ mPendingCommitLength))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p HandleQueryContentEvent(), FAILED due to "
- "aEvent.mInput.MakeOffsetAbsolute(mSelection.StartOffset()) "
- "failure, mSelection={ StartOffset()=%d, Length()=%d }, "
- "aEvent={ mMessage=%s, mInput={ mOffset=%" PRId64 ", mLength=%" PRIu32 " } }",
+ "aEvent.mInput.MakeOffsetAbsolute(mSelection.StartOffset() + "
+ "mPendingCommitLength) failure, "
+ "mSelection={ StartOffset()=%d, Length()=%d }, "
+ "mPendingCommitLength=%" PRIu32 ", aEvent={ mMessage=%s, "
+ "mInput={ mOffset=%" PRId64 ", mLength=%" PRIu32 " } }",
this, mSelection.StartOffset(), mSelection.Length(),
- ToChar(aEvent.mMessage), aEvent.mInput.mOffset,
- aEvent.mInput.mLength));
+ mPendingCommitLength, ToChar(aEvent.mMessage),
+ aEvent.mInput.mOffset, aEvent.mInput.mLength));
return false;
}
}
switch (aEvent.mMessage) {
case eQuerySelectedText:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p HandleQueryContentEvent("
@@ -1108,16 +1125,19 @@ ContentCacheInParent::OnCompositionEvent
MOZ_RELEASE_ASSERT(mPendingCompositionCount < UINT8_MAX);
mPendingCompositionCount++;
}
mWidgetHasComposition = !aEvent.CausesDOMCompositionEndEvent();
if (!mWidgetHasComposition) {
mCompositionStart = UINT32_MAX;
+ if (mPendingCompositionCount == 1) {
+ mPendingCommitLength = aEvent.mData.Length();
+ }
}
// During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION,
// widget usually sends a eCompositionChange and/or eCompositionCommit event
// to finalize or clear the composition, respectively. In this time,
// we need to intercept all composition events here and pass the commit
// string for returning to the remote process as a result of
// RequestIMEToCommitComposition(). Then, eCommitComposition event will
@@ -1170,16 +1190,21 @@ ContentCacheInParent::OnEventNeedingAckH
("0x%p OnEventNeedingAckHandled(aWidget=0x%p, "
"aMessage=%s), mPendingEventsNeedingAck=%u, mPendingCompositionCount=%" PRIu8,
this, aWidget, ToChar(aMessage), mPendingEventsNeedingAck, mPendingCompositionCount));
if (WidgetCompositionEvent::IsFollowedByCompositionEnd(aMessage) ||
aMessage == eCompositionCommitRequestHandled) {
MOZ_RELEASE_ASSERT(mPendingCompositionCount > 0);
mPendingCompositionCount--;
+ // Forget pending commit string length if it's handled in the remote
+ // process. Note that this doesn't care too old composition's commit
+ // string because in such case, we cannot return proper information
+ // to IME synchornously.
+ mPendingCommitLength = 0;
}
MOZ_RELEASE_ASSERT(mPendingEventsNeedingAck > 0);
if (--mPendingEventsNeedingAck) {
return;
}
FlushPendingNotifications(aWidget);