[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.
This commit is contained in:
Katayama Hirofumi MZ
2026-03-01 20:12:45 +09:00
committed by GitHub
parent 3518663767
commit 06ae7ec211
7 changed files with 503 additions and 122 deletions

View File

@@ -39,6 +39,7 @@ list(APPEND SOURCE
GdiGetLocalDC.c
GdiReleaseLocalDC.c
GdiSetAttrs.c
GetCharWidth.c
GetClipBox.c
GetClipRgn.c
GetCurrentObject.c

View File

@@ -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);
}

View File

@@ -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 },

View File

@@ -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,

View File

@@ -14,6 +14,8 @@
#define NDEBUG
#include <debug.h>
#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;
}

View File

@@ -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)

View File

@@ -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);