From 06ae7ec21149aae07deb0578f38f4385822a7234 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Sun, 1 Mar 2026 20:12:45 +0900 Subject: [PATCH] [FREETYPE][NTGDI][GDI32][GDI32_APITEST] Rewrite GetCharWidth etc. (#8690) Refactoring and improve readability. JIRA issue: CORE-20505 - Add GreGetCharWidthW helper function. - Rewrite NtGdiGetCharWidthW using GreGetCharWidthW. - Refactor NtGdiGetGlyphIndicesW. - Improve sanity check of GetCharWidthA/W/I, GetCharWidth32A/W, and GetCharWidthFloatA/W. - Add GetCharWidth testcase to gdi32_apitest. --- .../rostests/apitests/gdi32/CMakeLists.txt | 1 + .../rostests/apitests/gdi32/GetCharWidth.c | 360 ++++++++++++++++++ modules/rostests/apitests/gdi32/testlist.c | 2 + win32ss/gdi/gdi32/objects/font.c | 64 ++-- win32ss/gdi/ntgdi/font.c | 61 +++ win32ss/gdi/ntgdi/freetype.c | 128 ++----- win32ss/gdi/ntgdi/text.h | 9 + 7 files changed, 503 insertions(+), 122 deletions(-) create mode 100644 modules/rostests/apitests/gdi32/GetCharWidth.c diff --git a/modules/rostests/apitests/gdi32/CMakeLists.txt b/modules/rostests/apitests/gdi32/CMakeLists.txt index 33d431ebc65..3b4134d1e14 100644 --- a/modules/rostests/apitests/gdi32/CMakeLists.txt +++ b/modules/rostests/apitests/gdi32/CMakeLists.txt @@ -39,6 +39,7 @@ list(APPEND SOURCE GdiGetLocalDC.c GdiReleaseLocalDC.c GdiSetAttrs.c + GetCharWidth.c GetClipBox.c GetClipRgn.c GetCurrentObject.c diff --git a/modules/rostests/apitests/gdi32/GetCharWidth.c b/modules/rostests/apitests/gdi32/GetCharWidth.c new file mode 100644 index 00000000000..c1fa03a8763 --- /dev/null +++ b/modules/rostests/apitests/gdi32/GetCharWidth.c @@ -0,0 +1,360 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test for GetCharWidth... functions + * COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "precomp.h" + +static void Test_CharWidthA(HDC hDC) +{ + BOOL ret; + INT anBuffer['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(NULL, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(NULL, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(NULL, 'A', 'Z', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(NULL, 'B', 'A', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(hDC, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); // + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(hDC, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); // + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(hDC, 'A', 'Z', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthA(hDC, 'A', 'B', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); +} + +static void Test_CharWidthW(HDC hDC) +{ + BOOL ret; + INT anBuffer['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(NULL, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(NULL, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(NULL, 'A', 'Z', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(NULL, 'B', 'A', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(hDC, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(hDC, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(hDC, 'A', 'Z', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthW(hDC, 'A', 'B', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); +} + +static void Test_CharWidthI(HDC hDC) +{ + BOOL ret; + WORD awBuffer['Z' - 'A' + 1]; + INT anWidths['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(NULL, 0, 0, NULL, NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(hDC, 0, 0, NULL, NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(NULL, 0, 1, awBuffer, anWidths); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_HANDLE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(hDC, 0, 1, awBuffer, NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(hDC, 0, 1, awBuffer, anWidths); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(hDC, 0, _countof(awBuffer), awBuffer, anWidths); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + +#if 0 // These tests take time in ReactOS + INT count = 0x2710000 / sizeof(INT); + PINT pn = malloc((count + 1) * sizeof(INT)); + PWORD pw = malloc((count + 1) * sizeof(WORD)); + + if (!pn || !pw) + { + skip("allocation failed\n"); + } + else + { + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(hDC, 0, count, pw, pn); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthI(hDC, 0, count + 1, pw, pn); + ok_int(ret, FALSE); + ok_err(0xBEEFCAFE); + } + + free(pn); + free(pw); +#endif +} + +static void Test_CharWidth32A(HDC hDC) +{ + BOOL ret; + INT anBuffer['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(NULL, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(NULL, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(NULL, 'A', 'Z', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(NULL, 'B', 'A', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(hDC, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); // + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(hDC, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); // + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(hDC, 'A', 'Z', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32A(hDC, 'A', 'B', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); +} + +static void Test_CharWidth32W(HDC hDC) +{ + BOOL ret; + INT anBuffer['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(NULL, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(NULL, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(NULL, 'A', 'Z', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(NULL, 'B', 'A', anBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(hDC, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(hDC, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(hDC, 'A', 'Z', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidth32W(hDC, 'A', 'B', anBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); +} + +static void Test_CharWidthFloatA(HDC hDC) +{ + BOOL ret; + FLOAT aeBuffer['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(NULL, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(NULL, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(NULL, 'A', 'Z', aeBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(NULL, 'B', 'A', aeBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(hDC, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); // + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(hDC, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); // + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(hDC, 'A', 'Z', aeBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatA(hDC, 'A', 'B', aeBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); +} + +static void Test_CharWidthFloatW(HDC hDC) +{ + BOOL ret; + FLOAT aeBuffer['Z' - 'A' + 1]; + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(NULL, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(NULL, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(NULL, 'A', 'Z', aeBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(NULL, 'B', 'A', aeBuffer); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(hDC, 'A', 'Z', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(hDC, 'B', 'A', NULL); + ok_int(ret, FALSE); + ok_err(ERROR_INVALID_PARAMETER); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(hDC, 'A', 'Z', aeBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); + + SetLastError(0xBEEFCAFE); + ret = GetCharWidthFloatW(hDC, 'A', 'B', aeBuffer); + ok_int(ret, TRUE); + ok_err(0xBEEFCAFE); +} + +START_TEST(GetCharWidth) +{ + HDC hDC = CreateCompatibleDC(NULL); + Test_CharWidthA(hDC); + Test_CharWidthW(hDC); + Test_CharWidthI(hDC); + Test_CharWidth32A(hDC); + Test_CharWidth32W(hDC); + Test_CharWidthFloatA(hDC); + Test_CharWidthFloatW(hDC); + DeleteDC(hDC); +} diff --git a/modules/rostests/apitests/gdi32/testlist.c b/modules/rostests/apitests/gdi32/testlist.c index 12bf3cc6122..d71ebf3eaa7 100644 --- a/modules/rostests/apitests/gdi32/testlist.c +++ b/modules/rostests/apitests/gdi32/testlist.c @@ -39,6 +39,7 @@ extern void func_GdiGetLocalBrush(void); extern void func_GdiGetLocalDC(void); extern void func_GdiReleaseLocalDC(void); extern void func_GdiSetAttrs(void); +extern void func_GetCharWidth(void); extern void func_GetClipBox(void); extern void func_GetClipRgn(void); extern void func_GetCurrentObject(void); @@ -117,6 +118,7 @@ const struct test winetest_testlist[] = { "GdiGetLocalDC", func_GdiGetLocalDC }, { "GdiReleaseLocalDC", func_GdiReleaseLocalDC }, { "GdiSetAttrs", func_GdiSetAttrs }, + { "GetCharWidth", func_GetCharWidth }, { "GetClipBox", func_GetClipBox }, { "GetClipRgn", func_GetClipRgn }, { "GetCurrentObject", func_GetCurrentObject }, diff --git a/win32ss/gdi/gdi32/objects/font.c b/win32ss/gdi/gdi32/objects/font.c index 3829109897e..79fcdb0d55d 100644 --- a/win32ss/gdi/gdi32/objects/font.c +++ b/win32ss/gdi/gdi32/objects/font.c @@ -706,7 +706,6 @@ GetCharABCWidthsFloatW(HDC hdc, /* * @implemented - * */ BOOL WINAPI @@ -716,7 +715,8 @@ GetCharWidthFloatW(HDC hdc, PFLOAT pxBuffer) { DPRINT("GetCharWidthsFloatW\n"); - if ((!pxBuffer) || (iFirstChar > iLastChar)) + if ((!pxBuffer) || (iFirstChar > iLastChar) || HIWORD(iLastChar) || + (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC) || !GdiValidateHandle(hdc)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -731,7 +731,6 @@ GetCharWidthFloatW(HDC hdc, /* * @implemented - * */ BOOL WINAPI @@ -741,7 +740,8 @@ GetCharWidthW(HDC hdc, LPINT lpBuffer) { DPRINT("GetCharWidthsW\n"); - if ((!lpBuffer) || (iFirstChar > iLastChar)) + if ((!lpBuffer) || (iFirstChar > iLastChar) || HIWORD(iLastChar) || + (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC) || !GdiValidateHandle(hdc)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -756,7 +756,6 @@ GetCharWidthW(HDC hdc, /* * @implemented - * */ BOOL WINAPI @@ -766,7 +765,8 @@ GetCharWidth32W(HDC hdc, LPINT lpBuffer) { DPRINT("GetCharWidths32W\n"); - if ((!lpBuffer) || (iFirstChar > iLastChar)) + if ((!lpBuffer) || (iFirstChar > iLastChar) || HIWORD(iLastChar) || + (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC) || !GdiValidateHandle(hdc)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -779,10 +779,8 @@ GetCharWidth32W(HDC hdc, lpBuffer); } - /* * @implemented - * */ BOOL WINAPI @@ -812,10 +810,9 @@ BOOL WINAPI GetCharWidthA( HDC hdc, - UINT iFirstChar, - UINT iLastChar, - LPINT lpBuffer -) + UINT iFirstChar, + UINT iLastChar, + LPINT lpBuffer) { INT wlen, count = 0; LPSTR str; @@ -824,6 +821,12 @@ GetCharWidthA( DPRINT("GetCharWidthsA\n"); + if (!lpBuffer || (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC) || !GdiValidateHandle(hdc)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count); if (!str) return FALSE; @@ -855,10 +858,9 @@ BOOL WINAPI GetCharWidth32A( HDC hdc, - UINT iFirstChar, - UINT iLastChar, - LPINT lpBuffer -) + UINT iFirstChar, + UINT iLastChar, + LPINT lpBuffer) { INT wlen, count = 0; LPSTR str; @@ -867,6 +869,12 @@ GetCharWidth32A( DPRINT("GetCharWidths32A\n"); + if (!lpBuffer || (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC) || !GdiValidateHandle(hdc)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count); if (!str) return FALSE; @@ -898,10 +906,9 @@ BOOL APIENTRY GetCharWidthFloatA( HDC hdc, - UINT iFirstChar, - UINT iLastChar, - PFLOAT pxBuffer -) + UINT iFirstChar, + UINT iLastChar, + PFLOAT pxBuffer) { INT wlen, count = 0; LPSTR str; @@ -910,6 +917,12 @@ GetCharWidthFloatA( DPRINT("GetCharWidthsFloatA\n"); + if (!pxBuffer || (GDI_HANDLE_GET_TYPE(hdc) != GDI_OBJECT_TYPE_DC) || !GdiValidateHandle(hdc)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count); if (!str) return FALSE; @@ -1037,16 +1050,19 @@ GetCharWidthI(HDC hdc, UINT giFirst, UINT cgi, LPWORD pgi, - LPINT lpBuffer - ) + LPINT lpBuffer) { DPRINT("GetCharWidthsI\n"); - if (!lpBuffer || (!pgi && (giFirst == MAXUSHORT))) // Cannot be at max. + + if (!lpBuffer || (!pgi && HIWORD(giFirst))) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (!cgi) return TRUE; + + if (!cgi) + return TRUE; + return NtGdiGetCharWidthW( hdc, giFirst, cgi, diff --git a/win32ss/gdi/ntgdi/font.c b/win32ss/gdi/ntgdi/font.c index 6ee26b7b3af..5639e20127c 100644 --- a/win32ss/gdi/ntgdi/font.c +++ b/win32ss/gdi/ntgdi/font.c @@ -14,6 +14,8 @@ #define NDEBUG #include +#define MAX_TEXT_BUFFER 0x2710000 + HFONT APIENTRY HfontCreate( _In_ const ENUMLOGFONTEXDVW *pelfw, @@ -1309,3 +1311,62 @@ NtGdiHfontCreate( return HfontCreate(&SafeLogfont, cjElfw, lft, fl, pvCliData); } + + +/* This function is called from GetCharWidthA/W/I, GetCharWidth32A/W, and GetCharWidthFloatA/W. */ +BOOL NTAPI +NtGdiGetCharWidthW( + _In_ HDC hDC, + _In_ UINT FirstChar, + _In_ UINT Count, + _In_reads_opt_(Count) PCWCH UnSafepwc, + _In_ FLONG fl, + _Out_writes_bytes_(Count * sizeof(INT)) PVOID Buffer) +{ + BOOL ret = FALSE; + PVOID pTmpBuffer = NULL; + PWCHAR pSafePwc = NULL; + NTSTATUS Status; + WCHAR StackPwc[40]; + INT StackBuffer[40]; + + if (!Count || Count > MAX_TEXT_BUFFER / sizeof(INT)) + return FALSE; + + if (UnSafepwc) + { + if (Count <= _countof(StackPwc)) + pSafePwc = StackPwc; + else + pSafePwc = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), GDITAG_TEXT); + + if (!pSafePwc) + return FALSE; + + Status = MmCopyFromCaller(pSafePwc, UnSafepwc, Count * sizeof(WCHAR)); + if (!NT_SUCCESS(Status)) + goto Cleanup; + } + + if (Count <= _countof(StackBuffer)) + pTmpBuffer = StackBuffer; + else + pTmpBuffer = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), GDITAG_TEXT); + + if (!pTmpBuffer) + goto Cleanup; + + ret = GreGetCharWidthW(hDC, FirstChar, Count, pSafePwc, fl, pTmpBuffer); + if (ret) + { + Status = MmCopyToCaller(Buffer, pTmpBuffer, Count * sizeof(INT)); + ret = NT_SUCCESS(Status); + } + +Cleanup: + if (pTmpBuffer && pTmpBuffer != StackBuffer) + ExFreePoolWithTag(pTmpBuffer, GDITAG_TEXT); + if (pSafePwc && pSafePwc != StackPwc) + ExFreePoolWithTag(pSafePwc, GDITAG_TEXT); + return ret; +} diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 92070ec1fde..9eba4037d76 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -7655,80 +7655,34 @@ NtGdiGetCharABCWidthsW( /* * @implemented */ -BOOL -APIENTRY -NtGdiGetCharWidthW( +BOOL APIENTRY +GreGetCharWidthW( _In_ HDC hDC, _In_ UINT FirstChar, _In_ UINT Count, - _In_reads_opt_(Count) PCWCH UnSafepwc, + _In_reads_opt_(Count) PCWCH Safepwc, _In_ FLONG fl, - _Out_writes_bytes_(Count * sizeof(ULONG)) PVOID Buffer) + _Out_writes_bytes_(Count * sizeof(INT)) PVOID Buffer) { - NTSTATUS Status = STATUS_SUCCESS; - LPINT SafeBuff; - PFLOAT SafeBuffF = NULL; PDC dc; PDC_ATTR pdcattr; PTEXTOBJ TextObj; PFONTGDI FontGDI; FT_Face face; FT_CharMap charmap, found = NULL; - UINT i, glyph_index, BufferSize; + UINT i, glyph_index; HFONT hFont = 0; - PWCHAR Safepwc = NULL; LOGFONTW *plf; - - if (UnSafepwc) - { - UINT pwcSize = Count * sizeof(WCHAR); - Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT); - - if(!Safepwc) - { - EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - _SEH2_TRY - { - ProbeForRead(UnSafepwc, pwcSize, 1); - RtlCopyMemory(Safepwc, UnSafepwc, pwcSize); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; - } - - if (!NT_SUCCESS(Status)) - { - SetLastNtError(Status); - return FALSE; - } - - BufferSize = Count * sizeof(INT); // Same size! - SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT); - if (!fl) SafeBuffF = (PFLOAT) SafeBuff; - if (SafeBuff == NULL) - { - if(Safepwc) - ExFreePoolWithTag(Safepwc, GDITAG_TEXT); - - EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } + PINT SafeBuffI; + PFLOAT SafeBuffF; dc = DC_LockDc(hDC); if (dc == NULL) { - if(Safepwc) - ExFreePoolWithTag(Safepwc, GDITAG_TEXT); - - ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } + pdcattr = dc->pdcattr; hFont = pdcattr->hlfntNew; TextObj = RealizeFontInit(hFont); @@ -7736,10 +7690,6 @@ NtGdiGetCharWidthW( if (TextObj == NULL) { - if(Safepwc) - ExFreePoolWithTag(Safepwc, GDITAG_TEXT); - - ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; } @@ -7749,6 +7699,7 @@ NtGdiGetCharWidthW( face = FontGDI->SharedFace->Face; if (face->charmap == NULL) { + // FIXME: Select better charmap for (i = 0; i < (UINT)face->num_charmaps; i++) { charmap = face->charmaps[i]; @@ -7759,21 +7710,20 @@ NtGdiGetCharWidthW( } } - if (!found) + if (!found && FT_IS_SFNT(face)) // Not found and (TrueType or OpenType)? { DPRINT1("WARNING: Could not find desired charmap!\n"); - - if(Safepwc) - ExFreePoolWithTag(Safepwc, GDITAG_TEXT); - - ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); EngSetLastError(ERROR_INVALID_HANDLE); + TEXTOBJ_UnlockText(TextObj); return FALSE; } - IntLockFreeType(); - FT_Set_Charmap(face, found); - IntUnLockFreeType(); + if (found) + { + IntLockFreeType(); + FT_Set_Charmap(face, found); + IntUnLockFreeType(); + } } plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; @@ -7783,6 +7733,11 @@ NtGdiGetCharWidthW( IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); FT_Set_Transform(face, NULL, NULL); + if (!fl) + SafeBuffF = (PFLOAT)Buffer; + else + SafeBuffI = (PINT)Buffer; + for (i = FirstChar; i < FirstChar+Count; i++) { if (Safepwc) @@ -7791,23 +7746,20 @@ NtGdiGetCharWidthW( glyph_index = get_glyph_index_flagged(face, i, (fl & GCW_INDICES)); FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + if (!fl) SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6); else - SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6; + SafeBuffI[i - FirstChar] = (face->glyph->advance.x + 32) >> 6; } + IntUnLockFreeType(); TEXTOBJ_UnlockText(TextObj); - MmCopyToCaller(Buffer, SafeBuff, BufferSize); - if(Safepwc) - ExFreePoolWithTag(Safepwc, GDITAG_TEXT); - - ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); return TRUE; } -static BOOL IntGetFontDefaultChar(_In_ FT_Face Face, _In_ PWCHAR pDefChar) +static BOOL IntGetFontDefaultChar(_In_ FT_Face Face, _Out_ PWCHAR pDefChar) { TT_OS2 *pOS2; FT_WinFNT_HeaderRec WinFNT; @@ -7865,10 +7817,10 @@ NtGdiGetGlyphIndicesW( INT i; WCHAR DefChar = 0xffff; PWORD Buffer = NULL; - WORD StackBuffer[256]; + WORD StackBuffer[40]; size_t pwcSize; PWSTR Safepwc = NULL; - WCHAR pwcStack[256]; + WCHAR pwcStack[40]; LPCWSTR UnSafepwc = pwc; LPWORD UnSafepgi = pgi; FT_Face Face; @@ -7935,7 +7887,6 @@ NtGdiGetGlyphIndicesW( if (!Buffer || !Safepwc) { Status = STATUS_NO_MEMORY; - DPRINT1("ExAllocatePoolWithTag\n"); goto ErrorRet; } } @@ -7948,17 +7899,7 @@ NtGdiGetGlyphIndicesW( IntUnLockFreeType(); } - _SEH2_TRY - { - ProbeForRead(UnSafepwc, pwcSize, 1); - RtlCopyMemory(Safepwc, UnSafepwc, pwcSize); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; - + Status = MmCopyFromCaller(Safepwc, UnSafepwc, pwcSize); if (!NT_SUCCESS(Status)) { DPRINT1("Status: %08lX\n", Status); @@ -7976,16 +7917,7 @@ NtGdiGetGlyphIndicesW( } IntUnLockFreeType(); - _SEH2_TRY - { - ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1); - RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD)); - } - _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) - { - Status = _SEH2_GetExceptionCode(); - } - _SEH2_END; + Status = MmCopyToCaller(UnSafepgi, Buffer, cwc * sizeof(WORD)); ErrorRet: if (Buffer && Buffer != StackBuffer) diff --git a/win32ss/gdi/ntgdi/text.h b/win32ss/gdi/ntgdi/text.h index 11e01ab7800..b6d56992991 100644 --- a/win32ss/gdi/ntgdi/text.h +++ b/win32ss/gdi/ntgdi/text.h @@ -166,3 +166,12 @@ BOOL WINAPI GreGetTextMetricsW( _In_ HDC hdc, _Out_ LPTEXTMETRICW lptm); #define IntUnLockProcessPrivateFonts(W32Process) \ ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&W32Process->PrivateFontListLock) + +BOOL APIENTRY +GreGetCharWidthW( + _In_ HDC hDC, + _In_ UINT FirstChar, + _In_ UINT Count, + _In_reads_opt_(Count) PCWCH Safepwc, + _In_ ULONG fl, + _Out_writes_bytes_(Count * sizeof(INT)) PVOID pTmpBuffer);