diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 9b9d9cc4fdd..8b9a4311cc4 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -493,9 +493,11 @@ BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage) } static __inline VOID -FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, - const LOGFONTW *LogFont, - const PLIST_ENTRY Head); +FindBestFontFromList( + _Out_ FONTOBJ **FontObj, + _Inout_ ULONG *MatchPenalty, + _In_ const LOGFONTW *LogFont, + _In_ const LIST_ENTRY *Head); static BOOL MatchFontName(PSHARED_FACE SharedFace, PUNICODE_STRING Name1, FT_UShort NameID, FT_UShort LangID); @@ -1716,6 +1718,88 @@ UINT FASTCALL IntGetCharSet(INT nIndex, FT_ULong CodePageRange1) /* pixels to points */ #define PX2PT(pixels) FT_MulDiv((pixels), 72, 96) +/* Borrowed and adapted from Wine */ +static BOOL select_charmap(FT_Face ft_face, FT_Encoding encoding) +{ + FT_Error ft_err = FT_Err_Invalid_CharMap_Handle; + FT_CharMap cmap0, cmap1, cmap2, cmap3, cmap_def; + FT_Int i; + + cmap0 = cmap1 = cmap2 = cmap3 = cmap_def = NULL; + + for (i = 0; i < ft_face->num_charmaps; i++) + { + if (ft_face->charmaps[i]->encoding == encoding) + { + DPRINT("found cmap with platform_id %u, encoding_id %u\n", + ft_face->charmaps[i]->platform_id, ft_face->charmaps[i]->encoding_id); + + switch (ft_face->charmaps[i]->platform_id) + { + default: + cmap_def = ft_face->charmaps[i]; + break; + case 0: /* Apple Unicode */ + cmap0 = ft_face->charmaps[i]; + break; + case 1: /* Macintosh */ + cmap1 = ft_face->charmaps[i]; + break; + case 2: /* ISO */ + cmap2 = ft_face->charmaps[i]; + break; + case 3: /* Microsoft */ + cmap3 = ft_face->charmaps[i]; + break; + } + } +#ifdef __REACTOS__ +// FIXME: +// Wine bug: for each loop iteration, a FT_Set_Charmap() call is made. +// ReactOS fix: Instead, loop until we retrieve all the cmap pointers +// of interest, then do one single FT_Set_Charmap() call using the +// preferred cmap. +#endif + + if (cmap3) /* prefer Microsoft cmap table */ + ft_err = FT_Set_Charmap(ft_face, cmap3); + else if (cmap1) + ft_err = FT_Set_Charmap(ft_face, cmap1); + else if (cmap2) + ft_err = FT_Set_Charmap(ft_face, cmap2); + else if (cmap0) + ft_err = FT_Set_Charmap(ft_face, cmap0); + else if (cmap_def) + ft_err = FT_Set_Charmap(ft_face, cmap_def); + } + + return ft_err == FT_Err_Ok; +} + +/* Borrowed from Wine */ +static FT_Encoding pick_charmap( FT_Face face, int charset ) +{ + static const FT_Encoding regular_order[] = { FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, FT_ENCODING_MS_SYMBOL, 0 }; + static const FT_Encoding symbol_order[] = { FT_ENCODING_MS_SYMBOL, FT_ENCODING_UNICODE, FT_ENCODING_APPLE_ROMAN, 0 }; + const FT_Encoding *encs = regular_order; + + if (charset == SYMBOL_CHARSET) encs = symbol_order; + + while (*encs != 0) + { + if (select_charmap( face, *encs )) break; + encs++; + } + + if (!face->charmap && face->num_charmaps) + { + if (!FT_Set_Charmap(face, face->charmaps[0])) + return face->charmap->encoding; + } + + return *encs; +} + static INT FASTCALL IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex) @@ -1819,6 +1903,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, FontGDI->OriginalWeight = FW_DONTCARE; FontGDI->RequestWeight = FW_NORMAL; + os2_version = 0; IntLockFreeType(); pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); if (pOS2) @@ -1835,52 +1920,8 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, FontGDI->OriginalWeight = WinFNT.weight; } } - IntUnLockFreeType(); - RtlInitAnsiString(&AnsiString, Face->family_name); - Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE); - if (NT_SUCCESS(Status)) - { - if (Face->style_name && Face->style_name[0] && - strcmp(Face->style_name, "Regular") != 0) - { - RtlInitAnsiString(&AnsiString, Face->style_name); - Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE); - if (!NT_SUCCESS(Status)) - { - RtlFreeUnicodeString(&Entry->FaceName); - } - } - else - { - RtlInitUnicodeString(&Entry->StyleName, NULL); - } - } - if (!NT_SUCCESS(Status)) - { - if (PrivateEntry) - { - if (pLoadFont->PrivateEntry == PrivateEntry) - { - pLoadFont->PrivateEntry = NULL; - } - else - { - RemoveEntryList(&PrivateEntry->ListEntry); - } - ExFreePoolWithTag(PrivateEntry, TAG_FONT); - } - if (FontGDI->Filename) - ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); - EngFreeMem(FontGDI); - SharedFace_Release(SharedFace); - ExFreePoolWithTag(Entry, TAG_FONT); - return 0; - } - os2_version = 0; - IntLockFreeType(); - pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2); if (pOS2) { os2_version = pOS2->version; @@ -1928,6 +1969,72 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, IntUnLockFreeType(); } + /* + * If this is the first time the font face is loaded, + * activate a charmap in the font face. + * + * Note from FreeType documentation: + * https://freetype.org/freetype2/docs/reference/ft2-character_mapping.html#ft_charmap + * + * When a new face is created (either through FT_New_Face or + * FT_Open_Face), the library looks for a Unicode charmap within + * the list and automatically activates it. If there is no + * Unicode charmap, FreeType doesn't set an 'active' charmap. + */ + if (CharSetIndex == -1) + { + IntLockFreeType(); + pick_charmap(Face, FontGDI->CharSet); + if (!Face->charmap) + { + DPRINT1("ERROR: Could not find desired charmap!\n"); + // TODO: Actually fail font creation! + // Error = FT_Err_Invalid_CharMap_Handle; + } + IntUnLockFreeType(); + } + + RtlInitAnsiString(&AnsiString, Face->family_name); + Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE); + if (NT_SUCCESS(Status)) + { + if (Face->style_name && Face->style_name[0] && + strcmp(Face->style_name, "Regular") != 0) + { + RtlInitAnsiString(&AnsiString, Face->style_name); + Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE); + if (!NT_SUCCESS(Status)) + { + RtlFreeUnicodeString(&Entry->FaceName); + } + } + else + { + RtlInitUnicodeString(&Entry->StyleName, NULL); + } + } + if (!NT_SUCCESS(Status)) + { + if (PrivateEntry) + { + if (pLoadFont->PrivateEntry == PrivateEntry) + { + pLoadFont->PrivateEntry = NULL; + } + else + { + RemoveEntryList(&PrivateEntry->ListEntry); + } + ExFreePoolWithTag(PrivateEntry, TAG_FONT); + } + if (FontGDI->Filename) + ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); + EngFreeMem(FontGDI); + SharedFace_Release(SharedFace); + ExFreePoolWithTag(Entry, TAG_FONT); + return 0; + } + ++FaceCount; DPRINT("Font loaded: %s (%s)\n", Face->family_name ? Face->family_name : "", @@ -2032,6 +2139,25 @@ IntGdiLoadFontByIndexFromMemory(PGDI_LOAD_FONT pLoadFont, FT_Long FontIndex) return 0; /* Failure */ } + /* + * In IntGdiLoadFontsFromMemory, when CharSetIndex == -1, + * we will always activate a charmap in the font face. + * + * Note from FreeType documentation: + * https://freetype.org/freetype2/docs/reference/ft2-character_mapping.html#ft_charmap + * + * When a new face is created (either through FT_New_Face or + * FT_Open_Face), the library looks for a Unicode charmap within + * the list and automatically activates it. If there is no + * Unicode charmap, FreeType doesn't set an 'active' charmap. + */ + pick_charmap(Face, DEFAULT_CHARSET); + if (!Face->charmap) + { + DPRINT1("WARNING: Could not find default charmap!\n"); + // Error = FT_Err_Invalid_CharMap_Handle; + } + pLoadFont->IsTrueType = FT_IS_SFNT(Face); num_faces = Face->num_faces; SharedFace = SharedFace_Create(Face, pLoadFont->Memory); @@ -3260,11 +3386,12 @@ IntFreeFontNames(FONT_NAMES *Names) * IntGetOutlineTextMetrics * */ -INT FASTCALL -IntGetOutlineTextMetrics(PFONTGDI FontGDI, - UINT Size, - OUTLINETEXTMETRICW *Otm, - BOOL bLocked) +UINT FASTCALL +IntGetOutlineTextMetrics( + _In_ PFONTGDI FontGDI, + _In_ UINT Size, // If 0, then Otm == NULL. Otherwise, specifies size of Otm + _Out_ POUTLINETEXTMETRICW Otm, // If Otm != NULL, on return Otm->otmSize should be <= Size + _In_ BOOL bLocked) { TT_OS2 *pOS2; TT_HoriHeader *pHori; @@ -4414,86 +4541,27 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight) BOOL FASTCALL -TextIntUpdateSize(PDC dc, - PTEXTOBJ TextObj, - PFONTGDI FontGDI, - BOOL bDoLock) +TextIntUpdateSize( + _In_ PDC dc, + _In_ PTEXTOBJ TextObj, + _In_ PFONTGDI FontGDI, + _In_ BOOL bDoLock) { - FT_Face face; - INT error, n; - FT_CharMap charmap, found; - LOGFONTW *plf; + FT_Face face = FontGDI->SharedFace->Face; + PLOGFONTW plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; + FT_Error error; + + ASSERT(face->charmap); if (bDoLock) IntLockFreeType(); - face = FontGDI->SharedFace->Face; - if (face->charmap == NULL) - { - DPRINT("WARNING: No charmap selected!\n"); - DPRINT("This font face has %d charmaps\n", face->num_charmaps); - - found = NULL; - for (n = 0; n < face->num_charmaps; n++) - { - charmap = face->charmaps[n]; - if (charmap->encoding == FT_ENCODING_UNICODE) - { - found = charmap; - break; - } - } - if (!found) - { - for (n = 0; n < face->num_charmaps; n++) - { - charmap = face->charmaps[n]; - if (charmap->platform_id == TT_PLATFORM_APPLE_UNICODE) - { - found = charmap; - break; - } - } - } - if (!found) - { - for (n = 0; n < face->num_charmaps; n++) - { - charmap = face->charmaps[n]; - if (charmap->encoding == FT_ENCODING_MS_SYMBOL) - { - found = charmap; - break; - } - } - } - if (!found && face->num_charmaps > 0) - { - found = face->charmaps[0]; - } - if (!found) - { - DPRINT1("WARNING: Could not find desired charmap!\n"); - } - else - { - DPRINT("Found charmap encoding: %i\n", found->encoding); - error = FT_Set_Charmap(face, found); - if (error) - { - DPRINT1("WARNING: Could not set the charmap!\n"); - } - } - } - - plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; - error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); if (bDoLock) IntUnLockFreeType(); - if (error) + if (error != FT_Err_Ok) { DPRINT1("Error in setting pixel sizes: %d\n", error); return FALSE; @@ -5389,15 +5457,14 @@ DWORD FASTCALL ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) { - DWORD size = 0; - DWORD num_ranges = 0; + ULONG size = 0; + ULONG num_ranges = 0; FT_Face face = Font->SharedFace->Face; - if (face->charmap == NULL) - { - DPRINT1("FIXME: No charmap selected! This is a BUG!\n"); - return 0; - } + ASSERT(face->charmap); + + /* Lock FreeType for face lookup */ + IntLockFreeType(); if (face->charmap->encoding == FT_ENCODING_UNICODE) { @@ -5409,7 +5476,8 @@ ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n", face->num_glyphs, glyph_code, char_code); - if (!glyph_code) return 0; + if (!glyph_code) + goto Quit; if (glyphset) { @@ -5424,7 +5492,7 @@ ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) if (char_code < char_code_prev) { DPRINT1("Expected increasing char code from FT_Get_Next_Char\n"); - return 0; + goto Quit; } if (char_code - char_code_prev > 1) { @@ -5455,6 +5523,11 @@ ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset) glyphset->cRanges = num_ranges; glyphset->flAccel = 0; } + +Quit: + /* Unlock FreeType */ + IntUnLockFreeType(); + return size; } @@ -5473,9 +5546,8 @@ ftGdiGetTextMetricsW( TT_OS2 *pOS2; TT_HoriHeader *pHori; FT_WinFNT_HeaderRec Win; - ULONG Error; + FT_Error Error; NTSTATUS Status = STATUS_SUCCESS; - LOGFONTW *plf; if (!ptmwi) { @@ -5493,19 +5565,19 @@ ftGdiGetTextMetricsW( TextObj = RealizeFontInit(pdcattr->hlfntNew); if (NULL != TextObj) { - plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; FontGDI = ObjToGDI(TextObj->Font, FONT); + BOOL Success; Face = FontGDI->SharedFace->Face; // NOTE: GetTextMetrics simply ignores lfEscapement and XFORM. IntLockFreeType(); - Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); + Success = TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); FT_Set_Transform(Face, NULL, NULL); IntUnLockFreeType(); - if (0 != Error) + if (!Success) { DPRINT1("Error in setting pixel sizes: %u\n", Error); Status = STATUS_UNSUCCESSFUL; @@ -5949,13 +6021,13 @@ GetFontPenalty(const LOGFONTW * LogFont, static __inline VOID FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, const LOGFONTW *LogFont, - const PLIST_ENTRY Head) + const LIST_ENTRY *Head) { ULONG Penalty; PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; FONTGDI *FontGDI; - OUTLINETEXTMETRICW *Otm = NULL; + POUTLINETEXTMETRICW Otm = NULL; UINT OtmSize, OldOtmSize = 0; FT_Face Face; @@ -5964,9 +6036,8 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, ASSERT(LogFont); ASSERT(Head); - /* Start with a pretty big buffer */ - OldOtmSize = 0x200; - Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT); + /* Start with no buffer */ + OldOtmSize = 0; /* get the FontObj of lowest penalty */ for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) @@ -5985,6 +6056,8 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, if (Otm) ExFreePoolWithTag(Otm, GDITAG_TEXT); Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT); + if (Otm) + OldOtmSize = OtmSize; } /* update FontObj if lowest penalty */ @@ -5998,7 +6071,7 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, if (!OtmSize) continue; - OldOtmSize = OtmSize; + ASSERT(OtmSize <= OldOtmSize); Penalty = GetFontPenalty(LogFont, Otm, Face->style_name); if (*MatchPenalty == MAXULONG || Penalty < *MatchPenalty) @@ -7683,12 +7756,10 @@ NtGdiGetCharABCWidthsW( PTEXTOBJ TextObj; PFONTGDI FontGDI; FT_Face face; - FT_CharMap charmap, found = NULL; UINT i, glyph_index, BufferSize; - HFONT hFont = 0; + HFONT hFont = NULL; NTSTATUS Status = STATUS_SUCCESS; PWCHAR Safepwch = NULL; - LOGFONTW *plf; if (!Buffer) { @@ -7721,8 +7792,8 @@ NtGdiGetCharABCWidthsW( if (!NT_SUCCESS(Status)) { - if(Safepwch) - ExFreePoolWithTag(Safepwch , GDITAG_TEXT); + if (Safepwch) + ExFreePoolWithTag(Safepwch, GDITAG_TEXT); SetLastNtError(Status); return FALSE; @@ -7734,8 +7805,8 @@ NtGdiGetCharABCWidthsW( if (SafeBuff == NULL) { - if(Safepwch) - ExFreePoolWithTag(Safepwch , GDITAG_TEXT); + if (Safepwch) + ExFreePoolWithTag(Safepwch, GDITAG_TEXT); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; @@ -7746,8 +7817,8 @@ NtGdiGetCharABCWidthsW( { ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); - if(Safepwch) - ExFreePoolWithTag(Safepwch , GDITAG_TEXT); + if (Safepwch) + ExFreePoolWithTag(Safepwch, GDITAG_TEXT); EngSetLastError(ERROR_INVALID_HANDLE); return FALSE; @@ -7772,40 +7843,10 @@ NtGdiGetCharABCWidthsW( FontGDI = ObjToGDI(TextObj->Font, FONT); face = FontGDI->SharedFace->Face; - if (face->charmap == NULL) - { - 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(); - } - - plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; // NOTE: GetCharABCWidths simply ignores lfEscapement and XFORM. IntLockFreeType(); - IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); + TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); FT_Set_Transform(face, NULL, NULL); for (i = FirstChar; i < FirstChar+Count; i++) @@ -7853,8 +7894,8 @@ NtGdiGetCharABCWidthsW( ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); - if(Safepwch) - ExFreePoolWithTag(Safepwch , GDITAG_TEXT); + if (Safepwch) + ExFreePoolWithTag(Safepwch, GDITAG_TEXT); if (!NT_SUCCESS(Status)) { @@ -7887,11 +7928,9 @@ NtGdiGetCharWidthW( PTEXTOBJ TextObj; PFONTGDI FontGDI; FT_Face face; - FT_CharMap charmap, found = NULL; UINT i, glyph_index, BufferSize; - HFONT hFont = 0; + HFONT hFont = NULL; PWCHAR Safepwc = NULL; - LOGFONTW *plf; if (UnSafepwc) { @@ -7961,40 +8000,10 @@ NtGdiGetCharWidthW( FontGDI = ObjToGDI(TextObj->Font, FONT); face = FontGDI->SharedFace->Face; - if (face->charmap == NULL) - { - 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"); - - if(Safepwc) - ExFreePoolWithTag(Safepwc, GDITAG_TEXT); - - ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); - EngSetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - IntLockFreeType(); - FT_Set_Charmap(face, found); - IntUnLockFreeType(); - } - - plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; // NOTE: GetCharWidth simply ignores lfEscapement and XFORM. IntLockFreeType(); - IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight); + TextIntUpdateSize(dc, TextObj, FontGDI, FALSE); FT_Set_Transform(face, NULL, NULL); for (i = FirstChar; i < FirstChar+Count; i++) @@ -8017,7 +8026,7 @@ NtGdiGetCharWidthW( TEXTOBJ_UnlockText(TextObj); MmCopyToCaller(Buffer, SafeBuff, BufferSize); - if(Safepwc) + if (Safepwc) ExFreePoolWithTag(Safepwc, GDITAG_TEXT); ExFreePoolWithTag(SafeBuff, GDITAG_TEXT); diff --git a/win32ss/gdi/ntgdi/text.h b/win32ss/gdi/ntgdi/text.h index 11e01ab7800..287e0dc2a86 100644 --- a/win32ss/gdi/ntgdi/text.h +++ b/win32ss/gdi/ntgdi/text.h @@ -130,14 +130,34 @@ BOOL FASTCALL IntGdiRemoveFontResource( HANDLE FASTCALL IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded); BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont); ULONG FASTCALL ftGdiGetGlyphOutline(PDC, WCHAR, UINT, LPGLYPHMETRICS, ULONG, PVOID, const MAT2*, BOOL); -INT FASTCALL IntGetOutlineTextMetrics(PFONTGDI, UINT, OUTLINETEXTMETRICW*, BOOL); -BOOL FASTCALL TextIntUpdateSize(PDC,PTEXTOBJ,PFONTGDI,BOOL); + +UINT FASTCALL +IntGetOutlineTextMetrics( + _In_ PFONTGDI FontGDI, + _In_ UINT Size, // If 0, then Otm == NULL. Otherwise, specifies size of Otm + _Out_ POUTLINETEXTMETRICW Otm, // If Otm != NULL, on return Otm->otmSize should be <= Size + _In_ BOOL bLocked); + +BOOL +FASTCALL +TextIntUpdateSize( + _In_ PDC dc, + _In_ PTEXTOBJ TextObj, + _In_ PFONTGDI FontGDI, + _In_ BOOL bDoLock); + BOOL FASTCALL ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS); BOOL FASTCALL TextIntGetTextExtentPoint(PDC, PTEXTOBJ, PCWCH, INT, ULONG, PINT, PINT, PSIZE, FLONG); BOOL FASTCALL ftGdiGetTextMetricsW(HDC,PTMW_INTERNAL); DWORD FASTCALL IntGetFontLanguageInfo(PDC); INT FASTCALL ftGdiGetTextCharsetInfo(PDC,PFONTSIGNATURE,DWORD); -DWORD FASTCALL ftGetFontUnicodeRanges(PFONTGDI, PGLYPHSET); + +ULONG +FASTCALL +ftGetFontUnicodeRanges( + _In_ PFONTGDI Font, + _Out_opt_ PGLYPHSET glyphset); + DWORD FASTCALL ftGdiGetFontData(PFONTGDI,DWORD,DWORD,PVOID,DWORD); BOOL FASTCALL IntGdiGetFontResourceInfo(PUNICODE_STRING,PVOID,DWORD*,DWORD); BOOL FASTCALL ftGdiRealizationInfo(PFONTGDI,PREALIZATION_INFO);