From 2b92bf78d1939cfb785b6911dbb2b8ab1843a527 Mon Sep 17 00:00:00 2001 From: Matt Finnicum Date: Fri, 4 Aug 2006 15:47:44 -0400 Subject: [PATCH] riched20: Implement EM_SETPASSWORDCHAR and EM_GETPASSWORDCHAR. --- dlls/riched20/editor.c | 28 ++++++++++++++++++---- dlls/riched20/editor.h | 2 ++ dlls/riched20/editstr.h | 1 + dlls/riched20/paint.c | 20 ++++++++++++---- dlls/riched20/run.c | 46 ++++++++++++++++++++++++++++++------ dlls/riched20/string.c | 26 ++++++++++++++++++++ dlls/riched20/tests/editor.c | 25 ++++++++++++++++++++ 7 files changed, 132 insertions(+), 16 deletions(-) diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 7389407b9c3..12687829750 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -58,7 +58,7 @@ - EM_GETOLEINTERFACE + EM_GETOPTIONS + EM_GETPARAFORMAT - - EM_GETPASSWORDCHAR 2.0 + + EM_GETPASSWORDCHAR 2.0 - EM_GETPUNCTUATION 1.0asian + EM_GETRECT - EM_GETREDONAME 2.0 @@ -105,7 +105,7 @@ + EM_SETOPTIONS (partially implemented) - EM_SETPALETTE 2.0 + EM_SETPARAFORMAT - - EM_SETPASSWORDCHAR 2.0 + + EM_SETPASSWORDCHAR 2.0 - EM_SETPUNCTUATION 1.0asian + EM_SETREADONLY no beep on modification attempt + EM_SETRECT @@ -1146,6 +1146,12 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { ed->pFontCache[i].hFont = NULL; } ME_CheckCharOffsets(ed); + + if (GetWindowLongW(hWnd, GWL_STYLE) & ES_PASSWORD) + ed->cPasswordMask = '*'; + else + ed->cPasswordMask = 0; + return ed; } @@ -1418,7 +1424,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP UNSUPPORTED_MSG(EM_GETLANGOPTIONS) UNSUPPORTED_MSG(EM_GETLIMITTEXT) /* UNSUPPORTED_MSG(EM_GETOLEINTERFACE) separate stub */ - UNSUPPORTED_MSG(EM_GETPASSWORDCHAR) UNSUPPORTED_MSG(EM_GETREDONAME) UNSUPPORTED_MSG(EM_GETTEXTMODE) UNSUPPORTED_MSG(EM_GETTYPOGRAPHYOPTIONS) @@ -1432,7 +1437,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP UNSUPPORTED_MSG(EM_SETFONTSIZE) UNSUPPORTED_MSG(EM_SETLANGOPTIONS) UNSUPPORTED_MSG(EM_SETPALETTE) - UNSUPPORTED_MSG(EM_SETPASSWORDCHAR) UNSUPPORTED_MSG(EM_SETSCROLLPOS) UNSUPPORTED_MSG(EM_SETTABSTOPS) UNSUPPORTED_MSG(EM_SETTARGETDEVICE) @@ -1933,6 +1937,10 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP LPDATAOBJECT dataObj = NULL; CHARRANGE range; HRESULT hr = S_OK; + + if (editor->cPasswordMask) + return 0; /* Copying or Cutting masked text isn't allowed */ + ME_GetSelection(editor, (int*)&range.cpMin, (int*)&range.cpMax); if(editor->lpOleCallback) hr = IRichEditOleCallback_GetClipboardData(editor->lpOleCallback, &range, RECO_COPY, &dataObj); @@ -2473,6 +2481,10 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP LPVOID *ppvObj = (LPVOID*) lParam; return CreateIRichEditOle(editor, ppvObj); } + case EM_GETPASSWORDCHAR: + { + return editor->cPasswordMask; + } case EM_SETOLECALLBACK: if(editor->lpOleCallback) IUnknown_Release(editor->lpOleCallback); @@ -2514,7 +2526,13 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP } } return ret; - } + } + case EM_SETPASSWORDCHAR: + { + editor->cPasswordMask = wParam; + ME_RewrapRepaint(editor); + return 0; + } default: do_default: return DefWindowProcW(hWnd, msg, wParam, lParam); diff --git a/dlls/riched20/editor.h b/dlls/riched20/editor.h index a4d4980a0c7..93952fd0da9 100644 --- a/dlls/riched20/editor.h +++ b/dlls/riched20/editor.h @@ -75,6 +75,8 @@ const char *ME_GetDITypeName(ME_DIType type); int ME_GetOptimalBuffer(int nLen); ME_String *ME_MakeString(LPCWSTR szText); ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars); +ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars); +ME_String *ME_MakeStringB(int nMaxChars); ME_String *ME_StrDup(ME_String *s); void ME_DestroyString(ME_String *s); void ME_AppendString(ME_String *s1, ME_String *s2); diff --git a/dlls/riched20/editstr.h b/dlls/riched20/editstr.h index 10e4be2cfe8..7d096e870f1 100644 --- a/dlls/riched20/editstr.h +++ b/dlls/riched20/editstr.h @@ -320,6 +320,7 @@ typedef struct tagME_TextEditor int mode; BOOL bHideSelection; BOOL AutoURLDetect_bEnable; + WCHAR cPasswordMask; } ME_TextEditor; typedef struct tagME_Context diff --git a/dlls/riched20/paint.c b/dlls/riched20/paint.c index f3f5ac1901f..f26583c3243 100644 --- a/dlls/riched20/paint.c +++ b/dlls/riched20/paint.c @@ -222,7 +222,8 @@ void ME_DrawGraphics(ME_Context *c, int x, int y, ME_Run *run, } } -static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para) { +static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph *para) +{ ME_Run *run = &rundi->member.run; ME_DisplayItem *start = ME_FindItemBack(rundi, diStartRow); int runofs = run->nCharOfs+para->nCharOfs; @@ -247,9 +248,20 @@ static void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Pa if (run->nFlags & MERF_GRAPHICS) ME_DrawGraphics(c, x, y, run, para, (runofs >= nSelFrom) && (runofs < nSelTo)); else - ME_DrawTextWithStyle(c, x, y, - run->strText->szData, ME_StrVLen(run->strText), run->style, NULL, - nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight); + { + if (c->editor->cPasswordMask) + { + ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,ME_StrVLen(run->strText)); + ME_DrawTextWithStyle(c, x, y, + szMasked->szData, ME_StrVLen(szMasked), run->style, NULL, + nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight); + ME_DestroyString(szMasked); + } + else + ME_DrawTextWithStyle(c, x, y, + run->strText->szData, ME_StrVLen(run->strText), run->style, NULL, + nSelFrom-runofs,nSelTo-runofs, c->pt.y+start->member.row.nYPos, start->member.row.nHeight); + } } COLORREF ME_GetBackColor(ME_TextEditor *editor) diff --git a/dlls/riched20/run.c b/dlls/riched20/run.c index a2c121a3147..d74d68f7848 100644 --- a/dlls/riched20/run.c +++ b/dlls/riched20/run.c @@ -532,6 +532,9 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run) */ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) { + ME_String *strRunText; + /* This could point to either the run's real text, or it's masked form in a password control */ + int fit = 0, fit1 = 0; HGDIOBJ hOldFont; HDC hDC; @@ -553,21 +556,30 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run) return 0; return 1; } + + if (editor->cPasswordMask) + strRunText = ME_MakeStringR(editor->cPasswordMask,ME_StrVLen(run->strText)); + else + strRunText = run->strText; hDC = GetDC(editor->hWnd); hOldFont = ME_SelectStyleFont(editor, hDC, run->style); - GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen, + GetTextExtentExPointW(hDC, strRunText->szData, strRunText->nLen, cx, &fit, NULL, &sz); - if (fit != run->strText->nLen) + if (fit != strRunText->nLen) { int chars = 1; - GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2); - fit1 = ME_StrRelPos(run->strText, fit, &chars); - GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3); + GetTextExtentPoint32W(hDC, strRunText->szData, fit, &sz2); + fit1 = ME_StrRelPos(strRunText, fit, &chars); + GetTextExtentPoint32W(hDC, strRunText->szData, fit1, &sz3); if (cx >= (sz2.cx+sz3.cx)/2) fit = fit1; } + + if (editor->cPasswordMask) + ME_DestroyString(strRunText); + ME_UnselectStyleFont(editor, hDC, run->style, hOldFont); ReleaseDC(editor->hWnd, hDC); return fit; @@ -584,6 +596,8 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset) SIZE size; HDC hDC = GetDC(editor->hWnd); HGDIOBJ hOldFont; + ME_String *strRunText; + /* This could point to either the run's real text, or it's masked form in a password control */ if (pRun->nFlags & MERF_GRAPHICS) { @@ -591,10 +605,18 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset) ME_GetGraphicsSize(editor, pRun, &size); return 1; } + + if (editor->cPasswordMask) + strRunText = ME_MakeStringR(editor->cPasswordMask,ME_StrVLen(pRun->strText)); + else + strRunText = pRun->strText; + hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style); - GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size); + GetTextExtentPoint32W(hDC, strRunText->szData, nOffset, &size); ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont); ReleaseDC(editor->hWnd, hDC); + if (editor->cPasswordMask) + ME_DestroyString(strRunText); return size.cx; } @@ -631,7 +653,17 @@ SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLe * this is wasteful for MERF_NONTEXT runs, but that shouldn't matter * in practice */ - ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size); + + if (c->editor->cPasswordMask) + { + ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen); + ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size); + ME_DestroyString(szMasked); + } + else + { + ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size); + } *pAscent = run->style->tm.tmAscent; *pDescent = run->style->tm.tmDescent; size.cy = *pAscent + *pDescent; diff --git a/dlls/riched20/string.c b/dlls/riched20/string.c index b5293734600..57a304a0af1 100644 --- a/dlls/riched20/string.c +++ b/dlls/riched20/string.c @@ -50,6 +50,32 @@ ME_String *ME_MakeStringN(LPCWSTR szText, int nMaxChars) return s; } +ME_String *ME_MakeStringR(WCHAR cRepeat, int nMaxChars) +{ /* Make a string by repeating a char nMaxChars times */ + int i; + ME_String *s = ALLOC_OBJ(ME_String); + + s->nLen = nMaxChars; + s->nBuffer = ME_GetOptimalBuffer(s->nLen+1); + s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); + + for (i = 0;iszData[i] = cRepeat; + s->szData[s->nLen] = 0; + return s; +} + +ME_String *ME_MakeStringB(int nMaxChars) +{ /* Create a buffer (uninitialized string) of size nMaxChars */ + ME_String *s = ALLOC_OBJ(ME_String); + + s->nLen = nMaxChars; + s->nBuffer = ME_GetOptimalBuffer(s->nLen+1); + s->szData = ALLOC_N_OBJ(WCHAR, s->nBuffer); + s->szData[s->nLen] = 0; + return s; +} + ME_String *ME_StrDup(ME_String *s) { return ME_MakeStringN(s->szData, s->nLen); diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c index ccb81de990e..6153e6eb32c 100644 --- a/dlls/riched20/tests/editor.c +++ b/dlls/riched20/tests/editor.c @@ -873,6 +873,30 @@ static void test_EM_SETUNDOLIMIT() DestroyWindow(hwndRichEdit); } +static void test_ES_PASSWORD() +{ + /* This isn't hugely testable, so we're just going to run it through it's paces. */ + + HWND hwndRichEdit = new_richedit(NULL); + WCHAR result; + + /* First, check the default of a regular control */ + result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); + ok (result == 0, + "EM_GETPASSWORDCHAR returned %c by default, instead of NULL\n",result); + + /* Now, set it to something normal */ + SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, 'x', 0); + result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); + ok (result == 120, + "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result); + + /* Now, set it to something odd */ + SendMessage(hwndRichEdit, EM_SETPASSWORDCHAR, (WCHAR)1234, 0); + result = SendMessage(hwndRichEdit, EM_GETPASSWORDCHAR, 0, 0); + ok (result == 1234, + "EM_GETPASSWORDCHAR returned %c (%d) when set to 'x', instead of x (120)\n",result,result); +} START_TEST( editor ) { @@ -893,6 +917,7 @@ START_TEST( editor ) test_WM_GETTEXT(); test_EM_AUTOURLDETECT(); test_EM_SETUNDOLIMIT(); + test_ES_PASSWORD(); /* Set the environment variable WINETEST_RICHED20 to keep windows * responsive and open for 30 seconds. This is useful for debugging.