From: Baruch Rutman Date: Thu, 27 Sep 2018 22:00:31 +0000 (+0300) Subject: [LPK] Implement LpkPSMTextOut(). (#890) X-Git-Tag: 0.4.12-dev~580 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=a494d0583fe3805f1b33ed0d65e6a6f7ed8f8e0b;hp=b3179a0771c30e0d7bcc7839899811558e0105c4 [LPK] Implement LpkPSMTextOut(). (#890) - The function is almost fully implemented, but some return values change wildly. The results are mostly compatible to the Windows results. - Remove #ifdef (this is primary ReactOS code). --- diff --git a/dll/win32/lpk/lpk.c b/dll/win32/lpk/lpk.c index b567d744ca5..b99e8a3c65f 100644 --- a/dll/win32/lpk/lpk.c +++ b/dll/win32/lpk/lpk.c @@ -14,6 +14,97 @@ LPK_LPEDITCONTROL_LIST LpkEditControl = {EditCreate, EditIchToXY, EditMou EditVerifyText, EditNextWord, EditSetMenu, EditProcessMenu, EditCreateCaret, EditAdjustCaret}; +#define PREFIX 38 +#define ALPHA_PREFIX 30 /* Win16: Alphabet prefix */ +#define KANA_PREFIX 31 /* Win16: Katakana prefix */ + +static int PSM_FindLastPrefix(LPCWSTR str, int count) +{ + int i, prefix_count = 0, index = -1; + + for (i = 0; i < count - 1; i++) + { + if (str[i] == PREFIX && str[i + 1] != PREFIX) + { + index = i - prefix_count; + prefix_count++; + } + else if (str[i] == PREFIX && str[i + 1] == PREFIX) + { + i++; + } + } + return index; +} + +static void PSM_PrepareToDraw(LPCWSTR str, INT count, LPWSTR new_str, LPINT new_count) +{ + int len, i = 0, j = 0; + + while (i < count) + { + if (str[i] == PREFIX || (iswspace(str[i]) && str[i] != L' ')) + { + if(i < count - 1 && str[i + 1] == PREFIX) + new_str[j++] = str[i++]; + else + i++; + } + else + { + new_str[j++] = str[i++]; + } + } + + new_str[j] = L'\0'; + len = wcslen(new_str); + *new_count = len; +} + +/* Can be used with also LpkDrawTextEx if it will be implemented */ +static void LPK_DrawUnderscore(HDC hdc, int x, int y, LPCWSTR str, int count, int offset) +{ + SCRIPT_STRING_ANALYSIS ssa; + int prefix_x; + int prefix_end; + int pos; + SIZE size; + HPEN hpen; + HPEN oldPen; + HRESULT hr = S_FALSE; + + if (offset == -1) + return; + + if (ScriptIsComplex(str, count, SIC_COMPLEX) == S_OK) + { + hr = ScriptStringAnalyse(hdc, str, count, (3 * count / 2 + 16), + -1, SSA_GLYPHS, -1, NULL, NULL, NULL, NULL, NULL, &ssa); + } + + if (hr == S_OK) + { + ScriptStringCPtoX(ssa, offset, FALSE, &pos); + prefix_x = x + pos; + ScriptStringCPtoX(ssa, offset, TRUE, &pos); + prefix_end = x + pos; + ScriptStringFree(&ssa); + } + else + { + GetTextExtentPointW(hdc, str, offset, &size); + prefix_x = x + size.cx; + GetTextExtentPointW(hdc, str, offset + 1, &size); + prefix_end = x + size.cx - 1; + } + hpen = CreatePen(PS_SOLID, 1, GetTextColor(hdc)); + oldPen = SelectObject(hdc, hpen); + MoveToEx(hdc, prefix_x, y, NULL); + LineTo(hdc, prefix_end, y); + SelectObject(hdc, oldPen); + DeleteObject(hpen); +} + BOOL WINAPI DllMain( @@ -196,14 +287,7 @@ LpkGetCharacterPlacement( { int pos = 0; - hr = ScriptStringAnalyse(hdc, lpString, nSet, -#ifdef __REACTOS__ - /* ReactOS r57677 and r57679 */ - (3 * nSet / 2 + 16), -#else - (1.5 * nSet + 16), -#endif - -1, SSA_GLYPHS, -1, + hr = ScriptStringAnalyse(hdc, lpString, nSet, (3 * nSet / 2 + 16), -1, SSA_GLYPHS, -1, NULL, NULL, NULL, NULL, NULL, &ssa); if (hr == S_OK) { @@ -232,3 +316,55 @@ LpkGetCharacterPlacement( return ret; } + +/* Stripped down version of DrawText, can only draw single line text and Prefix underscore + * (only on the last found amperstand) + * only flags to be found to be of use in testing: + * + * DT_NOPREFIX - Draw the string as is without removal of the amperstands and without underscore + * DT_HIDEPREFIX - Draw the string without underscore + * DT_PREFIXONLY - Draw only the underscore + * + * without any of these flags the behavior is the string being drawn without the amperstands and + * with the underscore. + * user32 has an equivalent function - UserLpkPSMTextOut + */ +INT WINAPI LpkPSMTextOut(HDC hdc, int x, int y, LPCWSTR lpString, int cString, DWORD dwFlags) +{ + SIZE size; + TEXTMETRICW tm; + int prefix_offset, len; + LPWSTR display_str = NULL; + + if (!lpString || cString <= 0) + return 0; + + if (dwFlags & DT_NOPREFIX) + { + LpkExtTextOut(hdc, x, y, (dwFlags & DT_RTLREADING) ? ETO_RTLREADING : 0, NULL, lpString, cString - 1, NULL, 0); + GetTextExtentPointW(hdc, lpString, cString, &size); + return size.cx; + } + + display_str = HeapAlloc(GetProcessHeap(), 0, (cString + 1) * sizeof(WCHAR)); + + if (!display_str) + return 0; + + PSM_PrepareToDraw(lpString, cString, display_str, &len); + + if (!(dwFlags & DT_PREFIXONLY)) + LpkExtTextOut(hdc, x, y, (dwFlags & DT_RTLREADING) ? ETO_RTLREADING : 0, NULL, display_str, len, NULL, 0); + + if (!(dwFlags & DT_HIDEPREFIX)) + { + prefix_offset = PSM_FindLastPrefix(lpString, cString); + GetTextMetricsW(hdc, &tm); + LPK_DrawUnderscore(hdc, x, y + tm.tmAscent + 1, display_str, len, prefix_offset); + } + + GetTextExtentPointW(hdc, display_str, len + 1, &size); + HeapFree(GetProcessHeap(), 0, display_str); + + return size.cx; +} diff --git a/dll/win32/lpk/lpk.spec b/dll/win32/lpk/lpk.spec index 910d3dc65db..1ef05e1a747 100644 --- a/dll/win32/lpk/lpk.spec +++ b/dll/win32/lpk/lpk.spec @@ -6,6 +6,6 @@ @ stdcall LpkExtTextOut(long long long long ptr wstr long ptr long) @ stdcall LpkGetCharacterPlacement(long wstr long long ptr long long) @ stdcall LpkGetTextExtentExPoint(long long long long long long long long long) -@ stdcall LpkPSMTextOut(long long long long long long) +@ stdcall LpkPSMTextOut(long long long wstr long long) @ stdcall LpkUseGDIWidthCache(long long long long long) @ stdcall ftsWordBreak(long long long long long) diff --git a/dll/win32/lpk/ros_lpk.h b/dll/win32/lpk/ros_lpk.h index 0fb1fe341d1..ecb3ef91fc5 100644 --- a/dll/win32/lpk/ros_lpk.h +++ b/dll/win32/lpk/ros_lpk.h @@ -66,7 +66,6 @@ DWORD WINAPI LpkTabbedTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD BOOL WINAPI LpkDllInitialize (HANDLE hDll, DWORD dwReason, LPVOID lpReserved); DWORD WINAPI LpkDrawTextEx(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9, DWORD x10); DWORD WINAPI LpkGetTextExtentExPoint(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6,DWORD x7,DWORD x8,DWORD x9); -DWORD WINAPI LpkPSMTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6); DWORD WINAPI LpkUseGDIWidthCache(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5); DWORD WINAPI ftsWordBreak(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5); @@ -77,6 +76,8 @@ BOOL WINAPI LpkExtTextOut(HDC hdc, int x, int y, UINT fuOptions, const RECT *lpr DWORD WINAPI LpkGetCharacterPlacement(HDC hdc, LPCWSTR lpString, INT uCount, INT nMaxExtent, GCP_RESULTSW *lpResults, DWORD dwFlags, DWORD dwUnused); + +INT WINAPI LpkPSMTextOut(HDC hdc, int x, int y, LPCWSTR lpString, int cString, DWORD dwFlags); /* bidi.c */ #define WINE_GCPW_FORCE_LTR 0 diff --git a/dll/win32/lpk/stub.c b/dll/win32/lpk/stub.c index 51d8eda0e44..b601a358682 100644 --- a/dll/win32/lpk/stub.c +++ b/dll/win32/lpk/stub.c @@ -48,15 +48,6 @@ DWORD WINAPI LpkGetTextExtentExPoint(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x return 0; } -/* - * @unimplemented - */ -DWORD WINAPI LpkPSMTextOut(DWORD x1,DWORD x2,DWORD x3,DWORD x4,DWORD x5,DWORD x6) -{ - UNIMPLEMENTED - return 0; -} - /* * @unimplemented */