Bug 424663 crashes [@ CalcCharacterPositionAtoW][@ imm32.dll@0x3e24] involving Chinese IME r=VYV03354+ere,sr=roc,a1906=dveditz

git-svn-id: svn://10.0.0.236/trunk@255763 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
masayuki%d-toybox.com 2009-01-08 04:08:58 +00:00
parent 5ab4df3384
commit c99efa61bf
4 changed files with 122 additions and 65 deletions

View File

@ -209,7 +209,8 @@ PRUint32 VirtualKey::GetNativeUniChars (PRUint8 aShiftState, PRUint16* aUniChars
KeyboardLayout::KeyboardLayout ()
KeyboardLayout::KeyboardLayout () :
mKeyboardLayout(0), mCodePage(0)
{
#ifndef WINCE
mDeadKeyTableListHead = nsnull;
@ -361,7 +362,18 @@ KeyboardLayout::GetUniCharsWithShiftState(PRUint8 aVirtualKey,
void KeyboardLayout::LoadLayout (HKL aLayout)
{
if (mKeyboardLayout == aLayout)
return;
mKeyboardLayout = aLayout;
mIMEProperty = ::ImmGetProperty(aLayout, IGP_PROPERTY);
#ifndef WINCE
WORD langID = LOWORD(aLayout);
::GetLocaleInfoA(MAKELCID(langID, SORT_DEFAULT),
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
(PSTR)&mCodePage, sizeof(mCodePage));
PRUint32 shiftState;
BYTE kbdState [256];
BYTE originalKbdState [256];
@ -372,7 +384,6 @@ void KeyboardLayout::LoadLayout (HKL aLayout)
mActiveDeadKey = -1;
mNumOfChars = 0;
mKeyboardLayout = aLayout;
ReleaseDeadKeyTables ();
@ -452,6 +463,8 @@ void KeyboardLayout::LoadLayout (HKL aLayout)
}
::SetKeyboardState (originalKbdState);
#else
mCodePage = ::GetACP();
#endif
}

View File

@ -137,6 +137,8 @@ class KeyboardLayout
#define NUM_OF_KEYS 50
HKL mKeyboardLayout;
UINT mCodePage;
DWORD mIMEProperty;
VirtualKey mVirtualKeys [NUM_OF_KEYS];
DeadKeyTableListEntry* mDeadKeyTableListHead;
@ -183,6 +185,10 @@ public:
PRUint32 GetUniCharsWithShiftState(PRUint8 aVirtualKey, PRUint8 aShiftStates,
PRUint16* aUniChars,
PRUint32 aMaxChars) const;
HKL GetLayout() { return mKeyboardLayout; }
UINT GetCodePage() { return mCodePage; }
DWORD GetIMEProperty() { return mIMEProperty; }
};
#endif

View File

@ -312,7 +312,6 @@ PRUint32 nsWindow::sInstanceCount = 0;
PRBool nsWindow::sIMEIsComposing = PR_FALSE;
PRBool nsWindow::sIMEIsStatusChanged = PR_FALSE;
DWORD nsWindow::sIMEProperty = 0;
nsString* nsWindow::sIMECompUnicode = NULL;
PRUint8* nsWindow::sIMEAttributeArray = NULL;
PRInt32 nsWindow::sIMEAttributeArrayLength = 0;
@ -326,6 +325,10 @@ PRUnichar* nsWindow::sIMEReconvertUnicode = NULL;
RECT* nsWindow::sIMECompCharPos = nsnull;
PRInt32 nsWindow::sIMECaretHeight = 0;
PRBool nsWindow::gSwitchKeyboardLayout = PR_FALSE;
static KeyboardLayout gKbdLayout;
PRBool nsWindow::sIsInEndSession = PR_FALSE;
BOOL nsWindow::sIsRegistered = FALSE;
@ -708,7 +711,7 @@ nsWindow::nsWindow() : nsBaseWidget()
static BOOL gbInitGlobalValue = FALSE;
if (! gbInitGlobalValue) {
gbInitGlobalValue = TRUE;
gKeyboardLayout = GetKeyboardLayout(0);
gKbdLayout.LoadLayout(GetKeyboardLayout(0));
// mouse message of MSIME98/2000
nsWindow::uWM_MSIME_MOUSE = ::RegisterWindowMessage(RWM_MOUSE);
@ -735,10 +738,6 @@ nsWindow::nsWindow() : nsBaseWidget()
}
HKL nsWindow::gKeyboardLayout = 0;
PRBool nsWindow::gSwitchKeyboardLayout = PR_FALSE;
static KeyboardLayout gKbdLayout;
//-------------------------------------------------------------------------
//
// nsWindow destructor
@ -3509,10 +3508,12 @@ BOOL nsWindow::OnChar(UINT charCode, UINT aScanCode, PRUint32 aFlags)
// Keep the characters unshifted for shortcuts and accesskeys and make sure
// that numbers are always passed as such (among others: bugs 50255 and 351310)
if (uniChar && (mIsControlDown || mIsAltDown)) {
UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK, gKeyboardLayout);
UINT virtualKeyCode = ::MapVirtualKeyEx(aScanCode, MAPVK_VSC_TO_VK,
gKbdLayout.GetLayout());
UINT unshiftedCharCode =
virtualKeyCode >= '0' && virtualKeyCode <= '9' ? virtualKeyCode :
mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode, MAPVK_VK_TO_CHAR, gKeyboardLayout) : 0;
mIsShiftDown ? ::MapVirtualKeyEx(virtualKeyCode, MAPVK_VK_TO_CHAR,
gKbdLayout.GetLayout()) : 0;
// ignore diacritics (top bit set) and key mapping errors (char code 0)
if ((INT)unshiftedCharCode > 0)
uniChar = unshiftedCharCode;
@ -3581,9 +3582,8 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
// This changes the state of the keyboard for the current thread only,
// and we'll restore it soon, so this should be OK.
::SetKeyboardState(kbdState);
HKL oldLayout = gKeyboardLayout;
gKeyboardLayout = loadedLayout;
gKbdLayout.LoadLayout(gKeyboardLayout);
HKL oldLayout = gKbdLayout.GetLayout();
gKbdLayout.LoadLayout(loadedLayout);
nsAutoTArray<KeyPair,10> keySequence;
SetupKeyModifiersSequence(&keySequence, aModifierFlags);
@ -3602,7 +3602,8 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
::SetKeyboardState(kbdState);
SetupModKeyState();
if (i == keySequence.Length() - 1 && aCharacters.Length() > 0) {
UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC, gKeyboardLayout);
UINT scanCode = ::MapVirtualKeyEx(aNativeKeyCode, MAPVK_VK_TO_VSC,
gKbdLayout.GetLayout());
nsFakeCharMessage msg = { aCharacters.CharAt(0), scanCode };
OnKeyDown(key, 0, &msg);
} else {
@ -3623,8 +3624,7 @@ nsWindow::SynthesizeNativeKeyEvent(PRInt32 aNativeKeyboardLayout,
// Restore old key state and layout
::SetKeyboardState(originalKbdState);
gKeyboardLayout = oldLayout;
gKbdLayout.LoadLayout(gKeyboardLayout);
gKbdLayout.LoadLayout(oldLayout);
SetupModKeyState();
UnloadKeyboardLayout(loadedLayout);
@ -4708,7 +4708,7 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT
if (WA_INACTIVE == fActive) {
gJustGotDeactivate = PR_TRUE;
if (mIsTopWidgetWindow)
mLastKeyboardLayout = gKeyboardLayout;
mLastKeyboardLayout = gKbdLayout.GetLayout();
} else {
gJustGotActivate = PR_TRUE;
nsMouseEvent event(PR_TRUE, NS_MOUSE_ACTIVATE, this,
@ -5000,7 +5000,7 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT
break;
case WM_INPUTLANGCHANGE:
result = OnInputLangChange((HKL)lParam, aRetValue);
result = OnInputLangChange((HKL)lParam);
break;
case WM_IME_STARTCOMPOSITION:
@ -6432,6 +6432,8 @@ NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
return NS_OK;
}
// XXX itABC v5.30 on Vista is E0210804. Probably, we should not use these
// values for checking the current IME.
#define ZH_CN_INTELLEGENT_ABC_IME ((HKL)0xe0040804L)
#define ZH_CN_MS_PINYIN_IME_3_0 ((HKL)0xe00e0804L)
#define ZH_CN_NEIMA_IME ((HKL)0xe0050804L)
@ -6495,10 +6497,10 @@ nsWindow::HandleTextEvent(HIMC hIMEContext,PRBool aCheckAttr)
::ImmSetCandidateWindow(hIMEContext, &candForm);
// somehow the "Intellegent ABC IME" in Simplified Chinese
// somehow the "Intelligent ABC IME" in Simplified Chinese
// window listen to the caret position to decide where to put the
// candidate window
if (gKeyboardLayout == ZH_CN_INTELLEGENT_ABC_IME)
if (gKbdLayout.GetLayout() == ZH_CN_INTELLEGENT_ABC_IME)
{
CreateCaret(mWnd, nsnull, 1, 1);
SetCaretPos(candForm.ptCurrentPos.x, candForm.ptCurrentPos.y);
@ -6572,7 +6574,7 @@ nsWindow::HandleStartComposition(HIMC hIMEContext)
printf("Candidate window position: x=%d, y=%d\n", candForm.ptCurrentPos.x, candForm.ptCurrentPos.y);
#endif
if (!gPinYinIMECaretCreated && PINYIN_IME_ON_XP(gKeyboardLayout))
if (!gPinYinIMECaretCreated && PINYIN_IME_ON_XP(gKbdLayout.GetLayout()))
{
gPinYinIMECaretCreated = CreateCaret(mWnd, nsnull, 1, 1);
SetCaretPos(candForm.ptCurrentPos.x, candForm.ptCurrentPos.y);
@ -6709,17 +6711,12 @@ nsWindow::GetTextRangeList(PRUint32* textRangeListLengthResult,nsTextRangeArray*
//==========================================================================
BOOL nsWindow::OnInputLangChange(HKL aHKL, LRESULT *oRetValue)
BOOL nsWindow::OnInputLangChange(HKL aHKL)
{
#ifdef KE_DEBUG
printf("OnInputLanguageChange\n");
#endif
if (gKeyboardLayout != aHKL)
{
gKeyboardLayout = aHKL;
gKbdLayout.LoadLayout(gKeyboardLayout);
}
gKbdLayout.LoadLayout(aHKL);
ResetInputState();
@ -6787,6 +6784,21 @@ void nsWindow::GetCompositionString(HIMC aHIMC, DWORD aIndex, nsString* aStrUnic
aStrUnicode->SetLength(lRtn);
}
PRBool nsWindow::ConvertToANSIString(const nsAFlatString& aStr, UINT aCodePage,
nsACString& aANSIStr)
{
int len = ::WideCharToMultiByte(aCodePage, 0,
(LPCWSTR)aStr.get(), aStr.Length(),
NULL, 0, NULL, NULL);
NS_ENSURE_TRUE(len >= 0, PR_FALSE);
if (!EnsureStringLength(aANSIStr, len))
return PR_FALSE;
::WideCharToMultiByte(aCodePage, 0, (LPCWSTR)aStr.get(), aStr.Length(),
(LPSTR)aANSIStr.BeginWriting(), len, NULL, NULL);
return PR_TRUE;
}
//==========================================================================
BOOL nsWindow::OnIMEComposition(LPARAM aGCS)
{
@ -6874,29 +6886,61 @@ BOOL nsWindow::OnIMEComposition(LPARAM aGCS)
//--------------------------------------------------------
// 2. Get GCS_COMPCLAUSE
//--------------------------------------------------------
long compClauseLen, compClauseLen2;
compClauseLen = ::ImmGetCompositionStringW(hIMEContext, GCS_COMPCLAUSE, NULL, 0);
long compClauseArrayByteCount =
::ImmGetCompositionStringW(hIMEContext, GCS_COMPCLAUSE, NULL, 0);
#ifdef DEBUG_IME
printf("GCS_COMPCLAUSE compClauseLen = %d\n", compClauseLen);
printf("GCS_COMPCLAUSE compClauseArrayByteCount = %d\n",
compClauseArrayByteCount);
#endif
compClauseLen = compClauseLen / sizeof(PRUint32);
long compClauseArrayLength = compClauseArrayByteCount / sizeof(PRUint32);
if (compClauseArrayLength > 0) {
if (compClauseArrayByteCount > sIMECompClauseArraySize) {
if (sIMECompClauseArray)
delete [] sIMECompClauseArray;
// Allocate some extra space to avoid reallocations.
PRInt32 arrayLength = compClauseArrayLength + 32;
sIMECompClauseArray = new PRUint32[arrayLength];
sIMECompClauseArraySize = arrayLength * sizeof(PRUint32);
}
if (compClauseLen > sIMECompClauseArraySize) {
if (sIMECompClauseArray)
delete [] sIMECompClauseArray;
// Allocate some extra space to avoid reallocations.
sIMECompClauseArray = new PRUint32[compClauseLen + 32];
sIMECompClauseArraySize = compClauseLen + 32;
// Intelligent ABC IME (Simplified Chinese IME, the code page is 936)
// will crash in ImmGetCompositionStringW for GCS_COMPCLAUSE (bug 424663).
// See comment 35 of the bug for the detail. Therefore, we should use A
// API for it, however, we should not kill Unicode support on all IMEs.
PRBool useA_API = !(gKbdLayout.GetIMEProperty() & IME_PROP_UNICODE);
long compClauseArrayByteCount2 = useA_API ?
::ImmGetCompositionStringA(hIMEContext, GCS_COMPCLAUSE,
sIMECompClauseArray,
sIMECompClauseArraySize) :
::ImmGetCompositionStringW(hIMEContext, GCS_COMPCLAUSE,
sIMECompClauseArray,
sIMECompClauseArraySize);
NS_ASSERTION(compClauseArrayByteCount2 == compClauseArrayByteCount,
"strange result");
if (compClauseArrayByteCount > compClauseArrayByteCount2)
compClauseArrayLength = compClauseArrayByteCount2 / sizeof(PRUint32);
if (useA_API) {
// Convert each values of sIMECompClauseArray. The values mean offset of
// the clauses in ANSI string. But we need the values in Unicode string.
nsCAutoString compANSIStr;
if (ConvertToANSIString(*sIMECompUnicode,
gKbdLayout.GetCodePage(), compANSIStr)) {
PRUint32 maxlen = compANSIStr.Length();
sIMECompClauseArray[0] = 0; // first value must be 0
for (PRInt32 i = 1; i < compClauseArrayLength; i++) {
PRUint32 len = PR_MIN(sIMECompClauseArray[i], maxlen);
sIMECompClauseArray[i] =
::MultiByteToWideChar(gKbdLayout.GetCodePage(), MB_PRECOMPOSED,
(LPCSTR)compANSIStr.get(), len, NULL, 0);
}
}
}
}
compClauseLen2 = ::ImmGetCompositionStringW(hIMEContext, GCS_COMPCLAUSE, sIMECompClauseArray,
sIMECompClauseArraySize * sizeof(PRUint32));
compClauseLen2 = compClauseLen2 / sizeof(PRUint32);
NS_ASSERTION(compClauseLen2 == compClauseLen, "strange result");
if (compClauseLen > compClauseLen2)
compClauseLen = compClauseLen2;
sIMECompClauseArrayLength = compClauseLen;
// compClauseArrayLength may be negative. I.e., ImmGetCompositionStringW
// may return an error code.
sIMECompClauseArrayLength = PR_MAX(0, compClauseArrayLength);
//--------------------------------------------------------
// 3. Get GCS_COMPATTR
@ -6912,12 +6956,15 @@ BOOL nsWindow::OnIMEComposition(LPARAM aGCS)
if (sIMEAttributeArray)
delete [] sIMEAttributeArray;
// Allocate some extra space to avoid reallocations.
sIMEAttributeArray = new PRUint8[attrStrLen + 64];
sIMEAttributeArraySize = attrStrLen + 64;
PRInt32 arrayLength = attrStrLen + 64;
sIMEAttributeArray = new PRUint8[arrayLength];
sIMEAttributeArraySize = arrayLength * sizeof(PRUint8);
}
attrStrLen = ::ImmGetCompositionStringW(hIMEContext, GCS_COMPATTR, sIMEAttributeArray, sIMEAttributeArraySize);
sIMEAttributeArrayLength = attrStrLen;
// attrStrLen may be negative. I.e., ImmGetCompositionStringW may return an
// error code.
sIMEAttributeArrayLength = PR_MAX(0, attrStrLen);
//--------------------------------------------------------
// 4. Get GCS_CURSOPOS
@ -6967,12 +7014,7 @@ BOOL nsWindow::OnIMEEndComposition()
printf("OnIMEEndComposition\n");
#endif
if (sIMEIsComposing) {
HIMC hIMEContext;
if (sIMEProperty & (IME_PROP_SPECIAL_UI | IME_PROP_AT_CARET))
return PR_FALSE;
hIMEContext = ::ImmGetContext(mWnd);
HIMC hIMEContext = ::ImmGetContext(mWnd);
if (hIMEContext==NULL)
return PR_TRUE;
@ -7278,12 +7320,7 @@ BOOL nsWindow::OnIMEStartComposition()
#ifdef DEBUG_IME
printf("OnIMEStartComposition\n");
#endif
HIMC hIMEContext;
if (sIMEProperty & (IME_PROP_SPECIAL_UI | IME_PROP_AT_CARET))
return PR_FALSE;
hIMEContext = ::ImmGetContext(mWnd);
HIMC hIMEContext = ::ImmGetContext(mWnd);
if (hIMEContext == NULL)
return PR_TRUE;

View File

@ -323,7 +323,7 @@ protected:
UINT MapFromNativeToDOM(UINT aNativeKeyCode);
BOOL OnInputLangChange(HKL aHKL, LRESULT *oResult);
BOOL OnInputLangChange(HKL aHKL);
BOOL OnIMEChar(BYTE aByte1, BYTE aByte2, LPARAM aKeyState);
BOOL OnIMEComposition(LPARAM aGCS);
BOOL OnIMECompositionFull();
@ -340,6 +340,9 @@ protected:
void ResolveIMECaretPos(nsWindow* aClient,
nsRect& aEventResult,
nsRect& aResult);
PRBool ConvertToANSIString(const nsAFlatString& aStr,
UINT aCodePage,
nsACString& aANSIStr);
virtual PRBool DispatchKeyEvent(PRUint32 aEventType, WORD aCharCode,
const nsTArray<nsAlternativeCharCode>* aAlternativeChars,
@ -396,7 +399,6 @@ protected:
static PRBool sIMEIsComposing;
static PRBool sIMEIsStatusChanged;
static DWORD sIMEProperty;
static nsString* sIMECompUnicode;
static PRUint8* sIMEAttributeArray;
static PRInt32 sIMEAttributeArrayLength;
@ -466,7 +468,6 @@ protected:
HIMC mOldIMC;
PRUint32 mIMEEnabled;
static HKL gKeyboardLayout;
static PRBool gSwitchKeyboardLayout;
HKL mLastKeyboardLayout;