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