1 /*
2  * Copyright (c) 1996, 2016, 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_TextArea.h"
29 #include "awt_TextField.h"
30 #include "awt_Canvas.h"
31 
32 #include "jni.h"
33 #include "awt_Font.h"
34 
35 
36 /***********************************************************************/
37 // struct for _SetText() method
38 struct SetTextStruct {
39     jobject textcomponent;
40     jstring text;
41 };
42 // struct for _Select() method
43 struct SelectStruct {
44     jobject textcomponent;
45     jint start, end;
46 };
47 // struct for _EnableEditing() method
48 struct EnableEditingStruct {
49     jobject textcomponent;
50     jboolean on;
51 };
52 /************************************************************************
53  * AwtTextComponent fields
54  */
55 
56 /************************************************************************
57  * AwtTextComponent methods
58  */
59 
60 jmethodID AwtTextComponent::canAccessClipboardMID;
61 
AwtTextComponent()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     m_hEditCtrl       = NULL;
70     m_bIgnoreEnChange = FALSE;
71 //    javaEventsMask = 0;    // accessibility support
72 }
73 
GetClassName()74 LPCTSTR AwtTextComponent::GetClassName() {
75     static BOOL richedLibraryLoaded = FALSE;
76     if (!richedLibraryLoaded) {
77         JDK_LoadSystemLibrary("RICHED20.DLL");
78         richedLibraryLoaded = TRUE;
79     }
80     return RICHEDIT_CLASS;
81 }
82 
83 /* Create a new AwtTextArea or AwtTextField object and window.   */
Create(jobject peer,jobject parent,BOOL isMultiline)84 AwtTextComponent* AwtTextComponent::Create(jobject peer, jobject parent, BOOL isMultiline)
85 {
86     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
87 
88     jobject target = NULL;
89     AwtTextComponent* c = NULL;
90 
91     try {
92         if (env->EnsureLocalCapacity(1) < 0) {
93             return NULL;
94         }
95 
96         PDATA pData;
97         AwtCanvas* awtParent;
98 
99         JNI_CHECK_PEER_GOTO(parent, done);
100         awtParent = (AwtCanvas*)pData;
101 
102         target = env->GetObjectField(peer, AwtObject::targetID);
103         JNI_CHECK_NULL_GOTO(target, "null target", done);
104 
105         if(isMultiline){
106             c = new AwtTextArea();
107         }else{
108             c = new AwtTextField();
109         }
110 
111         {
112             /* Adjust style for scrollbar visibility and word wrap  */
113             DWORD scroll_style;
114 
115             if(isMultiline){
116 
117                  jint scrollbarVisibility =
118                      env->GetIntField(target, AwtTextArea::scrollbarVisibilityID);
119 
120                  switch (scrollbarVisibility) {
121                      case java_awt_TextArea_SCROLLBARS_NONE:
122                          scroll_style = ES_AUTOVSCROLL;
123                          break;
124                      case java_awt_TextArea_SCROLLBARS_VERTICAL_ONLY:
125                          scroll_style = WS_VSCROLL | ES_AUTOVSCROLL;
126                          break;
127                      case java_awt_TextArea_SCROLLBARS_HORIZONTAL_ONLY:
128                          scroll_style = WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL;
129                          break;
130                      case java_awt_TextArea_SCROLLBARS_BOTH:
131                      default:
132                          scroll_style = WS_VSCROLL | WS_HSCROLL |
133                              ES_AUTOVSCROLL | ES_AUTOHSCROLL;
134                          break;
135                 }
136             }
137 
138           DWORD style = WS_CHILD | WS_CLIPSIBLINGS | ES_LEFT;
139 
140           /*
141            * Specify ES_DISABLENOSCROLL - RichEdit control style to disable
142            * scrollbars instead of hiding them when not needed.
143            */
144           style |= isMultiline ?  ES_MULTILINE | ES_WANTRETURN | scroll_style
145               | ES_DISABLENOSCROLL : ES_AUTOHSCROLL;
146 
147 
148           DWORD exStyle = WS_EX_CLIENTEDGE;
149           if (GetRTL()) {
150               exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
151               if (GetRTLReadingOrder())
152                   exStyle |= WS_EX_RTLREADING;
153           }
154 
155 
156           jint x = env->GetIntField(target, AwtComponent::xID);
157           jint y = env->GetIntField(target, AwtComponent::yID);
158           jint width = env->GetIntField(target, AwtComponent::widthID);
159           jint height = env->GetIntField(target, AwtComponent::heightID);
160 
161           c->CreateHWnd(env, L"", style, exStyle,
162                         x, y, width, height,
163                         awtParent->GetHWnd(),
164                         reinterpret_cast<HMENU>(static_cast<INT_PTR>(
165                 awtParent->CreateControlID())),
166                         ::GetSysColor(COLOR_WINDOWTEXT),
167                         ::GetSysColor(COLOR_WINDOW),
168                         peer);
169 
170           // Fix for 4753116.
171           // If it is not win95 (we are using Richedit 2.0)
172           // we set plain text mode, in which the control is
173           // similar to a standard edit control:
174           //  - The text in a plain text control can have only
175           //    one format.
176           //  - The user cannot paste rich text formats, such as RTF
177           //    or embedded objects into a plain text control.
178           //  - Rich text mode controls always have a default
179           //    end-of-document marker or carriage return,
180           //    to format paragraphs.
181           // kdm@sparc.spb.su
182           c->SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT, 0);
183 
184           c->m_backgroundColorSet = TRUE;
185           /* suppress inheriting parent's color. */
186           c->UpdateBackground(env, target);
187           c->SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
188                          MAKELPARAM(1, 1));
189           /*
190            * Fix for BugTraq Id 4260109.
191            * Set the text limit to the maximum.
192            * Use EM_EXLIMITTEXT for RichEdit controls.
193            * For some reason RichEdit 1.0 becomes read-only if the
194            * specified limit is greater than 0x7FFFFFFD.
195            */
196           c->SendMessage(EM_EXLIMITTEXT, 0, 0x7FFFFFFD);
197 
198           /* Unregister RichEdit built-in drop target. */
199           VERIFY(::RevokeDragDrop(c->GetHWnd()) != DRAGDROP_E_INVALIDHWND);
200 
201           /* To enforce CF_TEXT format for paste operations. */
202           VERIFY(c->SendMessage(EM_SETOLECALLBACK, 0,
203                                 (LPARAM)&GetOleCallback()));
204 
205           c->SendMessage(EM_SETEVENTMASK, 0, ENM_CHANGE);
206         }
207     } catch (...) {
208         env->DeleteLocalRef(target);
209         throw;
210     }
211 
212 done:
213     env->DeleteLocalRef(target);
214 
215     return c;
216 }
217 
Dispose()218 void AwtTextComponent::Dispose()
219 {
220     if (m_hEditCtrl != NULL) {
221         VERIFY(::DestroyWindow(m_hEditCtrl));
222         m_hEditCtrl = NULL;
223     }
224     AwtComponent::Dispose();
225 }
226 
227 
228 LRESULT
WindowProc(UINT message,WPARAM wParam,LPARAM lParam)229 AwtTextComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
230 
231     switch (message) {
232         case WM_PRINTCLIENT:
233           {
234             FORMATRANGE fr;
235             HDC hPrinterDC = (HDC)wParam;
236             int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES);
237             int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES);
238             int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX);
239             int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY);
240 
241             // Ensure the printer DC is in MM_TEXT mode.
242             ::SetMapMode ( hPrinterDC, MM_TEXT );
243 
244             // Rendering to the same DC we are measuring.
245             ::ZeroMemory(&fr, sizeof(fr));
246             fr.hdc = fr.hdcTarget = hPrinterDC;
247             // Set up the page.
248             fr.rcPage.left     = fr.rcPage.top = 0;
249             fr.rcPage.right    = (nHorizRes/nLogPixelsX) * 1440; // in twips
250             fr.rcPage.bottom   = (nVertRes/nLogPixelsY) * 1440;
251             fr.rc.left   = fr.rcPage.left;
252             fr.rc.top    = fr.rcPage.top;
253             fr.rc.right  = fr.rcPage.right;
254             fr.rc.bottom = fr.rcPage.bottom;
255 
256             // start printing from the first visible line
257             LRESULT nLine = SendMessage(EM_GETFIRSTVISIBLELINE, 0, 0);
258             LONG startCh = static_cast<LONG>(SendMessage(EM_LINEINDEX,
259                                                          (WPARAM)nLine, 0));
260             fr.chrg.cpMin = startCh;
261             fr.chrg.cpMax = -1;
262 
263             SendMessage(EM_FORMATRANGE, TRUE, (LPARAM)&fr);
264           }
265 
266         break;
267     }
268 
269     return AwtComponent::WindowProc(message, wParam, lParam);
270 }
271 
EditGetCharFromPos(POINT & pt)272 LONG AwtTextComponent::EditGetCharFromPos(POINT& pt) {
273     return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0,
274             reinterpret_cast<LPARAM>(&pt)));
275 }
276 
277 /* Set a suitable font to IME against the component font. */
SetFont(AwtFont * font)278 void AwtTextComponent::SetFont(AwtFont* font)
279 {
280     DASSERT(font != NULL);
281     if (font->GetAscent() < 0) {
282         AwtFont::SetupAscent(font);
283     }
284 
285     int index = font->GetInputHFontIndex();
286     if (index < 0)
287         /* In this case, user cannot get any suitable font for input. */
288         index = 0;
289 
290     //im --- changed for over the spot composing
291     m_hFont = font->GetHFont(index);
292     SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(FALSE, 0));
293     SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
294                 MAKELPARAM(1, 1));
295 
296     /*
297      * WM_SETFONT reverts foreground color to the default for
298      * rich edit controls. So we have to restore it manually.
299      */
300     SetColor(GetColor());
301     VERIFY(::InvalidateRect(GetHWnd(), NULL, TRUE));
302     //im --- end
303 
304 }
305 
RemoveCR(WCHAR * pStr)306 int AwtTextComponent::RemoveCR(WCHAR *pStr)
307 {
308     int i, nLen = 0;
309 
310     if (pStr) {
311         /* check to see if there are any CR's */
312         if (wcschr(pStr, L'\r') == NULL) {
313             return static_cast<int>(wcslen(pStr));
314         }
315 
316         for (i=0; pStr[i] != 0; i++) {
317             if (m_isLFonly == TRUE) {
318                 if (pStr[i] == L'\r') {
319                     continue;
320                 }
321             } else {
322                 if (pStr[i] == L'\r' && pStr[i + 1] != L'\n') {
323                     continue;
324                 }
325             }
326             pStr[nLen++] = pStr[i];
327         }
328         pStr[nLen] = 0;
329     }
330     return nLen;
331 }
332 
333 MsgRouting
WmNotify(UINT notifyCode)334 AwtTextComponent::WmNotify(UINT notifyCode)
335 {
336     if (notifyCode == EN_CHANGE) {
337         /*
338          * Ignore notifications if the text hasn't been changed.
339          * EN_CHANGE sent on character formatting changes as well.
340          */
341         if (m_bIgnoreEnChange == FALSE) {
342             m_bCanUndo = TRUE;
343             DoCallback("valueChanged", "()V");
344         } else {
345             m_bCanUndo = FALSE;
346         }
347     }
348     return mrDoDefault;
349 }
350 
IsFocusingMouseMessage(MSG * pMsg)351 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg)
352 {
353     return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK;
354 }
355 
356 MsgRouting
HandleEvent(MSG * msg,BOOL synthetic)357 AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic)
358 {
359     MsgRouting returnVal;
360 
361     if (msg->message == WM_RBUTTONUP ||
362                (msg->message == WM_SYSKEYDOWN && msg->wParam == VK_F10 &&
363                 HIBYTE(::GetKeyState(VK_SHIFT)))) {
364         POINT p;
365         if (msg->message == WM_RBUTTONUP) {
366             VERIFY(::GetCursorPos(&p));
367         } else {
368             p.x = -1;
369             p.y = -1;
370         }
371 
372         if (!::PostMessage(GetHWnd(), WM_CONTEXTMENU, (WPARAM)GetHWnd(),
373                            MAKELPARAM(p.x, p.y))) {
374             JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
375             JNU_ThrowInternalError(env, "Message not posted, native event queue may be full.");
376             env->ExceptionDescribe();
377             env->ExceptionClear();
378         }
379         delete msg;
380         return mrConsume;
381     }
382 
383     /*
384      * Store the 'synthetic' parameter so that the WM_PASTE security check
385      * happens only for synthetic events.
386      */
387     m_synthetic = synthetic;
388     returnVal = AwtComponent::HandleEvent(msg, synthetic);
389     m_synthetic = FALSE;
390     return returnVal;
391 }
392 
393 /*
394  * If this Paste is occurring because of a synthetic Java event (e.g.,
395  * a synthesized <CTRL>-V KeyEvent), then verify that the TextComponent
396  * has permission to access the Clipboard before pasting. If permission
397  * is denied, we should throw a SecurityException, but currently do not
398  * because when we detect the security violation, we are in the Toolkit
399  * thread, not the thread which dispatched the illegal event.
400  */
401 MsgRouting
WmPaste()402 AwtTextComponent::WmPaste()
403 {
404     if (m_synthetic) {
405         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
406         if (env->EnsureLocalCapacity(1) < 0) {
407             return mrConsume;
408         }
409         jobject target = GetTarget(env);
410         jboolean canAccessClipboard =
411             env->CallBooleanMethod (target, AwtTextComponent::canAccessClipboardMID);
412         env->DeleteLocalRef(target);
413         return (canAccessClipboard) ? mrDoDefault : mrConsume;
414     }
415     else {
416         return mrDoDefault;
417     }
418 }
419 
420 //im --- override to over the spot composition
SetCompositionWindow(RECT & rc)421 void AwtTextComponent::SetCompositionWindow(RECT& rc)
422 {
423     HWND hwnd = ImmGetHWnd();
424     HIMC hIMC = ImmGetContext(hwnd);
425     // rc is not used for text component.
426     COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} };
427     GetCaretPos(&(cf.ptCurrentPos));
428     // the proxy is the native focus owner and it contains the composition window
429     // let's convert the position to a coordinate space relative to proxy
430     ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1);
431     ImmSetCompositionWindow(hIMC, &cf);
432 
433     LOGFONT lf;
434     GetObject(m_hFont, sizeof(LOGFONT), &lf);
435     ImmSetCompositionFont(hIMC, &lf);
436     ImmReleaseContext(hwnd, hIMC);
437 }
438 //im --- end
439 
getJavaSelPos(LONG orgPos)440 LONG AwtTextComponent::getJavaSelPos(LONG orgPos)
441 {
442     long wlen;
443     long pos = 0;
444     long cur = 0;
445     LPTSTR wbuf;
446 
447     if ((wlen = GetTextLength()) == 0)
448         return 0;
449     wbuf = new TCHAR[wlen + 1];
450     GetText(wbuf, wlen + 1);
451     if (m_isLFonly == TRUE) {
452         wlen = RemoveCR(wbuf);
453     }
454 
455     while (cur < orgPos && pos++ < wlen) {
456         if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) {
457             cur++;
458         }
459         cur++;
460     }
461     delete[] wbuf;
462     return pos;
463 }
464 
getWin32SelPos(LONG orgPos)465 LONG AwtTextComponent::getWin32SelPos(LONG orgPos)
466 {
467     long wlen;
468     long pos = 0;
469     long cur = 0;
470     LPTSTR wbuf;
471 
472     if ((wlen = GetTextLength()) == 0)
473        return 0;
474     wbuf = new TCHAR[wlen + 1];
475     GetText(wbuf, wlen + 1);
476     if (m_isLFonly == TRUE) {
477         RemoveCR(wbuf);
478     }
479 
480     while (cur < orgPos && pos < wlen) {
481         if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) {
482             pos++;
483         }
484         pos++;
485         cur++;
486     }
487     delete[] wbuf;
488     return pos;
489 }
490 
CheckLineSeparator(WCHAR * pStr)491 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr)
492 {
493     if (pStr == NULL) {
494         return;
495     }
496 
497     if (GetTextLength() == 0) {
498         m_EOLchecked = FALSE;
499     }
500 
501     // check to see if there are any LF's
502     if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) {
503         return;
504     }
505 
506     for (int i=0; pStr[i] != 0; i++) {
507         if (pStr[i] == L'\n') {
508             if (i > 0 && pStr[i-1] == L'\r') {
509                 m_isLFonly = FALSE;
510             } else {
511                 m_isLFonly = TRUE;
512             }
513             m_EOLchecked = TRUE;
514             return;
515         }
516     }
517 }
518 
SetSelRange(LONG start,LONG end)519 void AwtTextComponent::SetSelRange(LONG start, LONG end)
520 {
521     SendMessage(EM_SETSEL,
522                 getWin32SelPos(start),
523                 getWin32SelPos(end));
524     // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing
525     // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus
526 }
527 
_GetText(void * param)528 jstring AwtTextComponent::_GetText(void *param)
529 {
530     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
531 
532     jobject self = (jobject)param;
533 
534     AwtTextComponent *c = NULL;
535     jstring result = NULL;
536 
537     PDATA pData;
538     JNI_CHECK_PEER_GOTO(self, ret);
539 
540     c = (AwtTextComponent *)pData;
541     if (::IsWindow(c->GetHWnd()))
542     {
543         int len = ::GetWindowTextLength(c->GetHWnd());
544         if (len == 0) {
545             /* Make java null string */
546             jchar *jc = new jchar[0];
547             result = env->NewString(jc, 0);
548             delete [] jc;
549         } else {
550             WCHAR* buf = new WCHAR[len + 1];
551             c->GetText(buf, len + 1);
552             c->RemoveCR(buf);
553             result = JNU_NewStringPlatform(env, buf);
554             delete [] buf;
555         }
556     }
557 ret:
558     env->DeleteGlobalRef(self);
559 
560     if (result != NULL)
561     {
562         jstring globalRef = (jstring)env->NewGlobalRef(result);
563         env->DeleteLocalRef(result);
564         return globalRef;
565     }
566     else
567     {
568         return NULL;
569     }
570 }
571 
_SetText(void * param)572 void AwtTextComponent::_SetText(void *param)
573 {
574     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
575 
576     SetTextStruct *sts = (SetTextStruct *)param;
577     jobject self = sts->textcomponent;
578     jstring text = sts->text;
579 
580     AwtTextComponent *c = NULL;
581 
582     PDATA pData;
583     JNI_CHECK_PEER_GOTO(self, ret);
584     c = (AwtTextComponent *)pData;
585     if (::IsWindow(c->GetHWnd()))
586     {
587         int length = env->GetStringLength(text);
588         WCHAR* buffer = new WCHAR[length + 1];
589         env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer));
590         buffer[length] = 0;
591         c->CheckLineSeparator(buffer);
592         c->RemoveCR(buffer);
593         c->SetText(buffer);
594         delete[] buffer;
595     }
596 ret:
597     env->DeleteGlobalRef(self);
598     env->DeleteGlobalRef(text);
599 
600     delete sts;
601 }
602 
_GetSelectionStart(void * param)603 jint AwtTextComponent::_GetSelectionStart(void *param)
604 {
605     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
606 
607     jobject self = (jobject)param;
608 
609     jint result = 0;
610     AwtTextComponent *c = NULL;
611 
612     PDATA pData;
613     JNI_CHECK_PEER_GOTO(self, ret);
614     c = (AwtTextComponent *)pData;
615     if (::IsWindow(c->GetHWnd()))
616     {
617         long start;
618         c->SendMessage(EM_GETSEL, (WPARAM)&start);
619         result = c->getJavaSelPos(start);
620     }
621 ret:
622     env->DeleteGlobalRef(self);
623 
624     return result;
625 }
626 
_GetSelectionEnd(void * param)627 jint AwtTextComponent::_GetSelectionEnd(void *param)
628 {
629     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
630 
631     jobject self = (jobject)param;
632 
633     jint result = 0;
634     AwtTextComponent *c = NULL;
635 
636     PDATA pData;
637     JNI_CHECK_PEER_GOTO(self, ret);
638     c = (AwtTextComponent *)pData;
639     if (::IsWindow(c->GetHWnd()))
640     {
641         long end;
642         c->SendMessage(EM_GETSEL, 0, (LPARAM)&end);
643         result = c->getJavaSelPos(end);
644     }
645 ret:
646     env->DeleteGlobalRef(self);
647 
648     return result;
649 }
650 
_Select(void * param)651 void AwtTextComponent::_Select(void *param)
652 {
653     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
654 
655     SelectStruct *ss = (SelectStruct *)param;
656     jobject self = ss->textcomponent;
657     jint start = ss->start;
658     jint end = ss->end;
659 
660     AwtTextComponent *c = NULL;
661 
662     PDATA pData;
663     JNI_CHECK_PEER_GOTO(self, ret);
664     c = (AwtTextComponent *)pData;
665     if (::IsWindow(c->GetHWnd()))
666     {
667         c->SetSelRange(start, end);
668         c->SendMessage(EM_SCROLLCARET);
669     }
670 ret:
671     env->DeleteGlobalRef(self);
672 
673     delete ss;
674 }
675 
_EnableEditing(void * param)676 void AwtTextComponent::_EnableEditing(void *param)
677 {
678     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
679 
680     EnableEditingStruct *ees = (EnableEditingStruct *)param;
681     jobject self = ees->textcomponent;
682     jboolean on = ees->on;
683 
684     AwtTextComponent *c = NULL;
685 
686     PDATA pData;
687     JNI_CHECK_PEER_GOTO(self, ret);
688     c = (AwtTextComponent *)pData;
689     if (::IsWindow(c->GetHWnd()))
690     {
691         c->SendMessage(EM_SETREADONLY, !on);
692     }
693 ret:
694     env->DeleteGlobalRef(self);
695 
696     delete ees;
697 }
698 
699 /*
700  * Disabled edit control has grayed foreground.
701  * Disabled RichEdit 1.0 control has original foreground.
702  * Thus we have to set grayed foreground manually.
703  */
Enable(BOOL bEnable)704 void AwtTextComponent::Enable(BOOL bEnable)
705 {
706     AwtComponent::Enable(bEnable);
707     SetColor(GetColor());
708 }
709 
710 
711 /*
712  * WM_CTLCOLOR is not sent by rich edit controls.
713  * Use EM_SETCHARFORMAT and EM_SETBKGNDCOLOR to set
714  * respectively foreground and background color.
715  */
SetColor(COLORREF c)716 void AwtTextComponent::SetColor(COLORREF c) {
717     AwtComponent::SetColor(c);
718 
719     CHARFORMAT cf;
720     memset(&cf, 0, sizeof(cf));
721     cf.cbSize = sizeof(cf);
722     cf.dwMask = CFM_COLOR;
723 
724     cf.crTextColor = ::IsWindowEnabled(GetHWnd()) ? GetColor() : ::GetSysColor(COLOR_3DSHADOW);
725 
726     /*
727      * The documentation for EM_GETCHARFORMAT is not exactly
728      * correct. It appears that wParam has the same meaning
729      * as for EM_SETCHARFORMAT. Our task is to secure that
730      * all the characters in the control have the required
731      * formatting. That's why we use SCF_ALL.
732      */
733     VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf));
734     VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf));
735 }
736 
737 /*
738  * In responce to EM_SETBKGNDCOLOR rich edit changes
739  * its bg color and repaints itself so we don't need
740  * to force repaint.
741  */
SetBackgroundColor(COLORREF c)742 void AwtTextComponent::SetBackgroundColor(COLORREF c) {
743     AwtComponent::SetBackgroundColor(c);
744     SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor());
745 }
746 
EditGetSel(CHARRANGE & cr)747 void AwtTextComponent::EditGetSel(CHARRANGE &cr) {
748     SendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&cr));
749 }
750 
751 
752 /************************************************************************
753  * WTextComponentPeer native methods
754  */
755 
756 extern "C" {
757 
758 /*
759  * Class:     sun_awt_windows_WTextComponentPeer
760  * Method:    getText
761  * Signature: ()Ljava/lang/String;
762  */
763 JNIEXPORT jstring JNICALL
Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv * env,jobject self)764 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self)
765 {
766     TRY;
767 
768     jobject selfGlobalRef = env->NewGlobalRef(self);
769 
770     jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall(
771         (void*(*)(void*))AwtTextComponent::_GetText,
772         (void *)selfGlobalRef);
773     // selfGlobalRef is deleted in _GetText
774     if (globalRef != NULL)
775     {
776         jstring localRef = (jstring)env->NewLocalRef(globalRef);
777         env->DeleteGlobalRef(globalRef);
778         return localRef;
779     }
780     else
781     {
782         return NULL;
783     }
784 
785     CATCH_BAD_ALLOC_RET(NULL);
786 }
787 
788 /*
789  * Class:     sun_awt_windows_WTextComponentPeer
790  * Method:    setText
791  * Signature: (Ljava/lang/String;)V
792  */
793 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv * env,jobject self,jstring text)794 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self,
795                                                 jstring text)
796 {
797     TRY;
798 
799     SetTextStruct *sts = new SetTextStruct;
800     sts->textcomponent = env->NewGlobalRef(self);
801     sts->text = (jstring)env->NewGlobalRef(text);
802 
803     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts);
804     // global refs and sts are deleted in _SetText
805 
806     CATCH_BAD_ALLOC;
807 }
808 
809 /*
810  * Class:     sun_awt_windows_WTextComponentPeer
811  * Method:    getSelectionStart
812  * Signature: ()I
813  */
814 JNIEXPORT jint JNICALL
Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv * env,jobject self)815 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env,
816                                                           jobject self)
817 {
818     TRY;
819 
820     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
821         (void *(*)(void *))AwtTextComponent::_GetSelectionStart,
822         env->NewGlobalRef(self))));
823     // global ref is deleted in _GetSelectionStart()
824 
825     CATCH_BAD_ALLOC_RET(0);
826 }
827 
828 /*
829  * Class:     sun_awt_windows_WTextComponentPeer
830  * Method:    getSelectionEnd
831  * Signature: ()I
832  */
833 JNIEXPORT jint JNICALL
Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv * env,jobject self)834 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env,
835                                                         jobject self)
836 {
837     TRY;
838 
839     return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
840         (void *(*)(void *))AwtTextComponent::_GetSelectionEnd,
841         env->NewGlobalRef(self))));
842     // global ref is deleted in _GetSelectionEnd()
843 
844     CATCH_BAD_ALLOC_RET(0);
845 }
846 
847 /*
848  * Class:     sun_awt_windows_WTextComponentPeer
849  * Method:    select
850  * Signature: (II)V
851  */
852 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv * env,jobject self,jint start,jint end)853 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self,
854                                                jint start, jint end)
855 {
856     TRY;
857 
858     SelectStruct *ss = new SelectStruct;
859     ss->textcomponent = env->NewGlobalRef(self);
860     ss->start = start;
861     ss->end = end;
862 
863     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss);
864     // global ref and ss are deleted in _Select
865 
866     CATCH_BAD_ALLOC;
867 }
868 
869 /*
870  * Class:     sun_awt_windows_WTextComponentPeer
871  * Method:    enableEditing
872  * Signature: (Z)V
873  */
874 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv * env,jobject self,jboolean on)875 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env,
876                                                       jobject self,
877                                                       jboolean on)
878 {
879     TRY;
880 
881     EnableEditingStruct *ees = new EnableEditingStruct;
882     ees->textcomponent = env->NewGlobalRef(self);
883     ees->on = on;
884 
885     AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees);
886     // global ref and ees are deleted in _EnableEditing()
887 
888     CATCH_BAD_ALLOC;
889 }
890 
891 /*
892  * Class:     sun_awt_windows_WTextComponentPeer
893  * Method:    initIDs
894  * Signature: ()V
895  */
896 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv * env,jclass cls)897 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls)
898 {
899     TRY;
900 
901     jclass textComponentClassID = env->FindClass("java/awt/TextComponent");
902     CHECK_NULL(textComponentClassID);
903 
904     AwtTextComponent::canAccessClipboardMID =
905         env->GetMethodID(textComponentClassID, "canAccessClipboard", "()Z");
906     env->DeleteLocalRef(textComponentClassID);
907 
908     DASSERT(AwtTextComponent::canAccessClipboardMID != NULL);
909 
910     CATCH_BAD_ALLOC;
911 }
912 
913 
914 AwtTextComponent::OleCallback AwtTextComponent::sm_oleCallback;
915 
916 /************************************************************************
917  * Inner class OleCallback definition.
918  */
919 
OleCallback()920 AwtTextComponent::OleCallback::OleCallback() {
921     m_refs = 0;
922     AddRef();
923 }
924 
925 STDMETHODIMP
QueryInterface(REFIID riid,LPVOID * ppvObj)926 AwtTextComponent::OleCallback::QueryInterface(REFIID riid, LPVOID * ppvObj) {
927      if (::IsEqualIID(riid, IID_IUnknown) ||::IsEqualIID(riid, IID_IRichEditOleCallback)  ) {
928          *ppvObj = static_cast<IRichEditOleCallback*>(this);
929          AddRef();
930          return S_OK;
931      }
932      *ppvObj = NULL;
933      return E_NOINTERFACE;
934 }
935 
936 
STDMETHODIMP_(ULONG)937 STDMETHODIMP_(ULONG)
938 AwtTextComponent::OleCallback::AddRef() {
939     return ++m_refs;
940 }
941 
STDMETHODIMP_(ULONG)942 STDMETHODIMP_(ULONG)
943 AwtTextComponent::OleCallback::Release() {
944     return (ULONG)--m_refs;
945 }
946 
947 STDMETHODIMP
GetNewStorage(LPSTORAGE FAR * ppstg)948 AwtTextComponent::OleCallback::GetNewStorage(LPSTORAGE FAR * ppstg) {
949     return E_NOTIMPL;
950 }
951 
952 STDMETHODIMP
GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe,LPOLEINPLACEUIWINDOW FAR * ppipuiDoc,LPOLEINPLACEFRAMEINFO pipfinfo)953 AwtTextComponent::OleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe,
954                                                  LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
955                                                  LPOLEINPLACEFRAMEINFO pipfinfo)
956 {
957     return E_NOTIMPL;
958 }
959 
960 STDMETHODIMP
ShowContainerUI(BOOL fShow)961 AwtTextComponent::OleCallback::ShowContainerUI(BOOL fShow) {
962     return E_NOTIMPL;
963 }
964 
965 STDMETHODIMP
QueryInsertObject(LPCLSID pclsid,LPSTORAGE pstg,LONG cp)966 AwtTextComponent::OleCallback::QueryInsertObject(LPCLSID pclsid,
967                                                  LPSTORAGE pstg,
968                                                  LONG cp) {
969     return S_OK;
970 }
971 
972 STDMETHODIMP
DeleteObject(LPOLEOBJECT poleobj)973 AwtTextComponent::OleCallback::DeleteObject(LPOLEOBJECT poleobj) {
974     return S_OK;
975 }
976 
977 STDMETHODIMP
QueryAcceptData(LPDATAOBJECT pdataobj,CLIPFORMAT * pcfFormat,DWORD reco,BOOL fReally,HGLOBAL hMetaPict)978 AwtTextComponent::OleCallback::QueryAcceptData(LPDATAOBJECT pdataobj,
979                                                CLIPFORMAT *pcfFormat,
980                                                DWORD reco,
981                                                BOOL fReally,
982                                                HGLOBAL hMetaPict) {
983     if (reco == RECO_PASTE) {
984         // If CF_TEXT format is available edit controls will select it,
985         // otherwise if it is CF_UNICODETEXT is available it will be
986         // selected, otherwise if CF_OEMTEXT is available it will be selected.
987         if (::IsClipboardFormatAvailable(CF_TEXT)) {
988             *pcfFormat = CF_TEXT;
989         } else if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
990             *pcfFormat = CF_UNICODETEXT;
991         } else if (::IsClipboardFormatAvailable(CF_OEMTEXT)) {
992             *pcfFormat = CF_OEMTEXT;
993         } else {
994             // Don't allow rich edit to paste clipboard data
995             // in other formats.
996             *pcfFormat = CF_TEXT;
997         }
998     }
999 
1000     return S_OK;
1001 }
1002 
1003 STDMETHODIMP
ContextSensitiveHelp(BOOL fEnterMode)1004 AwtTextComponent::OleCallback::ContextSensitiveHelp(BOOL fEnterMode) {
1005     return S_OK;
1006 }
1007 
1008 STDMETHODIMP
GetClipboardData(CHARRANGE * pchrg,DWORD reco,LPDATAOBJECT * ppdataobj)1009 AwtTextComponent::OleCallback::GetClipboardData(CHARRANGE *pchrg,
1010                                                 DWORD reco,
1011                                                 LPDATAOBJECT *ppdataobj) {
1012     return E_NOTIMPL;
1013 }
1014 
1015 STDMETHODIMP
GetDragDropEffect(BOOL fDrag,DWORD grfKeyState,LPDWORD pdwEffect)1016 AwtTextComponent::OleCallback::GetDragDropEffect(BOOL fDrag,
1017                                                  DWORD grfKeyState,
1018                                                  LPDWORD pdwEffect) {
1019 
1020     return E_NOTIMPL;
1021 }
1022 
1023 
1024 STDMETHODIMP
GetContextMenu(WORD seltype,LPOLEOBJECT lpoleobj,CHARRANGE FAR * lpchrg,HMENU FAR * lphmenu)1025 AwtTextComponent::OleCallback::GetContextMenu(WORD seltype,
1026                                               LPOLEOBJECT lpoleobj,
1027                                               CHARRANGE FAR * lpchrg,
1028                                               HMENU FAR * lphmenu) {
1029     return E_NOTIMPL;
1030 }
1031 
1032 
1033 /*
1034  * This routine is a window procedure for the subclass of the standard edit control
1035  * used to generate context menu. RichEdit controls don't have built-in context menu.
1036  * To implement this functionality we have to create an invisible edit control and
1037  * forward WM_CONTEXTMENU messages from a RichEdit control to this helper edit control.
1038  * While the edit control context menu is active we intercept the message generated in
1039  * response to particular item selection and forward it back to the RichEdit control.
1040  * (See AwtTextArea::WmContextMenu for more details).
1041  */
1042 
1043 WNDPROC AwtTextComponent::sm_pDefWindowProc = NULL;
1044 
1045 LRESULT
EditProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)1046 AwtTextComponent::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
1047 
1048     static BOOL bContextMenuActive = FALSE;
1049 
1050     LRESULT retValue = 0;
1051     MsgRouting mr = mrDoDefault;
1052 
1053     DASSERT(::IsWindow(::GetParent(hWnd)));
1054 
1055     switch (message) {
1056     case WM_UNDO:
1057     case WM_CUT:
1058     case WM_COPY:
1059     case WM_PASTE:
1060     case WM_CLEAR:
1061     case EM_SETSEL:
1062         if (bContextMenuActive) {
1063             ::SendMessage(::GetParent(hWnd), message, wParam, lParam);
1064             mr = mrConsume;
1065         }
1066         break;
1067     case WM_CONTEXTMENU:
1068         bContextMenuActive = TRUE;
1069         break;
1070     }
1071 
1072     if (mr == mrDoDefault) {
1073         DASSERT(sm_pDefWindowProc != NULL);
1074         retValue = ::CallWindowProc(sm_pDefWindowProc,
1075                                     hWnd, message, wParam, lParam);
1076     }
1077 
1078     if (message == WM_CONTEXTMENU) {
1079         bContextMenuActive = FALSE;
1080     }
1081 
1082     return retValue;
1083 }
1084 
1085 MsgRouting
WmContextMenu(HWND hCtrl,UINT xPos,UINT yPos)1086 AwtTextComponent::WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos) {
1087     /* Use the system provided edit control class to generate context menu. */
1088     if (m_hEditCtrl == NULL) {
1089         DWORD dwStyle = WS_CHILD;
1090         DWORD dwExStyle = 0;
1091         m_hEditCtrl = ::CreateWindowEx(dwExStyle,
1092                                         L"EDIT",
1093                                         L"TEXT",
1094                                         dwStyle,
1095                                         0, 0, 0, 0,
1096                                         GetHWnd(),
1097                                         reinterpret_cast<HMENU>(
1098                                          static_cast<INT_PTR>(
1099                                              CreateControlID())),
1100                                         AwtToolkit::GetInstance().GetModuleHandle(),
1101                                         NULL);
1102         DASSERT(m_hEditCtrl != NULL);
1103         if (sm_pDefWindowProc == NULL) {
1104             sm_pDefWindowProc = (WNDPROC)::GetWindowLongPtr(m_hEditCtrl,
1105                                                          GWLP_WNDPROC);
1106         }
1107         ::SetLastError(0);
1108         INT_PTR ret = ::SetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC,
1109                                    (INT_PTR)AwtTextArea::EditProc);
1110         DASSERT(ret != 0 || ::GetLastError() == 0);
1111     }
1112 
1113     /*
1114      * Tricks on the edit control to ensure that its context menu has
1115      * the correct set of enabled items according to the RichEdit state.
1116      */
1117     ::SetWindowText(m_hEditCtrl, TEXT("TEXT"));
1118 
1119     if (m_bCanUndo == TRUE && SendMessage(EM_CANUNDO)) {
1120         /* Enable 'Undo' item. */
1121         ::SendMessage(m_hEditCtrl, WM_CHAR, 'A', 0);
1122     }
1123 
1124     {
1125         /*
1126          * Initial selection for the edit control - (0,1).
1127          * This enables 'Cut', 'Copy' and 'Delete' and 'Select All'.
1128          */
1129         INT nStart = 0;
1130         INT nEnd = 1;
1131         if (SendMessage(EM_SELECTIONTYPE) == SEL_EMPTY) {
1132             /*
1133              * RichEdit selection is empty - clear selection of the edit control.
1134              * This disables 'Cut', 'Copy' and 'Delete'.
1135              */
1136             nStart = -1;
1137             nEnd = 0;
1138         } else {
1139 
1140             CHARRANGE cr;
1141             EditGetSel(cr);
1142             /* Check if all the text is selected. */
1143             if (cr.cpMin == 0) {
1144 
1145                 int len = ::GetWindowTextLength(GetHWnd());
1146                 if (cr.cpMin == 0 && cr.cpMax >= len) {
1147                     /*
1148                      * All the text is selected in RichEdit - select all the
1149                      * text in the edit control. This disables 'Select All'.
1150                      */
1151                     nStart = 0;
1152                     nEnd = -1;
1153                 }
1154             }
1155         }
1156         ::SendMessage(m_hEditCtrl, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
1157     }
1158 
1159     /* Disable 'Paste' item if the RichEdit control is read-only. */
1160     ::SendMessage(m_hEditCtrl, EM_SETREADONLY,
1161                   GetStyle() & ES_READONLY ? TRUE : FALSE, 0);
1162 
1163     POINT p;
1164     p.x = xPos;
1165     p.y = yPos;
1166 
1167     /*
1168      * If the context menu is requested with SHIFT+F10 or VK_APPS key,
1169      * we position its top left corner to the center of the RichEdit
1170      * client rect.
1171      */
1172     if (p.x == -1 && p.y == -1) {
1173         RECT r;
1174         VERIFY(::GetClientRect(GetHWnd(), &r));
1175         p.x = (r.left + r.right) / 2;
1176         p.y = (r.top + r.bottom) / 2;
1177         VERIFY(::ClientToScreen(GetHWnd(), &p));
1178     }
1179 
1180     // The context menu steals focus from the proxy.
1181     // So, set the focus-restore flag up.
1182     SetRestoreFocus(TRUE);
1183     ::SendMessage(m_hEditCtrl, WM_CONTEXTMENU, (WPARAM)m_hEditCtrl, MAKELPARAM(p.x, p.y));
1184     SetRestoreFocus(FALSE);
1185 
1186     return mrConsume;
1187 }
1188 
1189 //
1190 // Accessibility support
1191 //
1192 
1193 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead
1194 /*
1195  * Handle WmKeyDown to catch keystrokes which may move the caret,
1196  * and fire events as appropriate when that happens, if they are wanted
1197  *
1198  * Note: mouse clicks come through WmKeyDown as well (do they??!?!)
1199  *
1200 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt,
1201                                    UINT flags, BOOL system) {
1202 
1203     printf("AwtTextComponent::WmKeyDown called\r\n");
1204 
1205 
1206     // NOTE: WmKeyDown won't be processed 'till well after we return
1207     //       so we need to modify the values based on the keystroke
1208     //
1209     static long oldStart = -1;
1210     static long oldEnd = -1;
1211 
1212     // most keystrokes can move the caret
1213     // so we'll simply check to see if the caret has moved!
1214     if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) {
1215         long start;
1216         long end;
1217         SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
1218         if (start != oldStart || end != oldEnd) {
1219 
1220             printf("  -> calling TextComponent.selectionValuesChanged()\r\n");
1221             printf("  -> old = (%d, %d); new = (%d, %d)\r\n",
1222                     oldStart, oldEnd, start, end);
1223 
1224             DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details...
1225             oldStart = start;
1226             oldEnd = end;
1227         }
1228     }
1229 
1230     return AwtComponent::WmKeyDown(wkey, repCnt, flags, system);
1231 }
1232 */
1233 } /* extern "C" */
1234