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.
  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 */
  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
  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  */
 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 
 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 //
 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         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 //
 347 int 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 //
 425 int 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 //
 437 int 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 }