[NTGDI][FREETYPE][SDK] Rewrite NtGdiGetCharABCWidthsW (#8704)

Refactor and improve readability.
JIRA issue: CORE-20505
- Add GreGetCharABCWidthsW helper function.
- Rewrite NtGdiGetCharABCWidthsW by using
  GreGetCharABCWidthsW.
This commit is contained in:
Katayama Hirofumi MZ
2026-03-13 18:24:26 +09:00
committed by GitHub
parent 4b75ec5508
commit e6328fbf1e
4 changed files with 134 additions and 151 deletions

View File

@@ -1678,7 +1678,7 @@ APIENTRY
NtGdiGetCharABCWidthsW(
_In_ HDC hdc,
_In_ UINT wchFirst,
_In_ ULONG cwch,
_In_ UINT cwch,
_In_reads_opt_(cwch) PCWCH pwch,
_In_ FLONG fl,
_Out_writes_bytes_(cwch * sizeof(ABC)) PVOID pvBuf);

View File

@@ -1370,3 +1370,64 @@ Cleanup:
ExFreePoolWithTag(pSafePwc, GDITAG_TEXT);
return ret;
}
/* This function is called from GetCharABCWidthsA/W/I and GetCharABCWidthsFloatA/W. */
BOOL NTAPI
NtGdiGetCharABCWidthsW(
_In_ HDC hDC,
_In_ UINT FirstChar,
_In_ UINT Count,
_In_reads_opt_(Count) PCWCH UnSafepwch,
_In_ FLONG fl,
_Out_writes_bytes_(Count * sizeof(ABC)) PVOID Buffer)
{
BOOL ret = FALSE;
PVOID SafeBuff = NULL;
PWCHAR Safepwch = NULL;
ULONG cbABCs;
NTSTATUS Status;
WCHAR Stackpwch[28];
ABC StackABCs[28];
if (!Buffer || (UnSafepwch && !Count) || Count > MAX_TEXT_BUFFER / sizeof(ABC))
return FALSE;
if (UnSafepwch)
{
UINT pwchSize = Count * sizeof(WCHAR);
if (Count <= _countof(Stackpwch))
Safepwch = Stackpwch;
else
Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
if (!Safepwch)
return FALSE;
Status = MmCopyFromCaller(Safepwch, UnSafepwch, pwchSize);
if (!NT_SUCCESS(Status))
goto Cleanup;
}
cbABCs = Count * sizeof(ABC);
if (Count <= _countof(StackABCs))
SafeBuff = StackABCs;
else
SafeBuff = ExAllocatePoolWithTag(PagedPool, cbABCs, GDITAG_TEXT);
if (!SafeBuff)
goto Cleanup;
ret = GreGetCharABCWidthsW(hDC, FirstChar, Count, Safepwch, fl, SafeBuff);
if (ret)
{
Status = MmCopyToCaller(Buffer, SafeBuff, cbABCs);
ret = NT_SUCCESS(Status);
}
Cleanup:
if (SafeBuff && SafeBuff != StackABCs)
ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
if (Safepwch && Safepwch != Stackpwch)
ExFreePoolWithTag(Safepwch, GDITAG_TEXT);
return ret;
}

View File

@@ -7449,95 +7449,68 @@ cleanup:
return Result;
}
static BOOL FASTCALL IntSelectFaceCharmap(FT_Face face)
{
if (face->charmap)
return TRUE;
FT_CharMap charmap, found = NULL;
for (UINT i = 0; i < (UINT)face->num_charmaps; i++)
{
charmap = face->charmaps[i];
if (charmap->encoding != 0)
{
found = charmap;
break;
}
}
if (!found && FT_IS_SFNT(face)) // Not found and (TrueType or OpenType)?
{
DPRINT1("WARNING: Could not find desired charmap!\n");
return FALSE;
}
if (found)
{
IntLockFreeType();
FT_Set_Charmap(face, found);
IntUnLockFreeType();
}
return TRUE;
}
/*
* @implemented
*/
BOOL
APIENTRY
NtGdiGetCharABCWidthsW(
* @implemented
*/
BOOL APIENTRY
GreGetCharABCWidthsW(
_In_ HDC hDC,
_In_ UINT FirstChar,
_In_ ULONG Count,
_In_reads_opt_(Count) PCWCH UnSafepwch,
_In_ UINT Count,
_In_reads_opt_(Count) PCWCH Safepwch,
_In_ FLONG fl,
_Out_writes_bytes_(Count * sizeof(ABC)) PVOID Buffer)
_Out_writes_bytes_(Count * sizeof(ABC)) PVOID SafeBuffer)
{
LPABC SafeBuff;
LPABCFLOAT SafeBuffF = NULL;
PABC SafeBuffI;
PABCFLOAT SafeBuffF;
PDC dc;
PDC_ATTR pdcattr;
PTEXTOBJ TextObj;
PFONTGDI FontGDI;
FT_Face face;
FT_CharMap charmap, found = NULL;
UINT i, glyph_index, BufferSize;
HFONT hFont = 0;
NTSTATUS Status = STATUS_SUCCESS;
PWCHAR Safepwch = NULL;
LOGFONTW *plf;
if (!Buffer)
{
EngSetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (UnSafepwch)
{
UINT pwchSize = Count * sizeof(WCHAR);
Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
if(!Safepwch)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
_SEH2_TRY
{
ProbeForRead(UnSafepwch, pwchSize, 1);
RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
if (!NT_SUCCESS(Status))
{
if(Safepwch)
ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
SetLastNtError(Status);
return FALSE;
}
BufferSize = Count * sizeof(ABC); // Same size!
SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
if (SafeBuff == NULL)
{
if(Safepwch)
ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
UINT i, glyph_index;
HFONT hFont = NULL;
PLOGFONTW plf;
dc = DC_LockDc(hDC);
if (dc == NULL)
{
ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
if(Safepwch)
ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
pdcattr = dc->pdcattr;
hFont = pdcattr->hlfntNew;
TextObj = RealizeFontInit(hFont);
@@ -7546,11 +7519,6 @@ NtGdiGetCharABCWidthsW(
if (TextObj == NULL)
{
ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
if(Safepwch)
ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
@@ -7558,33 +7526,11 @@ NtGdiGetCharABCWidthsW(
FontGDI = ObjToGDI(TextObj->Font, FONT);
face = FontGDI->SharedFace->Face;
if (face->charmap == NULL)
if (!IntSelectFaceCharmap(face))
{
for (i = 0; i < (UINT)face->num_charmaps; i++)
{
charmap = face->charmaps[i];
if (charmap->encoding != 0)
{
found = charmap;
break;
}
}
if (!found)
{
DPRINT1("WARNING: Could not find desired charmap!\n");
ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
if(Safepwch)
ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
IntLockFreeType();
FT_Set_Charmap(face, found);
IntUnLockFreeType();
TEXTOBJ_UnlockText(TextObj);
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
@@ -7594,18 +7540,20 @@ NtGdiGetCharABCWidthsW(
IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
FT_Set_Transform(face, NULL, NULL);
if (!fl)
SafeBuffF = SafeBuffer;
else
SafeBuffI = SafeBuffer;
for (i = FirstChar; i < FirstChar+Count; i++)
{
int adv, lsb, bbx, left, right;
if (Safepwch)
{
glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], (fl & GCABCW_INDICES));
}
else
{
glyph_index = get_glyph_index_flagged(face, i, (fl & GCABCW_INDICES));
}
FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
left = (INT)face->glyph->metrics.horiBearingX & -64;
@@ -7628,27 +7576,15 @@ NtGdiGetCharABCWidthsW(
}
else
{
SafeBuff[i - FirstChar].abcA = lsb;
SafeBuff[i - FirstChar].abcB = bbx;
SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
SafeBuffI[i - FirstChar].abcA = lsb;
SafeBuffI[i - FirstChar].abcB = bbx;
SafeBuffI[i - FirstChar].abcC = adv - lsb - bbx;
}
}
IntUnLockFreeType();
TEXTOBJ_UnlockText(TextObj);
Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
if(Safepwch)
ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return FALSE;
}
DPRINT("NtGdiGetCharABCWidths Worked!\n");
return TRUE;
}
@@ -7669,7 +7605,6 @@ GreGetCharWidthW(
PTEXTOBJ TextObj;
PFONTGDI FontGDI;
FT_Face face;
FT_CharMap charmap, found = NULL;
UINT i, glyph_index;
HFONT hFont = 0;
LOGFONTW *plf;
@@ -7697,33 +7632,11 @@ GreGetCharWidthW(
FontGDI = ObjToGDI(TextObj->Font, FONT);
face = FontGDI->SharedFace->Face;
if (face->charmap == NULL)
if (!IntSelectFaceCharmap(face))
{
// FIXME: Select better charmap
for (i = 0; i < (UINT)face->num_charmaps; i++)
{
charmap = face->charmaps[i];
if (charmap->encoding != 0)
{
found = charmap;
break;
}
}
if (!found && FT_IS_SFNT(face)) // Not found and (TrueType or OpenType)?
{
DPRINT1("WARNING: Could not find desired charmap!\n");
EngSetLastError(ERROR_INVALID_HANDLE);
TEXTOBJ_UnlockText(TextObj);
return FALSE;
}
if (found)
{
IntLockFreeType();
FT_Set_Charmap(face, found);
IntUnLockFreeType();
}
TEXTOBJ_UnlockText(TextObj);
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;

View File

@@ -173,5 +173,14 @@ GreGetCharWidthW(
_In_ UINT FirstChar,
_In_ UINT Count,
_In_reads_opt_(Count) PCWCH Safepwc,
_In_ ULONG fl,
_In_ FLONG fl,
_Out_writes_bytes_(Count * sizeof(INT)) PVOID pTmpBuffer);
BOOL APIENTRY
GreGetCharABCWidthsW(
_In_ HDC hDC,
_In_ UINT FirstChar,
_In_ UINT Count,
_In_reads_opt_(Count) PCWCH Safepwch,
_In_ FLONG fl,
_Out_writes_bytes_(Count * sizeof(ABC)) PVOID SafeBuffer);