mirror of
https://github.com/reactos/reactos.git
synced 2026-06-08 17:02:56 +08:00
[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:
committed by
GitHub
parent
3518663767
commit
06ae7ec211
@@ -39,6 +39,7 @@ list(APPEND SOURCE
|
||||
GdiGetLocalDC.c
|
||||
GdiReleaseLocalDC.c
|
||||
GdiSetAttrs.c
|
||||
GetCharWidth.c
|
||||
GetClipBox.c
|
||||
GetClipRgn.c
|
||||
GetCurrentObject.c
|
||||
|
||||
360
modules/rostests/apitests/gdi32/GetCharWidth.c
Normal file
360
modules/rostests/apitests/gdi32/GetCharWidth.c
Normal 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);
|
||||
}
|
||||
@@ -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 },
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user