From e6328fbf1ea01928dc1876736245a77a903db819 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Fri, 13 Mar 2026 18:24:26 +0900 Subject: [PATCH] [NTGDI][FREETYPE][SDK] Rewrite NtGdiGetCharABCWidthsW (#8704) Refactor and improve readability. JIRA issue: CORE-20505 - Add GreGetCharABCWidthsW helper function. - Rewrite NtGdiGetCharABCWidthsW by using GreGetCharABCWidthsW. --- sdk/include/psdk/ntgdi.h | 2 +- win32ss/gdi/ntgdi/font.c | 61 ++++++++++ win32ss/gdi/ntgdi/freetype.c | 211 ++++++++++------------------------- win32ss/gdi/ntgdi/text.h | 11 +- 4 files changed, 134 insertions(+), 151 deletions(-) diff --git a/sdk/include/psdk/ntgdi.h b/sdk/include/psdk/ntgdi.h index eeda8ff7294..f2271669f49 100644 --- a/sdk/include/psdk/ntgdi.h +++ b/sdk/include/psdk/ntgdi.h @@ -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); diff --git a/win32ss/gdi/ntgdi/font.c b/win32ss/gdi/ntgdi/font.c index 5639e20127c..d3ffb725071 100644 --- a/win32ss/gdi/ntgdi/font.c +++ b/win32ss/gdi/ntgdi/font.c @@ -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; +} diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 9eba4037d76..aad6972a49c 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -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; diff --git a/win32ss/gdi/ntgdi/text.h b/win32ss/gdi/ntgdi/text.h index b6d56992991..9b7eeaae377 100644 --- a/win32ss/gdi/ntgdi/text.h +++ b/win32ss/gdi/ntgdi/text.h @@ -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);