1 /* 2 * Copyright (c) 1996, 2009, 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_Toolkit.h" 27 #include "awt_TextComponent.h" 28 #include "awt_Canvas.h" 29 30 #include "jni.h" 31 #include "awt_Font.h" 32 33 34 /***********************************************************************/ 35 // struct for _SetText() method 36 struct SetTextStruct { 37 jobject textcomponent; 38 jstring text; 39 }; 40 // struct for _Select() method 41 struct SelectStruct { 42 jobject textcomponent; 43 jint start, end; 44 }; 45 // struct for _EnableEditing() method 46 struct EnableEditingStruct { 47 jobject textcomponent; 48 jboolean on; 49 }; 50 /************************************************************************ 51 * AwtTextComponent fields 52 */ 53 54 /* java.awt.TextComponent fields */ 55 jfieldID AwtTextComponent::canAccessClipboardID; 56 57 58 /************************************************************************ 59 * AwtTextComponent methods 60 */ 61 62 AwtTextComponent::AwtTextComponent() { 63 m_synthetic = FALSE; 64 m_lStartPos = -1; 65 m_lEndPos = -1; 66 m_lLastPos = -1; 67 m_isLFonly = FALSE; 68 m_EOLchecked = FALSE; 69 // javaEventsMask = 0; // accessibility support 70 } 71 72 LPCTSTR AwtTextComponent::GetClassName() { 73 return TEXT("EDIT"); /* System provided edit control class */ 74 } 75 76 /* Set a suitable font to IME against the component font. */ 77 void AwtTextComponent::SetFont(AwtFont* font) 78 { 79 DASSERT(font != NULL); 80 if (font->GetAscent() < 0) { 81 AwtFont::SetupAscent(font); 82 } 83 84 int index = font->GetInputHFontIndex(); 85 if (index < 0) 86 /* In this case, user cannot get any suitable font for input. */ 87 index = 0; 88 89 //im --- changed for over the spot composing 90 m_hFont = font->GetHFont(index); 91 SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(FALSE, 0)); 92 SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, 93 MAKELPARAM(1, 1)); 94 95 /* 96 * WM_SETFONT reverts foreground color to the default for 97 * rich edit controls. So we have to restore it manually. 98 */ 99 SetColor(GetColor()); 100 VERIFY(::InvalidateRect(GetHWnd(), NULL, TRUE)); 101 //im --- end 102 103 } 104 105 int AwtTextComponent::RemoveCR(WCHAR *pStr) 106 { 107 int i, nLen = 0; 108 109 if (pStr) { 110 /* check to see if there are any CR's */ 111 if (wcschr(pStr, L'\r') == NULL) { 112 return static_cast<int>(wcslen(pStr)); 113 } 114 115 for (i=0; pStr[i] != 0; i++) { 116 if (m_isLFonly == TRUE) { 117 if (pStr[i] == L'\r') { 118 continue; 119 } 120 } else { 121 if (pStr[i] == L'\r' && pStr[i + 1] != L'\n') { 122 continue; 123 } 124 } 125 pStr[nLen++] = pStr[i]; 126 } 127 pStr[nLen] = 0; 128 } 129 return nLen; 130 } 131 132 MsgRouting 133 AwtTextComponent::WmNotify(UINT notifyCode) 134 { 135 if (notifyCode == EN_CHANGE) { 136 DoCallback("valueChanged", "()V"); 137 } 138 return mrDoDefault; 139 } 140 141 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg) 142 { 143 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK; 144 } 145 146 MsgRouting 147 AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic) 148 { 149 MsgRouting returnVal; 150 151 /* 152 * Store the 'synthetic' parameter so that the WM_PASTE security check 153 * happens only for synthetic events. 154 */ 155 m_synthetic = synthetic; 156 returnVal = AwtComponent::HandleEvent(msg, synthetic); 157 m_synthetic = FALSE; 158 return returnVal; 159 } 160 161 /* 162 * If this Paste is occuring because of a synthetic Java event (e.g., 163 * a synthesized <CTRL>-V KeyEvent), then verify that the TextComponent 164 * has permission to access the Clipboard before pasting. If permission 165 * is denied, we should throw a SecurityException, but currently do not 166 * because when we detect the security violation, we are in the Toolkit 167 * thread, not the thread which dispatched the illegal event. 168 */ 169 MsgRouting 170 AwtTextComponent::WmPaste() 171 { 172 if (m_synthetic) { 173 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 174 if (env->EnsureLocalCapacity(1) < 0) { 175 return mrConsume; 176 } 177 jobject target = GetTarget(env); 178 jboolean canAccessClipboard = 179 env->GetBooleanField(target, 180 AwtTextComponent::canAccessClipboardID); 181 env->DeleteLocalRef(target); 182 return (canAccessClipboard) ? mrDoDefault : mrConsume; 183 } 184 else { 185 return mrDoDefault; 186 } 187 } 188 189 //im --- override to over the spot composition 190 void AwtTextComponent::SetCompositionWindow(RECT& rc) 191 { 192 HWND hwnd = ImmGetHWnd(); 193 HIMC hIMC = ImmGetContext(hwnd); 194 // rc is not used for text component. 195 COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} }; 196 GetCaretPos(&(cf.ptCurrentPos)); 197 // the proxy is the native focus owner and it contains the composition window 198 // let's convert the position to a coordinate space relative to proxy 199 ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1); 200 ImmSetCompositionWindow(hIMC, &cf); 201 202 LOGFONT lf; 203 GetObject(m_hFont, sizeof(LOGFONT), &lf); 204 ImmSetCompositionFont(hIMC, &lf); 205 ImmReleaseContext(hwnd, hIMC); 206 } 207 //im --- end 208 209 LONG AwtTextComponent::getJavaSelPos(LONG orgPos) 210 { 211 long wlen; 212 long pos = 0; 213 long cur = 0; 214 LPTSTR wbuf; 215 216 if ((wlen = GetTextLength()) == 0) 217 return 0; 218 wbuf = new TCHAR[wlen + 1]; 219 GetText(wbuf, wlen + 1); 220 if (m_isLFonly == TRUE) { 221 wlen = RemoveCR(wbuf); 222 } 223 224 while (cur < orgPos && pos++ < wlen) { 225 if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) { 226 cur++; 227 } 228 cur++; 229 } 230 delete[] wbuf; 231 return pos; 232 } 233 234 LONG AwtTextComponent::getWin32SelPos(LONG orgPos) 235 { 236 long wlen; 237 long pos = 0; 238 long cur = 0; 239 LPTSTR wbuf; 240 241 if ((wlen = GetTextLength()) == 0) 242 return 0; 243 wbuf = new TCHAR[wlen + 1]; 244 GetText(wbuf, wlen + 1); 245 if (m_isLFonly == TRUE) { 246 RemoveCR(wbuf); 247 } 248 249 while (cur < orgPos && pos < wlen) { 250 if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) { 251 pos++; 252 } 253 pos++; 254 cur++; 255 } 256 delete[] wbuf; 257 return pos; 258 } 259 260 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr) 261 { 262 if (pStr == NULL) { 263 return; 264 } 265 266 if (GetTextLength() == 0) { 267 m_EOLchecked = FALSE; 268 } 269 270 // check to see if there are any LF's 271 if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) { 272 return; 273 } 274 275 for (int i=0; pStr[i] != 0; i++) { 276 if (pStr[i] == L'\n') { 277 if (i > 0 && pStr[i-1] == L'\r') { 278 m_isLFonly = FALSE; 279 } else { 280 m_isLFonly = TRUE; 281 } 282 m_EOLchecked = TRUE; 283 return; 284 } 285 } 286 } 287 288 void AwtTextComponent::SetSelRange(LONG start, LONG end) 289 { 290 SendMessage(EM_SETSEL, 291 getWin32SelPos(start), 292 getWin32SelPos(end)); 293 // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing 294 // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus 295 } 296 297 jstring AwtTextComponent::_GetText(void *param) 298 { 299 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 300 301 jobject self = (jobject)param; 302 303 AwtTextComponent *c = NULL; 304 jstring result = NULL; 305 306 PDATA pData; 307 JNI_CHECK_PEER_GOTO(self, ret); 308 309 c = (AwtTextComponent *)pData; 310 if (::IsWindow(c->GetHWnd())) 311 { 312 int len = ::GetWindowTextLength(c->GetHWnd()); 313 if (len == 0) { 314 /* Make java null string */ 315 jchar *jc = new jchar[0]; 316 result = env->NewString(jc, 0); 317 delete [] jc; 318 } else { 319 WCHAR* buf = new WCHAR[len + 1]; 320 c->GetText(buf, len + 1); 321 c->RemoveCR(buf); 322 result = JNU_NewStringPlatform(env, buf); 323 delete [] buf; 324 } 325 } 326 ret: 327 env->DeleteGlobalRef(self); 328 329 if (result != NULL) 330 { 331 jstring globalRef = (jstring)env->NewGlobalRef(result); 332 env->DeleteLocalRef(result); 333 return globalRef; 334 } 335 else 336 { 337 return NULL; 338 } 339 } 340 341 void AwtTextComponent::_SetText(void *param) 342 { 343 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 344 345 SetTextStruct *sts = (SetTextStruct *)param; 346 jobject self = sts->textcomponent; 347 jstring text = sts->text; 348 349 AwtTextComponent *c = NULL; 350 351 PDATA pData; 352 JNI_CHECK_PEER_GOTO(self, ret); 353 c = (AwtTextComponent *)pData; 354 if (::IsWindow(c->GetHWnd())) 355 { 356 int length = env->GetStringLength(text); 357 WCHAR* buffer = new WCHAR[length + 1]; 358 env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer)); 359 buffer[length] = 0; 360 c->CheckLineSeparator(buffer); 361 c->RemoveCR(buffer); 362 c->SetText(buffer); 363 delete[] buffer; 364 } 365 ret: 366 env->DeleteGlobalRef(self); 367 env->DeleteGlobalRef(text); 368 369 delete sts; 370 } 371 372 jint AwtTextComponent::_GetSelectionStart(void *param) 373 { 374 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 375 376 jobject self = (jobject)param; 377 378 jint result = 0; 379 AwtTextComponent *c = NULL; 380 381 PDATA pData; 382 JNI_CHECK_PEER_GOTO(self, ret); 383 c = (AwtTextComponent *)pData; 384 if (::IsWindow(c->GetHWnd())) 385 { 386 long start; 387 c->SendMessage(EM_GETSEL, (WPARAM)&start); 388 result = c->getJavaSelPos(start); 389 } 390 ret: 391 env->DeleteGlobalRef(self); 392 393 return result; 394 } 395 396 jint AwtTextComponent::_GetSelectionEnd(void *param) 397 { 398 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 399 400 jobject self = (jobject)param; 401 402 jint result = 0; 403 AwtTextComponent *c = NULL; 404 405 PDATA pData; 406 JNI_CHECK_PEER_GOTO(self, ret); 407 c = (AwtTextComponent *)pData; 408 if (::IsWindow(c->GetHWnd())) 409 { 410 long end; 411 c->SendMessage(EM_GETSEL, 0, (LPARAM)&end); 412 result = c->getJavaSelPos(end); 413 } 414 ret: 415 env->DeleteGlobalRef(self); 416 417 return result; 418 } 419 420 void AwtTextComponent::_Select(void *param) 421 { 422 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 423 424 SelectStruct *ss = (SelectStruct *)param; 425 jobject self = ss->textcomponent; 426 jint start = ss->start; 427 jint end = ss->end; 428 429 AwtTextComponent *c = NULL; 430 431 PDATA pData; 432 JNI_CHECK_PEER_GOTO(self, ret); 433 c = (AwtTextComponent *)pData; 434 if (::IsWindow(c->GetHWnd())) 435 { 436 c->SetSelRange(start, end); 437 c->SendMessage(EM_SCROLLCARET); 438 } 439 ret: 440 env->DeleteGlobalRef(self); 441 442 delete ss; 443 } 444 445 void AwtTextComponent::_EnableEditing(void *param) 446 { 447 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 448 449 EnableEditingStruct *ees = (EnableEditingStruct *)param; 450 jobject self = ees->textcomponent; 451 jboolean on = ees->on; 452 453 AwtTextComponent *c = NULL; 454 455 PDATA pData; 456 JNI_CHECK_PEER_GOTO(self, ret); 457 c = (AwtTextComponent *)pData; 458 if (::IsWindow(c->GetHWnd())) 459 { 460 c->SendMessage(EM_SETREADONLY, !on); 461 } 462 ret: 463 env->DeleteGlobalRef(self); 464 465 delete ees; 466 } 467 468 469 /************************************************************************ 470 * WTextComponentPeer native methods 471 */ 472 473 extern "C" { 474 475 /* 476 * Class: sun_awt_windows_WTextComponentPeer 477 * Method: getText 478 * Signature: ()Ljava/lang/String; 479 */ 480 JNIEXPORT jstring JNICALL 481 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self) 482 { 483 TRY; 484 485 jobject selfGlobalRef = env->NewGlobalRef(self); 486 487 jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall( 488 (void*(*)(void*))AwtTextComponent::_GetText, 489 (void *)selfGlobalRef); 490 // selfGlobalRef is deleted in _GetText 491 if (globalRef != NULL) 492 { 493 jstring localRef = (jstring)env->NewLocalRef(globalRef); 494 env->DeleteGlobalRef(globalRef); 495 return localRef; 496 } 497 else 498 { 499 return NULL; 500 } 501 502 CATCH_BAD_ALLOC_RET(NULL); 503 } 504 505 /* 506 * Class: sun_awt_windows_WTextComponentPeer 507 * Method: setText 508 * Signature: (Ljava/lang/String;)V 509 */ 510 JNIEXPORT void JNICALL 511 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self, 512 jstring text) 513 { 514 TRY; 515 516 SetTextStruct *sts = new SetTextStruct; 517 sts->textcomponent = env->NewGlobalRef(self); 518 sts->text = (jstring)env->NewGlobalRef(text); 519 520 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts); 521 // global refs and sts are deleted in _SetText 522 523 CATCH_BAD_ALLOC; 524 } 525 526 /* 527 * Class: sun_awt_windows_WTextComponentPeer 528 * Method: getSelectionStart 529 * Signature: ()I 530 */ 531 JNIEXPORT jint JNICALL 532 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env, 533 jobject self) 534 { 535 TRY; 536 537 return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall( 538 (void *(*)(void *))AwtTextComponent::_GetSelectionStart, 539 env->NewGlobalRef(self)))); 540 // global ref is deleted in _GetSelectionStart() 541 542 CATCH_BAD_ALLOC_RET(0); 543 } 544 545 /* 546 * Class: sun_awt_windows_WTextComponentPeer 547 * Method: getSelectionEnd 548 * Signature: ()I 549 */ 550 JNIEXPORT jint JNICALL 551 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env, 552 jobject self) 553 { 554 TRY; 555 556 return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall( 557 (void *(*)(void *))AwtTextComponent::_GetSelectionEnd, 558 env->NewGlobalRef(self)))); 559 // global ref is deleted in _GetSelectionEnd() 560 561 CATCH_BAD_ALLOC_RET(0); 562 } 563 564 /* 565 * Class: sun_awt_windows_WTextComponentPeer 566 * Method: select 567 * Signature: (II)V 568 */ 569 JNIEXPORT void JNICALL 570 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self, 571 jint start, jint end) 572 { 573 TRY; 574 575 SelectStruct *ss = new SelectStruct; 576 ss->textcomponent = env->NewGlobalRef(self); 577 ss->start = start; 578 ss->end = end; 579 580 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss); 581 // global ref and ss are deleted in _Select 582 583 CATCH_BAD_ALLOC; 584 } 585 586 /* 587 * Class: sun_awt_windows_WTextComponentPeer 588 * Method: enableEditing 589 * Signature: (Z)V 590 */ 591 JNIEXPORT void JNICALL 592 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env, 593 jobject self, 594 jboolean on) 595 { 596 TRY; 597 598 EnableEditingStruct *ees = new EnableEditingStruct; 599 ees->textcomponent = env->NewGlobalRef(self); 600 ees->on = on; 601 602 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees); 603 // global ref and ees are deleted in _EnableEditing() 604 605 CATCH_BAD_ALLOC; 606 } 607 608 /* 609 * Class: sun_awt_windows_WTextComponentPeer 610 * Method: initIDs 611 * Signature: ()V 612 */ 613 JNIEXPORT void JNICALL 614 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls) 615 { 616 TRY; 617 618 cls = env->FindClass("java/awt/TextComponent"); 619 if (cls != NULL) { 620 AwtTextComponent::canAccessClipboardID = 621 env->GetFieldID(cls, "canAccessClipboard", "Z"); 622 DASSERT(AwtTextComponent::canAccessClipboardID != NULL); 623 } 624 625 CATCH_BAD_ALLOC; 626 } 627 628 // 629 // Accessibility support 630 // 631 632 /* To be fully implemented in a future release 633 * 634 * Class: sun_awt_windows_WTextComponentPeer 635 * Method: getIndexAtPoint 636 * Signature: (II)I 637 * 638 JNIEXPORT jlong JNICALL 639 Java_sun_awt_windows_WTextComponentPeer_filterEvents(JNIEnv *env, jobject self, jlong mask) 640 { 641 TRY; 642 643 PDATA pData; 644 JNI_CHECK_PEER_RETURN_NULL(self); 645 AwtTextComponent* c = (AwtTextComponent*)pData; 646 647 jlong oldMask = c->javaEventsMask; 648 c->javaEventsMask = mask; 649 650 return oldMask; 651 652 CATCH_BAD_ALLOC_RET(0); 653 } 654 */ 655 656 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead 657 /* 658 * Handle WmKeyDown to catch keystrokes which may move the caret, 659 * and fire events as appropriate when that happens, if they are wanted 660 * 661 * Note: mouse clicks come through WmKeyDown as well (do they??!?!) 662 * 663 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt, 664 UINT flags, BOOL system) { 665 666 printf("AwtTextComponent::WmKeyDown called\r\n"); 667 668 669 // NOTE: WmKeyDown won't be processed 'till well after we return 670 // so we need to modify the values based on the keystroke 671 // 672 static long oldStart = -1; 673 static long oldEnd = -1; 674 675 // most keystrokes can move the caret 676 // so we'll simply check to see if the caret has moved! 677 if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) { 678 long start; 679 long end; 680 SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end); 681 if (start != oldStart || end != oldEnd) { 682 683 printf(" -> calling TextComponent.selectionValuesChanged()\r\n"); 684 printf(" -> old = (%d, %d); new = (%d, %d)\r\n", 685 oldStart, oldEnd, start, end); 686 687 DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details... 688 oldStart = start; 689 oldEnd = end; 690 } 691 } 692 693 return AwtComponent::WmKeyDown(wkey, repCnt, flags, system); 694 } 695 */ 696 697 /* To be fully implemented in a future release 698 * 699 * Class: sun_awt_windows_WTextComponentPeer 700 * Method: getIndexAtPoint 701 * Signature: (II)I 702 * 703 JNIEXPORT jint JNICALL 704 Java_sun_awt_windows_WTextComponentPeer_getIndexAtPoint(JNIEnv *env, jobject self, jint x, jint y) 705 { 706 TRY; 707 708 PDATA pData; 709 // JNI_CHECK_PEER_RETURN_VAL(self, -1); [[[FIXME]]] Peter Korn -> should return -1 here 710 JNI_CHECK_PEER_RETURN_NULL(self); 711 AwtTextComponent* c = (AwtTextComponent*)pData; 712 int indicies = c->SendMessage(EM_CHARFROMPOS, (WPARAM) 0, (LPARAM) MAKELPARAM(x, y)); 713 int index = LOWORD(indicies); // index into the line the (x,y) coord is on 714 int lineIndex = c->SendMessage(EM_LINEINDEX, HIWORD(indicies)); // index of start of line 715 return (index + lineIndex); 716 717 CATCH_BAD_ALLOC_RET(-1); 718 } 719 */ 720 721 /* To be fully implemented in a future release 722 * 723 * Class: sun_awt_windows_WTextComponentPeer 724 * Method: getCharacterBounds 725 * Signature: (I)Ljava/awt/Rectangle; 726 * 727 JNIEXPORT jobject JNICALL 728 Java_sun_awt_windows_WTextComponentPeer_getCharacterBounds(JNIEnv *env, jobject self, jint i) 729 { 730 731 // loop through lines with EM_LINELENGTH? e.g.: 732 // line = 0; ttl = 0; // index is passed in as 'i' above 733 // while (ttl < index) { 734 // ttl += SendMessage(EM_LINELENGTH, line++); 735 // } 736 // line-- (decrement back again) 737 // alternately, we could use EM_LINEINDEX to the same effect; perhaps slightly cleaner: 738 // computedIndex = 0; line = 0; 739 // while (computedIndex < index) { 740 // computedIndex = SendMessage(EM_LINEINDEX, 1 + line++); 741 // } 742 // line--; 743 744 // EM_POSFROMCHAR - convert char index into a Point 745 // wParam = (LPPOINT) lpPoint; // address of structure 746 // receiving character position 747 // lParam = (LPARAM) wCharIndex; // zero-based index of character 748 // 749 // still need to turn the above into a Rect somehow... 750 // (use font metrics on font info for letter to get height? use 751 // getLineHeight type of message?). 752 753 // WM_GETFONT - get the font struct for the window control 754 // wParam = lParam = 0 755 // returns an HFONT 756 // -or- 757 // GetTextMetrics(hDC) to get the text info for the font selected 758 // into the hDC of the control (tmHeight is what we want in the 759 // TEXTMETRIC struct). 760 // also GetCharWidth32() with the char at the index in question to get 761 // the width of that char 762 // *** Can't use GetTextMetrics/GetCharWidth32, as we don't have an hDC!! *** 763 764 TRY; 765 766 PDATA pData; 767 JNI_CHECK_PEER_RETURN_NULL(self); 768 AwtComponent* c = (AwtComponent*)pData; 769 /* 770 int line = 0; 771 int lineIndex = 0; 772 while (lineIndex < i) { 773 lineIndex = c->SendMessage(EM_LINEINDEX, 1 + line++); 774 } 775 line--; // line is now the line which contains our character at position 'i' 776 int offsetIndex = i - lineIndex; // offsetIndex is now distance in on the line 777 * / 778 POINT p; 779 780 c->SendMessage(EM_POSFROMCHAR, (WPARAM) &p, (LPARAM) i); // x coord is meaningful; y may not be 781 782 // need to calculate charWidth, charHeight, and set p.y to something meangful 783 784 jint charWidth; 785 jint charHeight; 786 787 /* 788 HFONT font = c->SendMessage(WM_GETFONT); 789 if (GetCharWidth32(c->hdc, i, i, &charWidth) != 0) { // [[[FIXME]]] need to get hDC! 790 791 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 792 jobject rect = JNU_NewObjectByName(env, "java/awt/Rectangle", "(IIII)V", 793 (jint) p.x, (jint) p.y, charWidth, charHeight); 794 795 return rect; 796 } 797 * / 798 return (jobject) 0; 799 800 CATCH_BAD_ALLOC_RET(0); 801 } 802 */ 803 804 } /* extern "C" */