1 /*
2 * Copyright (c) 2005, 2017, 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.
42 const 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 */
AwtInputTextInfor()46 AwtInputTextInfor::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 */
59 int
GetContextData(HIMC hIMC,const LPARAM flags)60 AwtInputTextInfor::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 */
~AwtInputTextInfor()165 AwtInputTextInfor::~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
MakeJavaString(JNIEnv * env,LPWSTR lpStrW,int cStrW)186 jstring 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 //
GetClauseInfor(int * & lpBndClauseW,jstring * & lpReadingClauseW)199 int 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 // For cases where IMM sends WM_IME_COMPOSITION with both GCS_COMPSTR and GCS_RESULTSTR
206 // The GCS_RESULTSTR part may have Caluse and Reading information which should not be ignored
207 if (NULL == m_pResultTextInfor) {
208 lpBndClauseW = NULL;
209 lpReadingClauseW = NULL;
210 return 0;
211 } else {
212 return m_pResultTextInfor->GetClauseInfor(lpBndClauseW, lpReadingClauseW);
213 }
214 }
215
216 int* bndClauseW = NULL;
217 jstring* readingClauseW = NULL;
218
219 //Convert ANSI string caluse information to UNICODE string clause information.
220 try {
221 bndClauseW = new int[m_cClauseW + 1];
222 readingClauseW = new jstring[m_cClauseW];
223 } catch (std::bad_alloc&) {
224 lpBndClauseW = NULL;
225 lpReadingClauseW = NULL;
226 delete [] bndClauseW;
227 throw;
228 }
229
230 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
231
232 for ( int cls = 0; cls < m_cClauseW; cls++ ) {
233 bndClauseW[cls] = m_lpClauseW[cls];
234
235 if ( m_lpReadClauseW[cls + 1] <= (DWORD)m_cReadStrW ) {
236 LPWSTR lpHWStrW = m_lpReadStrW + m_lpReadClauseW[cls];
237 int cHWStrW = m_lpReadClauseW[cls+1] - m_lpReadClauseW[cls];
238
239 if (PRIMARYLANGID(AwtComponent::GetInputLanguage()) == LANG_JAPANESE) {
240 LCID lcJPN = MAKELCID(MAKELANGID(LANG_JAPANESE,SUBLANG_DEFAULT),SORT_DEFAULT);
241 // Reading string is given in half width katakana in Japanese Windows
242 // Convert it to full width katakana.
243 int cFWStrW = ::LCMapString(lcJPN, LCMAP_FULLWIDTH, lpHWStrW, cHWStrW, NULL, 0);
244 LPWSTR lpFWStrW;
245 try {
246 lpFWStrW = new WCHAR[cFWStrW];
247 } catch (std::bad_alloc&) {
248 lpBndClauseW = NULL;
249 lpReadingClauseW = NULL;
250 delete [] bndClauseW;
251 delete [] readingClauseW;
252 throw;
253 }
254
255 ::LCMapString(lcJPN, LCMAP_FULLWIDTH, lpHWStrW, cHWStrW, lpFWStrW, cFWStrW);
256 readingClauseW[cls] = MakeJavaString(env, lpFWStrW, cFWStrW);
257 delete [] lpFWStrW;
258 } else {
259 readingClauseW[cls] = MakeJavaString(env, lpHWStrW, cHWStrW);
260 }
261 if (env->ExceptionCheck()) {
262 lpBndClauseW = NULL;
263 lpReadingClauseW = NULL;
264 delete [] bndClauseW;
265 delete [] readingClauseW;
266 return 0;
267 }
268 }
269 else {
270 readingClauseW[cls] = NULL;
271 }
272 }
273
274 bndClauseW[m_cClauseW] = m_cStrW;
275
276 int retVal = 0;
277 int cCommittedStrW = GetCommittedTextLength();
278
279 /* The conditions to merge the clause information are described below:
280 Senario 1:
281 m_flags & GCS_RESULTSTR is true only, this case m_pResultTextInfor must be NULL.
282 No need to merge.
283
284 Senario 2:
285 m_flags & GCS_COMPSTR is true only, this case m_pResultTextInfor is also NULL.
286 No need to merge either.
287
288 Senario 3:
289 m_flags & GCS_COMPSTR and m_flags & GCS_RESULTSTR both yield to true, in this case
290 m_pResultTextInfor won't be NULL and if there is nothing to commit though, we don't
291 have to merge. Or if the current composing string size is 0, we don't have to merge either.
292
293 So in clusion, the three conditions not not merge are:
294 1. no committed string
295 2. m_pResultTextInfor points to NULL
296 3. the current string size is 0;
297
298 Same rule applies to merge the attribute information.
299 */
300 if (m_cStrW == 0 || cCommittedStrW == 0 ||
301 m_pResultTextInfor == NULL) {
302 lpBndClauseW = bndClauseW;
303 lpReadingClauseW = readingClauseW;
304 retVal = m_cClauseW;
305 } else { /* partial commit case */
306 int* bndResultClauseW = NULL;
307 jstring* readingResultClauseW = NULL;
308 int cResultClauseW = m_pResultTextInfor->GetClauseInfor(bndResultClauseW, readingResultClauseW);
309
310 // Concatenate Clause information.
311 int cMergedClauseW = m_cClauseW + cResultClauseW;
312 int* bndMergedClauseW = NULL;
313 jstring* readingMergedClauseW = NULL;
314 try {
315 bndMergedClauseW = new int[cMergedClauseW+1];
316 readingMergedClauseW = new jstring[cMergedClauseW];
317 } catch (std::bad_alloc&) {
318 delete [] bndMergedClauseW;
319 delete [] bndClauseW;
320 delete [] readingClauseW;
321 throw;
322 }
323
324 int i = 0;
325 if (cResultClauseW > 0 && bndResultClauseW && readingResultClauseW) {
326 for (; i < cResultClauseW; i++) {
327 bndMergedClauseW[i] = bndResultClauseW[i];
328 readingMergedClauseW[i] = readingResultClauseW[i];
329 }
330 }
331
332 if (m_cClauseW > 0 && bndClauseW && readingClauseW) {
333 for(int j = 0; j < m_cClauseW; j++, i++) {
334 bndMergedClauseW[i] = bndClauseW[j] + cCommittedStrW;
335 readingMergedClauseW[i] = readingClauseW[j];
336 }
337 }
338 delete [] bndClauseW;
339 delete [] readingClauseW;
340 bndMergedClauseW[cMergedClauseW] = m_cStrW + cCommittedStrW;
341 lpBndClauseW = bndMergedClauseW;
342 lpReadingClauseW = readingMergedClauseW;
343 retVal = cMergedClauseW;
344 }
345
346 return retVal;
347 }
348
349 //
350 // Convert Attribute Information for DBCS string to that for Unicode string
351 // *lpBndAttrW and *lpValAttrW must be deleted by caller.
352 //
GetAttributeInfor(int * & lpBndAttrW,BYTE * & lpValAttrW)353 int AwtInputTextInfor::GetAttributeInfor(int*& lpBndAttrW, BYTE*& lpValAttrW) {
354 if (m_cStrW == 0 || m_cAttrW != m_cStrW) {
355 if (NULL == m_pResultTextInfor) {
356 lpBndAttrW = NULL;
357 lpValAttrW = NULL;
358
359 return 0;
360 } else {
361 return m_pResultTextInfor->GetAttributeInfor(lpBndAttrW, lpValAttrW);
362 }
363 }
364
365 int* bndAttrW = NULL;
366 BYTE* valAttrW = NULL;
367
368 //Scan attribute byte array and make attribute run information.
369 try {
370 bndAttrW = new int[m_cAttrW + 1];
371 valAttrW = new BYTE[m_cAttrW];
372 } catch (std::bad_alloc&) {
373 lpBndAttrW = NULL;
374 lpValAttrW = NULL;
375 delete [] bndAttrW;
376 throw;
377 }
378
379 int cAttrWT = 0;
380 bndAttrW[0] = 0;
381 valAttrW[0] = m_lpAttrW[0];
382 /* remove duplicate attribute in the m_lpAttrW array. */
383 for ( int offW = 1; offW < m_cAttrW; offW++ ) {
384 if ( m_lpAttrW[offW] != valAttrW[cAttrWT]) {
385 cAttrWT++;
386 bndAttrW[cAttrWT] = offW;
387 valAttrW[cAttrWT] = m_lpAttrW[offW];
388 }
389 }
390 bndAttrW[++cAttrWT] = m_cStrW;
391
392 int retVal = 0;
393
394 int cCommittedStrW = GetCommittedTextLength();
395 if (m_cStrW == 0 ||
396 cCommittedStrW == 0 || m_pResultTextInfor == NULL) {
397 lpBndAttrW = bndAttrW;
398 lpValAttrW = valAttrW;
399 retVal = cAttrWT;
400 } else {
401 int cMergedAttrW = 1 + cAttrWT;
402 int* bndMergedAttrW = NULL;
403 BYTE* valMergedAttrW = NULL;
404 try {
405 bndMergedAttrW = new int[cMergedAttrW+1];
406 valMergedAttrW = new BYTE[cMergedAttrW];
407 } catch (std::bad_alloc&) {
408 delete [] bndMergedAttrW;
409 delete [] bndAttrW;
410 delete [] valAttrW;
411 throw;
412 }
413 bndMergedAttrW[0] = 0;
414 valMergedAttrW[0] = ATTR_CONVERTED;
415 for (int j = 0; j < cAttrWT; j++) {
416 bndMergedAttrW[j+1] = bndAttrW[j]+cCommittedStrW;
417 valMergedAttrW[j+1] = valAttrW[j];
418 }
419 bndMergedAttrW[cMergedAttrW] = m_cStrW + cCommittedStrW;
420
421 delete [] bndAttrW;
422 delete [] valAttrW;
423 lpBndAttrW = bndMergedAttrW;
424 lpValAttrW = valMergedAttrW;
425 retVal = cMergedAttrW;
426 }
427
428 return retVal;
429 }
430
431 //
432 // Returns the cursor position of the current composition.
433 // returns 0 if the current mode is not GCS_COMPSTR
434 //
GetCursorPosition() const435 int AwtInputTextInfor::GetCursorPosition() const {
436 if (m_flags & GCS_COMPSTR) {
437 return m_cursorPosW;
438 } else {
439 return 0;
440 }
441 }
442
443
444 //
445 // Returns the committed text length
446 //
GetCommittedTextLength() const447 int AwtInputTextInfor::GetCommittedTextLength() const {
448
449 if ((m_flags & GCS_COMPSTR) && m_pResultTextInfor) {
450 return m_pResultTextInfor->GetCommittedTextLength();
451 }
452
453 if (m_flags & GCS_RESULTSTR)
454 return m_cStrW;
455 else
456 return 0;
457 }
458