Mercurial > hg > openjdk > jdk7 > jdk
view src/windows/native/sun/windows/awt_TextArea.cpp @ 4305:7181441faf72
7003962: AWT: securely load DLLs and launch executables using fully qualified path
Reviewed-by: art, bae, alanb
author | dcherepanov |
---|---|
date | Fri, 08 Apr 2011 16:44:14 +0400 |
parents | a06412e13bf7 |
children |
line wrap: on
line source
/* * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ #include "awt_Toolkit.h" #include "awt_TextArea.h" #include "awt_TextComponent.h" #include "awt_Canvas.h" #include "awt_Window.h" #include "awt_Frame.h" /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. */ /***********************************************************************/ // Struct for _ReplaceText() method struct ReplaceTextStruct { jobject textComponent; jstring text; int start, end; }; /************************************************************************ * AwtTextArea fields */ jfieldID AwtTextArea::scrollbarVisibilityID; WNDPROC AwtTextArea::sm_pDefWindowProc = NULL; /************************************************************************ * AwtTextArea methods */ AwtTextArea::AwtTextArea() { m_bIgnoreEnChange = FALSE; m_bCanUndo = FALSE; m_hEditCtrl = NULL; m_lHDeltaAccum = 0; m_lVDeltaAccum = 0; } AwtTextArea::~AwtTextArea() { } void AwtTextArea::Dispose() { if (m_hEditCtrl != NULL) { VERIFY(::DestroyWindow(m_hEditCtrl)); m_hEditCtrl = NULL; } AwtTextComponent::Dispose(); } LPCTSTR AwtTextArea::GetClassName() { static BOOL richedLibraryLoaded = FALSE; if (!richedLibraryLoaded) { JDK_LoadSystemLibrary("RICHED20.DLL"); richedLibraryLoaded = TRUE; } return RICHEDIT_CLASS; } /* Create a new AwtTextArea object and window. */ AwtTextArea* AwtTextArea::Create(jobject peer, jobject parent) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); jobject target = NULL; AwtTextArea* c = NULL; try { if (env->EnsureLocalCapacity(1) < 0) { return NULL; } PDATA pData; AwtCanvas* awtParent; JNI_CHECK_PEER_GOTO(parent, done); awtParent = (AwtCanvas*)pData; JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done); target = env->GetObjectField(peer, AwtObject::targetID); JNI_CHECK_NULL_GOTO(target, "null target", done); c = new AwtTextArea(); { /* Adjust style for scrollbar visibility and word wrap */ DWORD scroll_style; jint scrollbarVisibility = env->GetIntField(target, AwtTextArea::scrollbarVisibilityID); switch (scrollbarVisibility) { case java_awt_TextArea_SCROLLBARS_NONE: scroll_style = ES_AUTOVSCROLL; break; case java_awt_TextArea_SCROLLBARS_VERTICAL_ONLY: scroll_style = WS_VSCROLL | ES_AUTOVSCROLL; break; case java_awt_TextArea_SCROLLBARS_HORIZONTAL_ONLY: scroll_style = WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL; break; case java_awt_TextArea_SCROLLBARS_BOTH: scroll_style = WS_VSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL; break; } /* * Specify ES_DISABLENOSCROLL - RichEdit control style to disable * scrollbars instead of hiding them when not needed. */ DWORD style = WS_CHILD | WS_CLIPSIBLINGS | ES_LEFT | ES_MULTILINE | ES_WANTRETURN | scroll_style | ES_DISABLENOSCROLL; DWORD exStyle = WS_EX_CLIENTEDGE; if (GetRTL()) { exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR; if (GetRTLReadingOrder()) exStyle |= WS_EX_RTLREADING; } jint x = env->GetIntField(target, AwtComponent::xID); jint y = env->GetIntField(target, AwtComponent::yID); jint width = env->GetIntField(target, AwtComponent::widthID); jint height = env->GetIntField(target, AwtComponent::heightID); c->CreateHWnd(env, L"", style, exStyle, x, y, width, height, awtParent->GetHWnd(), reinterpret_cast<HMENU>(static_cast<INT_PTR>( awtParent->CreateControlID())), ::GetSysColor(COLOR_WINDOWTEXT), ::GetSysColor(COLOR_WINDOW), peer); // Fix for 4753116. // If it is not win95 (we are using Richedit 2.0) // we set plain text mode, in which the control is // similar to a standard edit control: // - The text in a plain text control can have only // one format. // - The user cannot paste rich text formats, such as RTF // or embedded objects into a plain text control. // - Rich text mode controls always have a default // end-of-document marker or carriage return, // to format paragraphs. // kdm@sparc.spb.su c->SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT, 0); c->m_backgroundColorSet = TRUE; /* suppress inheriting parent's color. */ c->UpdateBackground(env, target); c->SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELPARAM(1, 1)); /* * Fix for BugTraq Id 4260109. * Set the text limit to the maximum. * Use EM_EXLIMITTEXT for RichEdit controls. * For some reason RichEdit 1.0 becomes read-only if the * specified limit is greater than 0x7FFFFFFD. */ c->SendMessage(EM_EXLIMITTEXT, 0, 0x7FFFFFFD); /* Unregister RichEdit built-in drop target. */ VERIFY(::RevokeDragDrop(c->GetHWnd()) != DRAGDROP_E_INVALIDHWND); /* To enforce CF_TEXT format for paste operations. */ VERIFY(c->SendMessage(EM_SETOLECALLBACK, 0, (LPARAM)&GetOleCallback())); c->SendMessage(EM_SETEVENTMASK, 0, ENM_CHANGE); } } catch (...) { env->DeleteLocalRef(target); throw; } done: env->DeleteLocalRef(target); return c; } void AwtTextArea::EditSetSel(CHARRANGE &cr) { // Fix for 5003402: added restoring/hiding selection to enable automatic scrolling SendMessage(EM_HIDESELECTION, FALSE, TRUE); SendMessage(EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&cr)); SendMessage(EM_HIDESELECTION, TRUE, TRUE); // 6417581: force expected drawing if (IS_WINVISTA && cr.cpMin == cr.cpMax) { ::InvalidateRect(GetHWnd(), NULL, TRUE); } } void AwtTextArea::EditGetSel(CHARRANGE &cr) { SendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&cr)); } LONG AwtTextArea::EditGetCharFromPos(POINT& pt) { return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0, reinterpret_cast<LPARAM>(&pt))); } /* Count how many '\n's are there in jStr */ size_t AwtTextArea::CountNewLines(JNIEnv *env, jstring jStr, size_t maxlen) { size_t nNewlines = 0; if (jStr == NULL) { return nNewlines; } /* * Fix for BugTraq Id 4260109. * Don't use TO_WSTRING since it allocates memory on the stack * causing stack overflow when the text is very long. */ size_t length = env->GetStringLength(jStr) + 1; WCHAR *string = new WCHAR[length]; env->GetStringRegion(jStr, 0, static_cast<jsize>(length - 1), reinterpret_cast<jchar*>(string)); string[length-1] = '\0'; for (size_t i = 0; i < maxlen && i < length - 1; i++) { if (string[i] == L'\n') { nNewlines++; } } delete[] string; return nNewlines; } BOOL AwtTextArea::InheritsNativeMouseWheelBehavior() {return true;} MsgRouting AwtTextArea::PreProcessMsg(MSG& msg) { MsgRouting mr = mrPassAlong; static BOOL bPassAlongWmLButtonUp = TRUE; if (msg.message == WM_LBUTTONDBLCLK) { bPassAlongWmLButtonUp = FALSE; } /* * For some reason RichEdit 1.0 filters out WM_LBUTTONUP after * WM_LBUTTONDBLCLK. To work around this "feature" we send WM_LBUTTONUP * directly to the window procedure and consume instead of passing it * to the next hook. */ if (msg.message == WM_LBUTTONUP && bPassAlongWmLButtonUp == FALSE) { SendMessage(WM_LBUTTONUP, msg.wParam, msg.lParam); bPassAlongWmLButtonUp = TRUE; mr = mrConsume; } if (mr == mrPassAlong) { mr = AwtComponent::PreProcessMsg(msg); } return mr; } LRESULT AwtTextArea::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { LRESULT retValue = 0; MsgRouting mr = mrDoDefault; switch (message) { case WM_PRINTCLIENT: { FORMATRANGE fr; HDC hPrinterDC = (HDC)wParam; int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES); int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES); int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX); int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY); // Ensure the printer DC is in MM_TEXT mode. ::SetMapMode ( hPrinterDC, MM_TEXT ); // Rendering to the same DC we are measuring. ::ZeroMemory(&fr, sizeof(fr)); fr.hdc = fr.hdcTarget = hPrinterDC; // Set up the page. fr.rcPage.left = fr.rcPage.top = 0; fr.rcPage.right = (nHorizRes/nLogPixelsX) * 1440; // in twips fr.rcPage.bottom = (nVertRes/nLogPixelsY) * 1440; fr.rc.left = fr.rcPage.left; fr.rc.top = fr.rcPage.top; fr.rc.right = fr.rcPage.right; fr.rc.bottom = fr.rcPage.bottom; // start printing from the first visible line LRESULT nLine = SendMessage(EM_GETFIRSTVISIBLELINE, 0, 0); LONG startCh = static_cast<LONG>(SendMessage(EM_LINEINDEX, (WPARAM)nLine, 0)); fr.chrg.cpMin = startCh; fr.chrg.cpMax = -1; SendMessage(EM_FORMATRANGE, TRUE, (LPARAM)&fr); } break; case EM_SETCHARFORMAT: case WM_SETFONT: SetIgnoreEnChange(TRUE); break; } retValue = AwtComponent::WindowProc(message, wParam, lParam); switch (message) { case EM_SETCHARFORMAT: case WM_SETFONT: SetIgnoreEnChange(FALSE); break; } return retValue; } /* * This routine is a window procedure for the subclass of the standard edit control * used to generate context menu. RichEdit controls don't have built-in context menu. * To implement this functionality we have to create an invisible edit control and * forward WM_CONTEXTMENU messages from a RichEdit control to this helper edit control. * While the edit control context menu is active we intercept the message generated in * response to particular item selection and forward it back to the RichEdit control. * (See AwtTextArea::WmContextMenu for more details). */ LRESULT AwtTextArea::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bContextMenuActive = FALSE; LRESULT retValue = 0; MsgRouting mr = mrDoDefault; DASSERT(::IsWindow(::GetParent(hWnd))); switch (message) { case WM_UNDO: case WM_CUT: case WM_COPY: case WM_PASTE: case WM_CLEAR: case EM_SETSEL: if (bContextMenuActive) { ::SendMessage(::GetParent(hWnd), message, wParam, lParam); mr = mrConsume; } break; case WM_CONTEXTMENU: bContextMenuActive = TRUE; break; } if (mr == mrDoDefault) { DASSERT(sm_pDefWindowProc != NULL); retValue = ::CallWindowProc(sm_pDefWindowProc, hWnd, message, wParam, lParam); } if (message == WM_CONTEXTMENU) { bContextMenuActive = FALSE; } return retValue; } MsgRouting AwtTextArea::WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos) { /* Use the system provided edit control class to generate context menu. */ if (m_hEditCtrl == NULL) { DWORD dwStyle = WS_CHILD; DWORD dwExStyle = 0; m_hEditCtrl = ::CreateWindowEx(dwExStyle, L"EDIT", L"TEXT", dwStyle, 0, 0, 0, 0, GetHWnd(), reinterpret_cast<HMENU>( static_cast<INT_PTR>( CreateControlID())), AwtToolkit::GetInstance().GetModuleHandle(), NULL); DASSERT(m_hEditCtrl != NULL); if (sm_pDefWindowProc == NULL) { sm_pDefWindowProc = (WNDPROC)::GetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC); } ::SetLastError(0); INT_PTR ret = ::SetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC, (INT_PTR)AwtTextArea::EditProc); DASSERT(ret != 0 || ::GetLastError() == 0); } /* * Tricks on the edit control to ensure that its context menu has * the correct set of enabled items according to the RichEdit state. */ ::SetWindowText(m_hEditCtrl, TEXT("TEXT")); if (m_bCanUndo == TRUE && SendMessage(EM_CANUNDO)) { /* Enable 'Undo' item. */ ::SendMessage(m_hEditCtrl, WM_CHAR, 'A', 0); } { /* * Initial selection for the edit control - (0,1). * This enables 'Cut', 'Copy' and 'Delete' and 'Select All'. */ INT nStart = 0; INT nEnd = 1; if (SendMessage(EM_SELECTIONTYPE) == SEL_EMPTY) { /* * RichEdit selection is empty - clear selection of the edit control. * This disables 'Cut', 'Copy' and 'Delete'. */ nStart = -1; nEnd = 0; } else { CHARRANGE cr; EditGetSel(cr); /* Check if all the text is selected. */ if (cr.cpMin == 0) { int len = ::GetWindowTextLength(GetHWnd()); if (cr.cpMin == 0 && cr.cpMax >= len) { /* * All the text is selected in RichEdit - select all the * text in the edit control. This disables 'Select All'. */ nStart = 0; nEnd = -1; } } } ::SendMessage(m_hEditCtrl, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd); } /* Disable 'Paste' item if the RichEdit control is read-only. */ ::SendMessage(m_hEditCtrl, EM_SETREADONLY, GetStyle() & ES_READONLY ? TRUE : FALSE, 0); POINT p; p.x = xPos; p.y = yPos; /* * If the context menu is requested with SHIFT+F10 or VK_APPS key, * we position its top left corner to the center of the RichEdit * client rect. */ if (p.x == -1 && p.y == -1) { RECT r; VERIFY(::GetClientRect(GetHWnd(), &r)); p.x = (r.left + r.right) / 2; p.y = (r.top + r.bottom) / 2; VERIFY(::ClientToScreen(GetHWnd(), &p)); } // The context menu steals focus from the proxy. // So, set the focus-restore flag up. SetRestoreFocus(TRUE); ::SendMessage(m_hEditCtrl, WM_CONTEXTMENU, (WPARAM)m_hEditCtrl, MAKELPARAM(p.x, p.y)); SetRestoreFocus(FALSE); return mrConsume; } MsgRouting AwtTextArea::WmNcHitTest(UINT x, UINT y, LRESULT& retVal) { if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd())))) { retVal = HTCLIENT; return mrConsume; } return AwtTextComponent::WmNcHitTest(x, y, retVal); } MsgRouting AwtTextArea::WmNotify(UINT notifyCode) { if (notifyCode == EN_CHANGE) { /* * Ignore notifications if the text hasn't been changed. * EN_CHANGE sent on character formatting changes as well. */ if (m_bIgnoreEnChange == FALSE) { m_bCanUndo = TRUE; DoCallback("valueChanged", "()V"); } else { m_bCanUndo = FALSE; } } return mrDoDefault; } MsgRouting AwtTextArea::HandleEvent(MSG *msg, BOOL synthetic) { MsgRouting returnVal; /* * RichEdit 1.0 control starts internal message loop if the * left mouse button is pressed while the cursor is not over * the current selection or the current selection is empty. * Because of this we don't receive WM_MOUSEMOVE messages * while the left mouse button is pressed. To work around * this behavior we process the relevant mouse messages * by ourselves. * By consuming WM_MOUSEMOVE messages we also don't give * the RichEdit control a chance to recognize a drag gesture * and initiate its own drag-n-drop operation. * * The workaround also allows us to implement synthetic focus mechanism. * */ if (IsFocusingMouseMessage(msg)) { CHARRANGE cr; LONG lCurPos = EditGetCharFromPos(msg->pt); EditGetSel(cr); /* * NOTE: Plain EDIT control always clears selection on mouse * button press. We are clearing the current selection only if * the mouse pointer is not over the selected region. * In this case we sacrifice backward compatibility * to allow dnd of the current selection. */ if (lCurPos < cr.cpMin || cr.cpMax <= lCurPos) { if (msg->message == WM_LBUTTONDBLCLK) { SetStartSelectionPos(static_cast<LONG>(SendMessage( EM_FINDWORDBREAK, WB_MOVEWORDLEFT, lCurPos))); SetEndSelectionPos(static_cast<LONG>(SendMessage( EM_FINDWORDBREAK, WB_MOVEWORDRIGHT, lCurPos))); } else { SetStartSelectionPos(lCurPos); SetEndSelectionPos(lCurPos); } cr.cpMin = GetStartSelectionPos(); cr.cpMax = GetEndSelectionPos(); EditSetSel(cr); } delete msg; return mrConsume; } else if (msg->message == WM_LBUTTONUP) { /* * If the left mouse button is pressed on the selected region * we don't clear the current selection. We clear it on button * release instead. This is to allow dnd of the current selection. */ if (GetStartSelectionPos() == -1 && GetEndSelectionPos() == -1) { CHARRANGE cr; LONG lCurPos = EditGetCharFromPos(msg->pt); cr.cpMin = lCurPos; cr.cpMax = lCurPos; EditSetSel(cr); } /* * Cleanup the state variables when left mouse button is released. * These state variables are designed to reflect the selection state * while the left mouse button is pressed and be set to -1 otherwise. */ SetStartSelectionPos(-1); SetEndSelectionPos(-1); SetLastSelectionPos(-1); delete msg; return mrConsume; } else if (msg->message == WM_MOUSEMOVE && (msg->wParam & MK_LBUTTON)) { /* * We consume WM_MOUSEMOVE while the left mouse button is pressed, * so we have to simulate autoscrolling when mouse is moved outside * of the client area. */ POINT p; RECT r; BOOL bScrollLeft = FALSE; BOOL bScrollRight = FALSE; BOOL bScrollUp = FALSE; BOOL bScrollDown = FALSE; p.x = msg->pt.x; p.y = msg->pt.y; VERIFY(::GetClientRect(GetHWnd(), &r)); if (p.x < 0) { bScrollLeft = TRUE; p.x = 0; } else if (p.x > r.right) { bScrollRight = TRUE; p.x = r.right - 1; } if (p.y < 0) { bScrollUp = TRUE; p.y = 0; } else if (p.y > r.bottom) { bScrollDown = TRUE; p.y = r.bottom - 1; } LONG lCurPos = EditGetCharFromPos(p); if (GetStartSelectionPos() != -1 && GetEndSelectionPos() != -1 && lCurPos != GetLastSelectionPos()) { CHARRANGE cr; SetLastSelectionPos(lCurPos); cr.cpMin = GetStartSelectionPos(); cr.cpMax = GetLastSelectionPos(); EditSetSel(cr); } if (bScrollLeft == TRUE || bScrollRight == TRUE) { SCROLLINFO si; memset(&si, 0, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; VERIFY(::GetScrollInfo(GetHWnd(), SB_HORZ, &si)); if (bScrollLeft == TRUE) { si.nPos = si.nPos - si.nPage / 2; si.nPos = max(si.nMin, si.nPos); } else if (bScrollRight == TRUE) { si.nPos = si.nPos + si.nPage / 2; si.nPos = min(si.nPos, si.nMax); } /* * Okay to use 16-bit position since RichEdit control adjusts * its scrollbars so that their range is always 16-bit. */ DASSERT(abs(si.nPos) < 0x8000); SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, LOWORD(si.nPos))); } if (bScrollUp == TRUE) { SendMessage(EM_LINESCROLL, 0, -1); } else if (bScrollDown == TRUE) { SendMessage(EM_LINESCROLL, 0, 1); } delete msg; return mrConsume; } else if (msg->message == WM_RBUTTONUP || (msg->message == WM_SYSKEYDOWN && msg->wParam == VK_F10 && HIBYTE(::GetKeyState(VK_SHIFT)))) { POINT p; if (msg->message == WM_RBUTTONUP) { VERIFY(::GetCursorPos(&p)); } else { p.x = -1; p.y = -1; } if (!::PostMessage(GetHWnd(), WM_CONTEXTMENU, (WPARAM)GetHWnd(), MAKELPARAM(p.x, p.y))) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); JNU_ThrowInternalError(env, "Message not posted, native event queue may be full."); env->ExceptionDescribe(); env->ExceptionClear(); } delete msg; return mrConsume; } else if (msg->message == WM_MOUSEWHEEL) { // 4417236: If there is an old version of RichEd32.dll which // does not provide the mouse wheel scrolling we have to // interpret WM_MOUSEWHEEL as a sequence of scroll messages. // kdm@sparc.spb.su UINT platfScrollLines = 3; // Retrieve a number of scroll lines. ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &platfScrollLines, 0); if (platfScrollLines > 0) { HWND hWnd = GetHWnd(); LONG styles = ::GetWindowLong(hWnd, GWL_STYLE); RECT rect; // rect.left and rect.top are zero. // rect.right and rect.bottom contain the width and height VERIFY(::GetClientRect(hWnd, &rect)); // calculate a number of visible lines TEXTMETRIC tm; HDC hDC = ::GetDC(hWnd); DASSERT(hDC != NULL); VERIFY(::GetTextMetrics(hDC, &tm)); VERIFY(::ReleaseDC(hWnd, hDC)); LONG visibleLines = rect.bottom / tm.tmHeight + 1; LONG lineCount = static_cast<LONG>(::SendMessage(hWnd, EM_GETLINECOUNT, 0, 0)); BOOL sb_vert_disabled = (styles & WS_VSCROLL) == 0 || (lineCount <= visibleLines); LONG *delta_accum = &m_lVDeltaAccum; UINT wm_msg = WM_VSCROLL; int sb_type = SB_VERT; if (sb_vert_disabled && (styles & WS_HSCROLL)) { delta_accum = &m_lHDeltaAccum; wm_msg = WM_HSCROLL; sb_type = SB_HORZ; } int delta = (short) HIWORD(msg->wParam); *delta_accum += delta; if (abs(*delta_accum) >= WHEEL_DELTA) { if (platfScrollLines == WHEEL_PAGESCROLL) { // Synthesize a page down or a page up message. ::SendMessage(hWnd, wm_msg, (delta > 0) ? SB_PAGEUP : SB_PAGEDOWN, 0); *delta_accum = 0; } else { // We provide a friendly behavior of text scrolling. // During of scrolling the text can be out of the client // area's boundary. Here we try to prevent this behavior. SCROLLINFO si; ::ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; int actualScrollLines = abs((int)(platfScrollLines * (*delta_accum / WHEEL_DELTA))); for (int i = 0; i < actualScrollLines; i++) { if (::GetScrollInfo(hWnd, sb_type, &si)) { if ((wm_msg == WM_VSCROLL) && ((*delta_accum < 0 && si.nPos >= (si.nMax - (int) si.nPage)) || (*delta_accum > 0 && si.nPos <= si.nMin))) { break; } } // Here we don't send EM_LINESCROLL or EM_SCROLL // messages to rich edit because it doesn't // provide horizontal scrolling. // So it's only possible to scroll by 1 line // at a time to prevent scrolling when the // scrollbar thumb reaches its boundary position. ::SendMessage(hWnd, wm_msg, (*delta_accum>0) ? SB_LINEUP : SB_LINEDOWN, 0); } *delta_accum %= WHEEL_DELTA; } } else { *delta_accum = 0; } } delete msg; return mrConsume; // 4417236: end of fix } /* * Store the 'synthetic' parameter so that the WM_PASTE security check * happens only for synthetic events. */ m_synthetic = synthetic; returnVal = AwtComponent::HandleEvent(msg, synthetic); m_synthetic = FALSE; return returnVal; } /* * WM_CTLCOLOR is not sent by rich edit controls. * Use EM_SETCHARFORMAT and EM_SETBKGNDCOLOR to set * respectively foreground and background color. */ void AwtTextArea::SetColor(COLORREF c) { AwtComponent::SetColor(c); CHARFORMAT cf; memset(&cf, 0, sizeof(cf)); cf.cbSize = sizeof(cf); cf.dwMask = CFM_COLOR; cf.crTextColor = ::IsWindowEnabled(GetHWnd()) ? GetColor() : ::GetSysColor(COLOR_3DSHADOW); /* * The documentation for EM_GETCHARFORMAT is not exactly * correct. It appears that wParam has the same meaning * as for EM_SETCHARFORMAT. Our task is to secure that * all the characters in the control have the required * formatting. That's why we use SCF_ALL. */ VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf)); VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf)); } /* * In responce to EM_SETBKGNDCOLOR rich edit changes * its bg color and repaints itself so we don't need * to force repaint. */ void AwtTextArea::SetBackgroundColor(COLORREF c) { AwtComponent::SetBackgroundColor(c); SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor()); } /* * Disabled edit control has grayed foreground. * Disabled RichEdit 1.0 control has original foreground. * Thus we have to set grayed foreground manually. */ void AwtTextArea::Enable(BOOL bEnable) { AwtComponent::Enable(bEnable); SetColor(GetColor()); } /* Fix for 4776535, 4648702 * If width is 0 or 1 Windows hides the horizontal scroll bar even * if the WS_HSCROLL style is set. It is a bug in Windows. * As a workaround we should set an initial width to 2. * kdm@sparc.spb.su */ void AwtTextArea::Reshape(int x, int y, int w, int h) { if (w < 2) { w = 2; } AwtTextComponent::Reshape(x, y, w, h); } LONG AwtTextArea::getJavaSelPos(LONG orgPos) { long wlen; long pos = orgPos; long cur = 0; long retval = 0; LPTSTR wbuf; if ((wlen = GetTextLength()) == 0) return 0; wbuf = new TCHAR[wlen + 1]; GetText(wbuf, wlen + 1); if (m_isLFonly == TRUE) { wlen = RemoveCR(wbuf); } while (cur < pos && cur < wlen) { if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) { pos++; } cur++; retval++; } delete[] wbuf; return retval; } LONG AwtTextArea::getWin32SelPos(LONG orgPos) { if (GetTextLength() == 0) return 0; return orgPos; } void AwtTextArea::SetSelRange(LONG start, LONG end) { CHARRANGE cr; cr.cpMin = getWin32SelPos(start); cr.cpMax = getWin32SelPos(end); EditSetSel(cr); } void AwtTextArea::_ReplaceText(void *param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); ReplaceTextStruct *rts = (ReplaceTextStruct *)param; jobject textComponent = rts->textComponent; jstring text = rts->text; jint start = rts->start; jint end = rts->end; AwtTextComponent *c = NULL; PDATA pData; JNI_CHECK_PEER_GOTO(textComponent, done); JNI_CHECK_NULL_GOTO(text, "null string", done); c = (AwtTextComponent *)pData; if (::IsWindow(c->GetHWnd())) { jsize length = env->GetStringLength(text) + 1; // Bugid 4141477 - Can't use TO_WSTRING here because it uses alloca // WCHAR* buffer = TO_WSTRING(text); TCHAR *buffer = new TCHAR[length]; env->GetStringRegion(text, 0, length-1, reinterpret_cast<jchar*>(buffer)); buffer[length-1] = '\0'; c->CheckLineSeparator(buffer); c->RemoveCR(buffer); // Fix for 5003402: added restoring/hiding selection to enable automatic scrolling c->SendMessage(EM_HIDESELECTION, FALSE, TRUE); c->SendMessage(EM_SETSEL, start, end); c->SendMessage(EM_REPLACESEL, FALSE, (LPARAM)buffer); c->SendMessage(EM_HIDESELECTION, TRUE, TRUE); delete[] buffer; } done: env->DeleteGlobalRef(textComponent); env->DeleteGlobalRef(text); delete rts; } /************************************************************************ * TextArea native methods */ extern "C" { /* * Class: java_awt_TextArea * Method: initIDs * Signature: ()V */ JNIEXPORT void JNICALL Java_java_awt_TextArea_initIDs(JNIEnv *env, jclass cls) { TRY; AwtTextArea::scrollbarVisibilityID = env->GetFieldID(cls, "scrollbarVisibility", "I"); DASSERT(AwtTextArea::scrollbarVisibilityID != NULL); CATCH_BAD_ALLOC; } } /* extern "C" */ /************************************************************************ * WTextAreaPeer native methods */ extern "C" { /* * Class: sun_awt_windows_WTextAreaPeer * Method: create * Signature: (Lsun/awt/windows/WComponentPeer;)V */ JNIEXPORT void JNICALL Java_sun_awt_windows_WTextAreaPeer_create(JNIEnv *env, jobject self, jobject parent) { TRY; PDATA pData; JNI_CHECK_PEER_RETURN(parent); AwtToolkit::CreateComponent(self, parent, (AwtToolkit::ComponentFactory) AwtTextArea::Create); JNI_CHECK_PEER_CREATION_RETURN(self); CATCH_BAD_ALLOC; } /* * Class: sun_awt_windows_WTextAreaPeer * Method: replaceText * Signature: (Ljava/lang/String;II)V */ JNIEXPORT void JNICALL Java_sun_awt_windows_WTextAreaPeer_replaceText(JNIEnv *env, jobject self, jstring text, jint start, jint end) { TRY; jobject selfGlobalRef = env->NewGlobalRef(self); jstring textGlobalRef = (jstring)env->NewGlobalRef(text); ReplaceTextStruct *rts = new ReplaceTextStruct; rts->textComponent = selfGlobalRef; rts->text = textGlobalRef; rts->start = start; rts->end = end; AwtToolkit::GetInstance().SyncCall(AwtTextArea::_ReplaceText, rts); // global refs and rts are deleted in _ReplaceText() CATCH_BAD_ALLOC; } /* * Class: sun_awt_windows_WTextAreaPeer * Method: insertText * Signature: (Ljava/lang/String;I)V */ JNIEXPORT void JNICALL Java_sun_awt_windows_WTextAreaPeer_insertText(JNIEnv *env, jobject self, jstring text, jint pos) { Java_sun_awt_windows_WTextAreaPeer_replaceText(env, self, text, pos, pos); } } /* extern "C" */ AwtTextArea::OleCallback AwtTextArea::sm_oleCallback; /************************************************************************ * Inner class OleCallback definition. */ AwtTextArea::OleCallback::OleCallback() { m_refs = 0; AddRef(); } STDMETHODIMP AwtTextArea::OleCallback::QueryInterface(REFIID riid, LPVOID * ppvObj) { TRY; if (::IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (void __RPC_FAR *__RPC_FAR)(IUnknown*)this; AddRef(); return S_OK; } else if (::IsEqualIID(riid, IID_IRichEditOleCallback)) { *ppvObj = (void __RPC_FAR *__RPC_FAR)(IRichEditOleCallback*)this; AddRef(); return S_OK; } else { *ppvObj = NULL; return E_NOINTERFACE; } CATCH_BAD_ALLOC_RET(E_OUTOFMEMORY); } STDMETHODIMP_(ULONG) AwtTextArea::OleCallback::AddRef() { return ++m_refs; } STDMETHODIMP_(ULONG) AwtTextArea::OleCallback::Release() { int refs; if ((refs = --m_refs) == 0) delete this; return (ULONG)refs; } STDMETHODIMP AwtTextArea::OleCallback::GetNewStorage(LPSTORAGE FAR * ppstg) { return E_NOTIMPL; } STDMETHODIMP AwtTextArea::OleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe, LPOLEINPLACEUIWINDOW FAR* ppipuiDoc, LPOLEINPLACEFRAMEINFO pipfinfo) { return E_NOTIMPL; } STDMETHODIMP AwtTextArea::OleCallback::ShowContainerUI(BOOL fShow) { return E_NOTIMPL; } STDMETHODIMP AwtTextArea::OleCallback::QueryInsertObject(LPCLSID pclsid, LPSTORAGE pstg, LONG cp) { return NOERROR; } STDMETHODIMP AwtTextArea::OleCallback::DeleteObject(LPOLEOBJECT poleobj) { return NOERROR; } STDMETHODIMP AwtTextArea::OleCallback::QueryAcceptData(LPDATAOBJECT pdataobj, CLIPFORMAT *pcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict) { if (reco == RECO_PASTE) { // If CF_TEXT format is available edit controls will select it, // otherwise if it is CF_UNICODETEXT is available it will be // selected, otherwise if CF_OEMTEXT is available it will be selected. if (::IsClipboardFormatAvailable(CF_TEXT)) { *pcfFormat = CF_TEXT; } else if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) { *pcfFormat = CF_UNICODETEXT; } else if (::IsClipboardFormatAvailable(CF_OEMTEXT)) { *pcfFormat = CF_OEMTEXT; } else { // Don't allow rich edit to paste clipboard data // in other formats. *pcfFormat = CF_TEXT; } } return NOERROR; } STDMETHODIMP AwtTextArea::OleCallback::ContextSensitiveHelp(BOOL fEnterMode) { return NOERROR; } STDMETHODIMP AwtTextArea::OleCallback::GetClipboardData(CHARRANGE *pchrg, DWORD reco, LPDATAOBJECT *ppdataobj) { return E_NOTIMPL; } STDMETHODIMP AwtTextArea::OleCallback::GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect) { return E_NOTIMPL; } STDMETHODIMP AwtTextArea::OleCallback::GetContextMenu(WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE FAR * lpchrg, HMENU FAR * lphmenu) { return E_NOTIMPL; }