Bug 532130 [IMM32] Support IMR_DOCUMENTFEED of WM_IME_REQUEST r=VYV03354

This commit is contained in:
Masayuki Nakano 2009-12-17 13:40:24 +09:00
parent ae2e55160f
commit 9402df2db5
2 changed files with 221 additions and 21 deletions

View File

@ -605,6 +605,11 @@ nsIMM32Handler::OnIMERequest(nsWindow* aWindow,
("IMM32: OnIMERequest, hWnd=%08x, IMR_QUERYCHARPOSITION\n",
aWindow->GetWindowHandle()));
return HandleQueryCharPosition(aWindow, lParam, oResult);
case IMR_DOCUMENTFEED:
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: OnIMERequest, hWnd=%08x, IMR_DOCUMENTFEED\n",
aWindow->GetWindowHandle()));
return HandleDocumentFeed(aWindow, lParam, oResult);
default:
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: OnIMERequest, hWnd=%08x, wParam=%08x\n",
@ -922,6 +927,24 @@ nsIMM32Handler::HandleEndComposition(nsWindow* aWindow)
mIsComposing = PR_FALSE;
}
static void
DumpReconvertString(RECONVERTSTRING* aReconv)
{
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
(" dwSize=%ld, dwVersion=%ld, dwStrLen=%ld, dwStrOffset=%ld\n",
aReconv->dwSize, aReconv->dwVersion,
aReconv->dwStrLen, aReconv->dwStrOffset));
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
(" dwCompStrLen=%ld, dwCompStrOffset=%ld, dwTargetStrLen=%ld, dwTargetStrOffset=%ld\n",
aReconv->dwCompStrLen, aReconv->dwCompStrOffset,
aReconv->dwTargetStrLen, aReconv->dwTargetStrOffset));
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
(" result str=\"%s\"\n",
NS_ConvertUTF16toUTF8(
nsAutoString((PRUnichar*)((char*)(aReconv) + aReconv->dwStrOffset),
aReconv->dwStrLen)).get()));
}
PRBool
nsIMM32Handler::HandleReconvert(nsWindow* aWindow,
LPARAM lParam,
@ -940,25 +963,23 @@ nsIMM32Handler::HandleReconvert(nsWindow* aWindow,
return PR_FALSE;
}
PRUint32 len = selection.mReply.mString.Length();
PRUint32 needSize = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
if (!pReconv) {
// Return need size to reconvert.
if (selection.mReply.mString.IsEmpty()) {
if (len == 0) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleReconvert, There are not selected text\n"));
return PR_FALSE;
}
PRUint32 len = selection.mReply.mString.Length();
*oResult = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
*oResult = needSize;
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleReconvert, SUCCEEDED result=%ld\n",
*oResult));
return PR_TRUE;
}
// Fill reconvert struct
PRUint32 len = selection.mReply.mString.Length();
PRUint32 needSize = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
if (pReconv->dwSize < needSize) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleReconvert, FAILED pReconv->dwSize=%ld, needSize=%ld\n",
@ -968,9 +989,7 @@ nsIMM32Handler::HandleReconvert(nsWindow* aWindow,
*oResult = needSize;
DWORD tmpSize = pReconv->dwSize;
::ZeroMemory(pReconv, tmpSize);
pReconv->dwSize = tmpSize;
// Fill reconvert struct
pReconv->dwVersion = 0;
pReconv->dwStrLen = len;
pReconv->dwStrOffset = sizeof(RECONVERTSTRING);
@ -979,12 +998,13 @@ nsIMM32Handler::HandleReconvert(nsWindow* aWindow,
pReconv->dwTargetStrLen = len;
pReconv->dwTargetStrOffset = 0;
::CopyMemory((LPVOID) (lParam + sizeof(RECONVERTSTRING)),
::CopyMemory(reinterpret_cast<LPVOID>(lParam + sizeof(RECONVERTSTRING)),
selection.mReply.mString.get(), len * sizeof(WCHAR));
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleReconvert, SUCCEEDED str=\"%s\"\n",
NS_ConvertUTF16toUTF8(selection.mReply.mString).get()));
("IMM32: HandleReconvert, SUCCEEDED result=%ld\n",
*oResult));
DumpReconvertString(pReconv);
return PR_TRUE;
}
@ -1046,6 +1066,132 @@ nsIMM32Handler::HandleQueryCharPosition(nsWindow* aWindow,
return PR_TRUE;
}
PRBool
nsIMM32Handler::HandleDocumentFeed(nsWindow* aWindow,
LPARAM lParam,
LRESULT *oResult)
{
*oResult = 0;
RECONVERTSTRING* pReconv = reinterpret_cast<RECONVERTSTRING*>(lParam);
nsIntPoint point(0, 0);
PRBool hasCompositionString =
mIsComposing && ShouldDrawCompositionStringOurselves();
PRInt32 targetOffset, targetLength;
if (!hasCompositionString) {
nsQueryContentEvent selection(PR_TRUE, NS_QUERY_SELECTED_TEXT, aWindow);
aWindow->InitEvent(selection, &point);
aWindow->DispatchWindowEvent(&selection);
if (!selection.mSucceeded) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, FAILED (NS_QUERY_SELECTED_TEXT)\n"));
return PR_FALSE;
}
targetOffset = PRInt32(selection.mReply.mOffset);
targetLength = PRInt32(selection.mReply.mString.Length());
} else {
targetOffset = PRInt32(mCompositionStart);
targetLength = PRInt32(mCompositionString.Length());
}
// XXX nsString::Find and nsString::RFind take PRInt32 for offset, so,
// we cannot support this message when the current offset is larger than
// PR_INT32_MAX.
if (targetOffset < 0 || targetLength < 0 ||
targetOffset + targetLength < 0) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, FAILED (The selection is out of range)\n"));
return PR_FALSE;
}
// Get all contents of the focused editor.
nsQueryContentEvent textContent(PR_TRUE, NS_QUERY_TEXT_CONTENT, aWindow);
textContent.InitForQueryTextContent(0, PR_UINT32_MAX);
aWindow->InitEvent(textContent, &point);
aWindow->DispatchWindowEvent(&textContent);
if (!textContent.mSucceeded) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, FAILED (NS_QUERY_TEXT_CONTENT)\n"));
return PR_FALSE;
}
nsAutoString str(textContent.mReply.mString);
if (targetOffset > PRInt32(str.Length())) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, FAILED (The caret offset is invalid)\n"));
return PR_FALSE;
}
// Get the focused paragraph, we decide that it starts from the previous CRLF
// (or start of the editor) to the next one (or the end of the editor).
PRInt32 paragraphStart = str.RFind("\n", PR_FALSE, targetOffset, -1) + 1;
PRInt32 paragraphEnd =
str.Find("\r", PR_FALSE, targetOffset + targetLength, -1);
if (paragraphEnd < 0) {
paragraphEnd = str.Length();
}
nsDependentSubstring paragraph(str, paragraphStart,
paragraphEnd - paragraphStart);
PRUint32 len = paragraph.Length();
PRUint32 needSize = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
if (!pReconv) {
*oResult = needSize;
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, SUCCEEDED result=%ld\n",
*oResult));
return PR_TRUE;
}
if (pReconv->dwSize < needSize) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, FAILED pReconv->dwSize=%ld, needSize=%ld\n",
pReconv->dwSize, needSize));
return PR_FALSE;
}
// Fill reconvert struct
pReconv->dwVersion = 0;
pReconv->dwStrLen = len;
pReconv->dwStrOffset = sizeof(RECONVERTSTRING);
if (hasCompositionString) {
pReconv->dwCompStrLen = targetLength;
pReconv->dwCompStrOffset =
(targetOffset - paragraphStart) * sizeof(WCHAR);
// Set composition target clause information
PRUint32 offset, length;
if (!GetTargetClauseRange(&offset, &length)) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, FAILED, by GetTargetClauseRange\n"));
return PR_FALSE;
}
pReconv->dwTargetStrLen = length;
pReconv->dwTargetStrOffset = (offset - paragraphStart) * sizeof(WCHAR);
} else {
pReconv->dwTargetStrLen = targetLength;
pReconv->dwTargetStrOffset =
(targetOffset - paragraphStart) * sizeof(WCHAR);
// There is no composition string, so, the length is zero but we should
// set the cursor offset to the composition str offset.
pReconv->dwCompStrLen = 0;
pReconv->dwCompStrOffset = pReconv->dwTargetStrOffset;
}
*oResult = needSize;
::CopyMemory(reinterpret_cast<LPVOID>(lParam + sizeof(RECONVERTSTRING)),
paragraph.BeginReading(), len * sizeof(WCHAR));
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: HandleDocumentFeed, SUCCEEDED result=%ld\n",
*oResult));
DumpReconvertString(pReconv);
return PR_TRUE;
}
static PRUint32
PlatformToNSAttr(PRUint8 aAttr)
{
@ -1227,6 +1373,47 @@ nsIMM32Handler::GetCompositionString(const nsIMEContext &aIMEContext,
NS_ConvertUTF16toUTF8(mCompositionString).get()));
}
PRBool
nsIMM32Handler::GetTargetClauseRange(PRUint32 *aOffset, PRUint32 *aLength)
{
NS_ENSURE_TRUE(aOffset, PR_FALSE);
NS_ENSURE_TRUE(mIsComposing, PR_FALSE);
NS_ENSURE_TRUE(ShouldDrawCompositionStringOurselves(), PR_FALSE);
PRBool found = PR_FALSE;
*aOffset = mCompositionStart;
for (PRUint32 i = 0; i < mAttributeArray.Length(); i++) {
if (mAttributeArray[i] == ATTR_TARGET_NOTCONVERTED ||
mAttributeArray[i] == ATTR_TARGET_CONVERTED) {
*aOffset = mCompositionStart + i;
found = PR_TRUE;
break;
}
}
if (!aLength) {
return PR_TRUE;
}
if (!found) {
// The all composition string is targetted when there is no ATTR_TARGET_*
// clause. E.g., there is only ATTR_INPUT
*aLength = mCompositionString.Length();
return PR_TRUE;
}
PRUint32 offsetInComposition = *aOffset - mCompositionStart;
*aLength = mCompositionString.Length() - offsetInComposition;
for (PRUint32 i = offsetInComposition; i < mAttributeArray.Length(); i++) {
if (mAttributeArray[i] != ATTR_TARGET_NOTCONVERTED &&
mAttributeArray[i] != ATTR_TARGET_CONVERTED) {
*aLength = i - offsetInComposition;
break;
}
}
return PR_TRUE;
}
PRBool
nsIMM32Handler::ConvertToANSIString(const nsAFlatString& aStr, UINT aCodePage,
nsACString& aANSIStr)
@ -1372,15 +1559,14 @@ nsIMM32Handler::SetIMERelatedWindowsPos(nsWindow* aWindow,
if (mIsComposing && !mCompositionString.IsEmpty()) {
// If there are no targetted selection, we should use it's first character
// rect instead.
PRUint32 offset = 0;
for (PRUint32 i = 0; i < mAttributeArray.Length(); i++) {
if (mAttributeArray[i] == ATTR_TARGET_NOTCONVERTED ||
mAttributeArray[i] == ATTR_TARGET_CONVERTED) {
offset = i;
break;
}
PRUint32 offset;
if (!GetTargetClauseRange(&offset)) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: SetIMERelatedWindowsPos, FAILED, by GetTargetClauseRange\n"));
return PR_FALSE;
}
ret = GetCharacterRectOfSelectedTextAt(aWindow, offset, r);
ret = GetCharacterRectOfSelectedTextAt(aWindow,
offset - mCompositionStart, r);
NS_ENSURE_TRUE(ret, PR_FALSE);
} else {
// If there are no composition string, we should use a first character

View File

@ -164,6 +164,7 @@ protected:
PRBool HandleReconvert(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
PRBool HandleQueryCharPosition(nsWindow* aWindow, LPARAM lParam,
LRESULT *oResult);
PRBool HandleDocumentFeed(nsWindow* aWindow, LPARAM lParam, LRESULT *oResult);
/**
* ResolveIMECaretPos
@ -196,6 +197,19 @@ protected:
nsIntRect &aCharRect);
PRBool GetCaretRect(nsWindow* aWindow, nsIntRect &aCaretRect);
void GetCompositionString(const nsIMEContext &aIMEContext, DWORD aIndex);
/**
* Get the current target clause of composition string.
* If there are one or more characters whose attribute is ATTR_TARGET_*,
* this returns the first character's offset and its length.
* Otherwise, e.g., the all characters are ATTR_INPUT, this returns
* the composition string range because the all is the current target.
*
* aLength can be null (default), but aOffset must not be null.
*
* The aOffset value is offset in the contents. So, when you need offset
* in the composition string, you need to subtract mCompositionStart from it.
*/
PRBool GetTargetClauseRange(PRUint32 *aOffset, PRUint32 *aLength = nsnull);
void DispatchTextEvent(nsWindow* aWindow, const nsIMEContext &aIMEContext,
PRBool aCheckAttr = PR_TRUE);
void SetTextRangeList(nsTArray<nsTextRange> &aTextRangeList);