1/* 2 * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#include "awt.h" 27#include <imm.h> 28#include "awt_Component.h" 29#include "awt_InputTextInfor.h" 30 31#define WCHAR_SZ sizeof(WCHAR) 32#define DWORD_SZ sizeof(DWORD) 33 34// The start and end index of the result and composition in GCS_INDEX array. 35#define START_RESULTSTR 0 36#define END_RESULTSTR 3 37#define START_COMPSTR 4 38#define END_COMPSTR 8 39 40// The GCS_INDEX array is partitioned into 2 parts, one is result string related and the 41// other is composing string related. 42const DWORD AwtInputTextInfor::GCS_INDEX[9]= {GCS_RESULTSTR, GCS_RESULTREADSTR, GCS_RESULTCLAUSE, 43 GCS_RESULTREADCLAUSE, GCS_COMPSTR, GCS_COMPREADSTR, 44 GCS_COMPCLAUSE, GCS_COMPREADCLAUSE,GCS_COMPATTR}; 45/* Default constructor */ 46AwtInputTextInfor::AwtInputTextInfor() : 47 m_flags(0), m_cursorPosW(0), m_jtext(NULL), m_pResultTextInfor(NULL), \ 48 m_cStrW(0), m_cReadStrW(0), m_cClauseW(0), m_cReadClauseW(0), m_cAttrW(0), \ 49 m_lpStrW(NULL), m_lpReadStrW(NULL), m_lpClauseW(NULL), m_lpReadClauseW(NULL), m_lpAttrW(NULL) 50{} 51 52 53/* Retrieve the context data from the current IMC. 54 Params: 55 HIMC hIMC - the input method context, must NOT be NULL 56 LPARAMS flags - message param to WM_IME_COMPOSITION. 57 Returns 0 if success. 58*/ 59int 60AwtInputTextInfor::GetContextData(HIMC hIMC, const LPARAM flags) { 61 62 DASSERT(hIMC != 0); 63 64 m_flags = flags; 65 // Based on different flags received, we use different GCS_XXX from the 66 // GCS_INDEX array. 67 int startIndex = 0, endIndex = 0; 68 69 if (flags & GCS_COMPSTR) { 70 startIndex = START_COMPSTR; 71 endIndex = END_COMPSTR; 72 /* For some window input method such as Chinese QuanPing, when the user 73 * commits some text, the IMM sends WM_IME_COMPOSITION with GCS_COMPSTR/GCS_RESULTSTR. 74 * So we have to extract the result string from IMC. For most of other cases, 75 * m_pResultTextInfor is NULL and this is why we choose to have a pointer as its member 76 * rather than having a list of the result string information. 77 */ 78 if (flags & GCS_RESULTSTR) { 79 m_pResultTextInfor = new AwtInputTextInfor; 80 m_pResultTextInfor->GetContextData(hIMC, GCS_RESULTSTR); 81 } 82 } else if (flags & GCS_RESULTSTR) { 83 startIndex = START_RESULTSTR; 84 endIndex = END_RESULTSTR; 85 } else { // unknown flags. 86 return -1; 87 } 88 89 /* Get the data from the input context */ 90 LONG cbData[5] = {0}; 91 LPVOID lpData[5] = {NULL}; 92 for (int i = startIndex, j = 0; i <= endIndex; i++, j++) { 93 cbData[j] = ::ImmGetCompositionString(hIMC, GCS_INDEX[i], NULL, 0); 94 if (cbData[j] == 0) { 95 lpData[j] = NULL; 96 } else { 97 LPBYTE lpTemp = new BYTE[cbData[j]]; 98 cbData[j] = ::ImmGetCompositionString(hIMC, GCS_INDEX[i], lpTemp, cbData[j]); 99 if (IMM_ERROR_GENERAL != cbData[j]) { 100 lpData[j] = (LPVOID)lpTemp; 101 } else { 102 lpData[j] = NULL; 103 return -1; 104 } 105 } 106 } 107 108 // Assign the context data 109 m_cStrW = cbData[0]/WCHAR_SZ; 110 m_lpStrW = (LPWSTR)lpData[0]; 111 112 m_cReadStrW = cbData[1]/WCHAR_SZ; 113 m_lpReadStrW = (LPWSTR)lpData[1]; 114 115 m_cClauseW = cbData[2]/DWORD_SZ - 1; 116 m_lpClauseW = (LPDWORD)lpData[2]; 117 118 m_cReadClauseW = cbData[3]/DWORD_SZ - 1; 119 m_lpReadClauseW = (LPDWORD)lpData[3]; 120 121 if (cbData[4] > 0) { 122 m_cAttrW = cbData[4]; 123 m_lpAttrW = (LPBYTE)lpData[4]; 124 } 125 126 // Get the cursor position 127 if (flags & GCS_COMPSTR) { 128 m_cursorPosW = ::ImmGetCompositionString(hIMC, GCS_CURSORPOS, 129 NULL, 0); 130 } 131 132 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 133 if (m_cStrW > 0) { 134 m_jtext = MakeJavaString(env, m_lpStrW, m_cStrW); 135 JNU_CHECK_EXCEPTION_RETURN(env, -1); 136 } 137 138 // Merge the string if necessary 139 if (m_pResultTextInfor != NULL) { 140 jstring jresultText = m_pResultTextInfor->GetText(); 141 if (m_jtext != NULL && jresultText != NULL) { 142 jstring jMergedtext = (jstring)JNU_CallMethodByName(env, NULL, jresultText, 143 "concat", 144 "(Ljava/lang/String;)Ljava/lang/String;", 145 m_jtext).l; 146 DASSERT(!safe_ExceptionOccurred(env)); 147 DASSERT(jMergedtext != NULL); 148 149 env->DeleteLocalRef(m_jtext); 150 m_jtext = jMergedtext; 151 } 152 else if (m_jtext == NULL && jresultText != NULL) { 153 /* No composing text, assign the committed text to m_jtext */ 154 m_jtext = (jstring)env->NewLocalRef(jresultText); 155 } 156 } 157 158 return 0; 159} 160 161/* 162 * Destructor 163 * free the pointer in the m_lpInfoStrW array 164 */ 165AwtInputTextInfor::~AwtInputTextInfor() { 166 167 if (m_jtext) { 168 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 169 env->DeleteLocalRef(m_jtext); 170 m_jtext = NULL; 171 } 172 173 delete [] m_lpStrW; 174 delete [] m_lpReadStrW; 175 delete [] m_lpClauseW; 176 delete [] m_lpReadClauseW; 177 delete [] m_lpAttrW; 178 179 if (m_pResultTextInfor) { 180 delete m_pResultTextInfor; 181 m_pResultTextInfor = NULL; 182 } 183} 184 185 186jstring AwtInputTextInfor::MakeJavaString(JNIEnv* env, LPWSTR lpStrW, int cStrW) { 187 188 if (env == NULL || lpStrW == NULL || cStrW == 0) { 189 return NULL; 190 } else { 191 return env->NewString(reinterpret_cast<jchar*>(lpStrW), cStrW); 192 } 193} 194 195// 196// Convert Clause and Reading Information for DBCS string to that for Unicode string 197// *lpBndClauseW and *lpReadingClauseW must be deleted by caller. 198// 199int AwtInputTextInfor::GetClauseInfor(int*& lpBndClauseW, jstring*& lpReadingClauseW) { 200 201 if ( m_cStrW ==0 || m_cClauseW ==0 || m_cClauseW != m_cReadClauseW || 202 m_lpClauseW == NULL || m_lpReadClauseW == NULL || 203 m_lpClauseW[0] != 0 || m_lpClauseW[m_cClauseW] != (DWORD)m_cStrW || 204 m_lpReadClauseW[0] != 0 || m_lpReadClauseW[m_cReadClauseW] != (DWORD)m_cReadStrW) { 205 lpBndClauseW = NULL; 206 lpReadingClauseW = NULL; 207 return 0; 208 } 209 210 int* bndClauseW = NULL; 211 jstring* readingClauseW = NULL; 212 213 //Convert ANSI string caluse information to UNICODE string clause information. 214 try { 215 bndClauseW = new int[m_cClauseW + 1]; 216 readingClauseW = new jstring[m_cClauseW]; 217 } catch (std::bad_alloc&) { 218 lpBndClauseW = NULL; 219 lpReadingClauseW = NULL; 220 delete [] bndClauseW; 221 throw; 222 } 223 224 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 225 226 for ( int cls = 0; cls < m_cClauseW; cls++ ) { 227 bndClauseW[cls] = m_lpClauseW[cls]; 228 229 if ( m_lpReadClauseW[cls + 1] <= (DWORD)m_cReadStrW ) { 230 LPWSTR lpHWStrW = m_lpReadStrW + m_lpReadClauseW[cls]; 231 int cHWStrW = m_lpReadClauseW[cls+1] - m_lpReadClauseW[cls]; 232 233 if (PRIMARYLANGID(AwtComponent::GetInputLanguage()) == LANG_JAPANESE) { 234 LCID lcJPN = MAKELCID(MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT),SORT_DEFAULT); 235 // Reading string is given in half width katakana in Japanese Windows 236 // Convert it to full width katakana. 237 int cFWStrW = ::LCMapString(lcJPN, LCMAP_FULLWIDTH, lpHWStrW, cHWStrW, NULL, 0); 238 LPWSTR lpFWStrW; 239 try { 240 lpFWStrW = new WCHAR[cFWStrW]; 241 } catch (std::bad_alloc&) { 242 lpBndClauseW = NULL; 243 lpReadingClauseW = NULL; 244 delete [] bndClauseW; 245 delete [] readingClauseW; 246 throw; 247 } 248 249 ::LCMapString(lcJPN, LCMAP_FULLWIDTH, lpHWStrW, cHWStrW, lpFWStrW, cFWStrW); 250 readingClauseW[cls] = MakeJavaString(env, lpFWStrW, cFWStrW); 251 delete [] lpFWStrW; 252 } else { 253 readingClauseW[cls] = MakeJavaString(env, lpHWStrW, cHWStrW); 254 } 255 if (env->ExceptionCheck()) { 256 lpBndClauseW = NULL; 257 lpReadingClauseW = NULL; 258 delete [] bndClauseW; 259 delete [] readingClauseW; 260 return 0; 261 } 262 } 263 else { 264 readingClauseW[cls] = NULL; 265 } 266 } 267 268 bndClauseW[m_cClauseW] = m_cStrW; 269 270 int retVal = 0; 271 int cCommittedStrW = GetCommittedTextLength(); 272 273 /* The conditions to merge the clause information are described below: 274 Senario 1: 275 m_flags & GCS_RESULTSTR is true only, this case m_pResultTextInfor must be NULL. 276 No need to merge. 277 278 Senario 2: 279 m_flags & GCS_COMPSTR is true only, this case m_pResultTextInfor is also NULL. 280 No need to merge either. 281 282 Senario 3: 283 m_flags & GCS_COMPSTR and m_flags & GCS_RESULTSTR both yield to true, in this case 284 m_pResultTextInfor won't be NULL and if there is nothing to commit though, we don't 285 have to merge. Or if the current composing string size is 0, we don't have to merge either. 286 287 So in clusion, the three conditions not not merge are: 288 1. no committed string 289 2. m_pResultTextInfor points to NULL 290 3. the current string size is 0; 291 292 Same rule applies to merge the attribute information. 293 */ 294 if (m_cStrW == 0 || cCommittedStrW == 0 || 295 m_pResultTextInfor == NULL) { 296 lpBndClauseW = bndClauseW; 297 lpReadingClauseW = readingClauseW; 298 retVal = m_cClauseW; 299 } else { /* partial commit case */ 300 int* bndResultClauseW = NULL; 301 jstring* readingResultClauseW = NULL; 302 int cResultClauseW = m_pResultTextInfor->GetClauseInfor(bndResultClauseW, readingResultClauseW); 303 304 // Concatenate Clause information. 305 int cMergedClauseW = m_cClauseW + cResultClauseW; 306 int* bndMergedClauseW = NULL; 307 jstring* readingMergedClauseW = NULL; 308 try { 309 bndMergedClauseW = new int[cMergedClauseW+1]; 310 readingMergedClauseW = new jstring[cMergedClauseW]; 311 } catch (std::bad_alloc&) { 312 delete [] bndMergedClauseW; 313 delete [] bndClauseW; 314 delete [] readingClauseW; 315 throw; 316 } 317 318 int i = 0; 319 if (cResultClauseW > 0 && bndResultClauseW && readingResultClauseW) { 320 for (; i < cResultClauseW; i++) { 321 bndMergedClauseW[i] = bndResultClauseW[i]; 322 readingMergedClauseW[i] = readingResultClauseW[i]; 323 } 324 } 325 326 if (m_cClauseW > 0 && bndClauseW && readingClauseW) { 327 for(int j = 0; j < m_cClauseW; j++, i++) { 328 bndMergedClauseW[i] = bndClauseW[j] + cCommittedStrW; 329 readingMergedClauseW[i] = readingClauseW[j]; 330 } 331 } 332 delete [] bndClauseW; 333 delete [] readingClauseW; 334 bndMergedClauseW[cMergedClauseW] = m_cStrW + cCommittedStrW; 335 lpBndClauseW = bndMergedClauseW; 336 lpReadingClauseW = readingMergedClauseW; 337 retVal = cMergedClauseW; 338 } 339 340 return retVal; 341} 342 343// 344// Convert Attribute Information for DBCS string to that for Unicode string 345// *lpBndAttrW and *lpValAttrW must be deleted by caller. 346// 347int AwtInputTextInfor::GetAttributeInfor(int*& lpBndAttrW, BYTE*& lpValAttrW) { 348 if (m_cStrW == 0 || m_cAttrW != m_cStrW) { 349 lpBndAttrW = NULL; 350 lpValAttrW = NULL; 351 352 return 0; 353 } 354 355 int* bndAttrW = NULL; 356 BYTE* valAttrW = NULL; 357 358 //Scan attribute byte array and make attribute run information. 359 try { 360 bndAttrW = new int[m_cAttrW + 1]; 361 valAttrW = new BYTE[m_cAttrW]; 362 } catch (std::bad_alloc&) { 363 lpBndAttrW = NULL; 364 lpValAttrW = NULL; 365 delete [] bndAttrW; 366 throw; 367 } 368 369 int cAttrWT = 0; 370 bndAttrW[0] = 0; 371 valAttrW[0] = m_lpAttrW[0]; 372 /* remove duplicate attribute in the m_lpAttrW array. */ 373 for ( int offW = 1; offW < m_cAttrW; offW++ ) { 374 if ( m_lpAttrW[offW] != valAttrW[cAttrWT]) { 375 cAttrWT++; 376 bndAttrW[cAttrWT] = offW; 377 valAttrW[cAttrWT] = m_lpAttrW[offW]; 378 } 379 } 380 bndAttrW[++cAttrWT] = m_cStrW; 381 382 int retVal = 0; 383 384 int cCommittedStrW = GetCommittedTextLength(); 385 if (m_cStrW == 0 || 386 cCommittedStrW == 0 || m_pResultTextInfor == NULL) { 387 lpBndAttrW = bndAttrW; 388 lpValAttrW = valAttrW; 389 retVal = cAttrWT; 390 } else { 391 int cMergedAttrW = 1 + cAttrWT; 392 int* bndMergedAttrW = NULL; 393 BYTE* valMergedAttrW = NULL; 394 try { 395 bndMergedAttrW = new int[cMergedAttrW+1]; 396 valMergedAttrW = new BYTE[cMergedAttrW]; 397 } catch (std::bad_alloc&) { 398 delete [] bndMergedAttrW; 399 delete [] bndAttrW; 400 delete [] valAttrW; 401 throw; 402 } 403 bndMergedAttrW[0] = 0; 404 valMergedAttrW[0] = ATTR_CONVERTED; 405 for (int j = 0; j < cAttrWT; j++) { 406 bndMergedAttrW[j+1] = bndAttrW[j]+cCommittedStrW; 407 valMergedAttrW[j+1] = valAttrW[j]; 408 } 409 bndMergedAttrW[cMergedAttrW] = m_cStrW + cCommittedStrW; 410 411 delete [] bndAttrW; 412 delete [] valAttrW; 413 lpBndAttrW = bndMergedAttrW; 414 lpValAttrW = valMergedAttrW; 415 retVal = cMergedAttrW; 416 } 417 418 return retVal; 419} 420 421// 422// Returns the cursor position of the current composition. 423// returns 0 if the current mode is not GCS_COMPSTR 424// 425int AwtInputTextInfor::GetCursorPosition() const { 426 if (m_flags & GCS_COMPSTR) { 427 return m_cursorPosW; 428 } else { 429 return 0; 430 } 431} 432 433 434// 435// Returns the committed text length 436// 437int AwtInputTextInfor::GetCommittedTextLength() const { 438 439 if ((m_flags & GCS_COMPSTR) && m_pResultTextInfor) { 440 return m_pResultTextInfor->GetCommittedTextLength(); 441 } 442 443 if (m_flags & GCS_RESULTSTR) 444 return m_cStrW; 445 else 446 return 0; 447} 448