xref: /reactos/win32ss/gdi/ntgdi/freetype.c (revision 3bb1e644)
1 /*
2  * PROJECT:         ReactOS win32 kernel mode subsystem
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         FreeType font engine interface
5  * PROGRAMMERS:     Copyright 2001 Huw D M Davies for CodeWeavers.
6  *                  Copyright 2006 Dmitry Timoshkov for CodeWeavers.
7  *                  Copyright 2016-2024 Katayama Hirofumi MZ.
8  */
9 
10 /** Includes ******************************************************************/
11 
12 #include <win32k.h>
13 
14 #include FT_GLYPH_H
15 #include FT_TYPE1_TABLES_H
16 #include FT_TRUETYPE_TABLES_H
17 #include FT_TRUETYPE_TAGS_H
18 #include FT_TRIGONOMETRY_H
19 #include FT_BITMAP_H
20 #include FT_OUTLINE_H
21 #include FT_WINFONTS_H
22 #include FT_SFNT_NAMES_H
23 #include FT_SYNTHESIS_H
24 #include FT_TRUETYPE_IDS_H
25 
26 #ifndef FT_INTERNAL_INTERNAL_H
27     #define  FT_INTERNAL_INTERNAL_H  <freetype/internal/internal.h>
28     #include FT_INTERNAL_INTERNAL_H
29 #endif
30 #include FT_INTERNAL_TRUETYPE_TYPES_H
31 
32 #include <gdi/eng/floatobj.h>
33 #include "font.h"
34 
35 #define NDEBUG
36 #include <debug.h>
37 
38 typedef struct _FONTLINK
39 {
40     LIST_ENTRY ListEntry; //< Entry in the FONTLINK_CHAIN::FontLinkList
41     BOOL bIgnore;
42     LOGFONTW LogFont;
43     PSHARED_FACE SharedFace;
44 } FONTLINK, *PFONTLINK;
45 
46 typedef struct _FONTLINK_CHAIN
47 {
48     LIST_ENTRY FontLinkList; //< List of FONTLINK's
49     LOGFONTW LogFont;
50     PZZWSTR pszzFontLink;
51     PTEXTOBJ pBaseTextObj;
52     FT_Face pDefFace;
53 } FONTLINK_CHAIN, *PFONTLINK_CHAIN;
54 
55 typedef struct _FONTLINK_CACHE
56 {
57     LIST_ENTRY ListEntry;
58     LOGFONTW LogFont;
59     FONTLINK_CHAIN Chain;
60 } FONTLINK_CACHE, *PFONTLINK_CACHE;
61 
62 #define FONTLINK_DEFAULT_CHAR 0x30FB // U+30FB (KATAKANA MIDDLE DOT)
63 
64 static DWORD s_chFontLinkDefaultChar = FONTLINK_DEFAULT_CHAR;
65 static WCHAR s_szDefFontLinkFileName[MAX_PATH] = L"";
66 static WCHAR s_szDefFontLinkFontName[MAX_PATH] = L"";
67 static BOOL s_fFontLinkUseAnsi = FALSE;
68 static BOOL s_fFontLinkUseOem = FALSE;
69 static BOOL s_fFontLinkUseSymbol = FALSE;
70 
71 #define MAX_FONTLINK_CACHE 128
72 static RTL_STATIC_LIST_HEAD(g_FontLinkCache); // The list of FONTLINK_CACHE
73 static LONG g_nFontLinkCacheCount = 0;
74 
75 static SIZE_T
SZZ_GetSize(_In_ PCZZWSTR pszz)76 SZZ_GetSize(_In_ PCZZWSTR pszz)
77 {
78     SIZE_T ret = 0, cch;
79     const WCHAR *pch = pszz;
80     while (*pch)
81     {
82         cch = wcslen(pch) + 1;
83         ret += cch;
84         pch += cch;
85     }
86     ++ret;
87     return ret * sizeof(WCHAR);
88 }
89 
90 static inline NTSTATUS
FontLink_LoadSettings(VOID)91 FontLink_LoadSettings(VOID)
92 {
93     NTSTATUS Status;
94     HKEY hKey;
95     DWORD cbData, dwValue;
96 
97     // Set the default values
98     s_chFontLinkDefaultChar = FONTLINK_DEFAULT_CHAR;
99 
100     // Open the registry key
101     Status = RegOpenKey(
102         L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink",
103         &hKey);
104     if (!NT_SUCCESS(Status))
105         return Status;
106 
107     cbData = sizeof(dwValue);
108     Status = RegQueryValue(hKey, L"FontLinkDefaultChar", REG_DWORD, &dwValue, &cbData);
109     if (NT_SUCCESS(Status) && cbData == sizeof(dwValue))
110         s_chFontLinkDefaultChar = dwValue;
111 
112     ZwClose(hKey); // Close the registry key
113     return STATUS_SUCCESS;
114 }
115 
116 static inline NTSTATUS
FontLink_LoadDefaultFonts(VOID)117 FontLink_LoadDefaultFonts(VOID)
118 {
119     NTSTATUS Status;
120     HKEY hKey;
121     DWORD cbData;
122     WCHAR szValue[MAX_PATH];
123 
124     // Set the default values
125     s_szDefFontLinkFileName[0] = s_szDefFontLinkFontName[0] = UNICODE_NULL;
126 
127     // Open the registry key
128     Status = RegOpenKey(
129         L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\FontAssoc\\Associated DefaultFonts",
130         &hKey);
131     if (!NT_SUCCESS(Status))
132         return Status;
133 
134     cbData = sizeof(szValue);
135     Status = RegQueryValue(hKey, L"AssocSystemFont", REG_SZ, szValue, &cbData);
136     if (NT_SUCCESS(Status))
137     {
138         szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
139         RtlStringCchCopyW(s_szDefFontLinkFileName, _countof(s_szDefFontLinkFileName), szValue);
140     }
141 
142     cbData = sizeof(szValue);
143     Status = RegQueryValue(hKey, L"FontPackage", REG_SZ, szValue, &cbData);
144     if (NT_SUCCESS(Status))
145     {
146         szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
147         RtlStringCchCopyW(s_szDefFontLinkFontName, _countof(s_szDefFontLinkFontName), szValue);
148     }
149 
150     ZwClose(hKey); // Close the registry key
151     return STATUS_SUCCESS;
152 }
153 
154 static inline NTSTATUS
FontLink_LoadDefaultCharset(VOID)155 FontLink_LoadDefaultCharset(VOID)
156 {
157     NTSTATUS Status;
158     HKEY hKey;
159     DWORD cbData;
160     WCHAR szValue[8];
161 
162     // Set the default values
163     s_fFontLinkUseAnsi = s_fFontLinkUseOem = s_fFontLinkUseSymbol = FALSE;
164 
165     // Open the registry key
166     Status = RegOpenKey(
167         L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\FontAssoc\\Associated Charset",
168         &hKey);
169     if (!NT_SUCCESS(Status))
170         return Status;
171 
172     cbData = sizeof(szValue);
173     Status = RegQueryValue(hKey, L"ANSI(00)", REG_SZ, szValue, &cbData);
174     if (NT_SUCCESS(Status))
175     {
176         szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
177         s_fFontLinkUseAnsi = !_wcsicmp(szValue, L"YES");
178     }
179 
180     cbData = sizeof(szValue);
181     Status = RegQueryValue(hKey, L"OEM(FF)", REG_SZ, szValue, &cbData);
182     if (NT_SUCCESS(Status))
183     {
184         szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
185         s_fFontLinkUseOem = !_wcsicmp(szValue, L"YES");
186     }
187 
188     cbData = sizeof(szValue);
189     Status = RegQueryValue(hKey, L"SYMBOL(02)", REG_SZ, szValue, &cbData);
190     if (NT_SUCCESS(Status))
191     {
192         szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun
193         s_fFontLinkUseSymbol = !_wcsicmp(szValue, L"YES");
194     }
195 
196     ZwClose(hKey); // Close the registry key
197     return STATUS_SUCCESS;
198 }
199 
200 static inline VOID
FontLink_Destroy(_Inout_ PFONTLINK pLink)201 FontLink_Destroy(_Inout_ PFONTLINK pLink)
202 {
203     ASSERT(pLink);
204     ExFreePoolWithTag(pLink, TAG_FONT);
205 }
206 
207 static inline BOOL
FontLink_Chain_IsPopulated(const FONTLINK_CHAIN * pChain)208 FontLink_Chain_IsPopulated(const FONTLINK_CHAIN *pChain)
209 {
210     return pChain->LogFont.lfFaceName[0];
211 }
212 
213 static VOID
FontLink_Chain_Free(_Inout_ PFONTLINK_CHAIN pChain)214 FontLink_Chain_Free(
215     _Inout_ PFONTLINK_CHAIN pChain)
216 {
217     PLIST_ENTRY Entry;
218     PFONTLINK pLink;
219 
220     if (!FontLink_Chain_IsPopulated(pChain)) // The chain is not populated yet
221         return;
222 
223     if (pChain->pszzFontLink)
224         ExFreePoolWithTag(pChain->pszzFontLink, TAG_FONT);
225 
226     while (!IsListEmpty(&pChain->FontLinkList))
227     {
228         Entry = RemoveHeadList(&pChain->FontLinkList);
229         pLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
230         FontLink_Destroy(pLink);
231     }
232 }
233 
234 static inline VOID
FontLink_AddCache(_In_ PFONTLINK_CACHE pCache)235 FontLink_AddCache(
236     _In_ PFONTLINK_CACHE pCache)
237 {
238     PLIST_ENTRY Entry;
239 
240     /* Add the new cache entry to the top of the cache list */
241     ++g_nFontLinkCacheCount;
242     InsertHeadList(&g_FontLinkCache, &pCache->ListEntry);
243 
244     /* If there are too many cache entries in the list, remove the oldest one at the bottom */
245     if (g_nFontLinkCacheCount > MAX_FONTLINK_CACHE)
246     {
247         ASSERT(!IsListEmpty(&g_FontLinkCache));
248         Entry = RemoveTailList(&g_FontLinkCache);
249         --g_nFontLinkCacheCount;
250         pCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
251         FontLink_Chain_Free(&pCache->Chain);
252         ExFreePoolWithTag(pCache, TAG_FONT);
253     }
254 }
255 
256 static inline VOID
IntRebaseList(_Inout_ PLIST_ENTRY pNewHead,_Inout_ PLIST_ENTRY pOldHead)257 IntRebaseList(
258     _Inout_ PLIST_ENTRY pNewHead,
259     _Inout_ PLIST_ENTRY pOldHead)
260 {
261     PLIST_ENTRY Entry;
262 
263     ASSERT(pNewHead != pOldHead);
264 
265     InitializeListHead(pNewHead);
266     while (!IsListEmpty(pOldHead))
267     {
268         Entry = RemoveTailList(pOldHead);
269         InsertHeadList(pNewHead, Entry);
270     }
271 }
272 
273 /// Add the chain to the cache (g_FontLinkCache) if the chain had been populated.
274 /// @param pChain The chain.
275 static inline VOID
FontLink_Chain_Finish(_Inout_ PFONTLINK_CHAIN pChain)276 FontLink_Chain_Finish(
277     _Inout_ PFONTLINK_CHAIN pChain)
278 {
279     PFONTLINK_CACHE pCache;
280 
281     if (!FontLink_Chain_IsPopulated(pChain))
282         return; // The chain is not populated yet
283 
284     pCache = ExAllocatePoolWithTag(PagedPool, sizeof(FONTLINK_CACHE), TAG_FONT);
285     if (!pCache)
286         return; // Out of memory
287 
288     pCache->LogFont = pChain->LogFont;
289     pCache->Chain = *pChain;
290     IntRebaseList(&pCache->Chain.FontLinkList, &pChain->FontLinkList);
291 
292     FontLink_AddCache(pCache);
293 }
294 
295 static inline PFONTLINK_CACHE
FontLink_FindCache(_In_ const LOGFONTW * pLogFont)296 FontLink_FindCache(
297     _In_ const LOGFONTW* pLogFont)
298 {
299     PLIST_ENTRY Entry;
300     PFONTLINK_CACHE pLinkCache;
301     for (Entry = g_FontLinkCache.Flink; Entry != &g_FontLinkCache; Entry = Entry->Flink)
302     {
303         pLinkCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
304         if (RtlEqualMemory(&pLinkCache->LogFont, pLogFont, sizeof(LOGFONTW)))
305             return pLinkCache;
306     }
307     return NULL;
308 }
309 
310 static inline VOID
FontLink_CleanupCache(VOID)311 FontLink_CleanupCache(VOID)
312 {
313     PLIST_ENTRY Entry;
314     PFONTLINK_CACHE pLinkCache;
315 
316     while (!IsListEmpty(&g_FontLinkCache))
317     {
318         Entry = RemoveHeadList(&g_FontLinkCache);
319         pLinkCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
320         FontLink_Chain_Free(&pLinkCache->Chain);
321         ExFreePoolWithTag(pLinkCache, TAG_FONT);
322     }
323 
324     g_nFontLinkCacheCount = 0;
325 }
326 
327 /* The ranges of the surrogate pairs */
328 #define HIGH_SURROGATE_MIN 0xD800U
329 #define HIGH_SURROGATE_MAX 0xDBFFU
330 #define LOW_SURROGATE_MIN  0xDC00U
331 #define LOW_SURROGATE_MAX  0xDFFFU
332 
333 #define IS_HIGH_SURROGATE(ch0) (HIGH_SURROGATE_MIN <= (ch0) && (ch0) <= HIGH_SURROGATE_MAX)
334 #define IS_LOW_SURROGATE(ch1)  (LOW_SURROGATE_MIN  <= (ch1) && (ch1) <=  LOW_SURROGATE_MAX)
335 
336 static inline DWORD
Utf32FromSurrogatePair(DWORD ch0,DWORD ch1)337 Utf32FromSurrogatePair(DWORD ch0, DWORD ch1)
338 {
339     return ((ch0 - HIGH_SURROGATE_MIN) << 10) + (ch1 - LOW_SURROGATE_MIN) + 0x10000;
340 }
341 
342 /* TPMF_FIXED_PITCH is confusing; brain-dead api */
343 #ifndef _TMPF_VARIABLE_PITCH
344     #define _TMPF_VARIABLE_PITCH    TMPF_FIXED_PITCH
345 #endif
346 
347 /* Is bold emulation necessary? */
348 #define EMUBOLD_NEEDED(original, request) \
349     (((request) != FW_DONTCARE) && ((request) - (original) >= FW_BOLD - FW_MEDIUM))
350 
351 extern const MATRIX gmxWorldToDeviceDefault;
352 extern const MATRIX gmxWorldToPageDefault;
353 static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
354 static POINTL PointZero = { 0, 0 };
355 
356 /* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
357 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
358 
359 FT_Library  g_FreeTypeLibrary;
360 
361 /* registry */
362 static UNICODE_STRING g_FontRegPath =
363     RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
364 
365 
366 /* The FreeType library is not thread safe, so we have
367    to serialize access to it */
368 static PFAST_MUTEX      g_FreeTypeLock;
369 
370 static RTL_STATIC_LIST_HEAD(g_FontListHead);
371 static BOOL             g_RenderingEnabled = TRUE;
372 
373 #define ASSERT_FREETYPE_LOCK_HELD() \
374     ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
375 
376 #define ASSERT_FREETYPE_LOCK_NOT_HELD() \
377     ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
378 
379 #define IntLockFreeType() \
380 do { \
381     ASSERT_FREETYPE_LOCK_NOT_HELD(); \
382     ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock); \
383 } while (0)
384 
385 #define IntUnLockFreeType() \
386 do { \
387     ASSERT_FREETYPE_LOCK_HELD(); \
388     ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock); \
389 } while(0)
390 
391 #define MAX_FONT_CACHE 256
392 
393 static RTL_STATIC_LIST_HEAD(g_FontCacheListHead);
394 static UINT g_FontCacheNumEntries;
395 
396 static PWCHAR g_ElfScripts[32] =   /* These are in the order of the fsCsb[0] bits */
397 {
398     L"Western", /* 00 */
399     L"Central_European",
400     L"Cyrillic",
401     L"Greek",
402     L"Turkish",
403     L"Hebrew",
404     L"Arabic",
405     L"Baltic",
406     L"Vietnamese", /* 08 */
407     NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 15 */
408     L"Thai",
409     L"Japanese",
410     L"CHINESE_GB2312",
411     L"Hangul",
412     L"CHINESE_BIG5",
413     L"Hangul(Johab)",
414     NULL, NULL, /* 23 */
415     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
416     L"Symbol" /* 31 */
417 };
418 
419 /*
420  *  For TranslateCharsetInfo
421  */
422 #define CP_SYMBOL   42
423 #define MAXTCIINDEX 32
424 static const CHARSETINFO g_FontTci[MAXTCIINDEX] =
425 {
426     /* ANSI */
427     { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
428     { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
429     { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
430     { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
431     { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
432     { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
433     { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
434     { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
435     { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
436     /* reserved by ANSI */
437     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
438     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
439     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
440     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
441     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
442     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
443     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
444     /* ANSI and OEM */
445     { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
446     { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
447     { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
448     { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
449     { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
450     { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
451     /* Reserved for alternate ANSI and OEM */
452     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
453     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
454     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
455     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
456     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
457     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
458     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
459     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
460     /* Reserved for system */
461     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
462     { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
463 };
464 
465 #ifndef CP_OEMCP
466     #define CP_OEMCP  1
467     #define CP_MACCP  2
468 #endif
469 
470 /* Get charset from specified codepage.
471    g_FontTci is used also in TranslateCharsetInfo. */
IntCharSetFromCodePage(UINT uCodePage)472 BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage)
473 {
474     UINT i;
475 
476     if (uCodePage == CP_OEMCP)
477         return OEM_CHARSET;
478 
479     if (uCodePage == CP_MACCP)
480         return MAC_CHARSET;
481 
482     for (i = 0; i < MAXTCIINDEX; ++i)
483     {
484         if (g_FontTci[i].ciACP == 0)
485             continue;
486 
487         if (g_FontTci[i].ciACP == uCodePage)
488             return g_FontTci[i].ciCharset;
489     }
490 
491     return DEFAULT_CHARSET;
492 }
493 
494 static __inline VOID
495 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
496                      const LOGFONTW *LogFont,
497                      const PLIST_ENTRY Head);
498 
499 static BOOL
500 MatchFontName(PSHARED_FACE SharedFace, PUNICODE_STRING Name1, FT_UShort NameID, FT_UShort LangID);
501 
502 static BOOL
FontLink_PrepareFontInfo(_Inout_ PFONTLINK pFontLink)503 FontLink_PrepareFontInfo(
504     _Inout_ PFONTLINK pFontLink)
505 {
506     FONTOBJ *pFontObj;
507     ULONG MatchPenalty;
508     UNICODE_STRING FaceName;
509     PPROCESSINFO Win32Process;
510     PFONTGDI pFontGDI;
511 
512     ASSERT_FREETYPE_LOCK_HELD();
513 
514     if (pFontLink->bIgnore)
515         return FALSE;
516 
517     if (pFontLink->SharedFace)
518         return TRUE;
519 
520     MatchPenalty = MAXULONG;
521     pFontObj = NULL;
522 
523     // Search private fonts
524     Win32Process = PsGetCurrentProcessWin32Process();
525     FindBestFontFromList(&pFontObj, &MatchPenalty, &pFontLink->LogFont,
526                          &Win32Process->PrivateFontListHead);
527 
528     // Search system fonts
529     FindBestFontFromList(&pFontObj, &MatchPenalty, &pFontLink->LogFont,
530                          &g_FontListHead);
531 
532     if (!pFontObj) // Not found?
533     {
534         pFontLink->bIgnore = TRUE;
535         return FALSE;
536     }
537 
538     pFontGDI = ObjToGDI(pFontObj, FONT);
539     pFontLink->SharedFace = pFontGDI->SharedFace;
540 
541     // FontLink uses family name
542     RtlInitUnicodeString(&FaceName, pFontLink->LogFont.lfFaceName);
543     if (!MatchFontName(pFontLink->SharedFace, &FaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) &&
544         !MatchFontName(pFontLink->SharedFace, &FaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID))
545     {
546         pFontLink->bIgnore = TRUE;
547         return FALSE;
548     }
549 
550     return TRUE;
551 }
552 
553 /* list head */
554 static RTL_STATIC_LIST_HEAD(g_FontSubstListHead);
555 
556 static void
SharedMem_AddRef(PSHARED_MEM Ptr)557 SharedMem_AddRef(PSHARED_MEM Ptr)
558 {
559     ASSERT_FREETYPE_LOCK_HELD();
560 
561     ++Ptr->RefCount;
562 }
563 
564 static void
SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)565 SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
566 {
567     Cache->OutlineRequiredSize = 0;
568     RtlInitUnicodeString(&Cache->FontFamily, NULL);
569     RtlInitUnicodeString(&Cache->FullName, NULL);
570 }
571 
572 static PSHARED_FACE
SharedFace_Create(FT_Face Face,PSHARED_MEM Memory)573 SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
574 {
575     PSHARED_FACE Ptr;
576     Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
577     if (Ptr)
578     {
579         Ptr->Face = Face;
580         Ptr->RefCount = 1;
581         Ptr->Memory = Memory;
582         SharedFaceCache_Init(&Ptr->EnglishUS);
583         SharedFaceCache_Init(&Ptr->UserLanguage);
584 
585         SharedMem_AddRef(Memory);
586         DPRINT("Creating SharedFace for %s\n", Face->family_name ? Face->family_name : "<NULL>");
587     }
588     return Ptr;
589 }
590 
591 static PSHARED_MEM
SharedMem_Create(PBYTE Buffer,ULONG BufferSize,BOOL IsMapping)592 SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
593 {
594     PSHARED_MEM Ptr;
595     Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
596     if (Ptr)
597     {
598         Ptr->Buffer = Buffer;
599         Ptr->BufferSize = BufferSize;
600         Ptr->RefCount = 1;
601         Ptr->IsMapping = IsMapping;
602         DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
603     }
604     return Ptr;
605 }
606 
607 static void
SharedFace_AddRef(PSHARED_FACE Ptr)608 SharedFace_AddRef(PSHARED_FACE Ptr)
609 {
610     ASSERT_FREETYPE_LOCK_HELD();
611 
612     ++Ptr->RefCount;
613 }
614 
615 static void
RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)616 RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
617 {
618     ASSERT_FREETYPE_LOCK_HELD();
619 
620     FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
621     RemoveEntryList(&Entry->ListEntry);
622     ExFreePoolWithTag(Entry, TAG_FONT);
623     g_FontCacheNumEntries--;
624     ASSERT(g_FontCacheNumEntries <= MAX_FONT_CACHE);
625 }
626 
627 static void
RemoveCacheEntries(FT_Face Face)628 RemoveCacheEntries(FT_Face Face)
629 {
630     PLIST_ENTRY CurrentEntry, NextEntry;
631     PFONT_CACHE_ENTRY FontEntry;
632 
633     ASSERT_FREETYPE_LOCK_HELD();
634 
635     for (CurrentEntry = g_FontCacheListHead.Flink;
636          CurrentEntry != &g_FontCacheListHead;
637          CurrentEntry = NextEntry)
638     {
639         FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
640         NextEntry = CurrentEntry->Flink;
641 
642         if (FontEntry->Hashed.Face == Face)
643         {
644             RemoveCachedEntry(FontEntry);
645         }
646     }
647 }
648 
SharedMem_Release(PSHARED_MEM Ptr)649 static void SharedMem_Release(PSHARED_MEM Ptr)
650 {
651     ASSERT_FREETYPE_LOCK_HELD();
652     ASSERT(Ptr->RefCount > 0);
653 
654     if (Ptr->RefCount <= 0)
655         return;
656 
657     --Ptr->RefCount;
658     if (Ptr->RefCount == 0)
659     {
660         DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
661         if (Ptr->IsMapping)
662             MmUnmapViewInSystemSpace(Ptr->Buffer);
663         else
664             ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
665         ExFreePoolWithTag(Ptr, TAG_FONT);
666     }
667 }
668 
669 static void
SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)670 SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
671 {
672     RtlFreeUnicodeString(&Cache->FontFamily);
673     RtlFreeUnicodeString(&Cache->FullName);
674 }
675 
676 static void
SharedFace_Release(PSHARED_FACE Ptr)677 SharedFace_Release(PSHARED_FACE Ptr)
678 {
679     IntLockFreeType();
680     ASSERT(Ptr->RefCount > 0);
681 
682     if (Ptr->RefCount <= 0)
683         return;
684 
685     --Ptr->RefCount;
686     if (Ptr->RefCount == 0)
687     {
688         DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name ? Ptr->Face->family_name : "<NULL>");
689         RemoveCacheEntries(Ptr->Face);
690         FT_Done_Face(Ptr->Face);
691         SharedMem_Release(Ptr->Memory);
692         SharedFaceCache_Release(&Ptr->EnglishUS);
693         SharedFaceCache_Release(&Ptr->UserLanguage);
694         ExFreePoolWithTag(Ptr, TAG_FONT);
695     }
696     IntUnLockFreeType();
697 }
698 
699 
700 static VOID FASTCALL
CleanupFontEntryEx(PFONT_ENTRY FontEntry,PFONTGDI FontGDI)701 CleanupFontEntryEx(PFONT_ENTRY FontEntry, PFONTGDI FontGDI)
702 {
703     // PFONTGDI FontGDI = FontEntry->Font;
704     PSHARED_FACE SharedFace = FontGDI->SharedFace;
705 
706     if (FontGDI->Filename)
707         ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
708 
709     if (FontEntry->StyleName.Buffer)
710         RtlFreeUnicodeString(&FontEntry->StyleName);
711 
712     if (FontEntry->FaceName.Buffer)
713         RtlFreeUnicodeString(&FontEntry->FaceName);
714 
715     EngFreeMem(FontGDI);
716     SharedFace_Release(SharedFace);
717     ExFreePoolWithTag(FontEntry, TAG_FONT);
718 }
719 
720 static __inline VOID FASTCALL
CleanupFontEntry(PFONT_ENTRY FontEntry)721 CleanupFontEntry(PFONT_ENTRY FontEntry)
722 {
723     CleanupFontEntryEx(FontEntry, FontEntry->Font);
724 }
725 
726 
FTVectorToPOINTFX(FT_Vector * vec,POINTFX * pt)727 static __inline void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
728 {
729     pt->x.value = vec->x >> 6;
730     pt->x.fract = (vec->x & 0x3f) << 10;
731     pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
732     pt->y.value = vec->y >> 6;
733     pt->y.fract = (vec->y & 0x3f) << 10;
734     pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
735 }
736 
737 /*
738    This function builds an FT_Fixed from a FIXED. It simply put f.value
739    in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
740 */
FT_FixedFromFIXED(FIXED f)741 static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
742 {
743     return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
744 }
745 
746 
747 #if DBG
DumpFontEntry(PFONT_ENTRY FontEntry)748 VOID DumpFontEntry(PFONT_ENTRY FontEntry)
749 {
750     const char *family_name;
751     const char *style_name;
752     FT_Face Face;
753     PFONTGDI FontGDI = FontEntry->Font;
754 
755     if (!FontGDI)
756     {
757         DPRINT("FontGDI NULL\n");
758         return;
759     }
760 
761     Face = (FontGDI->SharedFace ? FontGDI->SharedFace->Face : NULL);
762     if (Face)
763     {
764         family_name = Face->family_name;
765         style_name = Face->style_name;
766     }
767     else
768     {
769         family_name = "<invalid>";
770         style_name = "<invalid>";
771     }
772 
773     DPRINT("family_name '%s', style_name '%s', FaceName '%wZ', StyleName '%wZ', FontGDI %p, "
774            "FontObj %p, iUnique %lu, SharedFace %p, Face %p, CharSet %u, Filename '%S'\n",
775            family_name,
776            style_name,
777            &FontEntry->FaceName,
778            &FontEntry->StyleName,
779            FontGDI,
780            &FontGDI->FontObj,
781            FontGDI->iUnique,
782            FontGDI->SharedFace,
783            Face,
784            FontGDI->CharSet,
785            FontGDI->Filename);
786 }
787 
DumpFontList(PLIST_ENTRY Head)788 VOID DumpFontList(PLIST_ENTRY Head)
789 {
790     PLIST_ENTRY Entry;
791     PFONT_ENTRY CurrentEntry;
792 
793     DPRINT("## DumpFontList(%p)\n", Head);
794 
795     for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
796     {
797         CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
798         DumpFontEntry(CurrentEntry);
799     }
800 }
801 
DumpFontSubstEntry(PFONTSUBST_ENTRY pSubstEntry)802 VOID DumpFontSubstEntry(PFONTSUBST_ENTRY pSubstEntry)
803 {
804     DPRINT("%wZ,%u -> %wZ,%u\n",
805         &pSubstEntry->FontNames[FONTSUBST_FROM],
806         pSubstEntry->CharSets[FONTSUBST_FROM],
807         &pSubstEntry->FontNames[FONTSUBST_TO],
808         pSubstEntry->CharSets[FONTSUBST_TO]);
809 }
810 
DumpFontSubstList(VOID)811 VOID DumpFontSubstList(VOID)
812 {
813     PLIST_ENTRY         pHead = &g_FontSubstListHead;
814     PLIST_ENTRY         pListEntry;
815     PFONTSUBST_ENTRY    pSubstEntry;
816 
817     DPRINT("## DumpFontSubstList\n");
818 
819     for (pListEntry = pHead->Flink;
820          pListEntry != pHead;
821          pListEntry = pListEntry->Flink)
822     {
823         pSubstEntry = CONTAINING_RECORD(pListEntry, FONTSUBST_ENTRY, ListEntry);
824         DumpFontSubstEntry(pSubstEntry);
825     }
826 }
827 
DumpPrivateFontList(BOOL bDoLock)828 VOID DumpPrivateFontList(BOOL bDoLock)
829 {
830     PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
831 
832     if (!Win32Process)
833         return;
834 
835     if (bDoLock)
836     {
837         IntLockFreeType();
838         IntLockProcessPrivateFonts(Win32Process);
839     }
840 
841     DumpFontList(&Win32Process->PrivateFontListHead);
842 
843     if (bDoLock)
844     {
845         IntUnLockProcessPrivateFonts(Win32Process);
846         IntUnLockFreeType();
847     }
848 }
849 
DumpGlobalFontList(BOOL bDoLock)850 VOID DumpGlobalFontList(BOOL bDoLock)
851 {
852     if (bDoLock)
853         IntLockFreeType();
854 
855     DumpFontList(&g_FontListHead);
856 
857     if (bDoLock)
858         IntUnLockFreeType();
859 }
860 
DumpFontInfo(BOOL bDoLock)861 VOID DumpFontInfo(BOOL bDoLock)
862 {
863     DumpGlobalFontList(bDoLock);
864     DumpPrivateFontList(bDoLock);
865     DumpFontSubstList();
866 }
867 #endif
868 
869 /*
870  * IntLoadFontSubstList --- loads the list of font substitutes
871  */
872 BOOL FASTCALL
IntLoadFontSubstList(PLIST_ENTRY pHead)873 IntLoadFontSubstList(PLIST_ENTRY pHead)
874 {
875     NTSTATUS                        Status;
876     HANDLE                          KeyHandle;
877     OBJECT_ATTRIBUTES               ObjectAttributes;
878     KEY_FULL_INFORMATION            KeyFullInfo;
879     ULONG                           i, Length;
880     UNICODE_STRING                  FromW, ToW;
881     BYTE                            InfoBuffer[128];
882     PKEY_VALUE_FULL_INFORMATION     pInfo;
883     BYTE                            CharSets[FONTSUBST_FROM_AND_TO];
884     LPWSTR                          pch;
885     PFONTSUBST_ENTRY                pEntry;
886 
887     /* the FontSubstitutes registry key */
888     static UNICODE_STRING FontSubstKey =
889         RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
890                             L"Microsoft\\Windows NT\\CurrentVersion\\"
891                             L"FontSubstitutes");
892 
893     /* open registry key */
894     InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
895                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
896                                NULL, NULL);
897     Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
898     if (!NT_SUCCESS(Status))
899     {
900         DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
901         return FALSE;   /* failure */
902     }
903 
904     /* query count of values */
905     Status = ZwQueryKey(KeyHandle, KeyFullInformation,
906                         &KeyFullInfo, sizeof(KeyFullInfo), &Length);
907     if (!NT_SUCCESS(Status))
908     {
909         DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
910         ZwClose(KeyHandle);
911         return FALSE;   /* failure */
912     }
913 
914     /* for each value */
915     for (i = 0; i < KeyFullInfo.Values; ++i)
916     {
917         /* get value name */
918         Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
919                                      InfoBuffer, sizeof(InfoBuffer), &Length);
920         if (!NT_SUCCESS(Status))
921         {
922             DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
923             break;      /* failure */
924         }
925 
926         /* create FromW string */
927         pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
928         Length = pInfo->NameLength / sizeof(WCHAR);
929         pInfo->Name[Length] = UNICODE_NULL;   /* truncate */
930         if (!RtlCreateUnicodeString(&FromW, pInfo->Name))
931         {
932             Status = STATUS_INSUFFICIENT_RESOURCES;
933             DPRINT("RtlCreateUnicodeString failed\n");
934             break;      /* failure */
935         }
936 
937         /* query value */
938         Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation,
939                                  InfoBuffer, sizeof(InfoBuffer), &Length);
940         pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
941         if (!NT_SUCCESS(Status) || !pInfo->DataLength)
942         {
943             DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
944             RtlFreeUnicodeString(&FromW);
945             break;      /* failure */
946         }
947 
948         /* create ToW string */
949         pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
950         Length = pInfo->DataLength / sizeof(WCHAR);
951         pch[Length] = UNICODE_NULL; /* truncate */
952         if (!RtlCreateUnicodeString(&ToW, pch))
953         {
954             Status = STATUS_INSUFFICIENT_RESOURCES;
955             DPRINT("RtlCreateUnicodeString failed\n");
956             RtlFreeUnicodeString(&FromW);
957             break;      /* failure */
958         }
959 
960         /* does charset exist? (from) */
961         CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
962         pch = wcsrchr(FromW.Buffer, L',');
963         if (pch)
964         {
965             /* truncate */
966             *pch = UNICODE_NULL;
967             FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
968             /* parse charset number */
969             CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
970         }
971 
972         /* does charset exist? (to) */
973         CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
974         pch = wcsrchr(ToW.Buffer, L',');
975         if (pch)
976         {
977             /* truncate */
978             *pch = UNICODE_NULL;
979             ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
980             /* parse charset number */
981             CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
982         }
983 
984         /* is it identical? */
985         if (RtlEqualUnicodeString(&FromW, &ToW, TRUE) &&
986             CharSets[FONTSUBST_FROM] == CharSets[FONTSUBST_TO])
987         {
988             RtlFreeUnicodeString(&FromW);
989             RtlFreeUnicodeString(&ToW);
990             continue;
991         }
992 
993         /* allocate an entry */
994         pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
995         if (pEntry == NULL)
996         {
997             DPRINT("ExAllocatePoolWithTag failed\n");
998             RtlFreeUnicodeString(&FromW);
999             RtlFreeUnicodeString(&ToW);
1000             break;      /* failure */
1001         }
1002 
1003         /* store to *pEntry */
1004         pEntry->FontNames[FONTSUBST_FROM] = FromW;
1005         pEntry->FontNames[FONTSUBST_TO] = ToW;
1006         pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
1007         pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
1008 
1009         /* insert pEntry to *pHead */
1010         InsertTailList(pHead, &pEntry->ListEntry);
1011     }
1012 
1013     /* close now */
1014     ZwClose(KeyHandle);
1015 
1016     return NT_SUCCESS(Status);
1017 }
1018 
1019 BOOL FASTCALL
InitFontSupport(VOID)1020 InitFontSupport(VOID)
1021 {
1022     ULONG ulError;
1023 
1024     g_FontCacheNumEntries = 0;
1025 
1026     g_FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
1027     if (g_FreeTypeLock == NULL)
1028     {
1029         return FALSE;
1030     }
1031     ExInitializeFastMutex(g_FreeTypeLock);
1032 
1033     ulError = FT_Init_FreeType(&g_FreeTypeLibrary);
1034     if (ulError)
1035     {
1036         DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
1037         return FALSE;
1038     }
1039 
1040     if (!IntLoadFontsInRegistry())
1041     {
1042         DPRINT1("Fonts registry is empty.\n");
1043 
1044         /* Load font(s) with writing registry */
1045         IntLoadSystemFonts();
1046     }
1047 
1048     IntLoadFontSubstList(&g_FontSubstListHead);
1049 
1050 #if 0
1051     DumpFontInfo(TRUE);
1052 #endif
1053 
1054     FontLink_LoadSettings();
1055     FontLink_LoadDefaultFonts();
1056     FontLink_LoadDefaultCharset();
1057 
1058     return TRUE;
1059 }
1060 
1061 VOID FASTCALL
FreeFontSupport(VOID)1062 FreeFontSupport(VOID)
1063 {
1064     PLIST_ENTRY pHead, pEntry;
1065     PFONT_CACHE_ENTRY pFontCache;
1066     PFONTSUBST_ENTRY pSubstEntry;
1067     PFONT_ENTRY pFontEntry;
1068 
1069     // Cleanup the FontLink cache
1070     FontLink_CleanupCache();
1071 
1072     // Free font cache list
1073     pHead = &g_FontCacheListHead;
1074     while (!IsListEmpty(pHead))
1075     {
1076         pEntry = RemoveHeadList(pHead);
1077         pFontCache = CONTAINING_RECORD(pEntry, FONT_CACHE_ENTRY, ListEntry);
1078         RemoveCachedEntry(pFontCache);
1079     }
1080 
1081     // Free font subst list
1082     pHead = &g_FontSubstListHead;
1083     while (!IsListEmpty(pHead))
1084     {
1085         pEntry = RemoveHeadList(pHead);
1086         pSubstEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
1087         ExFreePoolWithTag(pSubstEntry, TAG_FONT);
1088     }
1089 
1090     // Free font list
1091     pHead = &g_FontListHead;
1092     while (!IsListEmpty(pHead))
1093     {
1094         pEntry = RemoveHeadList(pHead);
1095         pFontEntry = CONTAINING_RECORD(pEntry, FONT_ENTRY, ListEntry);
1096         CleanupFontEntry(pFontEntry);
1097     }
1098 
1099     if (g_FreeTypeLibrary)
1100     {
1101         FT_Done_Library(g_FreeTypeLibrary);
1102         g_FreeTypeLibrary = NULL;
1103     }
1104 
1105     ExFreePoolWithTag(g_FreeTypeLock, TAG_INTERNAL_SYNC);
1106     g_FreeTypeLock = NULL;
1107 }
1108 
IntNormalizeAngle(LONG nTenthsOfDegrees)1109 static LONG IntNormalizeAngle(LONG nTenthsOfDegrees)
1110 {
1111     nTenthsOfDegrees %= 360 * 10;
1112     if (nTenthsOfDegrees >= 0)
1113         return nTenthsOfDegrees;
1114     return nTenthsOfDegrees + 360 * 10;
1115 }
1116 
IntEscapeMatrix(FT_Matrix * pmat,LONG lfEscapement)1117 static VOID FASTCALL IntEscapeMatrix(FT_Matrix *pmat, LONG lfEscapement)
1118 {
1119     FT_Vector vecAngle;
1120     /* Convert the angle in tenths of degrees into degrees as a 16.16 fixed-point value */
1121     FT_Angle angle = INT_TO_FIXED(lfEscapement) / 10;
1122     FT_Vector_Unit(&vecAngle, angle);
1123     pmat->xx = vecAngle.x;
1124     pmat->xy = -vecAngle.y;
1125     pmat->yx = -pmat->xy;
1126     pmat->yy = pmat->xx;
1127 }
1128 
1129 static VOID FASTCALL
IntMatrixFromMx(FT_Matrix * pmat,const MATRIX * pmx)1130 IntMatrixFromMx(FT_Matrix *pmat, const MATRIX *pmx)
1131 {
1132     FLOATOBJ ef;
1133 
1134     /* Create a freetype matrix, by converting to 16.16 fixpoint format */
1135     ef = pmx->efM11;
1136     FLOATOBJ_MulLong(&ef, 0x00010000);
1137     pmat->xx = FLOATOBJ_GetLong(&ef);
1138 
1139     ef = pmx->efM21;
1140     FLOATOBJ_MulLong(&ef, 0x00010000);
1141     pmat->xy = -FLOATOBJ_GetLong(&ef); /* (*1) See below */
1142 
1143     ef = pmx->efM12;
1144     FLOATOBJ_MulLong(&ef, 0x00010000);
1145     pmat->yx = -FLOATOBJ_GetLong(&ef); /* (*1) See below */
1146 
1147     ef = pmx->efM22;
1148     FLOATOBJ_MulLong(&ef, 0x00010000);
1149     pmat->yy = FLOATOBJ_GetLong(&ef);
1150 
1151     // (*1): Y direction is mirrored as follows:
1152     //
1153     // [  M11  -M12 ]   [  X ]    [   M11*X + M12*Y  ]
1154     // [            ] * [    ] == [                  ]
1155     // [ -M21   M22 ]   [ -Y ]    [ -(M21*X + M22*Y) ].
1156 }
1157 
1158 static BOOL
SubstituteFontByList(PLIST_ENTRY pHead,PUNICODE_STRING pOutputName,PUNICODE_STRING pInputName,BYTE RequestedCharSet,BYTE CharSetMap[FONTSUBST_FROM_AND_TO])1159 SubstituteFontByList(PLIST_ENTRY        pHead,
1160                      PUNICODE_STRING    pOutputName,
1161                      PUNICODE_STRING    pInputName,
1162                      BYTE               RequestedCharSet,
1163                      BYTE               CharSetMap[FONTSUBST_FROM_AND_TO])
1164 {
1165     PLIST_ENTRY         pListEntry;
1166     PFONTSUBST_ENTRY    pSubstEntry;
1167     BYTE                CharSets[FONTSUBST_FROM_AND_TO];
1168 
1169     CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
1170     CharSetMap[FONTSUBST_TO] = RequestedCharSet;
1171 
1172     /* for each list entry */
1173     for (pListEntry = pHead->Flink;
1174          pListEntry != pHead;
1175          pListEntry = pListEntry->Flink)
1176     {
1177         pSubstEntry = CONTAINING_RECORD(pListEntry, FONTSUBST_ENTRY, ListEntry);
1178 
1179         CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
1180 
1181         if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
1182             CharSets[FONTSUBST_FROM] != RequestedCharSet)
1183         {
1184             continue;   /* not matched */
1185         }
1186 
1187         /* does charset number exist? (to) */
1188         if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
1189         {
1190             CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
1191         }
1192         else
1193         {
1194             CharSets[FONTSUBST_TO] = RequestedCharSet;
1195         }
1196 
1197         /* does font name match? */
1198         if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
1199                                    pInputName, TRUE))
1200         {
1201             continue;   /* not matched */
1202         }
1203 
1204         /* update *pOutputName */
1205         *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
1206 
1207         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
1208         {
1209             /* update CharSetMap */
1210             CharSetMap[FONTSUBST_FROM]  = CharSets[FONTSUBST_FROM];
1211             CharSetMap[FONTSUBST_TO]    = CharSets[FONTSUBST_TO];
1212         }
1213         return TRUE;   /* success */
1214     }
1215 
1216     return FALSE;
1217 }
1218 
1219 static VOID
IntUnicodeStringToBuffer(LPWSTR pszBuffer,SIZE_T cbBuffer,const UNICODE_STRING * pString)1220 IntUnicodeStringToBuffer(LPWSTR pszBuffer, SIZE_T cbBuffer, const UNICODE_STRING *pString)
1221 {
1222     SIZE_T cbLength = pString->Length;
1223 
1224     if (cbBuffer < sizeof(UNICODE_NULL))
1225         return;
1226 
1227     if (cbLength > cbBuffer - sizeof(UNICODE_NULL))
1228         cbLength = cbBuffer - sizeof(UNICODE_NULL);
1229 
1230     RtlCopyMemory(pszBuffer, pString->Buffer, cbLength);
1231     pszBuffer[cbLength / sizeof(WCHAR)] = UNICODE_NULL;
1232 }
1233 
1234 static NTSTATUS
DuplicateUnicodeString(PUNICODE_STRING Source,PUNICODE_STRING Destination)1235 DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
1236 {
1237     NTSTATUS Status = STATUS_NO_MEMORY;
1238     UNICODE_STRING Tmp;
1239 
1240     Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
1241     if (Tmp.Buffer)
1242     {
1243         Tmp.MaximumLength = Source->MaximumLength;
1244         Tmp.Length = 0;
1245         RtlCopyUnicodeString(&Tmp, Source);
1246 
1247         Destination->MaximumLength = Tmp.MaximumLength;
1248         Destination->Length = Tmp.Length;
1249         Destination->Buffer = Tmp.Buffer;
1250 
1251         Status = STATUS_SUCCESS;
1252     }
1253 
1254     return Status;
1255 }
1256 
1257 static BOOL
SubstituteFontRecurse(PLOGFONTW pLogFont)1258 SubstituteFontRecurse(PLOGFONTW pLogFont)
1259 {
1260     UINT            RecurseCount = 5;
1261     UNICODE_STRING  OutputNameW = { 0 };
1262     BYTE            CharSetMap[FONTSUBST_FROM_AND_TO];
1263     BOOL            Found;
1264     UNICODE_STRING  InputNameW;
1265 
1266     if (pLogFont->lfFaceName[0] == UNICODE_NULL)
1267         return FALSE;
1268 
1269     RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
1270 
1271     while (RecurseCount-- > 0)
1272     {
1273         Found = SubstituteFontByList(&g_FontSubstListHead,
1274                                      &OutputNameW, &InputNameW,
1275                                      pLogFont->lfCharSet, CharSetMap);
1276         if (!Found)
1277             break;
1278 
1279         IntUnicodeStringToBuffer(pLogFont->lfFaceName, sizeof(pLogFont->lfFaceName), &OutputNameW);
1280         RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
1281 
1282         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
1283             CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
1284         {
1285             pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
1286         }
1287     }
1288 
1289     return TRUE;    /* success */
1290 }
1291 
1292 // Quickly initialize a FONTLINK_CHAIN
1293 static inline VOID
FontLink_Chain_Init(_Out_ PFONTLINK_CHAIN pChain,_Inout_ PTEXTOBJ pTextObj,_In_ FT_Face face)1294 FontLink_Chain_Init(
1295     _Out_ PFONTLINK_CHAIN pChain,
1296     _Inout_ PTEXTOBJ pTextObj,
1297     _In_ FT_Face face)
1298 {
1299     RtlZeroMemory(pChain, sizeof(*pChain));
1300     pChain->pBaseTextObj = pTextObj;
1301     pChain->pDefFace = face;
1302     ASSERT(!FontLink_Chain_IsPopulated(pChain));
1303 }
1304 
1305 // The default FontLink data
1306 static const WCHAR s_szzDefFontLink[] =
1307     L"tahoma.ttf,Tahoma\0"
1308     L"msgothic.ttc,MS UI Gothic\0"
1309     L"mingliu.ttc,PMingLiU\0"
1310     L"simsun.ttc,SimSun\0"
1311     L"gulim.ttc,Gulim\0"
1312     L"\0";
1313 // The default fixed-pitch FontLink data
1314 static const WCHAR s_szzDefFixedFontLink[] =
1315     L"cour.ttf,Courier New\0"
1316     L"msgothic.ttc,MS Gothic\0"
1317     L"mingliu.ttc,MingLiU\0"
1318     L"simsun.ttc,NSimSun\0"
1319     L"gulim.ttc,GulimChe\0"
1320     L"\0";
1321 
1322 static NTSTATUS
FontLink_Chain_LoadReg(_Inout_ PFONTLINK_CHAIN pChain,_Inout_ PLOGFONTW pLF)1323 FontLink_Chain_LoadReg(
1324     _Inout_ PFONTLINK_CHAIN pChain,
1325     _Inout_ PLOGFONTW pLF)
1326 {
1327     NTSTATUS Status;
1328     HKEY hKey;
1329     DWORD cbData;
1330     WCHAR szzFontLink[512];
1331     SIZE_T FontLinkSize;
1332     PZZWSTR pszzFontLink = NULL;
1333 
1334     ASSERT(pLF->lfFaceName[0]);
1335 
1336     // Open the registry key
1337     Status = RegOpenKey(
1338         L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",
1339         &hKey);
1340     if (!NT_SUCCESS(Status))
1341         return Status;
1342 
1343     // Load the FontLink entry
1344     cbData = sizeof(szzFontLink);
1345     Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, szzFontLink, &cbData);
1346     if (!NT_SUCCESS(Status) &&
1347         (Status != STATUS_BUFFER_OVERFLOW) && (Status != STATUS_BUFFER_TOO_SMALL))
1348     {
1349         // Retry with substituted
1350         SubstituteFontRecurse(pLF);
1351         cbData = sizeof(szzFontLink);
1352         Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, szzFontLink, &cbData);
1353     }
1354 
1355     if ((Status == STATUS_BUFFER_OVERFLOW) || (Status == STATUS_BUFFER_TOO_SMALL))
1356     {
1357         // Buffer is too small. Retry with larger buffer
1358         if (cbData >= 2 * sizeof(WCHAR)) // Sanity check
1359         {
1360             FontLinkSize = cbData;
1361             pszzFontLink = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
1362             if (!pszzFontLink)
1363             {
1364                 ZwClose(hKey); // Close the registry key
1365                 return STATUS_NO_MEMORY;
1366             }
1367             Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, pszzFontLink, &cbData);
1368             if (!NT_SUCCESS(Status))
1369             {
1370                 ExFreePoolWithTag(pszzFontLink, TAG_FONT);
1371                 pszzFontLink = NULL;
1372             }
1373         }
1374     }
1375 
1376     ZwClose(hKey); // Close the registry key
1377 
1378     if (!NT_SUCCESS(Status)) // Failed to get registry value
1379     {
1380         // Use default value
1381         ASSERT(sizeof(szzFontLink) >= sizeof(s_szzDefFontLink));
1382         ASSERT(sizeof(szzFontLink) >= sizeof(s_szzDefFixedFontLink));
1383         if (!(pLF->lfPitchAndFamily & FIXED_PITCH))
1384             RtlCopyMemory(szzFontLink, s_szzDefFontLink, sizeof(s_szzDefFontLink));
1385         else
1386             RtlCopyMemory(szzFontLink, s_szzDefFixedFontLink, sizeof(s_szzDefFixedFontLink));
1387     }
1388 
1389     if (pszzFontLink)
1390     {
1391         // Ensure double-NUL-terminated
1392         ASSERT(FontLinkSize / sizeof(WCHAR) >= 2);
1393         pszzFontLink[FontLinkSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
1394         pszzFontLink[FontLinkSize / sizeof(WCHAR) - 2] = UNICODE_NULL;
1395     }
1396     else
1397     {
1398         // Ensure double-NUL-terminated
1399         szzFontLink[_countof(szzFontLink) - 1] = UNICODE_NULL;
1400         szzFontLink[_countof(szzFontLink) - 2] = UNICODE_NULL;
1401 
1402         FontLinkSize = SZZ_GetSize(szzFontLink);
1403         pszzFontLink = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
1404         if (!pszzFontLink)
1405             return STATUS_NO_MEMORY;
1406         RtlCopyMemory(pszzFontLink, szzFontLink, FontLinkSize);
1407     }
1408     pChain->pszzFontLink = pszzFontLink;
1409 
1410     return STATUS_SUCCESS;
1411 }
1412 
1413 static inline PFONTLINK
FontLink_Chain_FindLink(PFONTLINK_CHAIN pChain,PLOGFONTW plf)1414 FontLink_Chain_FindLink(
1415     PFONTLINK_CHAIN pChain,
1416     PLOGFONTW plf)
1417 {
1418     PLIST_ENTRY Entry, Head = &pChain->FontLinkList;
1419     PFONTLINK pLink;
1420 
1421     for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
1422     {
1423         pLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
1424         if (RtlEqualMemory(&pLink->LogFont, plf, sizeof(*plf)))
1425             return pLink;
1426     }
1427 
1428     return NULL;
1429 }
1430 
1431 static inline PFONTLINK
FontLink_Create(_Inout_ PFONTLINK_CHAIN pChain,_In_ const LOGFONTW * plfBase,_In_ LPCWSTR pszLink)1432 FontLink_Create(
1433     _Inout_ PFONTLINK_CHAIN pChain,
1434     _In_ const LOGFONTW *plfBase,
1435     _In_ LPCWSTR pszLink)
1436 {
1437     LPWSTR pch0, pch1;
1438     LOGFONTW lf;
1439     PFONTLINK pLink;
1440 
1441     lf = *plfBase;
1442 
1443     // pszLink: "<FontFileName>,<FaceName>[,...]"
1444     pch0 = wcschr(pszLink, L',');
1445     if (!pch0)
1446     {
1447         DPRINT1("%S\n", pszLink);
1448         return NULL; // Invalid FontLink data
1449     }
1450     ++pch0;
1451 
1452     pch1 = wcschr(pch0, L',');
1453     if (pch1)
1454         RtlStringCchCopyNW(lf.lfFaceName, _countof(lf.lfFaceName), pch0, pch1 - pch0);
1455     else
1456         RtlStringCchCopyW(lf.lfFaceName, _countof(lf.lfFaceName), pch0);
1457 
1458     SubstituteFontRecurse(&lf);
1459     DPRINT("lfFaceName: %S\n", lf.lfFaceName);
1460 
1461     if (RtlEqualMemory(plfBase, &lf, sizeof(lf)) || FontLink_Chain_FindLink(pChain, &lf))
1462         return NULL; // Already exists
1463 
1464     pLink = ExAllocatePoolZero(PagedPool, sizeof(FONTLINK), TAG_FONT);
1465     if (!pLink)
1466         return NULL; // Out of memory
1467 
1468     pLink->LogFont = lf;
1469     return pLink;
1470 }
1471 
1472 static NTSTATUS
FontLink_Chain_Populate(_Inout_ PFONTLINK_CHAIN pChain)1473 FontLink_Chain_Populate(
1474     _Inout_ PFONTLINK_CHAIN pChain)
1475 {
1476     NTSTATUS Status;
1477     PFONTLINK pLink;
1478     LOGFONTW lfBase;
1479     PTEXTOBJ pTextObj = pChain->pBaseTextObj;
1480     PFONTGDI pFontGDI;
1481     PWSTR pszLink;
1482     PFONTLINK_CACHE pLinkCache;
1483     WCHAR szEntry[MAX_PATH];
1484     BOOL bFixCharSet;
1485 
1486     InitializeListHead(&pChain->FontLinkList);
1487 
1488     lfBase = pTextObj->logfont.elfEnumLogfontEx.elfLogFont;
1489     pFontGDI = ObjToGDI(pTextObj->Font, FONT);
1490     lfBase.lfHeight = pFontGDI->lfHeight;
1491     lfBase.lfWidth = pFontGDI->lfWidth;
1492 
1493     // Use pTextObj->TextFace if lfFaceName was empty
1494     if (!lfBase.lfFaceName[0])
1495     {
1496         ASSERT(pTextObj->TextFace[0]);
1497         RtlStringCchCopyW(lfBase.lfFaceName, _countof(lfBase.lfFaceName), pTextObj->TextFace);
1498     }
1499 
1500     // Fix lfCharSet
1501     switch (lfBase.lfCharSet)
1502     {
1503         case ANSI_CHARSET:   bFixCharSet = !s_fFontLinkUseAnsi;    break;
1504         case OEM_CHARSET:    bFixCharSet = !s_fFontLinkUseOem;     break;
1505         case SYMBOL_CHARSET: bFixCharSet = !s_fFontLinkUseSymbol;  break;
1506         default:             bFixCharSet = TRUE;                   break;
1507     }
1508     if (bFixCharSet)
1509         lfBase.lfCharSet = DEFAULT_CHARSET;
1510 
1511     // Use cache if any
1512     pLinkCache = FontLink_FindCache(&lfBase);
1513     if (pLinkCache)
1514     {
1515         RemoveEntryList(&pLinkCache->ListEntry);
1516         *pChain = pLinkCache->Chain;
1517         IntRebaseList(&pChain->FontLinkList, &pLinkCache->Chain.FontLinkList);
1518         ExFreePoolWithTag(pLinkCache, TAG_FONT);
1519         return STATUS_SUCCESS;
1520     }
1521 
1522     pChain->LogFont = lfBase;
1523 
1524     // Load FontLink entry from registry
1525     Status = FontLink_Chain_LoadReg(pChain, &pChain->LogFont);
1526     if (!NT_SUCCESS(Status))
1527         return Status;
1528 
1529     pszLink = pChain->pszzFontLink;
1530     while (*pszLink)
1531     {
1532         DPRINT("pszLink: '%S'\n", pszLink);
1533         pLink = FontLink_Create(pChain, &lfBase, pszLink);
1534         if (pLink)
1535             InsertTailList(&pChain->FontLinkList, &pLink->ListEntry);
1536         pszLink += wcslen(pszLink) + 1;
1537     }
1538 
1539     // Use default settings (if any)
1540     if (s_szDefFontLinkFileName[0] && s_szDefFontLinkFontName[0])
1541     {
1542         RtlStringCchCopyW(szEntry, _countof(szEntry), s_szDefFontLinkFileName);
1543         RtlStringCchCatW(szEntry, _countof(szEntry), L",");
1544         RtlStringCchCatW(szEntry, _countof(szEntry), s_szDefFontLinkFontName);
1545         DPRINT("szEntry: '%S'\n", szEntry);
1546         pLink = FontLink_Create(pChain, &lfBase, szEntry);
1547         if (pLink)
1548             InsertTailList(&pChain->FontLinkList, &pLink->ListEntry);
1549     }
1550 
1551     ASSERT(FontLink_Chain_IsPopulated(pChain));
1552     return Status;
1553 }
1554 
1555 /*
1556  * IntLoadSystemFonts
1557  *
1558  * Search the system font directory and adds each font found.
1559  */
1560 VOID FASTCALL
IntLoadSystemFonts(VOID)1561 IntLoadSystemFonts(VOID)
1562 {
1563     OBJECT_ATTRIBUTES ObjectAttributes;
1564     UNICODE_STRING Directory, FileName, TempString;
1565     IO_STATUS_BLOCK Iosb;
1566     HANDLE hDirectory;
1567     BYTE *DirInfoBuffer;
1568     PFILE_DIRECTORY_INFORMATION DirInfo;
1569     BOOLEAN bRestartScan = TRUE;
1570     NTSTATUS Status;
1571     INT i;
1572     static UNICODE_STRING SearchPatterns[] =
1573     {
1574         RTL_CONSTANT_STRING(L"*.ttf"),
1575         RTL_CONSTANT_STRING(L"*.ttc"),
1576         RTL_CONSTANT_STRING(L"*.otf"),
1577         RTL_CONSTANT_STRING(L"*.otc"),
1578         RTL_CONSTANT_STRING(L"*.fon"),
1579         RTL_CONSTANT_STRING(L"*.fnt")
1580     };
1581     static UNICODE_STRING IgnoreFiles[] =
1582     {
1583         RTL_CONSTANT_STRING(L"."),
1584         RTL_CONSTANT_STRING(L".."),
1585     };
1586 
1587     RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
1588 
1589     InitializeObjectAttributes(
1590         &ObjectAttributes,
1591         &Directory,
1592         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1593         NULL,
1594         NULL);
1595 
1596     Status = ZwOpenFile(
1597                  &hDirectory,
1598                  SYNCHRONIZE | FILE_LIST_DIRECTORY,
1599                  &ObjectAttributes,
1600                  &Iosb,
1601                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1602                  FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
1603 
1604     if (NT_SUCCESS(Status))
1605     {
1606         for (i = 0; i < _countof(SearchPatterns); ++i)
1607         {
1608             DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
1609             if (DirInfoBuffer == NULL)
1610             {
1611                 ZwClose(hDirectory);
1612                 return;
1613             }
1614 
1615             FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
1616             if (FileName.Buffer == NULL)
1617             {
1618                 ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
1619                 ZwClose(hDirectory);
1620                 return;
1621             }
1622             FileName.Length = 0;
1623             FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
1624 
1625             while (1)
1626             {
1627                 Status = ZwQueryDirectoryFile(
1628                              hDirectory,
1629                              NULL,
1630                              NULL,
1631                              NULL,
1632                              &Iosb,
1633                              DirInfoBuffer,
1634                              0x4000,
1635                              FileDirectoryInformation,
1636                              FALSE,
1637                              &SearchPatterns[i],
1638                              bRestartScan);
1639 
1640                 if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
1641                 {
1642                     break;
1643                 }
1644 
1645                 DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
1646                 while (1)
1647                 {
1648                     SIZE_T ign;
1649 
1650                     TempString.Buffer = DirInfo->FileName;
1651                     TempString.Length = TempString.MaximumLength = DirInfo->FileNameLength;
1652 
1653                     /* Should we ignore this file? */
1654                     for (ign = 0; ign < _countof(IgnoreFiles); ++ign)
1655                     {
1656                         /* Yes.. */
1657                         if (RtlEqualUnicodeString(IgnoreFiles + ign, &TempString, FALSE))
1658                             break;
1659                     }
1660 
1661                     /* If we tried all Ignore patterns and there was no match, try to create a font */
1662                     if (ign == _countof(IgnoreFiles))
1663                     {
1664                         RtlCopyUnicodeString(&FileName, &Directory);
1665                         RtlAppendUnicodeStringToString(&FileName, &TempString);
1666                         if (!IntGdiAddFontResourceEx(&FileName, 0, AFRX_WRITE_REGISTRY))
1667                         {
1668                             DPRINT1("ERR: Failed to load %wZ\n", &FileName);
1669                         }
1670                     }
1671 
1672                     if (DirInfo->NextEntryOffset == 0)
1673                         break;
1674 
1675                     DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
1676                 }
1677 
1678                 bRestartScan = FALSE;
1679             }
1680 
1681             ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
1682             ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
1683         }
1684         ZwClose(hDirectory);
1685     }
1686 }
1687 
1688 /* NOTE: If nIndex < 0 then return the number of charsets. */
IntGetCharSet(INT nIndex,FT_ULong CodePageRange1)1689 UINT FASTCALL IntGetCharSet(INT nIndex, FT_ULong CodePageRange1)
1690 {
1691     UINT BitIndex, CharSet;
1692     UINT nCount = 0;
1693 
1694     if (CodePageRange1 == 0)
1695     {
1696         return (nIndex < 0) ? 1 : DEFAULT_CHARSET;
1697     }
1698 
1699     for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1700     {
1701         if (CodePageRange1 & (1 << BitIndex))
1702         {
1703             CharSet = g_FontTci[BitIndex].ciCharset;
1704             if ((nIndex >= 0) && (nCount == (UINT)nIndex))
1705             {
1706                 return CharSet;
1707             }
1708             ++nCount;
1709         }
1710     }
1711 
1712     return (nIndex < 0) ? nCount : ANSI_CHARSET;
1713 }
1714 
1715 /* pixels to points */
1716 #define PX2PT(pixels) FT_MulDiv((pixels), 72, 96)
1717 
1718 static INT FASTCALL
IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,PSHARED_FACE SharedFace,FT_Long FontIndex,INT CharSetIndex)1719 IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
1720                           PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
1721 {
1722     FT_Error            Error;
1723     PFONT_ENTRY         Entry;
1724     FONT_ENTRY_MEM*     PrivateEntry = NULL;
1725     FONTGDI *           FontGDI;
1726     NTSTATUS            Status;
1727     FT_Face             Face;
1728     ANSI_STRING         AnsiString;
1729     FT_WinFNT_HeaderRec WinFNT;
1730     INT                 FaceCount = 0, CharSetCount = 0;
1731     PUNICODE_STRING     pFileName       = pLoadFont->pFileName;
1732     DWORD               Characteristics = pLoadFont->Characteristics;
1733     PUNICODE_STRING     pValueName = &pLoadFont->RegValueName;
1734     TT_OS2 *            pOS2;
1735     INT                 BitIndex;
1736     FT_UShort           os2_version;
1737     FT_ULong            os2_ulCodePageRange1;
1738     FT_UShort           os2_usWeightClass;
1739 
1740     if (SharedFace == NULL && CharSetIndex == -1)
1741     {
1742         /* load a face from memory */
1743         IntLockFreeType();
1744         Error = FT_New_Memory_Face(
1745                     g_FreeTypeLibrary,
1746                     pLoadFont->Memory->Buffer,
1747                     pLoadFont->Memory->BufferSize,
1748                     ((FontIndex != -1) ? FontIndex : 0),
1749                     &Face);
1750 
1751         if (!Error)
1752             SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
1753 
1754         IntUnLockFreeType();
1755 
1756         if (!Error && FT_IS_SFNT(Face))
1757             pLoadFont->IsTrueType = TRUE;
1758 
1759         if (Error || SharedFace == NULL)
1760         {
1761             if (SharedFace)
1762                 SharedFace_Release(SharedFace);
1763 
1764             if (Error == FT_Err_Unknown_File_Format)
1765                 DPRINT1("Unknown font file format\n");
1766             else
1767                 DPRINT1("Error reading font (error code: %d)\n", Error);
1768             return 0;   /* failure */
1769         }
1770     }
1771     else
1772     {
1773         Face = SharedFace->Face;
1774         IntLockFreeType();
1775         SharedFace_AddRef(SharedFace);
1776         IntUnLockFreeType();
1777     }
1778 
1779     /* allocate a FONT_ENTRY */
1780     Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
1781     if (!Entry)
1782     {
1783         SharedFace_Release(SharedFace);
1784         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1785         return 0;   /* failure */
1786     }
1787 
1788     /* allocate a FONTGDI */
1789     FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
1790     if (!FontGDI)
1791     {
1792         SharedFace_Release(SharedFace);
1793         ExFreePoolWithTag(Entry, TAG_FONT);
1794         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1795         return 0;   /* failure */
1796     }
1797 
1798     /* set file name */
1799     if (pFileName)
1800     {
1801         FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
1802                                                   pFileName->Length + sizeof(UNICODE_NULL),
1803                                                   GDITAG_PFF);
1804         if (FontGDI->Filename == NULL)
1805         {
1806             EngFreeMem(FontGDI);
1807             SharedFace_Release(SharedFace);
1808             ExFreePoolWithTag(Entry, TAG_FONT);
1809             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1810             return 0;   /* failure */
1811         }
1812 
1813         RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
1814         FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
1815     }
1816     else
1817     {
1818         FontGDI->Filename = NULL;
1819 
1820         PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
1821         if (!PrivateEntry)
1822         {
1823             if (FontGDI->Filename)
1824                 ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1825             EngFreeMem(FontGDI);
1826             SharedFace_Release(SharedFace);
1827             ExFreePoolWithTag(Entry, TAG_FONT);
1828             return 0;
1829         }
1830 
1831         PrivateEntry->Entry = Entry;
1832         if (pLoadFont->PrivateEntry)
1833         {
1834             InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
1835         }
1836         else
1837         {
1838             InitializeListHead(&PrivateEntry->ListEntry);
1839             pLoadFont->PrivateEntry = PrivateEntry;
1840         }
1841     }
1842 
1843     /* set face */
1844     FontGDI->SharedFace = SharedFace;
1845     FontGDI->CharSet = ANSI_CHARSET;
1846     FontGDI->OriginalItalic = FALSE;
1847     FontGDI->RequestItalic = FALSE;
1848     FontGDI->OriginalWeight = FALSE;
1849     FontGDI->RequestWeight = FW_NORMAL;
1850 
1851     IntLockFreeType();
1852     pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1853     if (pOS2)
1854     {
1855         FontGDI->OriginalItalic = !!(pOS2->fsSelection & 0x1);
1856         FontGDI->OriginalWeight = pOS2->usWeightClass;
1857     }
1858     else
1859     {
1860         Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1861         if (!Error)
1862         {
1863             FontGDI->OriginalItalic = !!WinFNT.italic;
1864             FontGDI->OriginalWeight = WinFNT.weight;
1865         }
1866     }
1867     IntUnLockFreeType();
1868 
1869     RtlInitAnsiString(&AnsiString, Face->family_name);
1870     Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiString, TRUE);
1871     if (NT_SUCCESS(Status))
1872     {
1873         if (Face->style_name && Face->style_name[0] &&
1874             strcmp(Face->style_name, "Regular") != 0)
1875         {
1876             RtlInitAnsiString(&AnsiString, Face->style_name);
1877             Status = RtlAnsiStringToUnicodeString(&Entry->StyleName, &AnsiString, TRUE);
1878             if (!NT_SUCCESS(Status))
1879             {
1880                 RtlFreeUnicodeString(&Entry->FaceName);
1881             }
1882         }
1883         else
1884         {
1885             RtlInitUnicodeString(&Entry->StyleName, NULL);
1886         }
1887     }
1888     if (!NT_SUCCESS(Status))
1889     {
1890         if (PrivateEntry)
1891         {
1892             if (pLoadFont->PrivateEntry == PrivateEntry)
1893             {
1894                 pLoadFont->PrivateEntry = NULL;
1895             }
1896             else
1897             {
1898                 RemoveEntryList(&PrivateEntry->ListEntry);
1899             }
1900             ExFreePoolWithTag(PrivateEntry, TAG_FONT);
1901         }
1902         if (FontGDI->Filename)
1903             ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
1904         EngFreeMem(FontGDI);
1905         SharedFace_Release(SharedFace);
1906         ExFreePoolWithTag(Entry, TAG_FONT);
1907         return 0;
1908     }
1909 
1910     os2_version = 0;
1911     IntLockFreeType();
1912     pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
1913     if (pOS2)
1914     {
1915         os2_version = pOS2->version;
1916         os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
1917         os2_usWeightClass = pOS2->usWeightClass;
1918     }
1919     IntUnLockFreeType();
1920 
1921     if (pOS2 && os2_version >= 1)
1922     {
1923         /* get charset and weight from OS/2 header */
1924 
1925         /* Make sure we do not use this pointer anymore */
1926         pOS2 = NULL;
1927 
1928         for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
1929         {
1930             if (os2_ulCodePageRange1 & (1 << BitIndex))
1931             {
1932                 if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
1933                     continue;
1934 
1935                 if ((CharSetIndex == -1 && CharSetCount == 0) ||
1936                     CharSetIndex == CharSetCount)
1937                 {
1938                     FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
1939                 }
1940 
1941                 ++CharSetCount;
1942             }
1943         }
1944 
1945         /* set actual weight */
1946         FontGDI->OriginalWeight = os2_usWeightClass;
1947     }
1948     else
1949     {
1950         /* get charset from WinFNT header */
1951         IntLockFreeType();
1952         Error = FT_Get_WinFNT_Header(Face, &WinFNT);
1953         if (!Error)
1954         {
1955             FontGDI->CharSet = WinFNT.charset;
1956         }
1957         IntUnLockFreeType();
1958     }
1959 
1960     ++FaceCount;
1961     DPRINT("Font loaded: %s (%s)\n",
1962            Face->family_name ? Face->family_name : "<NULL>",
1963            Face->style_name ? Face->style_name : "<NULL>");
1964     DPRINT("Num glyphs: %d\n", Face->num_glyphs);
1965     DPRINT("CharSet: %d\n", FontGDI->CharSet);
1966 
1967     /* Add this font resource to the font table */
1968     Entry->Font = FontGDI;
1969     Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
1970 
1971     IntLockFreeType();
1972     if (Characteristics & FR_PRIVATE)
1973     {
1974         /* private font */
1975         PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
1976         IntLockProcessPrivateFonts(Win32Process);
1977         InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
1978         IntUnLockProcessPrivateFonts(Win32Process);
1979     }
1980     else
1981     {
1982         /* global font */
1983         InsertTailList(&g_FontListHead, &Entry->ListEntry);
1984     }
1985     IntUnLockFreeType();
1986 
1987     if (FontIndex == -1)
1988     {
1989         if (FT_IS_SFNT(Face))
1990         {
1991             TT_Face TrueType = (TT_Face)Face;
1992             if (TrueType->ttc_header.count > 1)
1993             {
1994                 FT_Long i;
1995                 for (i = 1; i < TrueType->ttc_header.count; ++i)
1996                 {
1997                     FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
1998                 }
1999             }
2000         }
2001         FontIndex = 0;
2002     }
2003 
2004     if (CharSetIndex == -1)
2005     {
2006         INT i;
2007         USHORT NameLength = Entry->FaceName.Length;
2008 
2009         if (Entry->StyleName.Length)
2010             NameLength += Entry->StyleName.Length + sizeof(WCHAR);
2011 
2012         if (pLoadFont->RegValueName.Length == 0)
2013         {
2014             pValueName->Length = 0;
2015             pValueName->MaximumLength = NameLength + sizeof(WCHAR);
2016             pValueName->Buffer = ExAllocatePoolWithTag(PagedPool,
2017                                                        pValueName->MaximumLength,
2018                                                        TAG_USTR);
2019             pValueName->Buffer[0] = UNICODE_NULL;
2020             RtlAppendUnicodeStringToString(pValueName, &Entry->FaceName);
2021         }
2022         else
2023         {
2024             UNICODE_STRING NewString;
2025             USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + NameLength;
2026             NewString.Length = 0;
2027             NewString.MaximumLength = Length + sizeof(WCHAR);
2028             NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
2029                                                      NewString.MaximumLength,
2030                                                      TAG_USTR);
2031             NewString.Buffer[0] = UNICODE_NULL;
2032 
2033             RtlAppendUnicodeStringToString(&NewString, pValueName);
2034             RtlAppendUnicodeToString(&NewString, L" & ");
2035             RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
2036 
2037             RtlFreeUnicodeString(pValueName);
2038             *pValueName = NewString;
2039         }
2040         if (Entry->StyleName.Length)
2041         {
2042             RtlAppendUnicodeToString(pValueName, L" ");
2043             RtlAppendUnicodeStringToString(pValueName, &Entry->StyleName);
2044         }
2045 
2046         for (i = 1; i < CharSetCount; ++i)
2047         {
2048             /* Do not count charsets towards 'faces' loaded */
2049             IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
2050         }
2051     }
2052 
2053     return FaceCount;   /* number of loaded faces */
2054 }
2055 
2056 static LPCWSTR FASTCALL
NameFromCharSet(BYTE CharSet)2057 NameFromCharSet(BYTE CharSet)
2058 {
2059     switch (CharSet)
2060     {
2061         case ANSI_CHARSET: return L"ANSI";
2062         case DEFAULT_CHARSET: return L"Default";
2063         case SYMBOL_CHARSET: return L"Symbol";
2064         case SHIFTJIS_CHARSET: return L"Shift_JIS";
2065         case HANGUL_CHARSET: return L"Hangul";
2066         case GB2312_CHARSET: return L"GB 2312";
2067         case CHINESEBIG5_CHARSET: return L"Chinese Big5";
2068         case OEM_CHARSET: return L"OEM";
2069         case JOHAB_CHARSET: return L"Johab";
2070         case HEBREW_CHARSET: return L"Hebrew";
2071         case ARABIC_CHARSET: return L"Arabic";
2072         case GREEK_CHARSET: return L"Greek";
2073         case TURKISH_CHARSET: return L"Turkish";
2074         case VIETNAMESE_CHARSET: return L"Vietnamese";
2075         case THAI_CHARSET: return L"Thai";
2076         case EASTEUROPE_CHARSET: return L"Eastern European";
2077         case RUSSIAN_CHARSET: return L"Russian";
2078         case MAC_CHARSET: return L"Mac";
2079         case BALTIC_CHARSET: return L"Baltic";
2080         default: return L"Unknown";
2081     }
2082 }
2083 
2084 /*
2085  * IntGdiAddFontResource
2086  *
2087  * Adds the font resource from the specified file to the system.
2088  */
2089 
2090 INT FASTCALL
IntGdiAddFontResourceEx(PUNICODE_STRING FileName,DWORD Characteristics,DWORD dwFlags)2091 IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics,
2092                         DWORD dwFlags)
2093 {
2094     NTSTATUS Status;
2095     HANDLE FileHandle;
2096     PVOID Buffer = NULL;
2097     IO_STATUS_BLOCK Iosb;
2098     PVOID SectionObject;
2099     SIZE_T ViewSize = 0, Length;
2100     LARGE_INTEGER SectionSize;
2101     OBJECT_ATTRIBUTES ObjectAttributes;
2102     GDI_LOAD_FONT LoadFont;
2103     INT FontCount;
2104     HANDLE KeyHandle;
2105     UNICODE_STRING PathName;
2106     LPWSTR pszBuffer;
2107     PFILE_OBJECT FileObject;
2108     static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
2109     static const UNICODE_STRING DosPathPrefix = RTL_CONSTANT_STRING(L"\\??\\");
2110 
2111     /* Build PathName */
2112     if (dwFlags & AFRX_DOS_DEVICE_PATH)
2113     {
2114         Length = DosPathPrefix.Length + FileName->Length + sizeof(UNICODE_NULL);
2115         pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
2116         if (!pszBuffer)
2117             return 0;   /* failure */
2118 
2119         RtlInitEmptyUnicodeString(&PathName, pszBuffer, Length);
2120         RtlAppendUnicodeStringToString(&PathName, &DosPathPrefix);
2121         RtlAppendUnicodeStringToString(&PathName, FileName);
2122     }
2123     else
2124     {
2125         Status = DuplicateUnicodeString(FileName, &PathName);
2126         if (!NT_SUCCESS(Status))
2127             return 0;   /* failure */
2128     }
2129 
2130     /* Open the font file */
2131     InitializeObjectAttributes(&ObjectAttributes, &PathName,
2132                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
2133     Status = ZwOpenFile(
2134                  &FileHandle,
2135                  FILE_GENERIC_READ | SYNCHRONIZE,
2136                  &ObjectAttributes,
2137                  &Iosb,
2138                  FILE_SHARE_READ,
2139                  FILE_SYNCHRONOUS_IO_NONALERT);
2140     if (!NT_SUCCESS(Status))
2141     {
2142         DPRINT1("Could not load font file: %wZ\n", &PathName);
2143         RtlFreeUnicodeString(&PathName);
2144         return 0;
2145     }
2146 
2147     Status = ObReferenceObjectByHandle(FileHandle, FILE_READ_DATA, NULL,
2148                                        KernelMode, (PVOID*)&FileObject, NULL);
2149     if (!NT_SUCCESS(Status))
2150     {
2151         DPRINT1("ObReferenceObjectByHandle failed.\n");
2152         ZwClose(FileHandle);
2153         RtlFreeUnicodeString(&PathName);
2154         return 0;
2155     }
2156 
2157     SectionSize.QuadPart = 0LL;
2158     Status = MmCreateSection(&SectionObject,
2159                              STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
2160                              NULL, &SectionSize, PAGE_READONLY,
2161                              SEC_COMMIT, FileHandle, FileObject);
2162     if (!NT_SUCCESS(Status))
2163     {
2164         DPRINT1("Could not map file: %wZ\n", &PathName);
2165         ZwClose(FileHandle);
2166         ObDereferenceObject(FileObject);
2167         RtlFreeUnicodeString(&PathName);
2168         return 0;
2169     }
2170     ZwClose(FileHandle);
2171 
2172     Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
2173     if (!NT_SUCCESS(Status))
2174     {
2175         DPRINT1("Could not map file: %wZ\n", &PathName);
2176         ObDereferenceObject(SectionObject);
2177         ObDereferenceObject(FileObject);
2178         RtlFreeUnicodeString(&PathName);
2179         return 0;
2180     }
2181 
2182     LoadFont.pFileName          = &PathName;
2183     LoadFont.Memory             = SharedMem_Create(Buffer, ViewSize, TRUE);
2184     LoadFont.Characteristics    = Characteristics;
2185     RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
2186     LoadFont.IsTrueType         = FALSE;
2187     LoadFont.CharSet            = DEFAULT_CHARSET;
2188     LoadFont.PrivateEntry       = NULL;
2189     FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
2190 
2191     /* Release our copy */
2192     IntLockFreeType();
2193     SharedMem_Release(LoadFont.Memory);
2194     IntUnLockFreeType();
2195 
2196     ObDereferenceObject(SectionObject);
2197 
2198     ObDereferenceObject(FileObject);
2199 
2200     /* Save the loaded font name into the registry */
2201     if (FontCount > 0 && (dwFlags & AFRX_WRITE_REGISTRY))
2202     {
2203         UNICODE_STRING NewString;
2204         SIZE_T Length;
2205         PWCHAR pszBuffer;
2206         LPCWSTR CharSetName;
2207         if (LoadFont.IsTrueType)
2208         {
2209             /* Append " (TrueType)" */
2210             Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length + sizeof(UNICODE_NULL);
2211             pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
2212             if (pszBuffer)
2213             {
2214                 RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
2215                 NewString.Buffer[0] = UNICODE_NULL;
2216                 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
2217                 RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
2218                 RtlFreeUnicodeString(&LoadFont.RegValueName);
2219                 LoadFont.RegValueName = NewString;
2220             }
2221             else
2222             {
2223                 // FIXME!
2224             }
2225         }
2226         else if (LoadFont.CharSet != DEFAULT_CHARSET)
2227         {
2228             /* Append " (CharSetName)" */
2229             CharSetName = NameFromCharSet(LoadFont.CharSet);
2230             Length = LoadFont.RegValueName.Length +
2231                      (wcslen(CharSetName) + 3) * sizeof(WCHAR) +
2232                      sizeof(UNICODE_NULL);
2233 
2234             pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
2235             if (pszBuffer)
2236             {
2237                 RtlInitEmptyUnicodeString(&NewString, pszBuffer, Length);
2238                 NewString.Buffer[0] = UNICODE_NULL;
2239                 RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
2240                 RtlAppendUnicodeToString(&NewString, L" (");
2241                 RtlAppendUnicodeToString(&NewString, CharSetName);
2242                 RtlAppendUnicodeToString(&NewString, L")");
2243                 RtlFreeUnicodeString(&LoadFont.RegValueName);
2244                 LoadFont.RegValueName = NewString;
2245             }
2246             else
2247             {
2248                 // FIXME!
2249             }
2250         }
2251 
2252         InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
2253                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2254                                    NULL, NULL);
2255         Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
2256         if (NT_SUCCESS(Status))
2257         {
2258             SIZE_T DataSize;
2259             LPWSTR pFileName;
2260 
2261             if (dwFlags & AFRX_ALTERNATIVE_PATH)
2262             {
2263                 pFileName = PathName.Buffer;
2264             }
2265             else
2266             {
2267                 pFileName = wcsrchr(PathName.Buffer, L'\\');
2268             }
2269 
2270             if (pFileName)
2271             {
2272                 if (!(dwFlags & AFRX_ALTERNATIVE_PATH))
2273                 {
2274                     pFileName++;
2275                 }
2276                 DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
2277                 ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
2278                               pFileName, DataSize);
2279             }
2280             ZwClose(KeyHandle);
2281         }
2282     }
2283     RtlFreeUnicodeString(&LoadFont.RegValueName);
2284 
2285     RtlFreeUnicodeString(&PathName);
2286     return FontCount;
2287 }
2288 
2289 INT FASTCALL
IntGdiAddFontResource(PUNICODE_STRING FileName,DWORD Characteristics)2290 IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
2291 {
2292     return IntGdiAddFontResourceEx(FileName, Characteristics, 0);
2293 }
2294 
2295 /* Borrowed from shlwapi!PathIsRelativeW */
PathIsRelativeW(LPCWSTR lpszPath)2296 BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
2297 {
2298     if (!lpszPath || !*lpszPath)
2299         return TRUE;
2300     if (*lpszPath == L'\\' || (*lpszPath && lpszPath[1] == L':'))
2301         return FALSE;
2302     return TRUE;
2303 }
2304 
2305 BOOL FASTCALL
IntLoadFontsInRegistry(VOID)2306 IntLoadFontsInRegistry(VOID)
2307 {
2308     NTSTATUS                        Status;
2309     HANDLE                          KeyHandle;
2310     OBJECT_ATTRIBUTES               ObjectAttributes;
2311     KEY_FULL_INFORMATION            KeyFullInfo;
2312     ULONG                           i, Length;
2313     UNICODE_STRING                  FontTitleW, FileNameW;
2314     SIZE_T                          InfoSize;
2315     LPBYTE                          InfoBuffer;
2316     PKEY_VALUE_FULL_INFORMATION     pInfo;
2317     LPWSTR                          pchPath;
2318     WCHAR                           szPath[MAX_PATH];
2319     INT                             nFontCount = 0;
2320     DWORD                           dwFlags;
2321 
2322     /* open registry key */
2323     InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
2324                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2325                                NULL, NULL);
2326     Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
2327     if (!NT_SUCCESS(Status))
2328     {
2329         DPRINT1("ZwOpenKey failed: 0x%08X\n", Status);
2330         return FALSE;   /* failure */
2331     }
2332 
2333     /* query count of values */
2334     Status = ZwQueryKey(KeyHandle, KeyFullInformation,
2335                         &KeyFullInfo, sizeof(KeyFullInfo), &Length);
2336     if (!NT_SUCCESS(Status))
2337     {
2338         DPRINT1("ZwQueryKey failed: 0x%08X\n", Status);
2339         ZwClose(KeyHandle);
2340         return FALSE;   /* failure */
2341     }
2342 
2343     /* allocate buffer */
2344     InfoSize = (MAX_PATH + 256) * sizeof(WCHAR);
2345     InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
2346     if (!InfoBuffer)
2347     {
2348         DPRINT1("ExAllocatePoolWithTag failed\n");
2349         ZwClose(KeyHandle);
2350         return FALSE;
2351     }
2352 
2353     /* for each value */
2354     for (i = 0; i < KeyFullInfo.Values; ++i)
2355     {
2356         /* get value name */
2357         Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
2358                                      InfoBuffer, InfoSize, &Length);
2359         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2360         {
2361             /* too short buffer */
2362             ExFreePoolWithTag(InfoBuffer, TAG_FONT);
2363             InfoSize *= 2;
2364             InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
2365             if (!InfoBuffer)
2366             {
2367                 DPRINT1("ExAllocatePoolWithTag failed\n");
2368                 break;
2369             }
2370             /* try again */
2371             Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
2372                                          InfoBuffer, InfoSize, &Length);
2373         }
2374         if (!NT_SUCCESS(Status))
2375         {
2376             DPRINT1("ZwEnumerateValueKey failed: 0x%08X\n", Status);
2377             break;      /* failure */
2378         }
2379 
2380         /* create FontTitleW string */
2381         pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
2382         Length = pInfo->NameLength / sizeof(WCHAR);
2383         pInfo->Name[Length] = UNICODE_NULL;   /* truncate */
2384         if (!RtlCreateUnicodeString(&FontTitleW, pInfo->Name))
2385         {
2386             Status = STATUS_INSUFFICIENT_RESOURCES;
2387             DPRINT1("RtlCreateUnicodeString failed\n");
2388             break;      /* failure */
2389         }
2390 
2391         /* query value */
2392         Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
2393                                  InfoBuffer, InfoSize, &Length);
2394         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2395         {
2396             /* too short buffer */
2397             ExFreePoolWithTag(InfoBuffer, TAG_FONT);
2398             InfoSize *= 2;
2399             InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
2400             if (!InfoBuffer)
2401             {
2402                 DPRINT1("ExAllocatePoolWithTag failed\n");
2403                 break;
2404             }
2405             /* try again */
2406             Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
2407                                      InfoBuffer, InfoSize, &Length);
2408         }
2409         pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
2410         if (!NT_SUCCESS(Status) || !pInfo->DataLength)
2411         {
2412             DPRINT1("ZwQueryValueKey failed: 0x%08X\n", Status);
2413             RtlFreeUnicodeString(&FontTitleW);
2414             break;      /* failure */
2415         }
2416 
2417         /* Build pchPath */
2418         pchPath = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
2419         Length = pInfo->DataLength / sizeof(WCHAR);
2420         pchPath[Length] = UNICODE_NULL; /* truncate */
2421 
2422         /* Load font(s) without writing registry */
2423         if (PathIsRelativeW(pchPath))
2424         {
2425             dwFlags = 0;
2426             Status = RtlStringCbPrintfW(szPath, sizeof(szPath),
2427                                         L"\\SystemRoot\\Fonts\\%s", pchPath);
2428         }
2429         else
2430         {
2431             dwFlags = AFRX_ALTERNATIVE_PATH | AFRX_DOS_DEVICE_PATH;
2432             Status = RtlStringCbCopyW(szPath, sizeof(szPath), pchPath);
2433         }
2434 
2435         if (NT_SUCCESS(Status))
2436         {
2437             RtlCreateUnicodeString(&FileNameW, szPath);
2438             nFontCount += IntGdiAddFontResourceEx(&FileNameW, 0, dwFlags);
2439             RtlFreeUnicodeString(&FileNameW);
2440         }
2441 
2442         RtlFreeUnicodeString(&FontTitleW);
2443     }
2444 
2445     /* close now */
2446     ZwClose(KeyHandle);
2447 
2448     /* free memory block */
2449     if (InfoBuffer)
2450     {
2451         ExFreePoolWithTag(InfoBuffer, TAG_FONT);
2452     }
2453 
2454     return (KeyFullInfo.Values != 0 && nFontCount != 0);
2455 }
2456 
2457 HANDLE FASTCALL
IntGdiAddFontMemResource(PVOID Buffer,DWORD dwSize,PDWORD pNumAdded)2458 IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
2459 {
2460     HANDLE Ret = NULL;
2461     GDI_LOAD_FONT LoadFont;
2462     PFONT_ENTRY_COLL_MEM EntryCollection;
2463     INT FaceCount;
2464 
2465     PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
2466     if (!BufferCopy)
2467     {
2468         *pNumAdded = 0;
2469         return NULL;
2470     }
2471     RtlCopyMemory(BufferCopy, Buffer, dwSize);
2472 
2473     LoadFont.pFileName          = NULL;
2474     LoadFont.Memory             = SharedMem_Create(BufferCopy, dwSize, FALSE);
2475     LoadFont.Characteristics    = FR_PRIVATE | FR_NOT_ENUM;
2476     RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
2477     LoadFont.IsTrueType         = FALSE;
2478     LoadFont.PrivateEntry       = NULL;
2479     FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
2480 
2481     RtlFreeUnicodeString(&LoadFont.RegValueName);
2482 
2483     /* Release our copy */
2484     IntLockFreeType();
2485     SharedMem_Release(LoadFont.Memory);
2486     IntUnLockFreeType();
2487 
2488     if (FaceCount > 0)
2489     {
2490         EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
2491         if (EntryCollection)
2492         {
2493             PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2494             EntryCollection->Entry = LoadFont.PrivateEntry;
2495             IntLockFreeType();
2496             IntLockProcessPrivateFonts(Win32Process);
2497             EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
2498             InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
2499             IntUnLockProcessPrivateFonts(Win32Process);
2500             IntUnLockFreeType();
2501             Ret = EntryCollection->Handle;
2502         }
2503     }
2504     *pNumAdded = FaceCount;
2505 
2506     return Ret;
2507 }
2508 
2509 // FIXME: Add RemoveFontResource
2510 
2511 VOID FASTCALL
IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)2512 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
2513 {
2514     PLIST_ENTRY Entry;
2515     PFONT_ENTRY_MEM FontEntry;
2516 
2517     while (!IsListEmpty(&Head->ListEntry))
2518     {
2519         Entry = RemoveHeadList(&Head->ListEntry);
2520         FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
2521 
2522         CleanupFontEntry(FontEntry->Entry);
2523         ExFreePoolWithTag(FontEntry, TAG_FONT);
2524     }
2525 
2526     CleanupFontEntry(Head->Entry);
2527     ExFreePoolWithTag(Head, TAG_FONT);
2528 }
2529 
2530 static VOID FASTCALL
UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)2531 UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
2532 {
2533     PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
2534     PLIST_ENTRY ListEntry;
2535     RemoveEntryList(&Collection->ListEntry);
2536 
2537     do {
2538         /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
2539         RemoveEntryList(&FontMemEntry->Entry->ListEntry);
2540 
2541         ListEntry = FontMemEntry->ListEntry.Flink;
2542         FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
2543 
2544     } while (FontMemEntry != Collection->Entry);
2545 }
2546 
2547 BOOL FASTCALL
IntGdiRemoveFontMemResource(HANDLE hMMFont)2548 IntGdiRemoveFontMemResource(HANDLE hMMFont)
2549 {
2550     PLIST_ENTRY Entry;
2551     PFONT_ENTRY_COLL_MEM CurrentEntry;
2552     PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
2553     PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2554 
2555     IntLockFreeType();
2556     IntLockProcessPrivateFonts(Win32Process);
2557     for (Entry = Win32Process->PrivateMemFontListHead.Flink;
2558          Entry != &Win32Process->PrivateMemFontListHead;
2559          Entry = Entry->Flink)
2560     {
2561         CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
2562 
2563         if (CurrentEntry->Handle == hMMFont)
2564         {
2565             EntryCollection = CurrentEntry;
2566             UnlinkFontMemCollection(CurrentEntry);
2567             break;
2568         }
2569     }
2570     IntUnLockProcessPrivateFonts(Win32Process);
2571     IntUnLockFreeType();
2572 
2573     if (EntryCollection)
2574     {
2575         IntGdiCleanupMemEntry(EntryCollection->Entry);
2576         ExFreePoolWithTag(EntryCollection, TAG_FONT);
2577         return TRUE;
2578     }
2579     return FALSE;
2580 }
2581 
2582 
2583 VOID FASTCALL
IntGdiCleanupPrivateFontsForProcess(VOID)2584 IntGdiCleanupPrivateFontsForProcess(VOID)
2585 {
2586     PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
2587     PLIST_ENTRY Entry;
2588     PFONT_ENTRY_COLL_MEM EntryCollection;
2589 
2590     DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
2591     do {
2592         Entry = NULL;
2593         EntryCollection = NULL;
2594 
2595         IntLockFreeType();
2596         IntLockProcessPrivateFonts(Win32Process);
2597         if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
2598         {
2599             Entry = Win32Process->PrivateMemFontListHead.Flink;
2600             EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
2601             UnlinkFontMemCollection(EntryCollection);
2602         }
2603         IntUnLockProcessPrivateFonts(Win32Process);
2604         IntUnLockFreeType();
2605 
2606         if (EntryCollection)
2607         {
2608             IntGdiCleanupMemEntry(EntryCollection->Entry);
2609             ExFreePoolWithTag(EntryCollection, TAG_FONT);
2610         }
2611         else
2612         {
2613             /* No Mem fonts anymore, see if we have any other private fonts left */
2614             Entry = NULL;
2615             IntLockFreeType();
2616             IntLockProcessPrivateFonts(Win32Process);
2617             if (!IsListEmpty(&Win32Process->PrivateFontListHead))
2618             {
2619                 Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
2620             }
2621             IntUnLockProcessPrivateFonts(Win32Process);
2622             IntUnLockFreeType();
2623 
2624             if (Entry)
2625             {
2626                 CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
2627             }
2628         }
2629 
2630     } while (Entry);
2631 }
2632 
2633 BOOL FASTCALL
IntIsFontRenderingEnabled(VOID)2634 IntIsFontRenderingEnabled(VOID)
2635 {
2636     return (gpsi->BitsPixel > 8) && g_RenderingEnabled;
2637 }
2638 
2639 VOID FASTCALL
IntEnableFontRendering(BOOL Enable)2640 IntEnableFontRendering(BOOL Enable)
2641 {
2642     g_RenderingEnabled = Enable;
2643 }
2644 
2645 FT_Render_Mode FASTCALL
IntGetFontRenderMode(LOGFONTW * logfont)2646 IntGetFontRenderMode(LOGFONTW *logfont)
2647 {
2648     switch (logfont->lfQuality)
2649     {
2650     case ANTIALIASED_QUALITY:
2651         break;
2652     case NONANTIALIASED_QUALITY:
2653         return FT_RENDER_MODE_MONO;
2654     case DRAFT_QUALITY:
2655         return FT_RENDER_MODE_LIGHT;
2656     case CLEARTYPE_QUALITY:
2657         if (!gspv.bFontSmoothing)
2658             break;
2659         if (!gspv.uiFontSmoothingType)
2660             break;
2661         return FT_RENDER_MODE_LCD;
2662     }
2663     return FT_RENDER_MODE_NORMAL;
2664 }
2665 
2666 
2667 NTSTATUS FASTCALL
TextIntCreateFontIndirect(CONST LPLOGFONTW lf,HFONT * NewFont)2668 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
2669 {
2670     PLFONT plfont;
2671     LOGFONTW *plf;
2672 
2673     ASSERT(lf);
2674     plfont = LFONT_AllocFontWithHandle();
2675     if (!plfont)
2676     {
2677         return STATUS_NO_MEMORY;
2678     }
2679 
2680     ExInitializePushLock(&plfont->lock);
2681     *NewFont = plfont->BaseObject.hHmgr;
2682     plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
2683     RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
2684     if (lf->lfEscapement != lf->lfOrientation)
2685     {
2686         /* This should really depend on whether GM_ADVANCED is set */
2687         plf->lfOrientation = plf->lfEscapement;
2688     }
2689     LFONT_UnlockFont(plfont);
2690 
2691     return STATUS_SUCCESS;
2692 }
2693 
2694 /*************************************************************************
2695  * TranslateCharsetInfo
2696  *
2697  * Fills a CHARSETINFO structure for a character set, code page, or
2698  * font. This allows making the correspondance between different labelings
2699  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
2700  * of the same encoding.
2701  *
2702  * Only one codepage will be set in Cs->fs. If TCI_SRCFONTSIG is used,
2703  * only one codepage should be set in *Src.
2704  *
2705  * RETURNS
2706  *   TRUE on success, FALSE on failure.
2707  *
2708  */
2709 static BOOLEAN
IntTranslateCharsetInfo(PDWORD Src,LPCHARSETINFO Cs,DWORD Flags)2710 IntTranslateCharsetInfo(PDWORD Src, /* [in]
2711                          if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
2712                          if flags == TCI_SRCCHARSET: a character set value
2713                          if flags == TCI_SRCCODEPAGE: a code page value */
2714                         LPCHARSETINFO Cs, /* [out] structure to receive charset information */
2715                         DWORD Flags /* [in] determines interpretation of lpSrc */)
2716 {
2717     int Index = 0;
2718 
2719     switch (Flags)
2720     {
2721     case TCI_SRCFONTSIG:
2722         while (Index < MAXTCIINDEX && 0 == (*Src >> Index & 0x0001))
2723         {
2724             Index++;
2725         }
2726         break;
2727     case TCI_SRCCODEPAGE:
2728         while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
2729         {
2730             Index++;
2731         }
2732         break;
2733     case TCI_SRCCHARSET:
2734         while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
2735         {
2736             Index++;
2737         }
2738         break;
2739     case TCI_SRCLOCALE:
2740         UNIMPLEMENTED;
2741         return FALSE;
2742     default:
2743         return FALSE;
2744     }
2745 
2746     if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
2747     {
2748         return FALSE;
2749     }
2750 
2751     RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
2752 
2753     return TRUE;
2754 }
2755 
2756 
face_has_symbol_charmap(FT_Face ft_face)2757 static BOOL face_has_symbol_charmap(FT_Face ft_face)
2758 {
2759     int i;
2760 
2761     for(i = 0; i < ft_face->num_charmaps; i++)
2762     {
2763         if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
2764             ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
2765         {
2766             return TRUE;
2767         }
2768     }
2769     return FALSE;
2770 }
2771 
2772 static void FASTCALL
FillTM(TEXTMETRICW * TM,PFONTGDI FontGDI,TT_OS2 * pOS2,TT_HoriHeader * pHori,FT_WinFNT_HeaderRec * pFNT)2773 FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
2774        TT_OS2 *pOS2, TT_HoriHeader *pHori,
2775        FT_WinFNT_HeaderRec *pFNT)
2776 {
2777     FT_Fixed XScale, YScale;
2778     int Ascent, Descent;
2779     FT_Face Face = FontGDI->SharedFace->Face;
2780 
2781     ASSERT_FREETYPE_LOCK_HELD();
2782 
2783     XScale = Face->size->metrics.x_scale;
2784     YScale = Face->size->metrics.y_scale;
2785 
2786     if (pFNT)
2787     {
2788         TM->tmHeight           = pFNT->pixel_height;
2789         TM->tmAscent           = pFNT->ascent;
2790         TM->tmDescent          = TM->tmHeight - TM->tmAscent;
2791         TM->tmInternalLeading  = pFNT->internal_leading;
2792         TM->tmExternalLeading  = pFNT->external_leading;
2793         TM->tmAveCharWidth     = pFNT->avg_width;
2794         TM->tmMaxCharWidth     = pFNT->max_width;
2795         TM->tmOverhang         = 0;
2796         TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
2797         TM->tmDigitizedAspectY = pFNT->vertical_resolution;
2798         TM->tmFirstChar        = pFNT->first_char;
2799         TM->tmLastChar         = pFNT->last_char;
2800         TM->tmDefaultChar      = pFNT->default_char + pFNT->first_char;
2801         TM->tmBreakChar        = pFNT->break_char + pFNT->first_char;
2802         TM->tmPitchAndFamily   = pFNT->pitch_and_family;
2803         TM->tmWeight       = FontGDI->RequestWeight;
2804         TM->tmItalic       = FontGDI->RequestItalic;
2805         TM->tmUnderlined   = FontGDI->RequestUnderline;
2806         TM->tmStruckOut    = FontGDI->RequestStrikeOut;
2807         TM->tmCharSet      = FontGDI->CharSet;
2808         return;
2809     }
2810 
2811     ASSERT(pOS2);
2812     if (!pOS2)
2813         return;
2814 
2815     if ((FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent == 0)
2816     {
2817         Ascent = pHori->Ascender;
2818         Descent = -pHori->Descender;
2819     }
2820     else
2821     {
2822         Ascent = (FT_Short)pOS2->usWinAscent;
2823         Descent = (FT_Short)pOS2->usWinDescent;
2824     }
2825 
2826     TM->tmAscent = FontGDI->tmAscent;
2827     TM->tmDescent = FontGDI->tmDescent;
2828     TM->tmHeight = TM->tmAscent + TM->tmDescent;
2829     TM->tmInternalLeading = FontGDI->tmInternalLeading;
2830 
2831     /* MSDN says:
2832      *  el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
2833      */
2834     TM->tmExternalLeading = max(0, (FT_MulFix(pHori->Line_Gap
2835                                     - ((Ascent + Descent)
2836                                        - (pHori->Ascender - pHori->Descender)),
2837                                     YScale) + 32) >> 6);
2838     if (FontGDI->lfWidth != 0)
2839         TM->tmAveCharWidth = FontGDI->lfWidth;
2840     else
2841         TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
2842 
2843     if (TM->tmAveCharWidth == 0)
2844         TM->tmAveCharWidth = 1;
2845 
2846     /* Correct forumla to get the maxcharwidth from unicode and ansi font */
2847     TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
2848 
2849     if (FontGDI->OriginalWeight != FW_DONTCARE &&
2850         FontGDI->OriginalWeight != FW_NORMAL)
2851     {
2852         TM->tmWeight = FontGDI->OriginalWeight;
2853     }
2854     else
2855     {
2856         TM->tmWeight = FontGDI->RequestWeight;
2857     }
2858 
2859     TM->tmOverhang = 0;
2860     TM->tmDigitizedAspectX = 96;
2861     TM->tmDigitizedAspectY = 96;
2862     if (face_has_symbol_charmap(Face) ||
2863         (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
2864     {
2865         USHORT cpOEM, cpAnsi;
2866 
2867         EngGetCurrentCodePage(&cpOEM, &cpAnsi);
2868         TM->tmFirstChar = 0;
2869         switch(cpAnsi)
2870         {
2871         case 1257: /* Baltic */
2872             TM->tmLastChar = 0xf8fd;
2873             break;
2874         default:
2875             TM->tmLastChar = 0xf0ff;
2876         }
2877         TM->tmBreakChar = 0x20;
2878         TM->tmDefaultChar = 0x1f;
2879     }
2880     else
2881     {
2882         TM->tmFirstChar = pOS2->usFirstCharIndex; /* Should be the first char in the cmap */
2883         TM->tmLastChar = pOS2->usLastCharIndex;   /* Should be min(cmap_last, os2_last) */
2884 
2885         if(pOS2->usFirstCharIndex <= 1)
2886             TM->tmBreakChar = pOS2->usFirstCharIndex + 2;
2887         else if (pOS2->usFirstCharIndex > 0xff)
2888             TM->tmBreakChar = 0x20;
2889         else
2890             TM->tmBreakChar = pOS2->usFirstCharIndex;
2891         TM->tmDefaultChar = TM->tmBreakChar - 1;
2892     }
2893 
2894     if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
2895     {
2896         TM->tmItalic = 0xFF;
2897     }
2898     else
2899     {
2900         TM->tmItalic = 0;
2901     }
2902     TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
2903     TM->tmStruckOut  = (FontGDI->RequestStrikeOut ? 0xFF : 0);
2904 
2905     if (!FT_IS_FIXED_WIDTH(Face))
2906     {
2907         switch (pOS2->panose[PAN_PROPORTION_INDEX])
2908         {
2909             case PAN_PROP_MONOSPACED:
2910                 TM->tmPitchAndFamily = 0;
2911                 break;
2912             default:
2913                 TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
2914                 break;
2915         }
2916     }
2917     else
2918     {
2919         TM->tmPitchAndFamily = 0;
2920     }
2921 
2922     switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
2923     {
2924     case PAN_FAMILY_SCRIPT:
2925         TM->tmPitchAndFamily |= FF_SCRIPT;
2926         break;
2927     case PAN_FAMILY_DECORATIVE:
2928         TM->tmPitchAndFamily |= FF_DECORATIVE;
2929         break;
2930 
2931     case PAN_ANY:
2932     case PAN_NO_FIT:
2933     case PAN_FAMILY_TEXT_DISPLAY:
2934     case PAN_FAMILY_PICTORIAL: /* Symbol fonts get treated as if they were text */
2935                                /* Which is clearly not what the panose spec says. */
2936         if (TM->tmPitchAndFamily == 0) /* Fixed */
2937         {
2938             TM->tmPitchAndFamily = FF_MODERN;
2939         }
2940         else
2941         {
2942             switch (pOS2->panose[PAN_SERIFSTYLE_INDEX])
2943             {
2944             case PAN_ANY:
2945             case PAN_NO_FIT:
2946             default:
2947                 TM->tmPitchAndFamily |= FF_DONTCARE;
2948                 break;
2949 
2950             case PAN_SERIF_COVE:
2951             case PAN_SERIF_OBTUSE_COVE:
2952             case PAN_SERIF_SQUARE_COVE:
2953             case PAN_SERIF_OBTUSE_SQUARE_COVE:
2954             case PAN_SERIF_SQUARE:
2955             case PAN_SERIF_THIN:
2956             case PAN_SERIF_BONE:
2957             case PAN_SERIF_EXAGGERATED:
2958             case PAN_SERIF_TRIANGLE:
2959                 TM->tmPitchAndFamily |= FF_ROMAN;
2960                 break;
2961 
2962             case PAN_SERIF_NORMAL_SANS:
2963             case PAN_SERIF_OBTUSE_SANS:
2964             case PAN_SERIF_PERP_SANS:
2965             case PAN_SERIF_FLARED:
2966             case PAN_SERIF_ROUNDED:
2967                 TM->tmPitchAndFamily |= FF_SWISS;
2968                 break;
2969             }
2970         }
2971         break;
2972     default:
2973         TM->tmPitchAndFamily |= FF_DONTCARE;
2974     }
2975 
2976     if (FT_IS_SCALABLE(Face))
2977     {
2978         TM->tmPitchAndFamily |= TMPF_VECTOR;
2979     }
2980     if (FT_IS_SFNT(Face))
2981     {
2982         TM->tmPitchAndFamily |= TMPF_TRUETYPE;
2983     }
2984 
2985     TM->tmCharSet = FontGDI->CharSet;
2986 }
2987 
2988 static NTSTATUS
2989 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
2990                         FT_UShort NameID, FT_UShort LangID);
2991 
2992 typedef struct FONT_NAMES
2993 {
2994     UNICODE_STRING FamilyNameW;     /* family name (TT_NAME_ID_FONT_FAMILY) */
2995     UNICODE_STRING FaceNameW;       /* face name (TT_NAME_ID_FULL_NAME) */
2996     UNICODE_STRING StyleNameW;      /* style name (TT_NAME_ID_FONT_SUBFAMILY) */
2997     UNICODE_STRING FullNameW;       /* unique name (TT_NAME_ID_UNIQUE_ID) */
2998     ULONG OtmSize;                  /* size of OUTLINETEXTMETRICW with extra data */
2999 } FONT_NAMES, *LPFONT_NAMES;
3000 
3001 static __inline void FASTCALL
IntInitFontNames(FONT_NAMES * Names,PSHARED_FACE SharedFace)3002 IntInitFontNames(FONT_NAMES *Names, PSHARED_FACE SharedFace)
3003 {
3004     ULONG OtmSize;
3005 
3006     RtlInitUnicodeString(&Names->FamilyNameW, NULL);
3007     RtlInitUnicodeString(&Names->FaceNameW, NULL);
3008     RtlInitUnicodeString(&Names->StyleNameW, NULL);
3009     RtlInitUnicodeString(&Names->FullNameW, NULL);
3010 
3011     /* family name */
3012     IntGetFontLocalizedName(&Names->FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
3013     /* face name */
3014     IntGetFontLocalizedName(&Names->FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
3015     /* style name */
3016     IntGetFontLocalizedName(&Names->StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
3017     /* unique name (full name) */
3018     IntGetFontLocalizedName(&Names->FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
3019 
3020     /* Calculate the size of OUTLINETEXTMETRICW with extra data */
3021     OtmSize = sizeof(OUTLINETEXTMETRICW) +
3022               Names->FamilyNameW.Length + sizeof(UNICODE_NULL) +
3023               Names->FaceNameW.Length + sizeof(UNICODE_NULL) +
3024               Names->StyleNameW.Length + sizeof(UNICODE_NULL) +
3025               Names->FullNameW.Length + sizeof(UNICODE_NULL);
3026     Names->OtmSize = OtmSize;
3027 }
3028 
3029 static __inline SIZE_T FASTCALL
IntStoreName(const UNICODE_STRING * pName,BYTE * pb)3030 IntStoreName(const UNICODE_STRING *pName, BYTE *pb)
3031 {
3032     RtlCopyMemory(pb, pName->Buffer, pName->Length);
3033     *(WCHAR *)&pb[pName->Length] = UNICODE_NULL;
3034     return pName->Length + sizeof(UNICODE_NULL);
3035 }
3036 
3037 static __inline BYTE *FASTCALL
IntStoreFontNames(const FONT_NAMES * Names,OUTLINETEXTMETRICW * Otm)3038 IntStoreFontNames(const FONT_NAMES *Names, OUTLINETEXTMETRICW *Otm)
3039 {
3040     BYTE *pb = (BYTE *)Otm + sizeof(OUTLINETEXTMETRICW);
3041 
3042     /* family name */
3043     Otm->otmpFamilyName = (LPSTR)(pb - (BYTE*) Otm);
3044     pb += IntStoreName(&Names->FamilyNameW, pb);
3045 
3046     /* face name */
3047     Otm->otmpFaceName = (LPSTR)(pb - (BYTE*) Otm);
3048     pb += IntStoreName(&Names->FaceNameW, pb);
3049 
3050     /* style name */
3051     Otm->otmpStyleName = (LPSTR)(pb - (BYTE*) Otm);
3052     pb += IntStoreName(&Names->StyleNameW, pb);
3053 
3054     /* unique name (full name) */
3055     Otm->otmpFullName = (LPSTR)(pb - (BYTE*) Otm);
3056     pb += IntStoreName(&Names->FullNameW, pb);
3057 
3058     return pb;
3059 }
3060 
3061 static __inline void FASTCALL
IntFreeFontNames(FONT_NAMES * Names)3062 IntFreeFontNames(FONT_NAMES *Names)
3063 {
3064     RtlFreeUnicodeString(&Names->FamilyNameW);
3065     RtlFreeUnicodeString(&Names->FaceNameW);
3066     RtlFreeUnicodeString(&Names->StyleNameW);
3067     RtlFreeUnicodeString(&Names->FullNameW);
3068 }
3069 
3070 /*************************************************************
3071  * IntGetOutlineTextMetrics
3072  *
3073  */
3074 INT FASTCALL
IntGetOutlineTextMetrics(PFONTGDI FontGDI,UINT Size,OUTLINETEXTMETRICW * Otm,BOOL bLocked)3075 IntGetOutlineTextMetrics(PFONTGDI FontGDI,
3076                          UINT Size,
3077                          OUTLINETEXTMETRICW *Otm,
3078                          BOOL bLocked)
3079 {
3080     TT_OS2 *pOS2;
3081     TT_HoriHeader *pHori;
3082     TT_Postscript *pPost;
3083     FT_Fixed XScale, YScale;
3084     FT_WinFNT_HeaderRec WinFNT;
3085     FT_Error Error;
3086     BYTE *pb;
3087     FONT_NAMES FontNames;
3088     PSHARED_FACE SharedFace = FontGDI->SharedFace;
3089     PSHARED_FACE_CACHE Cache;
3090     FT_Face Face = SharedFace->Face;
3091 
3092     if (bLocked)
3093         ASSERT_FREETYPE_LOCK_HELD();
3094     else
3095         ASSERT_FREETYPE_LOCK_NOT_HELD();
3096 
3097     if (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH)
3098     {
3099         Cache = &SharedFace->EnglishUS;
3100     }
3101     else
3102     {
3103         Cache = &SharedFace->UserLanguage;
3104     }
3105 
3106     if (Size == 0 && Cache->OutlineRequiredSize > 0)
3107     {
3108         ASSERT(Otm == NULL);
3109         return Cache->OutlineRequiredSize;
3110     }
3111 
3112     if (!bLocked)
3113         IntLockFreeType();
3114 
3115     IntInitFontNames(&FontNames, SharedFace);
3116     Cache->OutlineRequiredSize = FontNames.OtmSize;
3117 
3118     if (Size == 0)
3119     {
3120         ASSERT(Otm == NULL);
3121         IntFreeFontNames(&FontNames);
3122         if (!bLocked)
3123             IntUnLockFreeType();
3124         return Cache->OutlineRequiredSize;
3125     }
3126 
3127     ASSERT(Otm != NULL);
3128 
3129     if (Size < Cache->OutlineRequiredSize)
3130     {
3131         DPRINT1("Size %u < OutlineRequiredSize %u\n", Size,
3132                 Cache->OutlineRequiredSize);
3133         IntFreeFontNames(&FontNames);
3134         if (!bLocked)
3135             IntUnLockFreeType();
3136         return 0;   /* failure */
3137     }
3138 
3139     XScale = Face->size->metrics.x_scale;
3140     YScale = Face->size->metrics.y_scale;
3141 
3142     pOS2 = FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
3143     pHori = FT_Get_Sfnt_Table(Face, FT_SFNT_HHEA);
3144     pPost = FT_Get_Sfnt_Table(Face, FT_SFNT_POST); /* We can live with this failing */
3145     Error = FT_Get_WinFNT_Header(Face, &WinFNT);
3146 
3147     if (pOS2 == NULL && Error)
3148     {
3149         if (!bLocked)
3150             IntUnLockFreeType();
3151         DPRINT1("Can't find OS/2 table - not TT font?\n");
3152         IntFreeFontNames(&FontNames);
3153         return 0;
3154     }
3155 
3156     if (pHori == NULL && Error)
3157     {
3158         if (!bLocked)
3159             IntUnLockFreeType();
3160         DPRINT1("Can't find HHEA table - not TT font?\n");
3161         IntFreeFontNames(&FontNames);
3162         return 0;
3163     }
3164 
3165     Otm->otmSize = Cache->OutlineRequiredSize;
3166 
3167     FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &WinFNT : 0);
3168 
3169     if (!pOS2)
3170         goto skip_os2;
3171 
3172     Otm->otmFiller = 0;
3173     RtlCopyMemory(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
3174     Otm->otmfsSelection = pOS2->fsSelection;
3175     Otm->otmfsType = pOS2->fsType;
3176     Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
3177     Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
3178     Otm->otmItalicAngle = 0; /* POST table */
3179     Otm->otmEMSquare = Face->units_per_EM;
3180 
3181 #define SCALE_X(value)  ((FT_MulFix((value), XScale) + 32) >> 6)
3182 #define SCALE_Y(value)  ((FT_MulFix((value), YScale) + 32) >> 6)
3183 
3184     Otm->otmAscent = SCALE_Y(pOS2->sTypoAscender);
3185     Otm->otmDescent = SCALE_Y(pOS2->sTypoDescender);
3186     Otm->otmLineGap = SCALE_Y(pOS2->sTypoLineGap);
3187     Otm->otmsCapEmHeight = SCALE_Y(pOS2->sCapHeight);
3188     Otm->otmsXHeight = SCALE_Y(pOS2->sxHeight);
3189     Otm->otmrcFontBox.left = SCALE_X(Face->bbox.xMin);
3190     Otm->otmrcFontBox.right = SCALE_X(Face->bbox.xMax);
3191     Otm->otmrcFontBox.top = SCALE_Y(Face->bbox.yMax);
3192     Otm->otmrcFontBox.bottom = SCALE_Y(Face->bbox.yMin);
3193     Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
3194     Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
3195     Otm->otmMacLineGap = Otm->otmLineGap;
3196     Otm->otmusMinimumPPEM = 0; /* TT Header */
3197     Otm->otmptSubscriptSize.x = SCALE_X(pOS2->ySubscriptXSize);
3198     Otm->otmptSubscriptSize.y = SCALE_Y(pOS2->ySubscriptYSize);
3199     Otm->otmptSubscriptOffset.x = SCALE_X(pOS2->ySubscriptXOffset);
3200     Otm->otmptSubscriptOffset.y = SCALE_Y(pOS2->ySubscriptYOffset);
3201     Otm->otmptSuperscriptSize.x = SCALE_X(pOS2->ySuperscriptXSize);
3202     Otm->otmptSuperscriptSize.y = SCALE_Y(pOS2->ySuperscriptYSize);
3203     Otm->otmptSuperscriptOffset.x = SCALE_X(pOS2->ySuperscriptXOffset);
3204     Otm->otmptSuperscriptOffset.y = SCALE_Y(pOS2->ySuperscriptYOffset);
3205     Otm->otmsStrikeoutSize = SCALE_Y(pOS2->yStrikeoutSize);
3206     Otm->otmsStrikeoutPosition = SCALE_Y(pOS2->yStrikeoutPosition);
3207 
3208     if (!pPost)
3209     {
3210         Otm->otmsUnderscoreSize = 0;
3211         Otm->otmsUnderscorePosition = 0;
3212     }
3213     else
3214     {
3215         Otm->otmsUnderscoreSize = SCALE_Y(pPost->underlineThickness);
3216         Otm->otmsUnderscorePosition = SCALE_Y(pPost->underlinePosition);
3217     }
3218 
3219 #undef SCALE_X
3220 #undef SCALE_Y
3221 
3222 skip_os2:
3223     if (!bLocked)
3224         IntUnLockFreeType();
3225 
3226     pb = IntStoreFontNames(&FontNames, Otm);
3227     ASSERT(pb - (BYTE*)Otm == Cache->OutlineRequiredSize);
3228 
3229     IntFreeFontNames(&FontNames);
3230 
3231     return Cache->OutlineRequiredSize;
3232 }
3233 
3234 /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
3235 static BYTE
CharSetFromLangID(LANGID LangID)3236 CharSetFromLangID(LANGID LangID)
3237 {
3238     /* FIXME: Add more and fix if wrong */
3239     switch (PRIMARYLANGID(LangID))
3240     {
3241         case LANG_CHINESE:
3242             switch (SUBLANGID(LangID))
3243             {
3244                 case SUBLANG_CHINESE_TRADITIONAL:
3245                     return CHINESEBIG5_CHARSET;
3246                 case SUBLANG_CHINESE_SIMPLIFIED:
3247                 default:
3248                     break;
3249             }
3250             return GB2312_CHARSET;
3251 
3252         case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
3253         case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
3254             return EASTEUROPE_CHARSET;
3255 
3256         case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
3257         case LANG_SERBIAN: case LANG_UKRAINIAN:
3258             return RUSSIAN_CHARSET;
3259 
3260         case LANG_ARABIC:       return ARABIC_CHARSET;
3261         case LANG_GREEK:        return GREEK_CHARSET;
3262         case LANG_HEBREW:       return HEBREW_CHARSET;
3263         case LANG_JAPANESE:     return SHIFTJIS_CHARSET;
3264         case LANG_KOREAN:       return JOHAB_CHARSET;
3265         case LANG_TURKISH:      return TURKISH_CHARSET;
3266         case LANG_THAI:         return THAI_CHARSET;
3267         case LANG_LATVIAN:      return BALTIC_CHARSET;
3268         case LANG_VIETNAMESE:   return VIETNAMESE_CHARSET;
3269 
3270         case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
3271         case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
3272         case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
3273         case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
3274         case LANG_SWEDISH: default:
3275             return ANSI_CHARSET;
3276     }
3277 }
3278 
3279 static void
SwapEndian(LPVOID pvData,DWORD Size)3280 SwapEndian(LPVOID pvData, DWORD Size)
3281 {
3282     BYTE b, *pb = pvData;
3283     Size /= 2;
3284     while (Size-- > 0)
3285     {
3286         b = pb[0];
3287         pb[0] = pb[1];
3288         pb[1] = b;
3289         ++pb; ++pb;
3290     }
3291 }
3292 
3293 static NTSTATUS
IntGetFontLocalizedName(PUNICODE_STRING pNameW,PSHARED_FACE SharedFace,FT_UShort NameID,FT_UShort LangID)3294 IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
3295                         FT_UShort NameID, FT_UShort LangID)
3296 {
3297     FT_SfntName Name;
3298     INT i, Count, BestIndex, Score, BestScore;
3299     FT_Error Error;
3300     NTSTATUS Status = STATUS_NOT_FOUND;
3301     ANSI_STRING AnsiName;
3302     PSHARED_FACE_CACHE Cache;
3303     FT_Face Face = SharedFace->Face;
3304 
3305     RtlFreeUnicodeString(pNameW);
3306 
3307     /* select cache */
3308     if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
3309     {
3310         Cache = &SharedFace->EnglishUS;
3311     }
3312     else
3313     {
3314         Cache = &SharedFace->UserLanguage;
3315     }
3316 
3317     /* use cache if available */
3318     if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
3319     {
3320         return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
3321     }
3322     if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
3323     {
3324         return DuplicateUnicodeString(&Cache->FullName, pNameW);
3325     }
3326 
3327     BestIndex = -1;
3328     BestScore = 0;
3329 
3330     Count = FT_Get_Sfnt_Name_Count(Face);
3331     for (i = 0; i < Count; ++i)
3332     {
3333         Error = FT_Get_Sfnt_Name(Face, i, &Name);
3334         if (Error)
3335         {
3336             continue;   /* failure */
3337         }
3338 
3339         if (Name.name_id != NameID)
3340         {
3341             continue;   /* mismatched */
3342         }
3343 
3344         if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
3345             (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
3346              Name.encoding_id != TT_MS_ID_SYMBOL_CS))
3347         {
3348             continue;   /* not Microsoft Unicode name */
3349         }
3350 
3351         if (Name.string == NULL || Name.string_len == 0 ||
3352             (Name.string[0] == 0 && Name.string[1] == 0))
3353         {
3354             continue;   /* invalid string */
3355         }
3356 
3357         if (Name.language_id == LangID)
3358         {
3359             Score = 30;
3360             BestIndex = i;
3361             break;      /* best match */
3362         }
3363         else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
3364         {
3365             Score = 20;
3366         }
3367         else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
3368         {
3369             Score = 10;
3370         }
3371         else
3372         {
3373             Score = 0;
3374         }
3375 
3376         if (Score > BestScore)
3377         {
3378             BestScore = Score;
3379             BestIndex = i;
3380         }
3381     }
3382 
3383     if (BestIndex >= 0)
3384     {
3385         /* store the best name */
3386         Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
3387         if (!Error)
3388         {
3389             /* NOTE: Name.string is not null-terminated */
3390             UNICODE_STRING Tmp;
3391             Tmp.Buffer = (PWCH)Name.string;
3392             Tmp.Length = Tmp.MaximumLength = Name.string_len;
3393 
3394             pNameW->Length = 0;
3395             pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
3396             pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
3397 
3398             if (pNameW->Buffer)
3399             {
3400                 Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
3401                 if (Status == STATUS_SUCCESS)
3402                 {
3403                     /* Convert UTF-16 big endian to little endian */
3404                     SwapEndian(pNameW->Buffer, pNameW->Length);
3405                 }
3406             }
3407             else
3408             {
3409                 Status = STATUS_INSUFFICIENT_RESOURCES;
3410             }
3411         }
3412     }
3413 
3414     if (!NT_SUCCESS(Status))
3415     {
3416         /* defaulted */
3417         if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
3418         {
3419             RtlInitAnsiString(&AnsiName, Face->style_name);
3420             Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
3421         }
3422         else
3423         {
3424             RtlInitAnsiString(&AnsiName, Face->family_name);
3425             Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
3426         }
3427     }
3428 
3429     if (NT_SUCCESS(Status))
3430     {
3431         /* make cache */
3432         if (NameID == TT_NAME_ID_FONT_FAMILY)
3433         {
3434             ASSERT_FREETYPE_LOCK_HELD();
3435             if (!Cache->FontFamily.Buffer)
3436                 DuplicateUnicodeString(pNameW, &Cache->FontFamily);
3437         }
3438         else if (NameID == TT_NAME_ID_FULL_NAME)
3439         {
3440             ASSERT_FREETYPE_LOCK_HELD();
3441             if (!Cache->FullName.Buffer)
3442                 DuplicateUnicodeString(pNameW, &Cache->FullName);
3443         }
3444     }
3445 
3446     return Status;
3447 }
3448 
3449 static void FASTCALL
FontFamilyFillInfo(PFONTFAMILYINFO Info,LPCWSTR FaceName,LPCWSTR FullName,PFONTGDI FontGDI)3450 FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
3451                    LPCWSTR FullName, PFONTGDI FontGDI)
3452 {
3453     ANSI_STRING StyleA;
3454     UNICODE_STRING StyleW;
3455     TT_OS2 *pOS2;
3456     FONTSIGNATURE fs;
3457     CHARSETINFO CharSetInfo;
3458     unsigned i, Size;
3459     OUTLINETEXTMETRICW *Otm;
3460     LOGFONTW *Lf;
3461     TEXTMETRICW *TM;
3462     NEWTEXTMETRICW *Ntm;
3463     DWORD fs0;
3464     NTSTATUS status;
3465     PSHARED_FACE SharedFace = FontGDI->SharedFace;
3466     FT_Face Face = SharedFace->Face;
3467     UNICODE_STRING NameW;
3468 
3469     RtlInitUnicodeString(&NameW, NULL);
3470     RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
3471     ASSERT_FREETYPE_LOCK_HELD();
3472     Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL, TRUE);
3473     Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
3474     if (!Otm)
3475     {
3476         return;
3477     }
3478     ASSERT_FREETYPE_LOCK_HELD();
3479     Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm, TRUE);
3480     if (!Size)
3481     {
3482         ExFreePoolWithTag(Otm, GDITAG_TEXT);
3483         return;
3484     }
3485 
3486     Lf = &Info->EnumLogFontEx.elfLogFont;
3487     TM = &Otm->otmTextMetrics;
3488 
3489     Lf->lfHeight = TM->tmHeight;
3490     Lf->lfWidth = TM->tmAveCharWidth;
3491     Lf->lfWeight = TM->tmWeight;
3492     Lf->lfItalic = TM->tmItalic;
3493     Lf->lfPitchAndFamily = (TM->tmPitchAndFamily & 0xf1) + 1;
3494     Lf->lfCharSet = TM->tmCharSet;
3495     Lf->lfOutPrecision = OUT_OUTLINE_PRECIS;
3496     Lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
3497     Lf->lfQuality = PROOF_QUALITY;
3498 
3499     Ntm = &Info->NewTextMetricEx.ntmTm;
3500     Ntm->tmHeight = TM->tmHeight;
3501     Ntm->tmAscent = TM->tmAscent;
3502     Ntm->tmDescent = TM->tmDescent;
3503     Ntm->tmInternalLeading = TM->tmInternalLeading;
3504     Ntm->tmExternalLeading = TM->tmExternalLeading;
3505     Ntm->tmAveCharWidth = TM->tmAveCharWidth;
3506     Ntm->tmMaxCharWidth = TM->tmMaxCharWidth;
3507     Ntm->tmWeight = TM->tmWeight;
3508     Ntm->tmOverhang = TM->tmOverhang;
3509     Ntm->tmDigitizedAspectX = TM->tmDigitizedAspectX;
3510     Ntm->tmDigitizedAspectY = TM->tmDigitizedAspectY;
3511     Ntm->tmFirstChar = TM->tmFirstChar;
3512     Ntm->tmLastChar = TM->tmLastChar;
3513     Ntm->tmDefaultChar = TM->tmDefaultChar;
3514     Ntm->tmBreakChar = TM->tmBreakChar;
3515     Ntm->tmItalic = TM->tmItalic;
3516     Ntm->tmUnderlined = TM->tmUnderlined;
3517     Ntm->tmStruckOut = TM->tmStruckOut;
3518     Ntm->tmPitchAndFamily = TM->tmPitchAndFamily;
3519     Ntm->tmCharSet = TM->tmCharSet;
3520     Ntm->ntmFlags = TM->tmItalic ? NTM_ITALIC : 0;
3521 
3522     if (550 < TM->tmWeight) Ntm->ntmFlags |= NTM_BOLD;
3523 
3524     if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
3525 
3526     Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
3527                       ? TRUETYPE_FONTTYPE : 0);
3528 
3529     if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
3530         Info->FontType |= RASTER_FONTTYPE;
3531 
3532 
3533     /* face name */
3534     if (!FaceName)
3535         FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
3536 
3537     RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
3538 
3539     /* full name */
3540     if (!FullName)
3541         FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
3542 
3543     RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
3544                      sizeof(Info->EnumLogFontEx.elfFullName),
3545                      FullName);
3546 
3547     RtlInitAnsiString(&StyleA, Face->style_name);
3548     StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
3549     StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
3550     status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
3551     if (!NT_SUCCESS(status))
3552     {
3553         ExFreePoolWithTag(Otm, GDITAG_TEXT);
3554         return;
3555     }
3556     Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
3557 
3558     pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
3559 
3560     if (!pOS2)
3561     {
3562         ExFreePoolWithTag(Otm, GDITAG_TEXT);
3563         return;
3564     }
3565 
3566     Ntm->ntmSizeEM = Otm->otmEMSquare;
3567     Ntm->ntmCellHeight = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
3568     Ntm->ntmAvgWidth = 0;
3569 
3570     ExFreePoolWithTag(Otm, GDITAG_TEXT);
3571 
3572     fs.fsCsb[0] = pOS2->ulCodePageRange1;
3573     fs.fsCsb[1] = pOS2->ulCodePageRange2;
3574     fs.fsUsb[0] = pOS2->ulUnicodeRange1;
3575     fs.fsUsb[1] = pOS2->ulUnicodeRange2;
3576     fs.fsUsb[2] = pOS2->ulUnicodeRange3;
3577     fs.fsUsb[3] = pOS2->ulUnicodeRange4;
3578 
3579     if (0 == pOS2->version)
3580     {
3581         FT_UInt Dummy;
3582 
3583         if (FT_Get_First_Char(Face, &Dummy) < 0x100)
3584             fs.fsCsb[0] |= FS_LATIN1;
3585         else
3586             fs.fsCsb[0] |= FS_SYMBOL;
3587     }
3588 
3589     if (fs.fsCsb[0] == 0)
3590     {
3591         /* Let's see if we can find any interesting cmaps */
3592         for (i = 0; i < (UINT)Face->num_charmaps; i++)
3593         {
3594             switch (Face->charmaps[i]->encoding)
3595             {
3596             case FT_ENCODING_UNICODE:
3597             case FT_ENCODING_APPLE_ROMAN:
3598                 fs.fsCsb[0] |= FS_LATIN1;
3599                 break;
3600             case FT_ENCODING_MS_SYMBOL:
3601                 fs.fsCsb[0] |= FS_SYMBOL;
3602                 break;
3603             default:
3604                 break;
3605             }
3606         }
3607     }
3608 
3609     for (i = 0; i < MAXTCIINDEX; i++)
3610     {
3611         fs0 = 1L << i;
3612         if (fs.fsCsb[0] & fs0)
3613         {
3614             if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
3615             {
3616                 CharSetInfo.ciCharset = DEFAULT_CHARSET;
3617             }
3618             if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
3619             {
3620                 if (g_ElfScripts[i])
3621                     wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
3622                 else
3623                 {
3624                     DPRINT1("Unknown elfscript for bit %u\n", i);
3625                 }
3626             }
3627         }
3628     }
3629     Info->NewTextMetricEx.ntmFontSig = fs;
3630 }
3631 
3632 static BOOLEAN FASTCALL
GetFontFamilyInfoForList(const LOGFONTW * LogFont,PFONTFAMILYINFO Info,LPCWSTR NominalName,LONG * pCount,LONG MaxCount,PLIST_ENTRY Head)3633 GetFontFamilyInfoForList(const LOGFONTW *LogFont,
3634                          PFONTFAMILYINFO Info,
3635                          LPCWSTR NominalName,
3636                          LONG *pCount,
3637                          LONG MaxCount,
3638                          PLIST_ENTRY Head)
3639 {
3640     PLIST_ENTRY Entry;
3641     PFONT_ENTRY CurrentEntry;
3642     FONTGDI *FontGDI;
3643     FONTFAMILYINFO InfoEntry;
3644     LONG Count = *pCount;
3645 
3646     for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
3647     {
3648         CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
3649         FontGDI = CurrentEntry->Font;
3650         ASSERT(FontGDI);
3651 
3652         if (LogFont->lfCharSet != DEFAULT_CHARSET &&
3653             LogFont->lfCharSet != FontGDI->CharSet)
3654         {
3655             continue;   /* charset mismatch */
3656         }
3657 
3658         /* get one info entry */
3659         FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
3660 
3661         if (LogFont->lfFaceName[0] != UNICODE_NULL)
3662         {
3663             /* check name */
3664             if (_wcsnicmp(LogFont->lfFaceName,
3665                           InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
3666                           RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
3667                 _wcsnicmp(LogFont->lfFaceName,
3668                           InfoEntry.EnumLogFontEx.elfFullName,
3669                           RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
3670             {
3671                 continue;
3672             }
3673         }
3674 
3675         if (NominalName)
3676         {
3677             /* store the nominal name */
3678             RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
3679                              sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
3680                              NominalName);
3681         }
3682 
3683         /* store one entry to Info */
3684         if (0 <= Count && Count < MaxCount)
3685         {
3686             RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
3687         }
3688         Count++;
3689     }
3690 
3691     *pCount = Count;
3692 
3693     return TRUE;
3694 }
3695 
3696 static BOOLEAN FASTCALL
GetFontFamilyInfoForSubstitutes(const LOGFONTW * LogFont,PFONTFAMILYINFO Info,LONG * pCount,LONG MaxCount)3697 GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont,
3698                                 PFONTFAMILYINFO Info,
3699                                 LONG *pCount,
3700                                 LONG MaxCount)
3701 {
3702     PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
3703     PFONTSUBST_ENTRY pCurrentEntry;
3704     PUNICODE_STRING pFromW, pToW;
3705     LOGFONTW lf = *LogFont;
3706     PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
3707 
3708     for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
3709     {
3710         pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
3711 
3712         pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
3713         if (LogFont->lfFaceName[0] != UNICODE_NULL)
3714         {
3715             /* check name */
3716             if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
3717                 continue;   /* mismatch */
3718         }
3719 
3720         pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
3721         if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
3722             pCurrentEntry->CharSets[FONTSUBST_FROM] ==
3723             pCurrentEntry->CharSets[FONTSUBST_TO])
3724         {
3725             /* identical mapping */
3726             continue;
3727         }
3728 
3729         /* substitute and get the real name */
3730         IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
3731         SubstituteFontRecurse(&lf);
3732         if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
3733             continue;
3734 
3735         /* search in global fonts */
3736         IntLockFreeType();
3737         GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
3738 
3739         /* search in private fonts */
3740         IntLockProcessPrivateFonts(Win32Process);
3741         GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
3742                                  &Win32Process->PrivateFontListHead);
3743         IntUnLockProcessPrivateFonts(Win32Process);
3744         IntUnLockFreeType();
3745 
3746         if (LogFont->lfFaceName[0] != UNICODE_NULL)
3747         {
3748             /* it's already matched to the exact name and charset if the name
3749                was specified at here, then so don't scan more for another name */
3750             break;
3751         }
3752     }
3753 
3754     return TRUE;
3755 }
3756 
3757 BOOL
3758 FASTCALL
ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)3759 ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs)
3760 {
3761     if ( lprs )
3762     {
3763         lprs->nSize = sizeof(RASTERIZER_STATUS);
3764         lprs->wFlags = TT_AVAILABLE | TT_ENABLED;
3765         lprs->nLanguageID = gusLanguageID;
3766         return TRUE;
3767     }
3768     EngSetLastError(ERROR_INVALID_PARAMETER);
3769     return FALSE;
3770 }
3771 
3772 static DWORD
IntGetHash(IN LPCVOID pv,IN DWORD cdw)3773 IntGetHash(IN LPCVOID pv, IN DWORD cdw)
3774 {
3775     DWORD dwHash = cdw;
3776     const DWORD *pdw = pv;
3777 
3778     while (cdw-- > 0)
3779     {
3780         dwHash *= 3;
3781         dwHash ^= *pdw++;
3782     }
3783 
3784     return dwHash;
3785 }
3786 
3787 static FT_BitmapGlyph
IntFindGlyphCache(IN const FONT_CACHE_ENTRY * pCache)3788 IntFindGlyphCache(IN const FONT_CACHE_ENTRY *pCache)
3789 {
3790     PLIST_ENTRY CurrentEntry;
3791     PFONT_CACHE_ENTRY FontEntry;
3792     DWORD dwHash = pCache->dwHash;
3793 
3794     ASSERT_FREETYPE_LOCK_HELD();
3795 
3796     for (CurrentEntry = g_FontCacheListHead.Flink;
3797          CurrentEntry != &g_FontCacheListHead;
3798          CurrentEntry = CurrentEntry->Flink)
3799     {
3800         FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
3801         if (FontEntry->dwHash == dwHash &&
3802             FontEntry->Hashed.GlyphIndex == pCache->Hashed.GlyphIndex &&
3803             FontEntry->Hashed.Face == pCache->Hashed.Face &&
3804             FontEntry->Hashed.lfHeight == pCache->Hashed.lfHeight &&
3805             FontEntry->Hashed.lfWidth == pCache->Hashed.lfWidth &&
3806             FontEntry->Hashed.AspectValue == pCache->Hashed.AspectValue &&
3807             memcmp(&FontEntry->Hashed.matTransform, &pCache->Hashed.matTransform,
3808                    sizeof(FT_Matrix)) == 0)
3809         {
3810             break;
3811         }
3812     }
3813 
3814     if (CurrentEntry == &g_FontCacheListHead)
3815     {
3816         return NULL;
3817     }
3818 
3819     RemoveEntryList(CurrentEntry);
3820     InsertHeadList(&g_FontCacheListHead, CurrentEntry);
3821     return FontEntry->BitmapGlyph;
3822 }
3823 
3824 static FT_BitmapGlyph
IntGetBitmapGlyphWithCache(IN OUT PFONT_CACHE_ENTRY Cache,IN FT_GlyphSlot GlyphSlot)3825 IntGetBitmapGlyphWithCache(
3826     IN OUT PFONT_CACHE_ENTRY Cache,
3827     IN FT_GlyphSlot GlyphSlot)
3828 {
3829     FT_Glyph GlyphCopy;
3830     INT error;
3831     PFONT_CACHE_ENTRY NewEntry;
3832     FT_Bitmap AlignedBitmap;
3833     FT_BitmapGlyph BitmapGlyph;
3834 
3835     ASSERT_FREETYPE_LOCK_HELD();
3836 
3837     error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
3838     if (error)
3839     {
3840         DPRINT1("Failure caching glyph.\n");
3841         return NULL;
3842     };
3843 
3844     error = FT_Glyph_To_Bitmap(&GlyphCopy, Cache->Hashed.Aspect.RenderMode, 0, 1);
3845     if (error)
3846     {
3847         FT_Done_Glyph(GlyphCopy);
3848         DPRINT1("Failure rendering glyph.\n");
3849         return NULL;
3850     };
3851 
3852     NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
3853     if (!NewEntry)
3854     {
3855         DPRINT1("Alloc failure caching glyph.\n");
3856         FT_Done_Glyph(GlyphCopy);
3857         return NULL;
3858     }
3859 
3860     BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
3861     FT_Bitmap_New(&AlignedBitmap);
3862     if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
3863     {
3864         DPRINT1("Conversion failed\n");
3865         ExFreePoolWithTag(NewEntry, TAG_FONT);
3866         FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
3867         FT_Done_Glyph((FT_Glyph)BitmapGlyph);
3868         return NULL;
3869     }
3870 
3871     FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
3872     BitmapGlyph->bitmap = AlignedBitmap;
3873 
3874     NewEntry->BitmapGlyph = BitmapGlyph;
3875     NewEntry->dwHash = Cache->dwHash;
3876     NewEntry->Hashed = Cache->Hashed;
3877 
3878     InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
3879     if (++g_FontCacheNumEntries > MAX_FONT_CACHE)
3880     {
3881         NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
3882         RemoveCachedEntry(NewEntry);
3883     }
3884 
3885     return BitmapGlyph;
3886 }
3887 
3888 
get_native_glyph_outline(FT_Outline * outline,unsigned int buflen,char * buf)3889 static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3890 {
3891     TTPOLYGONHEADER *pph;
3892     TTPOLYCURVE *ppc;
3893     int needed = 0, point = 0, contour, first_pt;
3894     unsigned int pph_start, cpfx;
3895     DWORD type;
3896 
3897     for (contour = 0; contour < outline->n_contours; contour++)
3898     {
3899         /* Ignore contours containing one point */
3900         if (point == outline->contours[contour])
3901         {
3902             point++;
3903             continue;
3904         }
3905 
3906         pph_start = needed;
3907         pph = (TTPOLYGONHEADER *)(buf + needed);
3908         first_pt = point;
3909         if (buf)
3910         {
3911             pph->dwType = TT_POLYGON_TYPE;
3912             FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3913         }
3914         needed += sizeof(*pph);
3915         point++;
3916         while (point <= outline->contours[contour])
3917         {
3918             ppc = (TTPOLYCURVE *)(buf + needed);
3919             type = (outline->tags[point] & FT_Curve_Tag_On) ?
3920                 TT_PRIM_LINE : TT_PRIM_QSPLINE;
3921             cpfx = 0;
3922             do
3923             {
3924                 if (buf)
3925                     FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3926                 cpfx++;
3927                 point++;
3928             } while (point <= outline->contours[contour] &&
3929                     (outline->tags[point] & FT_Curve_Tag_On) ==
3930                     (outline->tags[point-1] & FT_Curve_Tag_On));
3931             /* At the end of a contour Windows adds the start point, but
3932                only for Beziers */
3933             if (point > outline->contours[contour] &&
3934                !(outline->tags[point-1] & FT_Curve_Tag_On))
3935             {
3936                 if (buf)
3937                     FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
3938                 cpfx++;
3939             }
3940             else if (point <= outline->contours[contour] &&
3941                       outline->tags[point] & FT_Curve_Tag_On)
3942             {
3943                 /* add closing pt for bezier */
3944                 if (buf)
3945                     FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
3946                 cpfx++;
3947                 point++;
3948             }
3949             if (buf)
3950             {
3951                 ppc->wType = type;
3952                 ppc->cpfx = cpfx;
3953             }
3954             needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
3955         }
3956         if (buf)
3957             pph->cb = needed - pph_start;
3958     }
3959     return needed;
3960 }
3961 
get_bezier_glyph_outline(FT_Outline * outline,unsigned int buflen,char * buf)3962 static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
3963 {
3964     /* Convert the quadratic Beziers to cubic Beziers.
3965        The parametric eqn for a cubic Bezier is, from PLRM:
3966        r(t) = at^3 + bt^2 + ct + r0
3967        with the control points:
3968        r1 = r0 + c/3
3969        r2 = r1 + (c + b)/3
3970        r3 = r0 + c + b + a
3971 
3972        A quadratic Bezier has the form:
3973        p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
3974 
3975        So equating powers of t leads to:
3976        r1 = 2/3 p1 + 1/3 p0
3977        r2 = 2/3 p1 + 1/3 p2
3978        and of course r0 = p0, r3 = p2
3979     */
3980     int contour, point = 0, first_pt;
3981     TTPOLYGONHEADER *pph;
3982     TTPOLYCURVE *ppc;
3983     DWORD pph_start, cpfx, type;
3984     FT_Vector cubic_control[4];
3985     unsigned int needed = 0;
3986 
3987     for (contour = 0; contour < outline->n_contours; contour++)
3988     {
3989         pph_start = needed;
3990         pph = (TTPOLYGONHEADER *)(buf + needed);
3991         first_pt = point;
3992         if (buf)
3993         {
3994             pph->dwType = TT_POLYGON_TYPE;
3995             FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
3996         }
3997         needed += sizeof(*pph);
3998         point++;
3999         while (point <= outline->contours[contour])
4000         {
4001             ppc = (TTPOLYCURVE *)(buf + needed);
4002             type = (outline->tags[point] & FT_Curve_Tag_On) ?
4003                 TT_PRIM_LINE : TT_PRIM_CSPLINE;
4004             cpfx = 0;
4005             do
4006             {
4007                 if (type == TT_PRIM_LINE)
4008                 {
4009                     if (buf)
4010                         FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
4011                     cpfx++;
4012                     point++;
4013                 }
4014                 else
4015                 {
4016                     /* Unlike QSPLINEs, CSPLINEs always have their endpoint
4017                        so cpfx = 3n */
4018 
4019                     /* FIXME: Possible optimization in endpoint calculation
4020                        if there are two consecutive curves */
4021                     cubic_control[0] = outline->points[point-1];
4022                     if (!(outline->tags[point-1] & FT_Curve_Tag_On))
4023                     {
4024                         cubic_control[0].x += outline->points[point].x + 1;
4025                         cubic_control[0].y += outline->points[point].y + 1;
4026                         cubic_control[0].x >>= 1;
4027                         cubic_control[0].y >>= 1;
4028                     }
4029                     if (point+1 > outline->contours[contour])
4030                         cubic_control[3] = outline->points[first_pt];
4031                     else
4032                     {
4033                         cubic_control[3] = outline->points[point+1];
4034                         if (!(outline->tags[point+1] & FT_Curve_Tag_On))
4035                         {
4036                             cubic_control[3].x += outline->points[point].x + 1;
4037                             cubic_control[3].y += outline->points[point].y + 1;
4038                             cubic_control[3].x >>= 1;
4039                             cubic_control[3].y >>= 1;
4040                         }
4041                     }
4042                     /* r1 = 1/3 p0 + 2/3 p1
4043                        r2 = 1/3 p2 + 2/3 p1 */
4044                     cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
4045                     cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
4046                     cubic_control[2] = cubic_control[1];
4047                     cubic_control[1].x += (cubic_control[0].x + 1) / 3;
4048                     cubic_control[1].y += (cubic_control[0].y + 1) / 3;
4049                     cubic_control[2].x += (cubic_control[3].x + 1) / 3;
4050                     cubic_control[2].y += (cubic_control[3].y + 1) / 3;
4051                     if (buf)
4052                     {
4053                         FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
4054                         FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
4055                         FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
4056                     }
4057                     cpfx += 3;
4058                     point++;
4059                 }
4060             } while (point <= outline->contours[contour] &&
4061                     (outline->tags[point] & FT_Curve_Tag_On) ==
4062                     (outline->tags[point-1] & FT_Curve_Tag_On));
4063             /* At the end of a contour Windows adds the start point,
4064                but only for Beziers and we've already done that.
4065             */
4066             if (point <= outline->contours[contour] &&
4067                outline->tags[point] & FT_Curve_Tag_On)
4068             {
4069                 /* This is the closing pt of a bezier, but we've already
4070                    added it, so just inc point and carry on */
4071                 point++;
4072             }
4073             if (buf)
4074             {
4075                 ppc->wType = type;
4076                 ppc->cpfx = cpfx;
4077             }
4078             needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
4079         }
4080         if (buf)
4081             pph->cb = needed - pph_start;
4082     }
4083     return needed;
4084 }
4085 
4086 static FT_Error
IntRequestFontSize(PDC dc,PFONTGDI FontGDI,LONG lfWidth,LONG lfHeight)4087 IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
4088 {
4089     FT_Error error;
4090     FT_Size_RequestRec  req;
4091     FT_Face face = FontGDI->SharedFace->Face;
4092     TT_OS2 *pOS2;
4093     TT_HoriHeader *pHori;
4094     FT_WinFNT_HeaderRec WinFNT;
4095     LONG Ascent, Descent, Sum, EmHeight, Width64;
4096 
4097     lfWidth = abs(lfWidth);
4098     if (lfHeight == 0)
4099     {
4100         if (lfWidth == 0)
4101         {
4102             DPRINT("lfHeight and lfWidth are zero.\n");
4103             lfHeight = -16;
4104         }
4105         else
4106         {
4107             lfHeight = lfWidth;
4108         }
4109     }
4110 
4111     if (lfHeight == -1)
4112         lfHeight = -2;
4113 
4114     if (FontGDI->Magic == FONTGDI_MAGIC &&
4115         FontGDI->lfHeight == lfHeight &&
4116         FontGDI->lfWidth == lfWidth)
4117     {
4118         return 0; /* Cached */
4119     }
4120 
4121     ASSERT_FREETYPE_LOCK_HELD();
4122     pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
4123     pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
4124 
4125     if (!pOS2 || !pHori)
4126     {
4127         error = FT_Get_WinFNT_Header(face, &WinFNT);
4128         if (error)
4129         {
4130             DPRINT1("%s: Failed to request font size.\n", face->family_name);
4131             ASSERT(FALSE);
4132             return error;
4133         }
4134 
4135         FontGDI->tmHeight           = WinFNT.pixel_height;
4136         FontGDI->tmAscent           = WinFNT.ascent;
4137         FontGDI->tmDescent          = FontGDI->tmHeight - FontGDI->tmAscent;
4138         FontGDI->tmInternalLeading  = WinFNT.internal_leading;
4139         FontGDI->Magic              = FONTGDI_MAGIC;
4140         FontGDI->lfHeight           = lfHeight;
4141         FontGDI->lfWidth            = lfWidth;
4142         return 0;
4143     }
4144 
4145     /*
4146      * NOTE: We cast TT_OS2.usWinAscent and TT_OS2.usWinDescent to signed FT_Short.
4147      * Why? See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswindescent
4148      *
4149      * > usWinDescent is "usually" a positive value ...
4150      *
4151      * We can read it as "not always". See CORE-14994.
4152      * See also: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
4153      */
4154 #define FM_SEL_USE_TYPO_METRICS 0x80
4155     if (lfHeight > 0)
4156     {
4157         /* case (A): lfHeight is positive */
4158         Sum = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
4159         if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
4160         {
4161             Ascent = pHori->Ascender;
4162             Descent = -pHori->Descender;
4163             Sum = Ascent + Descent;
4164         }
4165         else
4166         {
4167             Ascent = (FT_Short)pOS2->usWinAscent;
4168             Descent = (FT_Short)pOS2->usWinDescent;
4169         }
4170 
4171         FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
4172         FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
4173         FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
4174         FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
4175     }
4176     else if (lfHeight < 0)
4177     {
4178         /* case (B): lfHeight is negative */
4179         if (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS)
4180         {
4181             FontGDI->tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
4182             FontGDI->tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
4183         }
4184         else
4185         {
4186             FontGDI->tmAscent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinAscent, face->units_per_EM);
4187             FontGDI->tmDescent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinDescent, face->units_per_EM);
4188         }
4189         FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
4190         FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
4191     }
4192 #undef FM_SEL_USE_TYPO_METRICS
4193 
4194     FontGDI->Magic = FONTGDI_MAGIC;
4195     FontGDI->lfHeight = lfHeight;
4196     FontGDI->lfWidth = lfWidth;
4197 
4198     EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
4199     EmHeight = max(EmHeight, 1);
4200     EmHeight = min(EmHeight, USHORT_MAX);
4201 
4202 #if 1
4203     /* I think this is wrong implementation but its test result is better. */
4204     if (lfWidth != 0)
4205         Width64 = FT_MulDiv(lfWidth, face->units_per_EM, pOS2->xAvgCharWidth) << 6;
4206     else
4207         Width64 = 0;
4208 #else
4209     /* I think this is correct implementation but it is mismatching to the
4210        other metric functions. The test result is bad. */
4211     if (lfWidth != 0)
4212         Width64 = (FT_MulDiv(lfWidth, 96 * 5, 72 * 3) << 6); /* ??? FIXME */
4213     else
4214         Width64 = 0;
4215 #endif
4216 
4217     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
4218     req.width          = Width64;
4219     req.height         = (EmHeight << 6);
4220     req.horiResolution = 0;
4221     req.vertResolution = 0;
4222     return FT_Request_Size(face, &req);
4223 }
4224 
4225 BOOL
4226 FASTCALL
TextIntUpdateSize(PDC dc,PTEXTOBJ TextObj,PFONTGDI FontGDI,BOOL bDoLock)4227 TextIntUpdateSize(PDC dc,
4228                   PTEXTOBJ TextObj,
4229                   PFONTGDI FontGDI,
4230                   BOOL bDoLock)
4231 {
4232     FT_Face face;
4233     INT error, n;
4234     FT_CharMap charmap, found;
4235     LOGFONTW *plf;
4236 
4237     if (bDoLock)
4238         IntLockFreeType();
4239 
4240     face = FontGDI->SharedFace->Face;
4241     if (face->charmap == NULL)
4242     {
4243         DPRINT("WARNING: No charmap selected!\n");
4244         DPRINT("This font face has %d charmaps\n", face->num_charmaps);
4245 
4246         found = NULL;
4247         for (n = 0; n < face->num_charmaps; n++)
4248         {
4249             charmap = face->charmaps[n];
4250             if (charmap->encoding == FT_ENCODING_UNICODE)
4251             {
4252                 found = charmap;
4253                 break;
4254             }
4255         }
4256         if (!found)
4257         {
4258             for (n = 0; n < face->num_charmaps; n++)
4259             {
4260                 charmap = face->charmaps[n];
4261                 if (charmap->platform_id == TT_PLATFORM_APPLE_UNICODE)
4262                 {
4263                     found = charmap;
4264                     break;
4265                 }
4266             }
4267         }
4268         if (!found)
4269         {
4270             for (n = 0; n < face->num_charmaps; n++)
4271             {
4272                 charmap = face->charmaps[n];
4273                 if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
4274                 {
4275                     found = charmap;
4276                     break;
4277                 }
4278             }
4279         }
4280         if (!found && face->num_charmaps > 0)
4281         {
4282             found = face->charmaps[0];
4283         }
4284         if (!found)
4285         {
4286             DPRINT1("WARNING: Could not find desired charmap!\n");
4287         }
4288         else
4289         {
4290             DPRINT("Found charmap encoding: %i\n", found->encoding);
4291             error = FT_Set_Charmap(face, found);
4292             if (error)
4293             {
4294                 DPRINT1("WARNING: Could not set the charmap!\n");
4295             }
4296         }
4297     }
4298 
4299     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4300 
4301     error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
4302 
4303     if (bDoLock)
4304         IntUnLockFreeType();
4305 
4306     if (error)
4307     {
4308         DPRINT1("Error in setting pixel sizes: %d\n", error);
4309         return FALSE;
4310     }
4311 
4312     return TRUE;
4313 }
4314 
4315 static inline FT_UInt FASTCALL
get_glyph_index_symbol(FT_Face ft_face,UINT glyph)4316 get_glyph_index_symbol(FT_Face ft_face, UINT glyph)
4317 {
4318     FT_UInt ret;
4319 
4320     if (glyph < 0x100) glyph += 0xf000;
4321     /* there are a number of old pre-Unicode "broken" TTFs, which
4322        do have symbols at U+00XX instead of U+f0XX */
4323     if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
4324         ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
4325 
4326     return ret;
4327 }
4328 
4329 static inline FT_UInt FASTCALL
get_glyph_index(FT_Face ft_face,UINT glyph)4330 get_glyph_index(FT_Face ft_face, UINT glyph)
4331 {
4332     FT_UInt ret;
4333 
4334     if (face_has_symbol_charmap(ft_face))
4335     {
4336         ret = get_glyph_index_symbol(ft_face, glyph);
4337         if (ret != 0)
4338             return ret;
4339     }
4340 
4341     return FT_Get_Char_Index(ft_face, glyph);
4342 }
4343 
4344 static inline FT_UInt FASTCALL
get_glyph_index_flagged(FT_Face face,FT_ULong code,BOOL fCodeAsIndex)4345 get_glyph_index_flagged(FT_Face face, FT_ULong code, BOOL fCodeAsIndex)
4346 {
4347     return (fCodeAsIndex ? code : get_glyph_index(face, code));
4348 }
4349 
4350 static inline VOID
FontLink_Chain_Dump(_In_ PFONTLINK_CHAIN pChain)4351 FontLink_Chain_Dump(
4352     _In_ PFONTLINK_CHAIN pChain)
4353 {
4354 #if 0
4355     PLIST_ENTRY Entry, Head;
4356     PFONTLINK pFontLink;
4357     INT iLink = 0;
4358 
4359     DPRINT1("%S, %p, %p\n", pChain->LogFont.lfFaceName, pChain->pBaseTextObj, pChain->pDefFace);
4360 
4361     Head = &pChain->FontLinkList;
4362     for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4363     {
4364         pFontLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
4365         DPRINT1("FontLink #%d: %p, %d, %S, %p, %p\n",
4366                 iLink, pFontLink, pFontLink->bIgnore, pFontLink->LogFont.lfFaceName,
4367                 pFontLink->pFontGDI, pFontLink->SharedFace);
4368         ++iLink;
4369     }
4370 #endif
4371 }
4372 
4373 /// Search the target glyph and update the current font info.
4374 /// @return The glyph index
4375 static UINT
FontLink_Chain_FindGlyph(_Inout_ PFONTLINK_CHAIN pChain,_Out_ PFONT_CACHE_ENTRY pCache,_Inout_ FT_Face * pFace,_In_ UINT code,_In_ BOOL fCodeAsIndex)4376 FontLink_Chain_FindGlyph(
4377     _Inout_ PFONTLINK_CHAIN pChain,
4378     _Out_ PFONT_CACHE_ENTRY pCache,
4379     _Inout_ FT_Face *pFace,
4380     _In_ UINT code,
4381     _In_ BOOL fCodeAsIndex)
4382 {
4383     PFONTLINK pFontLink;
4384     PLIST_ENTRY Entry, Head;
4385     UINT index;
4386     FT_Face face;
4387 
4388     // Try the default font at first
4389     index = get_glyph_index_flagged(pChain->pDefFace, code, fCodeAsIndex);
4390     if (index)
4391     {
4392         DPRINT("code: 0x%08X, index: 0x%08X, fCodeAsIndex:%d\n", code, index, fCodeAsIndex);
4393         pCache->Hashed.Face = *pFace = pChain->pDefFace;
4394         return index; // The glyph is found on the default font
4395     }
4396 
4397     if (!FontLink_Chain_IsPopulated(pChain)) // The chain is not populated yet
4398     {
4399         FontLink_Chain_Populate(pChain);
4400         FontLink_Chain_Dump(pChain);
4401     }
4402 
4403     // Now the chain is populated. Looking for the target glyph...
4404     Head = &pChain->FontLinkList;
4405     for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
4406     {
4407         pFontLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
4408         if (!FontLink_PrepareFontInfo(pFontLink))
4409             continue; // This link is not useful, check the next one
4410 
4411         face = pFontLink->SharedFace->Face;
4412         index = get_glyph_index(face, code);
4413         if (!index)
4414             continue; // The glyph does not exist, continue searching
4415 
4416         // The target glyph is found in the chain
4417         DPRINT("code: 0x%08X, index: 0x%08X\n", code, index);
4418         pCache->Hashed.Face = *pFace = face;
4419         FT_Set_Transform(face, &pCache->Hashed.matTransform, NULL);
4420         return index;
4421     }
4422 
4423     // No target glyph found in the chain: use default glyph
4424     code = s_chFontLinkDefaultChar;
4425     index = get_glyph_index(*pFace, code);
4426     DPRINT("code: 0x%08X, index: 0x%08X\n", code, index);
4427     pCache->Hashed.Face = *pFace = pChain->pDefFace;
4428     return index;
4429 }
4430 
4431 /*
4432  * Based on WineEngGetGlyphOutline
4433  */
4434 ULONG
4435 FASTCALL
ftGdiGetGlyphOutline(PDC dc,WCHAR wch,UINT iFormat,LPGLYPHMETRICS pgm,ULONG cjBuf,PVOID pvBuf,LPMAT2 pmat2,BOOL bIgnoreRotation)4436 ftGdiGetGlyphOutline(
4437     PDC dc,
4438     WCHAR wch,
4439     UINT iFormat,
4440     LPGLYPHMETRICS pgm,
4441     ULONG cjBuf,
4442     PVOID pvBuf,
4443     LPMAT2 pmat2,
4444     BOOL bIgnoreRotation)
4445 {
4446     PDC_ATTR pdcattr;
4447     PTEXTOBJ TextObj;
4448     PFONTGDI FontGDI;
4449     HFONT hFont = 0;
4450     GLYPHMETRICS gm;
4451     ULONG Size;
4452     FT_Face ft_face;
4453     FT_UInt glyph_index;
4454     DWORD width, height, pitch, needed = 0;
4455     FT_Bitmap ft_bitmap;
4456     FT_Error error;
4457     INT left, right, top = 0, bottom = 0;
4458     FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
4459     FLOATOBJ eM11, widthRatio, eTemp;
4460     FT_Matrix mat, transMat = identityMat;
4461     BOOL needsTransform = FALSE;
4462     INT orientation;
4463     LONG aveWidth;
4464     INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
4465     OUTLINETEXTMETRICW *potm;
4466     XFORMOBJ xo;
4467     XFORML xform;
4468     LOGFONTW *plf;
4469 
4470     DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
4471            cjBuf, pvBuf, pmat2);
4472 
4473     pdcattr = dc->pdcattr;
4474 
4475     XFORMOBJ_vInit(&xo, &dc->pdcattr->mxWorldToDevice);
4476     XFORMOBJ_iGetXform(&xo, &xform);
4477     FLOATOBJ_SetFloat(&eM11, xform.eM11);
4478 
4479     hFont = pdcattr->hlfntNew;
4480     TextObj = RealizeFontInit(hFont);
4481 
4482     if (!TextObj)
4483     {
4484         EngSetLastError(ERROR_INVALID_HANDLE);
4485         return GDI_ERROR;
4486     }
4487     FontGDI = ObjToGDI(TextObj->Font, FONT);
4488     ft_face = FontGDI->SharedFace->Face;
4489 
4490     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4491     aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
4492     orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
4493 
4494     ASSERT_FREETYPE_LOCK_NOT_HELD();
4495     Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL, FALSE);
4496     potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
4497     if (!potm)
4498     {
4499         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4500         TEXTOBJ_UnlockText(TextObj);
4501         return GDI_ERROR;
4502     }
4503     ASSERT_FREETYPE_LOCK_NOT_HELD();
4504     Size = IntGetOutlineTextMetrics(FontGDI, Size, potm, FALSE);
4505     if (!Size)
4506     {
4507         /* FIXME: last error? */
4508         ExFreePoolWithTag(potm, GDITAG_TEXT);
4509         TEXTOBJ_UnlockText(TextObj);
4510         return GDI_ERROR;
4511     }
4512 
4513     IntLockFreeType();
4514     TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
4515     IntMatrixFromMx(&mat, DC_pmxWorldToDevice(dc));
4516     FT_Set_Transform(ft_face, &mat, NULL);
4517 
4518     TEXTOBJ_UnlockText(TextObj);
4519 
4520     glyph_index = get_glyph_index_flagged(ft_face, wch, (iFormat & GGO_GLYPH_INDEX));
4521     iFormat &= ~GGO_GLYPH_INDEX;
4522 
4523     if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
4524         load_flags |= FT_LOAD_NO_BITMAP;
4525 
4526     if (iFormat & GGO_UNHINTED)
4527     {
4528         load_flags |= FT_LOAD_NO_HINTING;
4529         iFormat &= ~GGO_UNHINTED;
4530     }
4531 
4532     error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
4533     if (error)
4534     {
4535         DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
4536         IntUnLockFreeType();
4537         if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
4538         return GDI_ERROR;
4539     }
4540     IntUnLockFreeType();
4541 
4542     FLOATOBJ_Set1(&widthRatio);
4543     if (aveWidth && potm)
4544     {
4545         // widthRatio = aveWidth * eM11 / potm->otmTextMetrics.tmAveCharWidth
4546         FLOATOBJ_SetLong(&widthRatio, aveWidth);
4547         FLOATOBJ_Mul(&widthRatio, &eM11);
4548         FLOATOBJ_DivLong(&widthRatio, potm->otmTextMetrics.tmAveCharWidth);
4549     }
4550 
4551     //left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
4552     FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX);
4553     FLOATOBJ_Mul(&eTemp, &widthRatio);
4554     left = FLOATOBJ_GetLong(&eTemp) & -64;
4555 
4556     //right = (INT)((ft_face->glyph->metrics.horiBearingX +
4557     //               ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
4558     FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiBearingX * ft_face->glyph->metrics.width);
4559     FLOATOBJ_Mul(&eTemp, &widthRatio);
4560     FLOATOBJ_AddLong(&eTemp, 63);
4561     right = FLOATOBJ_GetLong(&eTemp) & -64;
4562 
4563     //adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
4564     FLOATOBJ_SetLong(&eTemp, ft_face->glyph->metrics.horiAdvance);
4565     FLOATOBJ_Mul(&eTemp, &widthRatio);
4566     FLOATOBJ_AddLong(&eTemp, 63);
4567     adv = FLOATOBJ_GetLong(&eTemp) >> 6;
4568 
4569     lsb = left >> 6;
4570     bbx = (right - left) >> 6;
4571 
4572     DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
4573 
4574     IntLockFreeType();
4575 
4576     /* Width scaling transform */
4577     if (!FLOATOBJ_Equal1(&widthRatio))
4578     {
4579         FT_Matrix scaleMat;
4580 
4581         eTemp = widthRatio;
4582         FLOATOBJ_MulLong(&eTemp, 1 << 16);
4583 
4584         scaleMat.xx = FLOATOBJ_GetLong(&eTemp);
4585         scaleMat.xy = 0;
4586         scaleMat.yx = 0;
4587         scaleMat.yy = INT_TO_FIXED(1);
4588         FT_Matrix_Multiply(&scaleMat, &transMat);
4589         needsTransform = TRUE;
4590     }
4591 
4592     /* World transform */
4593     {
4594         FT_Matrix ftmatrix;
4595         PMATRIX pmx = DC_pmxWorldToDevice(dc);
4596 
4597         /* Create a freetype matrix, by converting to 16.16 fixpoint format */
4598         IntMatrixFromMx(&ftmatrix, pmx);
4599 
4600         if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
4601         {
4602             FT_Matrix_Multiply(&ftmatrix, &transMat);
4603             needsTransform = TRUE;
4604         }
4605     }
4606 
4607     /* Rotation transform */
4608     if (orientation)
4609     {
4610         FT_Matrix rotationMat;
4611         DPRINT("Rotation Trans!\n");
4612         IntEscapeMatrix(&rotationMat, orientation);
4613         FT_Matrix_Multiply(&rotationMat, &transMat);
4614         needsTransform = TRUE;
4615     }
4616 
4617     /* Extra transformation specified by caller */
4618     if (pmat2)
4619     {
4620         FT_Matrix extraMat;
4621         DPRINT("MAT2 Matrix Trans!\n");
4622         extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
4623         extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
4624         extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
4625         extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
4626         FT_Matrix_Multiply(&extraMat, &transMat);
4627         needsTransform = TRUE;
4628     }
4629 
4630     if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT); /* It looks like we are finished with potm ATM. */
4631 
4632     if (!needsTransform)
4633     {
4634         DPRINT("No Need to be Transformed!\n");
4635         top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
4636         bottom = (ft_face->glyph->metrics.horiBearingY -
4637                   ft_face->glyph->metrics.height) & -64;
4638         gm.gmCellIncX = adv;
4639         gm.gmCellIncY = 0;
4640     }
4641     else
4642     {
4643         INT xc, yc;
4644         FT_Vector vec;
4645         for (xc = 0; xc < 2; xc++)
4646         {
4647             for (yc = 0; yc < 2; yc++)
4648             {
4649                 vec.x = (ft_face->glyph->metrics.horiBearingX +
4650                          xc * ft_face->glyph->metrics.width);
4651                 vec.y = ft_face->glyph->metrics.horiBearingY -
4652                         yc * ft_face->glyph->metrics.height;
4653                 DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
4654                 FT_Vector_Transform(&vec, &transMat);
4655                 if (xc == 0 && yc == 0)
4656                 {
4657                     left = right = vec.x;
4658                     top = bottom = vec.y;
4659                 }
4660                 else
4661                 {
4662                     if (vec.x < left) left = vec.x;
4663                     else if (vec.x > right) right = vec.x;
4664                     if (vec.y < bottom) bottom = vec.y;
4665                     else if (vec.y > top) top = vec.y;
4666                 }
4667             }
4668         }
4669         left = left & -64;
4670         right = (right + 63) & -64;
4671         bottom = bottom & -64;
4672         top = (top + 63) & -64;
4673 
4674         DPRINT("Transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
4675         vec.x = ft_face->glyph->metrics.horiAdvance;
4676         vec.y = 0;
4677         FT_Vector_Transform(&vec, &transMat);
4678         gm.gmCellIncX = (vec.x+63) >> 6;
4679         gm.gmCellIncY = -((vec.y+63) >> 6);
4680     }
4681     gm.gmBlackBoxX = (right - left) >> 6;
4682     gm.gmBlackBoxY = (top - bottom) >> 6;
4683     gm.gmptGlyphOrigin.x = left >> 6;
4684     gm.gmptGlyphOrigin.y = top >> 6;
4685 
4686     DPRINT("CX %d CY %d BBX %u BBY %u GOX %d GOY %d\n",
4687            gm.gmCellIncX, gm.gmCellIncY,
4688            gm.gmBlackBoxX, gm.gmBlackBoxY,
4689            gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
4690 
4691     IntUnLockFreeType();
4692 
4693     if (iFormat == GGO_METRICS)
4694     {
4695         DPRINT("GGO_METRICS Exit!\n");
4696         *pgm = gm;
4697         return 1; /* FIXME */
4698     }
4699 
4700     if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
4701     {
4702         DPRINT1("Loaded a bitmap\n");
4703         return GDI_ERROR;
4704     }
4705 
4706     switch (iFormat)
4707     {
4708     case GGO_BITMAP:
4709     {
4710         width = gm.gmBlackBoxX;
4711         height = gm.gmBlackBoxY;
4712         pitch = ((width + 31) >> 5) << 2;
4713         needed = pitch * height;
4714 
4715         if (!pvBuf || !cjBuf) break;
4716         if (!needed) return GDI_ERROR;  /* empty glyph */
4717         if (needed > cjBuf)
4718             return GDI_ERROR;
4719 
4720         switch (ft_face->glyph->format)
4721         {
4722         case ft_glyph_format_bitmap:
4723         {
4724             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4725             INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
4726             INT h = min( height, ft_face->glyph->bitmap.rows );
4727             while (h--)
4728             {
4729                 RtlCopyMemory(dst, src, w);
4730                 src += ft_face->glyph->bitmap.pitch;
4731                 dst += pitch;
4732             }
4733             break;
4734         }
4735 
4736         case ft_glyph_format_outline:
4737         {
4738             ft_bitmap.width = width;
4739             ft_bitmap.rows = height;
4740             ft_bitmap.pitch = pitch;
4741             ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
4742             ft_bitmap.buffer = pvBuf;
4743 
4744             IntLockFreeType();
4745             if (needsTransform)
4746             {
4747                 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4748             }
4749             FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4750             /* Note: FreeType will only set 'black' bits for us. */
4751             RtlZeroMemory(pvBuf, needed);
4752             FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4753             IntUnLockFreeType();
4754             break;
4755         }
4756 
4757         default:
4758             DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4759             return GDI_ERROR;
4760         }
4761 
4762         break;
4763     }
4764 
4765     case GGO_GRAY2_BITMAP:
4766     case GGO_GRAY4_BITMAP:
4767     case GGO_GRAY8_BITMAP:
4768     {
4769         unsigned int mult, row, col;
4770         BYTE *start, *ptr;
4771 
4772         width = gm.gmBlackBoxX;
4773         height = gm.gmBlackBoxY;
4774         pitch = (width + 3) / 4 * 4;
4775         needed = pitch * height;
4776 
4777         if (!pvBuf || !cjBuf) break;
4778         if (!needed) return GDI_ERROR;  /* empty glyph */
4779         if (needed > cjBuf)
4780             return GDI_ERROR;
4781 
4782         switch (ft_face->glyph->format)
4783         {
4784         case ft_glyph_format_bitmap:
4785         {
4786             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
4787             INT h = min( height, ft_face->glyph->bitmap.rows );
4788             INT x;
4789             while (h--)
4790             {
4791                 for (x = 0; (UINT)x < pitch; x++)
4792                 {
4793                     if (x < ft_face->glyph->bitmap.width)
4794                         dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
4795                     else
4796                         dst[x] = 0;
4797                 }
4798                 src += ft_face->glyph->bitmap.pitch;
4799                 dst += pitch;
4800             }
4801             break;
4802         }
4803         case ft_glyph_format_outline:
4804         {
4805             ft_bitmap.width = width;
4806             ft_bitmap.rows = height;
4807             ft_bitmap.pitch = pitch;
4808             ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
4809             ft_bitmap.buffer = pvBuf;
4810 
4811             IntLockFreeType();
4812             if (needsTransform)
4813             {
4814                 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
4815             }
4816             FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
4817             RtlZeroMemory(ft_bitmap.buffer, cjBuf);
4818             FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
4819             IntUnLockFreeType();
4820 
4821             if (iFormat == GGO_GRAY2_BITMAP)
4822                 mult = 4;
4823             else if (iFormat == GGO_GRAY4_BITMAP)
4824                 mult = 16;
4825             else if (iFormat == GGO_GRAY8_BITMAP)
4826                 mult = 64;
4827             else
4828             {
4829                 return GDI_ERROR;
4830             }
4831 
4832             start = pvBuf;
4833             for (row = 0; row < height; row++)
4834             {
4835                 ptr = start;
4836                 for (col = 0; col < width; col++, ptr++)
4837                 {
4838                     *ptr = (((int)*ptr) * mult + 128) / 256;
4839                 }
4840                 start += pitch;
4841             }
4842 
4843             break;
4844         }
4845         default:
4846             DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
4847             return GDI_ERROR;
4848         }
4849 
4850         break;
4851     }
4852 
4853     case GGO_NATIVE:
4854     {
4855         FT_Outline *outline = &ft_face->glyph->outline;
4856 
4857         if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
4858 
4859         IntLockFreeType();
4860         if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
4861 
4862         needed = get_native_glyph_outline(outline, cjBuf, NULL);
4863 
4864         if (!pvBuf || !cjBuf)
4865         {
4866             IntUnLockFreeType();
4867             break;
4868         }
4869         if (needed > cjBuf)
4870         {
4871             IntUnLockFreeType();
4872             return GDI_ERROR;
4873         }
4874         get_native_glyph_outline(outline, cjBuf, pvBuf);
4875         IntUnLockFreeType();
4876         break;
4877     }
4878 
4879     case GGO_BEZIER:
4880     {
4881         FT_Outline *outline = &ft_face->glyph->outline;
4882         if (cjBuf == 0) pvBuf = NULL;
4883 
4884         if (needsTransform && pvBuf)
4885         {
4886             IntLockFreeType();
4887             FT_Outline_Transform(outline, &transMat);
4888             IntUnLockFreeType();
4889         }
4890         needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
4891 
4892         if (!pvBuf || !cjBuf)
4893             break;
4894         if (needed > cjBuf)
4895             return GDI_ERROR;
4896 
4897         get_bezier_glyph_outline(outline, cjBuf, pvBuf);
4898         break;
4899     }
4900 
4901     default:
4902         DPRINT1("Unsupported format %u\n", iFormat);
4903         return GDI_ERROR;
4904     }
4905 
4906     DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
4907 
4908     if (gm.gmBlackBoxX == 0)
4909         gm.gmBlackBoxX = 1;
4910     if (gm.gmBlackBoxY == 0)
4911         gm.gmBlackBoxY = 1;
4912 
4913     *pgm = gm;
4914     return needed;
4915 }
4916 
4917 static FT_BitmapGlyph
IntGetRealGlyph(IN OUT PFONT_CACHE_ENTRY Cache)4918 IntGetRealGlyph(
4919     IN OUT PFONT_CACHE_ENTRY Cache)
4920 {
4921     INT error;
4922     FT_GlyphSlot glyph;
4923     FT_BitmapGlyph realglyph;
4924 
4925     ASSERT_FREETYPE_LOCK_HELD();
4926 
4927     Cache->dwHash = IntGetHash(&Cache->Hashed, sizeof(Cache->Hashed) / sizeof(DWORD));
4928 
4929     realglyph = IntFindGlyphCache(Cache);
4930     if (realglyph)
4931         return realglyph;
4932 
4933     error = FT_Load_Glyph(Cache->Hashed.Face, Cache->Hashed.GlyphIndex, FT_LOAD_DEFAULT);
4934     if (error)
4935     {
4936         DPRINT1("WARNING: Failed to load and render glyph! [index: %d]\n", Cache->Hashed.GlyphIndex);
4937         return NULL;
4938     }
4939 
4940     glyph = Cache->Hashed.Face->glyph;
4941 
4942     if (Cache->Hashed.Aspect.Emu.Bold)
4943         FT_GlyphSlot_Embolden(glyph); /* Emulate Bold */
4944 
4945     if (Cache->Hashed.Aspect.Emu.Italic)
4946         FT_GlyphSlot_Oblique(glyph); /* Emulate Italic */
4947 
4948     realglyph = IntGetBitmapGlyphWithCache(Cache, glyph);
4949 
4950     if (!realglyph)
4951         DPRINT1("Failed to render glyph! [index: %d]\n", Cache->Hashed.GlyphIndex);
4952 
4953     return realglyph;
4954 }
4955 
4956 BOOL
4957 FASTCALL
TextIntGetTextExtentPoint(PDC dc,PTEXTOBJ TextObj,LPCWSTR String,INT Count,ULONG MaxExtent,LPINT Fit,LPINT Dx,LPSIZE Size,FLONG fl)4958 TextIntGetTextExtentPoint(PDC dc,
4959                           PTEXTOBJ TextObj,
4960                           LPCWSTR String,
4961                           INT Count,
4962                           ULONG MaxExtent,
4963                           LPINT Fit,
4964                           LPINT Dx,
4965                           LPSIZE Size,
4966                           FLONG fl)
4967 {
4968     PFONTGDI FontGDI;
4969     FT_BitmapGlyph realglyph;
4970     INT glyph_index, i, previous, nTenthsOfDegrees;
4971     ULONGLONG TotalWidth64 = 0;
4972     LOGFONTW *plf;
4973     BOOL use_kerning, bVerticalWriting;
4974     LONG ascender, descender;
4975     FONT_CACHE_ENTRY Cache;
4976     DWORD ch0, ch1;
4977     FONTLINK_CHAIN Chain;
4978 
4979     FontGDI = ObjToGDI(TextObj->Font, FONT);
4980 
4981     Cache.Hashed.Face = FontGDI->SharedFace->Face;
4982     if (NULL != Fit)
4983     {
4984         *Fit = 0;
4985     }
4986 
4987     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
4988     Cache.Hashed.lfHeight = plf->lfHeight;
4989     Cache.Hashed.lfWidth = plf->lfWidth;
4990     Cache.Hashed.Aspect.Emu.Bold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
4991     Cache.Hashed.Aspect.Emu.Italic = (plf->lfItalic && !FontGDI->OriginalItalic);
4992 
4993     // Check vertical writing (tategaki)
4994     nTenthsOfDegrees = IntNormalizeAngle(plf->lfEscapement - plf->lfOrientation);
4995     bVerticalWriting = ((nTenthsOfDegrees == 90 * 10) || (nTenthsOfDegrees == 270 * 10));
4996 
4997     if (IntIsFontRenderingEnabled())
4998         Cache.Hashed.Aspect.RenderMode = (BYTE)IntGetFontRenderMode(plf);
4999     else
5000         Cache.Hashed.Aspect.RenderMode = (BYTE)FT_RENDER_MODE_MONO;
5001 
5002     // NOTE: GetTextExtentPoint32 simply ignores lfEscapement and XFORM.
5003     IntLockFreeType();
5004     TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
5005     Cache.Hashed.matTransform = identityMat;
5006     FT_Set_Transform(Cache.Hashed.Face, NULL, NULL);
5007 
5008     FontLink_Chain_Init(&Chain, TextObj, Cache.Hashed.Face);
5009 
5010     use_kerning = FT_HAS_KERNING(Cache.Hashed.Face);
5011     previous = 0;
5012 
5013     for (i = 0; i < Count; i++)
5014     {
5015         ch0 = *String++;
5016         if (IS_HIGH_SURROGATE(ch0))
5017         {
5018             ++i;
5019             if (i >= Count)
5020                 break;
5021 
5022             ch1 = *String++;
5023             if (IS_LOW_SURROGATE(ch1))
5024                 ch0 = Utf32FromSurrogatePair(ch0, ch1);
5025         }
5026 
5027         glyph_index = FontLink_Chain_FindGlyph(&Chain, &Cache, &Cache.Hashed.Face, ch0,
5028                                                (fl & GTEF_INDICES));
5029         Cache.Hashed.GlyphIndex = glyph_index;
5030 
5031         realglyph = IntGetRealGlyph(&Cache);
5032         if (!realglyph)
5033             break;
5034 
5035         /* Retrieve kerning distance */
5036         if (use_kerning && previous && glyph_index)
5037         {
5038             FT_Vector delta;
5039             FT_Get_Kerning(Cache.Hashed.Face, previous, glyph_index, 0, &delta);
5040             TotalWidth64 += delta.x;
5041         }
5042 
5043         TotalWidth64 += realglyph->root.advance.x >> 10;
5044 
5045         if (((TotalWidth64 + 32) >> 6) <= MaxExtent && NULL != Fit)
5046         {
5047             *Fit = i + 1;
5048         }
5049         if (NULL != Dx)
5050         {
5051             Dx[i] = (TotalWidth64 + 32) >> 6;
5052         }
5053 
5054         previous = glyph_index;
5055     }
5056     ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
5057     ascender = FontGDI->tmAscent; /* Units above baseline */
5058     descender = FontGDI->tmDescent; /* Units below baseline */
5059     IntUnLockFreeType();
5060 
5061     if (bVerticalWriting)
5062     {
5063         Size->cx = ascender + descender;
5064         Size->cy = (TotalWidth64 + 32) >> 6;
5065     }
5066     else
5067     {
5068         Size->cx = (TotalWidth64 + 32) >> 6;
5069         Size->cy = ascender + descender;
5070     }
5071 
5072     FontLink_Chain_Finish(&Chain);
5073 
5074     return TRUE;
5075 }
5076 
5077 
5078 INT
5079 FASTCALL
ftGdiGetTextCharsetInfo(PDC Dc,LPFONTSIGNATURE lpSig,DWORD dwFlags)5080 ftGdiGetTextCharsetInfo(
5081     PDC Dc,
5082     LPFONTSIGNATURE lpSig,
5083     DWORD dwFlags)
5084 {
5085     PDC_ATTR pdcattr;
5086     UINT Ret = DEFAULT_CHARSET;
5087     INT i;
5088     HFONT hFont;
5089     PTEXTOBJ TextObj;
5090     PFONTGDI FontGdi;
5091     FONTSIGNATURE fs;
5092     TT_OS2 *pOS2;
5093     FT_Face Face;
5094     CHARSETINFO csi;
5095     DWORD cp, fs0;
5096     USHORT usACP, usOEM;
5097 
5098     pdcattr = Dc->pdcattr;
5099     hFont = pdcattr->hlfntNew;
5100     TextObj = RealizeFontInit(hFont);
5101 
5102     if (!TextObj)
5103     {
5104         EngSetLastError(ERROR_INVALID_HANDLE);
5105         return Ret;
5106     }
5107     FontGdi = ObjToGDI(TextObj->Font, FONT);
5108     Face = FontGdi->SharedFace->Face;
5109     TEXTOBJ_UnlockText(TextObj);
5110 
5111     memset(&fs, 0, sizeof(FONTSIGNATURE));
5112     IntLockFreeType();
5113     pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
5114     if (NULL != pOS2)
5115     {
5116         fs.fsCsb[0] = pOS2->ulCodePageRange1;
5117         fs.fsCsb[1] = pOS2->ulCodePageRange2;
5118         fs.fsUsb[0] = pOS2->ulUnicodeRange1;
5119         fs.fsUsb[1] = pOS2->ulUnicodeRange2;
5120         fs.fsUsb[2] = pOS2->ulUnicodeRange3;
5121         fs.fsUsb[3] = pOS2->ulUnicodeRange4;
5122         if (pOS2->version == 0)
5123         {
5124             FT_UInt dummy;
5125 
5126             if (FT_Get_First_Char( Face, &dummy ) < 0x100)
5127                 fs.fsCsb[0] |= FS_LATIN1;
5128             else
5129                 fs.fsCsb[0] |= FS_SYMBOL;
5130         }
5131     }
5132     pOS2 = NULL;
5133     IntUnLockFreeType();
5134     DPRINT("Csb 1=%x  0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
5135     if (fs.fsCsb[0] == 0)
5136     { /* Let's see if we can find any interesting cmaps */
5137         for (i = 0; i < Face->num_charmaps; i++)
5138         {
5139             switch (Face->charmaps[i]->encoding)
5140             {
5141             case FT_ENCODING_UNICODE:
5142             case FT_ENCODING_APPLE_ROMAN:
5143                 fs.fsCsb[0] |= FS_LATIN1;
5144                 break;
5145             case FT_ENCODING_MS_SYMBOL:
5146                 fs.fsCsb[0] |= FS_SYMBOL;
5147                 break;
5148             default:
5149                 break;
5150             }
5151         }
5152     }
5153     if (lpSig)
5154     {
5155         RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
5156     }
5157 
5158     RtlGetDefaultCodePage(&usACP, &usOEM);
5159     cp = usACP;
5160 
5161     if (IntTranslateCharsetInfo(&cp, &csi, TCI_SRCCODEPAGE))
5162         if (csi.fs.fsCsb[0] & fs.fsCsb[0])
5163         {
5164             DPRINT("Hit 1\n");
5165             Ret = csi.ciCharset;
5166             goto Exit;
5167         }
5168 
5169     for (i = 0; i < MAXTCIINDEX; i++)
5170     {
5171         fs0 = 1L << i;
5172         if (fs.fsCsb[0] & fs0)
5173         {
5174             if (IntTranslateCharsetInfo(&fs0, &csi, TCI_SRCFONTSIG))
5175             {
5176                 // *cp = csi.ciACP;
5177                 DPRINT("Hit 2\n");
5178                 Ret = csi.ciCharset;
5179                 goto Exit;
5180             }
5181             else
5182                 DPRINT1("TCI failing on %x\n", fs0);
5183         }
5184     }
5185 Exit:
5186     DPRINT("CharSet %u CodePage %u\n", csi.ciCharset, csi.ciACP);
5187     return (MAKELONG(csi.ciACP, csi.ciCharset));
5188 }
5189 
5190 
5191 DWORD
5192 FASTCALL
ftGetFontUnicodeRanges(PFONTGDI Font,PGLYPHSET glyphset)5193 ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
5194 {
5195     DWORD size = 0;
5196     DWORD num_ranges = 0;
5197     FT_Face face = Font->SharedFace->Face;
5198 
5199     if (face->charmap == NULL)
5200     {
5201         DPRINT1("FIXME: No charmap selected! This is a BUG!\n");
5202         return 0;
5203     }
5204 
5205     if (face->charmap->encoding == FT_ENCODING_UNICODE)
5206     {
5207         FT_UInt glyph_code = 0;
5208         FT_ULong char_code, char_code_prev;
5209 
5210         char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
5211 
5212         DPRINT("Face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
5213                face->num_glyphs, glyph_code, char_code);
5214 
5215         if (!glyph_code) return 0;
5216 
5217         if (glyphset)
5218         {
5219             glyphset->ranges[0].wcLow = (USHORT)char_code;
5220             glyphset->ranges[0].cGlyphs = 0;
5221             glyphset->cGlyphsSupported = 0;
5222         }
5223 
5224         num_ranges = 1;
5225         while (glyph_code)
5226         {
5227             if (char_code < char_code_prev)
5228             {
5229                 DPRINT1("Expected increasing char code from FT_Get_Next_Char\n");
5230                 return 0;
5231             }
5232             if (char_code - char_code_prev > 1)
5233             {
5234                 num_ranges++;
5235                 if (glyphset)
5236                 {
5237                     glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
5238                     glyphset->ranges[num_ranges - 1].cGlyphs = 1;
5239                     glyphset->cGlyphsSupported++;
5240                 }
5241             }
5242             else if (glyphset)
5243             {
5244                 glyphset->ranges[num_ranges - 1].cGlyphs++;
5245                 glyphset->cGlyphsSupported++;
5246             }
5247             char_code_prev = char_code;
5248             char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
5249         }
5250     }
5251     else
5252         DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
5253 
5254     size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
5255     if (glyphset)
5256     {
5257         glyphset->cbThis = size;
5258         glyphset->cRanges = num_ranges;
5259         glyphset->flAccel = 0;
5260     }
5261     return size;
5262 }
5263 
5264 
5265 BOOL
5266 FASTCALL
ftGdiGetTextMetricsW(HDC hDC,PTMW_INTERNAL ptmwi)5267 ftGdiGetTextMetricsW(
5268     HDC hDC,
5269     PTMW_INTERNAL ptmwi)
5270 {
5271     PDC dc;
5272     PDC_ATTR pdcattr;
5273     PTEXTOBJ TextObj;
5274     PFONTGDI FontGDI;
5275     FT_Face Face;
5276     TT_OS2 *pOS2;
5277     TT_HoriHeader *pHori;
5278     FT_WinFNT_HeaderRec Win;
5279     ULONG Error;
5280     NTSTATUS Status = STATUS_SUCCESS;
5281     LOGFONTW *plf;
5282 
5283     if (!ptmwi)
5284     {
5285         EngSetLastError(STATUS_INVALID_PARAMETER);
5286         return FALSE;
5287     }
5288     RtlZeroMemory(ptmwi, sizeof(TMW_INTERNAL));
5289 
5290     if (!(dc = DC_LockDc(hDC)))
5291     {
5292         EngSetLastError(ERROR_INVALID_HANDLE);
5293         return FALSE;
5294     }
5295     pdcattr = dc->pdcattr;
5296     TextObj = RealizeFontInit(pdcattr->hlfntNew);
5297     if (NULL != TextObj)
5298     {
5299         plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5300         FontGDI = ObjToGDI(TextObj->Font, FONT);
5301 
5302         Face = FontGDI->SharedFace->Face;
5303 
5304         // NOTE: GetTextMetrics simply ignores lfEscapement and XFORM.
5305         IntLockFreeType();
5306         Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
5307         FT_Set_Transform(Face, NULL, NULL);
5308 
5309         IntUnLockFreeType();
5310 
5311         if (0 != Error)
5312         {
5313             DPRINT1("Error in setting pixel sizes: %u\n", Error);
5314             Status = STATUS_UNSUCCESSFUL;
5315         }
5316         else
5317         {
5318             Status = STATUS_SUCCESS;
5319 
5320             IntLockFreeType();
5321             pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
5322             if (NULL == pOS2)
5323             {
5324                 DPRINT1("Can't find OS/2 table - not TT font?\n");
5325                 Status = STATUS_INTERNAL_ERROR;
5326             }
5327 
5328             pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
5329             if (NULL == pHori)
5330             {
5331                 DPRINT1("Can't find HHEA table - not TT font?\n");
5332                 Status = STATUS_INTERNAL_ERROR;
5333             }
5334 
5335             Error = FT_Get_WinFNT_Header(Face, &Win);
5336 
5337             if (NT_SUCCESS(Status) || !Error)
5338             {
5339                 FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
5340 
5341                 /* FIXME: Fill Diff member */
5342             }
5343 
5344             IntUnLockFreeType();
5345         }
5346         TEXTOBJ_UnlockText(TextObj);
5347     }
5348     else
5349     {
5350         Status = STATUS_INVALID_HANDLE;
5351     }
5352     DC_UnlockDc(dc);
5353 
5354     if (!NT_SUCCESS(Status))
5355     {
5356         SetLastNtError(Status);
5357         return FALSE;
5358     }
5359     return TRUE;
5360 }
5361 
5362 DWORD
5363 FASTCALL
ftGdiGetFontData(PFONTGDI FontGdi,DWORD Table,DWORD Offset,PVOID Buffer,DWORD Size)5364 ftGdiGetFontData(
5365     PFONTGDI FontGdi,
5366     DWORD Table,
5367     DWORD Offset,
5368     PVOID Buffer,
5369     DWORD Size)
5370 {
5371     DWORD Result = GDI_ERROR;
5372     FT_Face Face = FontGdi->SharedFace->Face;
5373 
5374     IntLockFreeType();
5375 
5376     if (FT_IS_SFNT(Face))
5377     {
5378         if (Table)
5379             Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
5380                     (Table << 8 & 0xFF0000);
5381 
5382         if (!Buffer) Size = 0;
5383 
5384         if (Buffer && Size)
5385         {
5386             FT_Error Error;
5387             FT_ULong Needed = 0;
5388 
5389             Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
5390 
5391             if ( !Error && Needed < Size) Size = Needed;
5392         }
5393         if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
5394             Result = Size;
5395     }
5396 
5397     IntUnLockFreeType();
5398 
5399     return Result;
5400 }
5401 
5402 #define GOT_PENALTY(name, value) Penalty += (value)
5403 
5404 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
5405 static UINT
GetFontPenalty(const LOGFONTW * LogFont,const OUTLINETEXTMETRICW * Otm,const char * style_name)5406 GetFontPenalty(const LOGFONTW *               LogFont,
5407                const OUTLINETEXTMETRICW *     Otm,
5408                const char *             style_name)
5409 {
5410     ULONG   Penalty = 0;
5411     BYTE    Byte;
5412     LONG    Long;
5413     BOOL    fNeedScaling = FALSE;
5414     const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
5415     const TEXTMETRICW * TM = &Otm->otmTextMetrics;
5416     WCHAR* ActualNameW;
5417 
5418     ASSERT(Otm);
5419     ASSERT(LogFont);
5420 
5421     /* FIXME: IntSizeSynth Penalty 20 */
5422     /* FIXME: SmallPenalty Penalty 1 */
5423     /* FIXME: FaceNameSubst Penalty 500 */
5424 
5425     Byte = LogFont->lfCharSet;
5426 
5427     if (Byte != TM->tmCharSet)
5428     {
5429         if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
5430         {
5431             /* CharSet Penalty 65000 */
5432             /* Requested charset does not match the candidate's. */
5433             GOT_PENALTY("CharSet", 65000);
5434         }
5435         else
5436         {
5437             if (UserCharSet != TM->tmCharSet)
5438             {
5439                 /* UNDOCUMENTED: Not user language */
5440                 GOT_PENALTY("UNDOCUMENTED:NotUserLanguage", 100);
5441 
5442                 if (ANSI_CHARSET != TM->tmCharSet)
5443                 {
5444                     /* UNDOCUMENTED: Not ANSI charset */
5445                     GOT_PENALTY("UNDOCUMENTED:NotAnsiCharSet", 100);
5446                 }
5447             }
5448         }
5449     }
5450 
5451     Byte = LogFont->lfOutPrecision;
5452     switch (Byte)
5453     {
5454         case OUT_DEFAULT_PRECIS:
5455             /* nothing to do */
5456             break;
5457         case OUT_DEVICE_PRECIS:
5458             if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
5459                 !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
5460             {
5461                 /* OutputPrecision Penalty 19000 */
5462                 /* Requested OUT_STROKE_PRECIS, but the device can't do it
5463                    or the candidate is not a vector font. */
5464                 GOT_PENALTY("OutputPrecision", 19000);
5465             }
5466             break;
5467         default:
5468             if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
5469             {
5470                 /* OutputPrecision Penalty 19000 */
5471                 /* Or OUT_STROKE_PRECIS not requested, and the candidate
5472                    is a vector font that requires GDI support. */
5473                 GOT_PENALTY("OutputPrecision", 19000);
5474             }
5475             break;
5476     }
5477 
5478     Byte = (LogFont->lfPitchAndFamily & 0x0F);
5479     if (Byte == DEFAULT_PITCH)
5480         Byte = VARIABLE_PITCH;
5481     if (Byte == FIXED_PITCH)
5482     {
5483         if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
5484         {
5485             /* FixedPitch Penalty 15000 */
5486             /* Requested a fixed pitch font, but the candidate is a
5487                variable pitch font. */
5488             GOT_PENALTY("FixedPitch", 15000);
5489         }
5490     }
5491     if (Byte == VARIABLE_PITCH)
5492     {
5493         if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
5494         {
5495             /* PitchVariable Penalty 350 */
5496             /* Requested a variable pitch font, but the candidate is not a
5497                variable pitch font. */
5498             GOT_PENALTY("PitchVariable", 350);
5499         }
5500     }
5501 
5502     Byte = (LogFont->lfPitchAndFamily & 0x0F);
5503     if (Byte == DEFAULT_PITCH)
5504     {
5505         if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
5506         {
5507             /* DefaultPitchFixed Penalty 1 */
5508             /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
5509             GOT_PENALTY("DefaultPitchFixed", 1);
5510         }
5511     }
5512 
5513     ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
5514 
5515     if (LogFont->lfFaceName[0] != UNICODE_NULL)
5516     {
5517         BOOL Found = FALSE;
5518 
5519         /* localized family name */
5520         if (!Found)
5521         {
5522             Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
5523         }
5524         /* localized full name */
5525         if (!Found)
5526         {
5527             ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
5528             Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
5529         }
5530         if (!Found)
5531         {
5532             /* FaceName Penalty 10000 */
5533             /* Requested a face name, but the candidate's face name
5534                does not match. */
5535             GOT_PENALTY("FaceName", 10000);
5536         }
5537     }
5538 
5539     Byte = (LogFont->lfPitchAndFamily & 0xF0);
5540     if (Byte != FF_DONTCARE)
5541     {
5542         if (Byte != (TM->tmPitchAndFamily & 0xF0))
5543         {
5544             /* Family Penalty 9000 */
5545             /* Requested a family, but the candidate's family is different. */
5546             GOT_PENALTY("Family", 9000);
5547         }
5548     }
5549 
5550     if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
5551     {
5552         /* FamilyUnknown Penalty 8000 */
5553         /* Requested a family, but the candidate has no family. */
5554         GOT_PENALTY("FamilyUnknown", 8000);
5555     }
5556 
5557     /* Is the candidate a non-vector font? */
5558     if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5559     {
5560         /* Is lfHeight specified? */
5561         if (LogFont->lfHeight != 0)
5562         {
5563             if (labs(LogFont->lfHeight) < TM->tmHeight)
5564             {
5565                 /* HeightBigger Penalty 600 */
5566                 /* The candidate is a nonvector font and is bigger than the
5567                    requested height. */
5568                 GOT_PENALTY("HeightBigger", 600);
5569                 /* HeightBiggerDifference Penalty 150 */
5570                 /* The candidate is a raster font and is larger than the
5571                    requested height. Penalty * height difference */
5572                 GOT_PENALTY("HeightBiggerDifference", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
5573 
5574                 fNeedScaling = TRUE;
5575             }
5576             if (TM->tmHeight < labs(LogFont->lfHeight))
5577             {
5578                 /* HeightSmaller Penalty 150 */
5579                 /* The candidate is a raster font and is smaller than the
5580                    requested height. Penalty * height difference */
5581                 GOT_PENALTY("HeightSmaller", 150 * labs(TM->tmHeight - labs(LogFont->lfHeight)));
5582 
5583                 fNeedScaling = TRUE;
5584             }
5585         }
5586     }
5587 
5588     switch (LogFont->lfPitchAndFamily & 0xF0)
5589     {
5590         case FF_ROMAN: case FF_MODERN: case FF_SWISS:
5591             switch (TM->tmPitchAndFamily & 0xF0)
5592             {
5593                 case FF_DECORATIVE: case FF_SCRIPT:
5594                     /* FamilyUnlikely Penalty 50 */
5595                     /* Requested a roman/modern/swiss family, but the
5596                        candidate is decorative/script. */
5597                     GOT_PENALTY("FamilyUnlikely", 50);
5598                     break;
5599                 default:
5600                     break;
5601             }
5602             break;
5603         case FF_DECORATIVE: case FF_SCRIPT:
5604             switch (TM->tmPitchAndFamily & 0xF0)
5605             {
5606                 case FF_ROMAN: case FF_MODERN: case FF_SWISS:
5607                     /* FamilyUnlikely Penalty 50 */
5608                     /* Or requested decorative/script, and the candidate is
5609                        roman/modern/swiss. */
5610                     GOT_PENALTY("FamilyUnlikely", 50);
5611                     break;
5612                 default:
5613                     break;
5614             }
5615         default:
5616             break;
5617     }
5618 
5619     if (LogFont->lfWidth != 0)
5620     {
5621         if (LogFont->lfWidth != TM->tmAveCharWidth)
5622         {
5623             /* Width Penalty 50 */
5624             /* Requested a nonzero width, but the candidate's width
5625                doesn't match. Penalty * width difference */
5626             GOT_PENALTY("Width", 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth));
5627 
5628             if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5629                 fNeedScaling = TRUE;
5630         }
5631     }
5632 
5633     if (fNeedScaling)
5634     {
5635         /* SizeSynth Penalty 50 */
5636         /* The candidate is a raster font that needs scaling by GDI. */
5637         GOT_PENALTY("SizeSynth", 50);
5638     }
5639 
5640     if (!LogFont->lfItalic && TM->tmItalic)
5641     {
5642         /* Italic Penalty 4 */
5643         /* Requested font and candidate font do not agree on italic status,
5644            and the desired result cannot be simulated. */
5645         /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
5646         GOT_PENALTY("Italic", 40);
5647     }
5648     else if (LogFont->lfItalic && !TM->tmItalic)
5649     {
5650         /* ItalicSim Penalty 1 */
5651         /* Requested italic font but the candidate is not italic,
5652            although italics can be simulated. */
5653         GOT_PENALTY("ItalicSim", 1);
5654     }
5655 
5656     if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
5657     {
5658         if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
5659         {
5660             /* NotTrueType Penalty 4 */
5661             /* Requested OUT_TT_PRECIS, but the candidate is not a
5662                TrueType font. */
5663             GOT_PENALTY("NotTrueType", 4);
5664         }
5665     }
5666 
5667     Long = LogFont->lfWeight;
5668     if (LogFont->lfWeight == FW_DONTCARE)
5669         Long = FW_NORMAL;
5670     if (Long != TM->tmWeight)
5671     {
5672         /* Weight Penalty 3 */
5673         /* The candidate's weight does not match the requested weight.
5674            Penalty * (weight difference/10) */
5675         GOT_PENALTY("Weight", 3 * (labs(Long - TM->tmWeight) / 10));
5676     }
5677 
5678     if (!LogFont->lfUnderline && TM->tmUnderlined)
5679     {
5680         /* Underline Penalty 3 */
5681         /* Requested font has no underline, but the candidate is
5682            underlined. */
5683         GOT_PENALTY("Underline", 3);
5684     }
5685 
5686     if (!LogFont->lfStrikeOut && TM->tmStruckOut)
5687     {
5688         /* StrikeOut Penalty 3 */
5689         /* Requested font has no strike-out, but the candidate is
5690            struck out. */
5691         GOT_PENALTY("StrikeOut", 3);
5692     }
5693 
5694     /* Is the candidate a non-vector font? */
5695     if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
5696     {
5697         if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
5698         {
5699             /* VectorHeightSmaller Penalty 2 */
5700             /* Candidate is a vector font that is smaller than the
5701                requested height. Penalty * height difference */
5702             GOT_PENALTY("VectorHeightSmaller", 2 * labs(TM->tmHeight - LogFont->lfHeight));
5703         }
5704         if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
5705         {
5706             /* VectorHeightBigger Penalty 1 */
5707             /* Candidate is a vector font that is bigger than the
5708                requested height. Penalty * height difference */
5709             GOT_PENALTY("VectorHeightBigger", 1 * labs(TM->tmHeight - LogFont->lfHeight));
5710         }
5711     }
5712 
5713     if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
5714     {
5715         /* DeviceFavor Penalty 2 */
5716         /* Extra penalty for all nondevice fonts. */
5717         GOT_PENALTY("DeviceFavor", 2);
5718     }
5719 
5720     if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
5721     {
5722         if (TM->tmAveCharWidth / TM->tmHeight >= 3)
5723         {
5724             /* Aspect Penalty 30 */
5725             /* The aspect rate is >= 3. It seems like a bad font. */
5726             GOT_PENALTY("Aspect", ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30);
5727         }
5728         else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
5729         {
5730             /* Aspect Penalty 30 */
5731             /* The aspect rate is >= 3. It seems like a bad font. */
5732             GOT_PENALTY("Aspect", ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30);
5733         }
5734     }
5735 
5736     if (Penalty < 200)
5737     {
5738         DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
5739             "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
5740             "tmCharSet:%d, tmWeight:%ld\n",
5741             Penalty, LogFont->lfFaceName, ActualNameW,
5742             LogFont->lfCharSet, LogFont->lfWeight,
5743             TM->tmCharSet, TM->tmWeight);
5744     }
5745 
5746     return Penalty;     /* success */
5747 }
5748 
5749 #undef GOT_PENALTY
5750 
5751 static __inline VOID
FindBestFontFromList(FONTOBJ ** FontObj,ULONG * MatchPenalty,const LOGFONTW * LogFont,const PLIST_ENTRY Head)5752 FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
5753                      const LOGFONTW *LogFont,
5754                      const PLIST_ENTRY Head)
5755 {
5756     ULONG Penalty;
5757     PLIST_ENTRY Entry;
5758     PFONT_ENTRY CurrentEntry;
5759     FONTGDI *FontGDI;
5760     OUTLINETEXTMETRICW *Otm = NULL;
5761     UINT OtmSize, OldOtmSize = 0;
5762     FT_Face Face;
5763 
5764     ASSERT(FontObj);
5765     ASSERT(MatchPenalty);
5766     ASSERT(LogFont);
5767     ASSERT(Head);
5768 
5769     /* Start with a pretty big buffer */
5770     OldOtmSize = 0x200;
5771     Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
5772 
5773     /* get the FontObj of lowest penalty */
5774     for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
5775     {
5776         CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
5777 
5778         FontGDI = CurrentEntry->Font;
5779         ASSERT(FontGDI);
5780         Face = FontGDI->SharedFace->Face;
5781 
5782         /* get text metrics */
5783         ASSERT_FREETYPE_LOCK_HELD();
5784         OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL, TRUE);
5785         if (OtmSize > OldOtmSize)
5786         {
5787             if (Otm)
5788                 ExFreePoolWithTag(Otm, GDITAG_TEXT);
5789             Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
5790         }
5791 
5792         /* update FontObj if lowest penalty */
5793         if (Otm)
5794         {
5795             ASSERT_FREETYPE_LOCK_HELD();
5796             IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
5797 
5798             ASSERT_FREETYPE_LOCK_HELD();
5799             OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm, TRUE);
5800             if (!OtmSize)
5801                 continue;
5802 
5803             OldOtmSize = OtmSize;
5804 
5805             Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
5806             if (*MatchPenalty == MAXULONG || Penalty < *MatchPenalty)
5807             {
5808                 *FontObj = GDIToObj(FontGDI, FONT);
5809                 *MatchPenalty = Penalty;
5810             }
5811         }
5812     }
5813 
5814     if (Otm)
5815         ExFreePoolWithTag(Otm, GDITAG_TEXT);
5816 }
5817 
5818 static
5819 VOID
5820 FASTCALL
IntFontType(PFONTGDI Font)5821 IntFontType(PFONTGDI Font)
5822 {
5823     PS_FontInfoRec psfInfo;
5824     FT_ULong tmp_size = 0;
5825     FT_Face Face = Font->SharedFace->Face;
5826 
5827     ASSERT_FREETYPE_LOCK_NOT_HELD();
5828     IntLockFreeType();
5829 
5830     if (FT_HAS_MULTIPLE_MASTERS(Face))
5831         Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
5832     if (FT_HAS_VERTICAL(Face))
5833         Font->FontObj.flFontType |= FO_VERT_FACE;
5834     if (!FT_IS_SCALABLE(Face))
5835         Font->FontObj.flFontType |= FO_TYPE_RASTER;
5836     if (FT_IS_SFNT(Face))
5837     {
5838         Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
5839         if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
5840             Font->FontObj.flFontType |= FO_POSTSCRIPT;
5841     }
5842     if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
5843     {
5844         Font->FontObj.flFontType |= FO_POSTSCRIPT;
5845     }
5846     /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
5847     if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
5848     {
5849         Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
5850     }
5851 
5852     IntUnLockFreeType();
5853 }
5854 
5855 static BOOL
MatchFontName(PSHARED_FACE SharedFace,PUNICODE_STRING Name1,FT_UShort NameID,FT_UShort LangID)5856 MatchFontName(PSHARED_FACE SharedFace, PUNICODE_STRING Name1, FT_UShort NameID, FT_UShort LangID)
5857 {
5858     NTSTATUS Status;
5859     UNICODE_STRING Name2;
5860 
5861     RtlInitUnicodeString(&Name2, NULL);
5862     Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
5863 
5864     if (NT_SUCCESS(Status))
5865     {
5866         if (RtlCompareUnicodeString(Name1, &Name2, TRUE) == 0)
5867         {
5868             RtlFreeUnicodeString(&Name2);
5869             return TRUE;
5870         }
5871 
5872         RtlFreeUnicodeString(&Name2);
5873     }
5874 
5875     return FALSE;
5876 }
5877 
5878 static BOOL
MatchFontNames(PSHARED_FACE SharedFace,LPCWSTR lfFaceName)5879 MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
5880 {
5881     UNICODE_STRING Name1;
5882 
5883     if (lfFaceName[0] == UNICODE_NULL)
5884         return FALSE;
5885 
5886     RtlInitUnicodeString(&Name1, lfFaceName);
5887 
5888     if (MatchFontName(SharedFace, &Name1, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
5889         MatchFontName(SharedFace, &Name1, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
5890     {
5891         return TRUE;
5892     }
5893     if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
5894     {
5895         if (MatchFontName(SharedFace, &Name1, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
5896             MatchFontName(SharedFace, &Name1, TT_NAME_ID_FULL_NAME, gusLanguageID))
5897         {
5898             return TRUE;
5899         }
5900     }
5901     return FALSE;
5902 }
5903 
5904 NTSTATUS
5905 FASTCALL
TextIntRealizeFont(HFONT FontHandle,PTEXTOBJ pTextObj)5906 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
5907 {
5908     NTSTATUS Status = STATUS_SUCCESS;
5909     PTEXTOBJ TextObj;
5910     PPROCESSINFO Win32Process;
5911     ULONG MatchPenalty;
5912     LOGFONTW *pLogFont;
5913     LOGFONTW SubstitutedLogFont;
5914 
5915     if (!pTextObj)
5916     {
5917         TextObj = TEXTOBJ_LockText(FontHandle);
5918         if (NULL == TextObj)
5919         {
5920             return STATUS_INVALID_HANDLE;
5921         }
5922 
5923         if (TextObj->fl & TEXTOBJECT_INIT)
5924         {
5925             TEXTOBJ_UnlockText(TextObj);
5926             return STATUS_SUCCESS;
5927         }
5928     }
5929     else
5930     {
5931         TextObj = pTextObj;
5932     }
5933 
5934     pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
5935 
5936     /* substitute */
5937     SubstitutedLogFont = *pLogFont;
5938     DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
5939     SubstituteFontRecurse(&SubstitutedLogFont);
5940     DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
5941 
5942     MatchPenalty = 0xFFFFFFFF;
5943     TextObj->Font = NULL;
5944 
5945     Win32Process = PsGetCurrentProcessWin32Process();
5946 
5947     /* Search private fonts */
5948     IntLockFreeType();
5949     IntLockProcessPrivateFonts(Win32Process);
5950     FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
5951                          &Win32Process->PrivateFontListHead);
5952     IntUnLockProcessPrivateFonts(Win32Process);
5953 
5954     /* Search system fonts */
5955     FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
5956                          &g_FontListHead);
5957     IntUnLockFreeType();
5958 
5959     if (NULL == TextObj->Font)
5960     {
5961         DPRINT1("Request font %S not found, no fonts loaded at all\n",
5962                 pLogFont->lfFaceName);
5963         Status = STATUS_NOT_FOUND;
5964     }
5965     else
5966     {
5967         UNICODE_STRING Name;
5968         PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
5969         PSHARED_FACE SharedFace = FontGdi->SharedFace;
5970 
5971         TextObj->TextFace[0] = UNICODE_NULL;
5972         IntLockFreeType();
5973         if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
5974         {
5975             IntUnLockFreeType();
5976             RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
5977         }
5978         else
5979         {
5980             RtlInitUnicodeString(&Name, NULL);
5981             Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
5982             IntUnLockFreeType();
5983             if (NT_SUCCESS(Status))
5984             {
5985                 /* truncated copy */
5986                 IntUnicodeStringToBuffer(TextObj->TextFace, sizeof(TextObj->TextFace), &Name);
5987                 RtlFreeUnicodeString(&Name);
5988             }
5989         }
5990 
5991         // Need hdev, when freetype is loaded need to create DEVOBJ for
5992         // Consumer and Producer.
5993         TextObj->Font->iUniq = 1; // Now it can be cached.
5994         IntFontType(FontGdi);
5995         FontGdi->flType = TextObj->Font->flFontType;
5996         FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
5997         FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
5998         FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
5999         if (pLogFont->lfWeight != FW_DONTCARE)
6000             FontGdi->RequestWeight = pLogFont->lfWeight;
6001         else
6002             FontGdi->RequestWeight = FW_NORMAL;
6003 
6004         TextObj->fl |= TEXTOBJECT_INIT;
6005         Status = STATUS_SUCCESS;
6006     }
6007 
6008     if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
6009 
6010     ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
6011 
6012     return Status;
6013 }
6014 
6015 static
6016 BOOL
6017 FASTCALL
IntGetFullFileName(POBJECT_NAME_INFORMATION NameInfo,ULONG Size,PUNICODE_STRING FileName)6018 IntGetFullFileName(
6019     POBJECT_NAME_INFORMATION NameInfo,
6020     ULONG Size,
6021     PUNICODE_STRING FileName)
6022 {
6023     NTSTATUS Status;
6024     OBJECT_ATTRIBUTES ObjectAttributes;
6025     HANDLE hFile;
6026     IO_STATUS_BLOCK IoStatusBlock;
6027     ULONG Desired;
6028 
6029     InitializeObjectAttributes(&ObjectAttributes,
6030                                FileName,
6031                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
6032                                NULL,
6033                                NULL);
6034 
6035     Status = ZwOpenFile(
6036                  &hFile,
6037                  0, // FILE_READ_ATTRIBUTES,
6038                  &ObjectAttributes,
6039                  &IoStatusBlock,
6040                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
6041                  0);
6042 
6043     if (!NT_SUCCESS(Status))
6044     {
6045         DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
6046         return FALSE;
6047     }
6048 
6049     Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
6050     ZwClose(hFile);
6051     if (!NT_SUCCESS(Status))
6052     {
6053         DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
6054         return FALSE;
6055     }
6056 
6057     return TRUE;
6058 }
6059 
6060 static BOOL
EqualFamilyInfo(const FONTFAMILYINFO * pInfo1,const FONTFAMILYINFO * pInfo2)6061 EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
6062 {
6063     const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
6064     const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
6065     const LOGFONTW *plf1 = &pLog1->elfLogFont;
6066     const LOGFONTW *plf2 = &pLog2->elfLogFont;
6067 
6068     if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
6069     {
6070         return FALSE;
6071     }
6072 
6073     if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
6074     {
6075         return FALSE;
6076     }
6077 
6078     return TRUE;
6079 }
6080 
6081 static VOID
IntAddNameFromFamInfo(LPWSTR psz,FONTFAMILYINFO * FamInfo)6082 IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
6083 {
6084     wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
6085     if (FamInfo->EnumLogFontEx.elfStyle[0] &&
6086         _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
6087     {
6088         wcscat(psz, L" ");
6089         wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
6090     }
6091 }
6092 
6093 BOOL
6094 FASTCALL
IntGdiGetFontResourceInfo(PUNICODE_STRING FileName,PVOID pBuffer,DWORD * pdwBytes,DWORD dwType)6095 IntGdiGetFontResourceInfo(
6096     PUNICODE_STRING FileName,
6097     PVOID pBuffer,
6098     DWORD *pdwBytes,
6099     DWORD dwType)
6100 {
6101     UNICODE_STRING EntryFileName;
6102     POBJECT_NAME_INFORMATION NameInfo1 = NULL, NameInfo2 = NULL;
6103     PLIST_ENTRY ListEntry;
6104     PFONT_ENTRY FontEntry;
6105     ULONG Size, i, Count;
6106     LPBYTE pbBuffer;
6107     BOOL IsEqual;
6108     FONTFAMILYINFO *FamInfo;
6109     const ULONG MaxFamInfo = 64;
6110     const ULONG MAX_FAM_INFO_BYTES = sizeof(FONTFAMILYINFO) * MaxFamInfo;
6111     BOOL bSuccess;
6112     const ULONG NAMEINFO_SIZE = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
6113 
6114     DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
6115 
6116     do
6117     {
6118         /* Create buffer for full path name */
6119         NameInfo1 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
6120         if (!NameInfo1)
6121             break;
6122 
6123         /* Get the full path name */
6124         if (!IntGetFullFileName(NameInfo1, NAMEINFO_SIZE, FileName))
6125             break;
6126 
6127         /* Create a buffer for the entries' names */
6128         NameInfo2 = ExAllocatePoolWithTag(PagedPool, NAMEINFO_SIZE, TAG_FINF);
6129         if (!NameInfo2)
6130             break;
6131 
6132         FamInfo = ExAllocatePoolWithTag(PagedPool, MAX_FAM_INFO_BYTES, TAG_FINF);
6133     } while (0);
6134 
6135     if (!NameInfo1 || !NameInfo2 || !FamInfo)
6136     {
6137         if (NameInfo2)
6138             ExFreePoolWithTag(NameInfo2, TAG_FINF);
6139 
6140         if (NameInfo1)
6141             ExFreePoolWithTag(NameInfo1, TAG_FINF);
6142 
6143         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6144         return FALSE;
6145     }
6146 
6147     Count = 0;
6148 
6149     /* Try to find the pathname in the global font list */
6150     IntLockFreeType();
6151     for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
6152          ListEntry = ListEntry->Flink)
6153     {
6154         FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
6155         if (FontEntry->Font->Filename == NULL)
6156             continue;
6157 
6158         RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
6159         if (!IntGetFullFileName(NameInfo2, NAMEINFO_SIZE, &EntryFileName))
6160             continue;
6161 
6162         if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
6163             continue;
6164 
6165         IsEqual = FALSE;
6166         FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
6167                            NULL, FontEntry->Font);
6168         for (i = 0; i < Count; ++i)
6169         {
6170             if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
6171             {
6172                 IsEqual = TRUE;
6173                 break;
6174             }
6175         }
6176         if (!IsEqual)
6177         {
6178             /* Found */
6179             ++Count;
6180             if (Count >= MaxFamInfo)
6181                 break;
6182         }
6183     }
6184     IntUnLockFreeType();
6185 
6186     /* Free the buffers */
6187     ExFreePoolWithTag(NameInfo1, TAG_FINF);
6188     ExFreePoolWithTag(NameInfo2, TAG_FINF);
6189 
6190     if (Count == 0 && dwType != 5)
6191     {
6192         /* Font could not be found in system table
6193            dwType == 5 will still handle this */
6194         ExFreePoolWithTag(FamInfo, TAG_FINF);
6195         return FALSE;
6196     }
6197 
6198     bSuccess = FALSE;
6199     switch (dwType)
6200     {
6201     case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
6202         Size = sizeof(DWORD);
6203         if (*pdwBytes == 0)
6204         {
6205             *pdwBytes = Size;
6206             bSuccess = TRUE;
6207         }
6208         else if (pBuffer)
6209         {
6210             if (*pdwBytes >= Size)
6211             {
6212                 *(DWORD*)pBuffer = Count;
6213             }
6214             *pdwBytes = Size;
6215             bSuccess = TRUE;
6216         }
6217         break;
6218 
6219     case 1: /* copy the font title */
6220         /* calculate the required size */
6221         Size = 0;
6222         for (i = 0; i < Count; ++i)
6223         {
6224             if (i > 0)
6225                 Size += 3;  /* " & " */
6226             Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
6227             if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
6228                 _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
6229             {
6230                 Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
6231             }
6232         }
6233         Size += 2;  /* "\0\0" */
6234         Size *= sizeof(WCHAR);
6235 
6236         if (*pdwBytes == 0)
6237         {
6238             *pdwBytes = Size;
6239             bSuccess = TRUE;
6240         }
6241         else if (pBuffer)
6242         {
6243             if (*pdwBytes >= Size)
6244             {
6245                 /* store font title to buffer */
6246                 WCHAR *psz = pBuffer;
6247                 *psz = 0;
6248                 for (i = 0; i < Count; ++i)
6249                 {
6250                     if (i > 0)
6251                         wcscat(psz, L" & ");
6252                     IntAddNameFromFamInfo(psz, &FamInfo[i]);
6253                 }
6254                 psz[wcslen(psz) + 1] = UNICODE_NULL;
6255                 *pdwBytes = Size;
6256                 bSuccess = TRUE;
6257             }
6258             else
6259             {
6260                 *pdwBytes = 1024;       /* this is confirmed value */
6261             }
6262         }
6263         break;
6264 
6265     case 2: /* Copy an array of LOGFONTW */
6266         Size = Count * sizeof(LOGFONTW);
6267         if (*pdwBytes == 0)
6268         {
6269             *pdwBytes = Size;
6270             bSuccess = TRUE;
6271         }
6272         else if (pBuffer)
6273         {
6274             if (*pdwBytes >= Size)
6275             {
6276                 pbBuffer = (LPBYTE)pBuffer;
6277                 for (i = 0; i < Count; ++i)
6278                 {
6279                     FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
6280                     RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
6281                     pbBuffer += sizeof(LOGFONTW);
6282                 }
6283             }
6284             *pdwBytes = Size;
6285             bSuccess = TRUE;
6286         }
6287         else
6288         {
6289             *pdwBytes = 1024;       /* this is confirmed value */
6290         }
6291         break;
6292 
6293     case 3:
6294         Size = sizeof(DWORD);
6295         if (*pdwBytes == 0)
6296         {
6297             *pdwBytes = Size;
6298             bSuccess = TRUE;
6299         }
6300         else if (pBuffer)
6301         {
6302             if (*pdwBytes >= Size)
6303             {
6304                 /* FIXME: What exactly is copied here? */
6305                 *(DWORD*)pBuffer = 1;
6306             }
6307             *pdwBytes = Size;
6308             bSuccess = TRUE;
6309         }
6310         break;
6311 
6312     case 4:     /* full file path */
6313         if (FileName->Length >= 4 * sizeof(WCHAR))
6314         {
6315             /* The beginning of FileName is \??\ */
6316             LPWSTR pch = FileName->Buffer + 4;
6317             DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
6318 
6319             Size = Length + sizeof(WCHAR);
6320             if (*pdwBytes == 0)
6321             {
6322                 *pdwBytes = Size;
6323                 bSuccess = TRUE;
6324             }
6325             else if (pBuffer)
6326             {
6327                 if (*pdwBytes >= Size)
6328                 {
6329                     RtlCopyMemory(pBuffer, pch, Size);
6330                 }
6331                 *pdwBytes = Size;
6332                 bSuccess = TRUE;
6333             }
6334         }
6335         break;
6336 
6337     case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
6338         Size = sizeof(BOOL);
6339         if (*pdwBytes == 0)
6340         {
6341             *pdwBytes = Size;
6342             bSuccess = TRUE;
6343         }
6344         else if (pBuffer)
6345         {
6346             if (*pdwBytes >= Size)
6347             {
6348                 *(BOOL*)pBuffer = Count == 0;
6349             }
6350             *pdwBytes = Size;
6351             bSuccess = TRUE;
6352         }
6353         break;
6354     }
6355     ExFreePoolWithTag(FamInfo, TAG_FINF);
6356 
6357     return bSuccess;
6358 }
6359 
6360 
6361 BOOL
6362 FASTCALL
ftGdiRealizationInfo(PFONTGDI Font,PREALIZATION_INFO Info)6363 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
6364 {
6365     if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
6366         Info->iTechnology = RI_TECH_BITMAP;
6367     else
6368     {
6369         if (FT_IS_SCALABLE(Font->SharedFace->Face))
6370             Info->iTechnology = RI_TECH_SCALABLE;
6371         else
6372             Info->iTechnology = RI_TECH_FIXED;
6373     }
6374     Info->iUniq = Font->FontObj.iUniq;
6375     Info->dwUnknown = -1;
6376     return TRUE;
6377 }
6378 
6379 
6380 DWORD
6381 FASTCALL
ftGdiGetKerningPairs(PFONTGDI Font,DWORD cPairs,LPKERNINGPAIR pKerningPair)6382 ftGdiGetKerningPairs( PFONTGDI Font,
6383                       DWORD cPairs,
6384                       LPKERNINGPAIR pKerningPair)
6385 {
6386     DWORD Count = 0;
6387     INT i = 0;
6388     FT_Face face = Font->SharedFace->Face;
6389 
6390     if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
6391     {
6392         FT_UInt previous_index = 0, glyph_index = 0;
6393         FT_ULong char_code, char_previous;
6394         FT_Vector delta;
6395 
6396         char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
6397 
6398         IntLockFreeType();
6399 
6400         while (glyph_index)
6401         {
6402             if (previous_index && glyph_index)
6403             {
6404                 FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
6405 
6406                 if (pKerningPair && cPairs)
6407                 {
6408                     pKerningPair[i].wFirst      = char_previous;
6409                     pKerningPair[i].wSecond     = char_code;
6410                     pKerningPair[i].iKernAmount = delta.x;
6411                     i++;
6412                     if (i == cPairs) break;
6413                 }
6414                 Count++;
6415             }
6416             previous_index = glyph_index;
6417             char_previous = char_code;
6418             char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
6419         }
6420         IntUnLockFreeType();
6421     }
6422     return Count;
6423 }
6424 
6425 
6426 ///////////////////////////////////////////////////////////////////////////
6427 //
6428 // Functions needing sorting.
6429 //
6430 ///////////////////////////////////////////////////////////////////////////
6431 
6432 LONG FASTCALL
IntGetFontFamilyInfo(HDC Dc,const LOGFONTW * SafeLogFont,PFONTFAMILYINFO SafeInfo,LONG InfoCount)6433 IntGetFontFamilyInfo(HDC Dc,
6434                      const LOGFONTW *SafeLogFont,
6435                      PFONTFAMILYINFO SafeInfo,
6436                      LONG InfoCount)
6437 {
6438     LONG AvailCount = 0;
6439     PPROCESSINFO Win32Process;
6440 
6441     /* Enumerate font families in the global list */
6442     IntLockFreeType();
6443     if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount,
6444                                   InfoCount, &g_FontListHead))
6445     {
6446         IntUnLockFreeType();
6447         return -1;
6448     }
6449 
6450     /* Enumerate font families in the process local list */
6451     Win32Process = PsGetCurrentProcessWin32Process();
6452     IntLockProcessPrivateFonts(Win32Process);
6453     if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, InfoCount,
6454                                   &Win32Process->PrivateFontListHead))
6455     {
6456         IntUnLockProcessPrivateFonts(Win32Process);
6457         IntUnLockFreeType();
6458         return -1;
6459     }
6460     IntUnLockProcessPrivateFonts(Win32Process);
6461     IntUnLockFreeType();
6462 
6463     /* Enumerate font families in the registry */
6464     if (!GetFontFamilyInfoForSubstitutes(SafeLogFont, SafeInfo, &AvailCount, InfoCount))
6465     {
6466         return -1;
6467     }
6468 
6469     return AvailCount;
6470 }
6471 
6472 LONG NTAPI
NtGdiGetFontFamilyInfo(HDC Dc,const LOGFONTW * UnsafeLogFont,PFONTFAMILYINFO UnsafeInfo,LPLONG UnsafeInfoCount)6473 NtGdiGetFontFamilyInfo(HDC Dc,
6474                        const LOGFONTW *UnsafeLogFont,
6475                        PFONTFAMILYINFO UnsafeInfo,
6476                        LPLONG UnsafeInfoCount)
6477 {
6478     NTSTATUS Status;
6479     LOGFONTW LogFont;
6480     PFONTFAMILYINFO Info;
6481     LONG GotCount, AvailCount, SafeInfoCount;
6482     ULONG DataSize;
6483 
6484     if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL)
6485     {
6486         EngSetLastError(ERROR_INVALID_PARAMETER);
6487         return -1;
6488     }
6489 
6490     Status = MmCopyFromCaller(&SafeInfoCount, UnsafeInfoCount, sizeof(SafeInfoCount));
6491     if (!NT_SUCCESS(Status))
6492     {
6493         EngSetLastError(ERROR_INVALID_PARAMETER);
6494         return -1;
6495     }
6496     GotCount = 0;
6497     Status = MmCopyToCaller(UnsafeInfoCount, &GotCount, sizeof(*UnsafeInfoCount));
6498     if (!NT_SUCCESS(Status))
6499     {
6500         EngSetLastError(ERROR_INVALID_PARAMETER);
6501         return -1;
6502     }
6503     Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
6504     if (!NT_SUCCESS(Status))
6505     {
6506         EngSetLastError(ERROR_INVALID_PARAMETER);
6507         return -1;
6508     }
6509     if (SafeInfoCount <= 0)
6510     {
6511         EngSetLastError(ERROR_INVALID_PARAMETER);
6512         return -1;
6513     }
6514 
6515     /* Allocate space for a safe copy */
6516     Status = RtlULongMult(SafeInfoCount, sizeof(FONTFAMILYINFO), &DataSize);
6517     if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
6518     {
6519         DPRINT1("Overflowed.\n");
6520         EngSetLastError(ERROR_INVALID_PARAMETER);
6521         return -1;
6522     }
6523     Info = ExAllocatePoolWithTag(PagedPool, DataSize, GDITAG_TEXT);
6524     if (Info == NULL)
6525     {
6526         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
6527         return -1;
6528     }
6529 
6530     /* Retrieve the information */
6531     AvailCount = IntGetFontFamilyInfo(Dc, &LogFont, Info, SafeInfoCount);
6532     GotCount = min(AvailCount, SafeInfoCount);
6533     SafeInfoCount = AvailCount;
6534 
6535     /* Return data to caller */
6536     if (GotCount > 0)
6537     {
6538         Status = RtlULongMult(GotCount, sizeof(FONTFAMILYINFO), &DataSize);
6539         if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
6540         {
6541             DPRINT1("Overflowed.\n");
6542             ExFreePoolWithTag(Info, GDITAG_TEXT);
6543             EngSetLastError(ERROR_INVALID_PARAMETER);
6544             return -1;
6545         }
6546         Status = MmCopyToCaller(UnsafeInfo, Info, DataSize);
6547         if (!NT_SUCCESS(Status))
6548         {
6549             ExFreePoolWithTag(Info, GDITAG_TEXT);
6550             EngSetLastError(ERROR_INVALID_PARAMETER);
6551             return -1;
6552         }
6553         Status = MmCopyToCaller(UnsafeInfoCount, &SafeInfoCount, sizeof(*UnsafeInfoCount));
6554         if (!NT_SUCCESS(Status))
6555         {
6556             ExFreePoolWithTag(Info, GDITAG_TEXT);
6557             EngSetLastError(ERROR_INVALID_PARAMETER);
6558             return -1;
6559         }
6560     }
6561 
6562     ExFreePoolWithTag(Info, GDITAG_TEXT);
6563 
6564     return GotCount;
6565 }
6566 
6567 static inline
6568 LONG
ScaleLong(LONG lValue,PFLOATOBJ pef)6569 ScaleLong(LONG lValue, PFLOATOBJ pef)
6570 {
6571     FLOATOBJ efTemp;
6572 
6573     /* Check if we have scaling different from 1 */
6574     if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1))
6575     {
6576         /* Need to multiply */
6577         FLOATOBJ_SetLong(&efTemp, lValue);
6578         FLOATOBJ_Mul(&efTemp, pef);
6579         lValue = FLOATOBJ_GetLong(&efTemp);
6580     }
6581 
6582     return lValue;
6583 }
6584 
6585 /*
6586  * Calculate X and Y disposition of the text.
6587  * NOTE: The disposition can be negative.
6588  */
6589 static BOOL
IntGetTextDisposition(OUT LONGLONG * pX64,OUT LONGLONG * pY64,IN LPCWSTR String,IN INT Count,IN OPTIONAL LPINT Dx,IN OUT PFONT_CACHE_ENTRY Cache,IN UINT fuOptions,IN BOOL bNoTransform,IN OUT PFONTLINK_CHAIN pChain)6590 IntGetTextDisposition(
6591     OUT LONGLONG *pX64,
6592     OUT LONGLONG *pY64,
6593     IN LPCWSTR String,
6594     IN INT Count,
6595     IN OPTIONAL LPINT Dx,
6596     IN OUT PFONT_CACHE_ENTRY Cache,
6597     IN UINT fuOptions,
6598     IN BOOL bNoTransform,
6599     IN OUT PFONTLINK_CHAIN pChain)
6600 {
6601     LONGLONG X64 = 0, Y64 = 0;
6602     INT i, glyph_index;
6603     FT_BitmapGlyph realglyph;
6604     FT_Face face = Cache->Hashed.Face;
6605     BOOL use_kerning = FT_HAS_KERNING(face);
6606     ULONG previous = 0;
6607     FT_Vector delta, vec;
6608     DWORD ch0, ch1;
6609 
6610     ASSERT_FREETYPE_LOCK_HELD();
6611 
6612     for (i = 0; i < Count; ++i)
6613     {
6614         ch0 = *String++;
6615         if (IS_HIGH_SURROGATE(ch0))
6616         {
6617             ++i;
6618             if (i >= Count)
6619                 return TRUE;
6620 
6621             ch1 = *String++;
6622             if (IS_LOW_SURROGATE(ch1))
6623                 ch0 = Utf32FromSurrogatePair(ch0, ch1);
6624         }
6625 
6626         glyph_index = FontLink_Chain_FindGlyph(pChain, Cache, &face, ch0,
6627                                                (fuOptions & ETO_GLYPH_INDEX));
6628         Cache->Hashed.GlyphIndex = glyph_index;
6629 
6630         realglyph = IntGetRealGlyph(Cache);
6631         if (!realglyph)
6632             return FALSE;
6633 
6634         /* Retrieve kerning distance */
6635         if (use_kerning && previous && glyph_index)
6636         {
6637             FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
6638             X64 += delta.x;
6639             Y64 -= delta.y;
6640         }
6641 
6642         if (NULL == Dx)
6643         {
6644             X64 += realglyph->root.advance.x >> 10;
6645             Y64 -= realglyph->root.advance.y >> 10;
6646         }
6647         else if (fuOptions & ETO_PDY)
6648         {
6649             vec.x = (Dx[2 * i + 0] << 6);
6650             vec.y = (Dx[2 * i + 1] << 6);
6651             if (!bNoTransform)
6652                 FT_Vector_Transform(&vec, &Cache->Hashed.matTransform);
6653             X64 += vec.x;
6654             Y64 -= vec.y;
6655         }
6656         else
6657         {
6658             vec.x = (Dx[i] << 6);
6659             vec.y = 0;
6660             if (!bNoTransform)
6661                 FT_Vector_Transform(&vec, &Cache->Hashed.matTransform);
6662             X64 += vec.x;
6663             Y64 -= vec.y;
6664         }
6665 
6666         previous = glyph_index;
6667     }
6668 
6669     *pX64 = X64;
6670     *pY64 = Y64;
6671     return TRUE;
6672 }
6673 
6674 VOID APIENTRY
IntEngFillPolygon(IN OUT PDC dc,IN POINTL * pPoints,IN UINT cPoints,IN BRUSHOBJ * BrushObj)6675 IntEngFillPolygon(
6676     IN OUT PDC dc,
6677     IN POINTL *pPoints,
6678     IN UINT cPoints,
6679     IN BRUSHOBJ *BrushObj)
6680 {
6681     SURFACE *psurf = dc->dclevel.pSurface;
6682     RECT Rect;
6683     UINT i;
6684     INT x, y;
6685 
6686     ASSERT_DC_PREPARED(dc);
6687     ASSERT(psurf != NULL);
6688 
6689     Rect.left = Rect.right = pPoints[0].x;
6690     Rect.top = Rect.bottom = pPoints[0].y;
6691     for (i = 1; i < cPoints; ++i)
6692     {
6693         x = pPoints[i].x;
6694         if (x < Rect.left)
6695             Rect.left = x;
6696         else if (Rect.right < x)
6697             Rect.right = x;
6698 
6699         y = pPoints[i].y;
6700         if (y < Rect.top)
6701             Rect.top = y;
6702         else if (Rect.bottom < y)
6703             Rect.bottom = y;
6704     }
6705 
6706     IntFillPolygon(dc, dc->dclevel.pSurface, BrushObj, pPoints, cPoints, Rect, &PointZero);
6707 }
6708 
6709 VOID
6710 FASTCALL
IntEngFillBox(IN OUT PDC dc,IN INT X,IN INT Y,IN INT Width,IN INT Height,IN BRUSHOBJ * BrushObj)6711 IntEngFillBox(
6712     IN OUT PDC dc,
6713     IN INT X,
6714     IN INT Y,
6715     IN INT Width,
6716     IN INT Height,
6717     IN BRUSHOBJ *BrushObj)
6718 {
6719     RECTL DestRect;
6720     SURFACE *psurf = dc->dclevel.pSurface;
6721 
6722     ASSERT_DC_PREPARED(dc);
6723     ASSERT(psurf != NULL);
6724 
6725     if (Width < 0)
6726     {
6727         X += Width;
6728         Width = -Width;
6729     }
6730 
6731     if (Height < 0)
6732     {
6733         Y += Height;
6734         Height = -Height;
6735     }
6736 
6737     DestRect.left = X;
6738     DestRect.right = X + Width;
6739     DestRect.top = Y;
6740     DestRect.bottom = Y + Height;
6741 
6742     IntEngBitBlt(&psurf->SurfObj,
6743                  NULL,
6744                  NULL,
6745                  (CLIPOBJ *)&dc->co,
6746                  NULL,
6747                  &DestRect,
6748                  NULL,
6749                  NULL,
6750                  BrushObj,
6751                  &PointZero,
6752                  ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
6753 }
6754 
6755 
6756 BOOL
6757 APIENTRY
IntExtTextOutW(IN PDC dc,IN INT XStart,IN INT YStart,IN UINT fuOptions,IN OPTIONAL PRECTL lprc,IN LPCWSTR String,IN INT Count,IN OPTIONAL LPINT Dx,IN DWORD dwCodePage)6758 IntExtTextOutW(
6759     IN PDC dc,
6760     IN INT XStart,
6761     IN INT YStart,
6762     IN UINT fuOptions,
6763     IN OPTIONAL PRECTL lprc,
6764     IN LPCWSTR String,
6765     IN INT Count,
6766     IN OPTIONAL LPINT Dx,
6767     IN DWORD dwCodePage)
6768 {
6769     /*
6770      * FIXME:
6771      * Call EngTextOut, which does the real work (calling DrvTextOut where
6772      * appropriate)
6773      */
6774 
6775     PDC_ATTR pdcattr;
6776     SURFOBJ *SurfObj, *SourceGlyphSurf;
6777     SURFACE *psurf;
6778     INT glyph_index, i;
6779     FT_Face face;
6780     FT_BitmapGlyph realglyph;
6781     LONGLONG X64, Y64, RealXStart64, RealYStart64, DeltaX64, DeltaY64;
6782     ULONG previous;
6783     RECTL DestRect, MaskRect;
6784     HBITMAP HSourceGlyph;
6785     SIZEL bitSize;
6786     FONTOBJ *FontObj;
6787     PFONTGDI FontGDI;
6788     PTEXTOBJ TextObj = NULL;
6789     EXLATEOBJ exloRGB2Dst, exloDst2RGB;
6790     POINT Start;
6791     PMATRIX pmxWorldToDevice;
6792     FT_Vector delta, vecAscent64, vecDescent64, vec;
6793     LOGFONTW *plf;
6794     BOOL use_kerning, bResult, DoBreak;
6795     FONT_CACHE_ENTRY Cache;
6796     FT_Matrix mat;
6797     BOOL bNoTransform;
6798     DWORD ch0, ch1;
6799     const DWORD del = 0x7f, nbsp = 0xa0; // DEL is ASCII DELETE and nbsp is a non-breaking space
6800     FONTLINK_CHAIN Chain;
6801     SIZE spaceWidth;
6802 
6803     /* Check if String is valid */
6804     if (Count > 0xFFFF || (Count > 0 && String == NULL))
6805     {
6806         EngSetLastError(ERROR_INVALID_PARAMETER);
6807         return FALSE;
6808     }
6809 
6810     if (PATH_IsPathOpen(dc->dclevel))
6811     {
6812         return PATH_ExtTextOut(dc,
6813                                XStart, YStart,
6814                                fuOptions,
6815                                lprc,
6816                                String, Count,
6817                                Dx);
6818     }
6819 
6820     DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
6821 
6822     if (!dc->dclevel.pSurface)
6823     {
6824         /* Memory DC with no surface selected */
6825         bResult = TRUE;
6826         goto Cleanup;
6827     }
6828 
6829     pdcattr = dc->pdcattr;
6830     if (pdcattr->flTextAlign & TA_UPDATECP)
6831     {
6832         Start.x = pdcattr->ptlCurrent.x;
6833         Start.y = pdcattr->ptlCurrent.y;
6834     }
6835     else
6836     {
6837         Start.x = XStart;
6838         Start.y = YStart;
6839     }
6840 
6841     IntLPtoDP(dc, &Start, 1);
6842     RealXStart64 = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
6843     RealYStart64 = ((LONGLONG)Start.y + dc->ptlDCOrig.y) << 6;
6844 
6845     MaskRect.left = 0;
6846     MaskRect.top = 0;
6847 
6848     psurf = dc->dclevel.pSurface;
6849     SurfObj = &psurf->SurfObj;
6850 
6851     if (pdcattr->iGraphicsMode == GM_ADVANCED)
6852         pmxWorldToDevice = DC_pmxWorldToDevice(dc);
6853     else
6854         pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
6855 
6856     if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
6857         DC_vUpdateBackgroundBrush(dc);
6858 
6859     if (lprc && (fuOptions & (ETO_CLIPPED | ETO_OPAQUE)))
6860     {
6861         IntLPtoDP(dc, (POINT*)lprc, 2);
6862         lprc->left   += dc->ptlDCOrig.x;
6863         lprc->top    += dc->ptlDCOrig.y;
6864         lprc->right  += dc->ptlDCOrig.x;
6865         lprc->bottom += dc->ptlDCOrig.y;
6866     }
6867 
6868     if (lprc && (fuOptions & ETO_OPAQUE))
6869     {
6870         IntEngFillBox(dc,
6871                       lprc->left, lprc->top,
6872                       lprc->right - lprc->left, lprc->bottom - lprc->top,
6873                       &dc->eboBackground.BrushObject);
6874         fuOptions &= ~ETO_OPAQUE;
6875     }
6876     else
6877     {
6878         if (pdcattr->jBkMode == OPAQUE)
6879         {
6880             fuOptions |= ETO_OPAQUE;
6881         }
6882     }
6883 
6884     TextObj = RealizeFontInit(pdcattr->hlfntNew);
6885     if (TextObj == NULL)
6886     {
6887         bResult = FALSE;
6888         goto Cleanup;
6889     }
6890 
6891     FontObj = TextObj->Font;
6892     ASSERT(FontObj);
6893     FontGDI = ObjToGDI(FontObj, FONT);
6894     ASSERT(FontGDI);
6895 
6896     IntLockFreeType();
6897     Cache.Hashed.Face = face = FontGDI->SharedFace->Face;
6898 
6899     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
6900     Cache.Hashed.lfHeight = plf->lfHeight;
6901     Cache.Hashed.lfWidth = plf->lfWidth;
6902     Cache.Hashed.Aspect.Emu.Bold = EMUBOLD_NEEDED(FontGDI->OriginalWeight, plf->lfWeight);
6903     Cache.Hashed.Aspect.Emu.Italic = (plf->lfItalic && !FontGDI->OriginalItalic);
6904 
6905     if (IntIsFontRenderingEnabled())
6906         Cache.Hashed.Aspect.RenderMode = (BYTE)IntGetFontRenderMode(plf);
6907     else
6908         Cache.Hashed.Aspect.RenderMode = (BYTE)FT_RENDER_MODE_MONO;
6909 
6910     if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
6911     {
6912         IntUnLockFreeType();
6913         bResult = FALSE;
6914         goto Cleanup;
6915     }
6916 
6917     FontLink_Chain_Init(&Chain, TextObj, face);
6918 
6919     /* Apply lfEscapement */
6920     if (FT_IS_SCALABLE(face) && plf->lfEscapement != 0)
6921         IntEscapeMatrix(&Cache.Hashed.matTransform, plf->lfEscapement);
6922     else
6923         Cache.Hashed.matTransform = identityMat;
6924 
6925     /* Apply the world transformation */
6926     IntMatrixFromMx(&mat, pmxWorldToDevice);
6927     FT_Matrix_Multiply(&mat, &Cache.Hashed.matTransform);
6928     FT_Set_Transform(face, &Cache.Hashed.matTransform, NULL);
6929 
6930     /* Is there no transformation? */
6931     bNoTransform = ((mat.xy == 0) && (mat.yx == 0) &&
6932                     (mat.xx == (1 << 16)) && (mat.yy == (1 << 16)));
6933 
6934     /* Calculate the ascent point and the descent point */
6935     vecAscent64.x = 0;
6936     vecAscent64.y = (FontGDI->tmAscent << 6);
6937     FT_Vector_Transform(&vecAscent64, &Cache.Hashed.matTransform);
6938     vecDescent64.x = 0;
6939     vecDescent64.y = -(FontGDI->tmDescent << 6);
6940     FT_Vector_Transform(&vecDescent64, &Cache.Hashed.matTransform);
6941 
6942     /* Process the vertical alignment and fix the real starting point. */
6943 #define VALIGN_MASK  (TA_TOP | TA_BASELINE | TA_BOTTOM)
6944     if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BASELINE)
6945     {
6946         NOTHING;
6947     }
6948     else if ((pdcattr->flTextAlign & VALIGN_MASK) == TA_BOTTOM)
6949     {
6950         RealXStart64 -= vecDescent64.x;
6951         RealYStart64 += vecDescent64.y;
6952     }
6953     else /* TA_TOP */
6954     {
6955         RealXStart64 -= vecAscent64.x;
6956         RealYStart64 += vecAscent64.y;
6957     }
6958 #undef VALIGN_MASK
6959 
6960     use_kerning = FT_HAS_KERNING(face);
6961 
6962     /* Calculate the text width if necessary */
6963     if ((fuOptions & ETO_OPAQUE) || (pdcattr->flTextAlign & (TA_CENTER | TA_RIGHT)))
6964     {
6965         if (!IntGetTextDisposition(&DeltaX64, &DeltaY64, String, Count, Dx, &Cache,
6966                                    fuOptions, bNoTransform, &Chain))
6967         {
6968             FontLink_Chain_Finish(&Chain);
6969             IntUnLockFreeType();
6970             bResult = FALSE;
6971             goto Cleanup;
6972         }
6973 
6974         /* Adjust the horizontal position by horizontal alignment */
6975         if ((pdcattr->flTextAlign & TA_CENTER) == TA_CENTER)
6976         {
6977             RealXStart64 -= DeltaX64 / 2;
6978             RealYStart64 -= DeltaY64 / 2;
6979         }
6980         else if ((pdcattr->flTextAlign & TA_RIGHT) == TA_RIGHT)
6981         {
6982             RealXStart64 -= DeltaX64;
6983             RealYStart64 -= DeltaY64;
6984         }
6985 
6986         /* Fill background */
6987         if (fuOptions & ETO_OPAQUE)
6988         {
6989             INT X0 = (RealXStart64 + vecAscent64.x + 32) >> 6;
6990             INT Y0 = (RealYStart64 - vecAscent64.y + 32) >> 6;
6991             INT DX = (DeltaX64 >> 6);
6992             if (Cache.Hashed.matTransform.xy == 0 && Cache.Hashed.matTransform.yx == 0)
6993             {
6994                 INT CY = (vecAscent64.y - vecDescent64.y + 32) >> 6;
6995                 IntEngFillBox(dc, X0, Y0, DX, CY, &dc->eboBackground.BrushObject);
6996             }
6997             else
6998             {
6999                 INT DY = (DeltaY64 >> 6);
7000                 INT X1 = ((RealXStart64 + vecDescent64.x + 32) >> 6);
7001                 INT Y1 = ((RealYStart64 - vecDescent64.y + 32) >> 6);
7002                 POINT Points[4] =
7003                 {
7004                     { X0,       Y0      },
7005                     { X0 + DX,  Y0 + DY },
7006                     { X1 + DX,  Y1 + DY },
7007                     { X1,       Y1      },
7008                 };
7009                 IntEngFillPolygon(dc, Points, 4, &dc->eboBackground.BrushObject);
7010             }
7011         }
7012     }
7013 
7014     EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
7015     EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
7016 
7017     if (pdcattr->ulDirty_ & DIRTY_TEXT)
7018         DC_vUpdateTextBrush(dc);
7019 
7020     /*
7021      * The main rendering loop.
7022      */
7023     X64 = RealXStart64;
7024     Y64 = RealYStart64;
7025     previous = 0;
7026     DoBreak = FALSE;
7027     bResult = TRUE; /* Assume success */
7028     for (i = 0; i < Count; ++i)
7029     {
7030         ch0 = *String++;
7031         if (IS_HIGH_SURROGATE(ch0))
7032         {
7033             ++i;
7034             if (i >= Count)
7035                 break;
7036 
7037             ch1 = *String++;
7038             if (IS_LOW_SURROGATE(ch1))
7039                 ch0 = Utf32FromSurrogatePair(ch0, ch1);
7040         }
7041 
7042         glyph_index = FontLink_Chain_FindGlyph(&Chain, &Cache, &face, ch0,
7043                                                (fuOptions & ETO_GLYPH_INDEX));
7044         Cache.Hashed.GlyphIndex = glyph_index;
7045 
7046         realglyph = IntGetRealGlyph(&Cache);
7047         if (!realglyph)
7048         {
7049             bResult = FALSE;
7050             break;
7051         }
7052 
7053         /* retrieve kerning distance and move pen position */
7054         if (use_kerning && previous && glyph_index && NULL == Dx)
7055         {
7056             FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
7057             X64 += delta.x;
7058             Y64 -= delta.y;
7059         }
7060 
7061         DPRINT("X64, Y64: %I64d, %I64d\n", X64, Y64);
7062         DPRINT("Advance: %d, %d\n", realglyph->root.advance.x, realglyph->root.advance.y);
7063 
7064         bitSize.cx = realglyph->bitmap.width;
7065         bitSize.cy = realglyph->bitmap.rows;
7066 
7067         /* Do chars > space & not DEL & not nbsp have a bitSize.cx of zero? */
7068         if (ch0 > L' ' && ch0 != del && ch0 != nbsp && bitSize.cx == 0)
7069             DPRINT1("WARNING: WChar 0x%04x has a bitSize.cx of zero\n", ch0);
7070 
7071         /* Don't ignore spaces or non-breaking spaces when computing offset.
7072          * This completes the fix of CORE-11787. */
7073         if ((pdcattr->flTextAlign & TA_UPDATECP) && bitSize.cx == 0 &&
7074             (ch0 == L' ' || ch0 == nbsp)) // Space chars needing x-dim widths
7075         {
7076             IntUnLockFreeType();
7077             /* Get the width of the space character */
7078             TextIntGetTextExtentPoint(dc, TextObj, L" ", 1, 0, NULL, 0, &spaceWidth, 0);
7079             IntLockFreeType();
7080             bitSize.cx = spaceWidth.cx;
7081             realglyph->left = 0;
7082         }
7083 
7084         MaskRect.right = realglyph->bitmap.width;
7085         MaskRect.bottom = realglyph->bitmap.rows;
7086 
7087         DestRect.left   = ((X64 + 32) >> 6) + realglyph->left;
7088         DestRect.right  = DestRect.left + bitSize.cx;
7089         DestRect.top    = ((Y64 + 32) >> 6) - realglyph->top;
7090         DestRect.bottom = DestRect.top + bitSize.cy;
7091 
7092         /* Check if the bitmap has any pixels */
7093         if ((bitSize.cx != 0) && (bitSize.cy != 0))
7094         {
7095             /*
7096              * We should create the bitmap out of the loop at the biggest possible
7097              * glyph size. Then use memset with 0 to clear it and sourcerect to
7098              * limit the work of the transbitblt.
7099              */
7100             HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
7101                                            BMF_8BPP, BMF_TOPDOWN,
7102                                            realglyph->bitmap.buffer);
7103             if (!HSourceGlyph)
7104             {
7105                 DPRINT1("WARNING: EngCreateBitmap() failed!\n");
7106                 bResult = FALSE;
7107                 break;
7108             }
7109 
7110             SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
7111             if (!SourceGlyphSurf)
7112             {
7113                 EngDeleteSurface((HSURF)HSourceGlyph);
7114                 DPRINT1("WARNING: EngLockSurface() failed!\n");
7115                 bResult = FALSE;
7116                 break;
7117             }
7118 
7119             /*
7120              * Use the font data as a mask to paint onto the DCs surface using a
7121              * brush.
7122              */
7123             if (lprc && (fuOptions & ETO_CLIPPED))
7124             {
7125                 // We do the check '>=' instead of '>' to possibly save an iteration
7126                 // through this loop, since it's breaking after the drawing is done,
7127                 // and x is always incremented.
7128                 if (DestRect.right >= lprc->right)
7129                 {
7130                     DestRect.right = lprc->right;
7131                     DoBreak = TRUE;
7132                 }
7133 
7134                 if (DestRect.bottom >= lprc->bottom)
7135                 {
7136                     DestRect.bottom = lprc->bottom;
7137                 }
7138             }
7139 
7140             if (!IntEngMaskBlt(SurfObj,
7141                                SourceGlyphSurf,
7142                                (CLIPOBJ *)&dc->co,
7143                                &exloRGB2Dst.xlo,
7144                                &exloDst2RGB.xlo,
7145                                &DestRect,
7146                                (PPOINTL)&MaskRect,
7147                                &dc->eboText.BrushObject,
7148                                &PointZero))
7149             {
7150                 DPRINT1("Failed to MaskBlt a glyph!\n");
7151             }
7152 
7153             EngUnlockSurface(SourceGlyphSurf);
7154             EngDeleteSurface((HSURF)HSourceGlyph);
7155         }
7156 
7157         if (DoBreak)
7158             break;
7159 
7160         if (NULL == Dx)
7161         {
7162             X64 += realglyph->root.advance.x >> 10;
7163             Y64 -= realglyph->root.advance.y >> 10;
7164         }
7165         else if (fuOptions & ETO_PDY)
7166         {
7167             vec.x = (Dx[2 * i + 0] << 6);
7168             vec.y = (Dx[2 * i + 1] << 6);
7169             if (!bNoTransform)
7170                 FT_Vector_Transform(&vec, &Cache.Hashed.matTransform);
7171             X64 += vec.x;
7172             Y64 -= vec.y;
7173         }
7174         else
7175         {
7176             vec.x = (Dx[i] << 6);
7177             vec.y = 0;
7178             if (!bNoTransform)
7179                 FT_Vector_Transform(&vec, &Cache.Hashed.matTransform);
7180             X64 += vec.x;
7181             Y64 -= vec.y;
7182         }
7183 
7184         DPRINT("New X64, New Y64: %I64d, %I64d\n", X64, Y64);
7185 
7186         previous = glyph_index;
7187     }
7188     /* Don't update position if String == NULL. Fixes CORE-19721. */
7189     if ((pdcattr->flTextAlign & TA_UPDATECP) && String)
7190         pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
7191 
7192     if (plf->lfUnderline || plf->lfStrikeOut) /* Underline or strike-out? */
7193     {
7194         /* Calculate the position and the thickness */
7195         INT underline_position, thickness;
7196         FT_Vector vecA64, vecB64;
7197 
7198         DeltaX64 = X64 - RealXStart64;
7199         DeltaY64 = Y64 - RealYStart64;
7200 
7201         if (!face->units_per_EM)
7202         {
7203             underline_position = 0;
7204             thickness = 1;
7205         }
7206         else
7207         {
7208             underline_position =
7209                 face->underline_position * face->size->metrics.y_ppem / face->units_per_EM;
7210             thickness =
7211                 face->underline_thickness * face->size->metrics.y_ppem / face->units_per_EM;
7212             if (thickness <= 0)
7213                 thickness = 1;
7214         }
7215 
7216         if (plf->lfUnderline) /* Draw underline */
7217         {
7218             vecA64.x = 0;
7219             vecA64.y = (-underline_position - thickness / 2) << 6;
7220             vecB64.x = 0;
7221             vecB64.y = vecA64.y + (thickness << 6);
7222             FT_Vector_Transform(&vecA64, &Cache.Hashed.matTransform);
7223             FT_Vector_Transform(&vecB64, &Cache.Hashed.matTransform);
7224             {
7225                 INT X0 = (RealXStart64 - vecA64.x + 32) >> 6;
7226                 INT Y0 = (RealYStart64 + vecA64.y + 32) >> 6;
7227                 INT DX = (DeltaX64 >> 6);
7228                 if (Cache.Hashed.matTransform.xy == 0 && Cache.Hashed.matTransform.yx == 0)
7229                 {
7230                     INT CY = (vecB64.y - vecA64.y + 32) >> 6;
7231                     IntEngFillBox(dc, X0, Y0, DX, CY, &dc->eboText.BrushObject);
7232                 }
7233                 else
7234                 {
7235                     INT DY = (DeltaY64 >> 6);
7236                     INT X1 = X0 + ((vecA64.x - vecB64.x + 32) >> 6);
7237                     INT Y1 = Y0 + ((vecB64.y - vecA64.y + 32) >> 6);
7238                     POINT Points[4] =
7239                     {
7240                         { X0,       Y0      },
7241                         { X0 + DX,  Y0 + DY },
7242                         { X1 + DX,  Y1 + DY },
7243                         { X1,       Y1      },
7244                     };
7245                     IntEngFillPolygon(dc, Points, 4, &dc->eboText.BrushObject);
7246                 }
7247             }
7248         }
7249 
7250         if (plf->lfStrikeOut) /* Draw strike-out */
7251         {
7252             vecA64.x = 0;
7253             vecA64.y = -(FontGDI->tmAscent << 6) / 3;
7254             vecB64.x = 0;
7255             vecB64.y = vecA64.y + (thickness << 6);
7256             FT_Vector_Transform(&vecA64, &Cache.Hashed.matTransform);
7257             FT_Vector_Transform(&vecB64, &Cache.Hashed.matTransform);
7258             {
7259                 INT X0 = (RealXStart64 - vecA64.x + 32) >> 6;
7260                 INT Y0 = (RealYStart64 + vecA64.y + 32) >> 6;
7261                 INT DX = (DeltaX64 >> 6);
7262                 if (Cache.Hashed.matTransform.xy == 0 && Cache.Hashed.matTransform.yx == 0)
7263                 {
7264                     INT CY = (vecB64.y - vecA64.y + 32) >> 6;
7265                     IntEngFillBox(dc, X0, Y0, DX, CY, &dc->eboText.BrushObject);
7266                 }
7267                 else
7268                 {
7269                     INT DY = (DeltaY64 >> 6);
7270                     INT X1 = X0 + ((vecA64.x - vecB64.x + 32) >> 6);
7271                     INT Y1 = Y0 + ((vecB64.y - vecA64.y + 32) >> 6);
7272                     POINT Points[4] =
7273                     {
7274                         { X0,       Y0      },
7275                         { X0 + DX,  Y0 + DY },
7276                         { X1 + DX,  Y1 + DY },
7277                         { X1,       Y1      },
7278                     };
7279                     IntEngFillPolygon(dc, Points, 4, &dc->eboText.BrushObject);
7280                 }
7281             }
7282         }
7283     }
7284 
7285     FontLink_Chain_Finish(&Chain);
7286 
7287     IntUnLockFreeType();
7288 
7289     EXLATEOBJ_vCleanup(&exloRGB2Dst);
7290     EXLATEOBJ_vCleanup(&exloDst2RGB);
7291 
7292 Cleanup:
7293     DC_vFinishBlit(dc, NULL);
7294 
7295     if (TextObj != NULL)
7296         TEXTOBJ_UnlockText(TextObj);
7297 
7298     return bResult;
7299 }
7300 
7301 
7302 BOOL
7303 APIENTRY
GreExtTextOutW(IN HDC hDC,IN INT XStart,IN INT YStart,IN UINT fuOptions,IN OPTIONAL PRECTL lprc,IN LPCWSTR String,IN INT Count,IN OPTIONAL LPINT Dx,IN DWORD dwCodePage)7304 GreExtTextOutW(
7305     IN HDC hDC,
7306     IN INT XStart,
7307     IN INT YStart,
7308     IN UINT fuOptions,
7309     IN OPTIONAL PRECTL lprc,
7310     IN LPCWSTR String,
7311     IN INT Count,
7312     IN OPTIONAL LPINT Dx,
7313     IN DWORD dwCodePage)
7314 {
7315     BOOL bResult;
7316     DC *dc;
7317 
7318     // TODO: Write test-cases to exactly match real Windows in different
7319     // bad parameters (e.g. does Windows check the DC or the RECT first?).
7320     dc = DC_LockDc(hDC);
7321     if (!dc)
7322     {
7323         EngSetLastError(ERROR_INVALID_HANDLE);
7324         return FALSE;
7325     }
7326 
7327     bResult = IntExtTextOutW( dc,
7328                               XStart,
7329                               YStart,
7330                               fuOptions,
7331                               lprc,
7332                               String,
7333                               Count,
7334                               Dx,
7335                               dwCodePage );
7336 
7337     DC_UnlockDc(dc);
7338 
7339     return bResult;
7340 }
7341 
7342 #define STACK_TEXT_BUFFER_SIZE 512
7343 
7344 BOOL
7345 APIENTRY
NtGdiExtTextOutW(IN HDC hDC,IN INT XStart,IN INT YStart,IN UINT fuOptions,IN OPTIONAL LPRECT UnsafeRect,IN LPWSTR UnsafeString,IN INT Count,IN OPTIONAL LPINT UnsafeDx,IN DWORD dwCodePage)7346 NtGdiExtTextOutW(
7347     IN HDC hDC,
7348     IN INT XStart,
7349     IN INT YStart,
7350     IN UINT fuOptions,
7351     IN OPTIONAL LPRECT UnsafeRect,
7352     IN LPWSTR UnsafeString,
7353     IN INT Count,
7354     IN OPTIONAL LPINT UnsafeDx,
7355     IN DWORD dwCodePage)
7356 {
7357     BOOL Result = FALSE;
7358     NTSTATUS Status = STATUS_SUCCESS;
7359     RECTL SafeRect;
7360     BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
7361     PVOID Buffer = LocalBuffer;
7362     LPCWSTR SafeString = NULL;
7363     LPINT SafeDx = NULL;
7364     ULONG BufSize, StringSize, DxSize = 0;
7365 
7366     /* Check if String is valid */
7367     if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
7368     {
7369         EngSetLastError(ERROR_INVALID_PARAMETER);
7370         return FALSE;
7371     }
7372 
7373     if (Count > 0)
7374     {
7375         /* Calculate buffer size for string and Dx values */
7376         BufSize = StringSize = Count * sizeof(WCHAR);
7377         if (UnsafeDx)
7378         {
7379             /* If ETO_PDY is specified, we have pairs of INTs */
7380             DxSize = (Count * sizeof(INT)) * ((fuOptions & ETO_PDY) ? 2 : 1);
7381             BufSize += DxSize;
7382         }
7383 
7384         /* Check if our local buffer is large enough */
7385         if (BufSize > sizeof(LocalBuffer))
7386         {
7387             /* It's not, allocate a temp buffer */
7388             Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, GDITAG_TEXT);
7389             if (!Buffer)
7390             {
7391                 return FALSE;
7392             }
7393         }
7394 
7395         /* Probe and copy user mode data to the buffer */
7396         _SEH2_TRY
7397         {
7398             /* Put the Dx before the String to assure alignment of 4 */
7399             SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
7400 
7401             /* Probe and copy the string */
7402             ProbeForRead(UnsafeString, StringSize, 1);
7403             RtlCopyMemory((PVOID)SafeString, UnsafeString, StringSize);
7404 
7405             /* If we have Dx values... */
7406             if (UnsafeDx)
7407             {
7408                 /* ... probe and copy them */
7409                 SafeDx = Buffer;
7410                 ProbeForRead(UnsafeDx, DxSize, 1);
7411                 RtlCopyMemory(SafeDx, UnsafeDx, DxSize);
7412             }
7413         }
7414         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7415         {
7416             Status = _SEH2_GetExceptionCode();
7417         }
7418         _SEH2_END
7419         if (!NT_SUCCESS(Status))
7420         {
7421             goto cleanup;
7422         }
7423     }
7424 
7425     /* If we have a rect, copy it */
7426     if (UnsafeRect)
7427     {
7428         _SEH2_TRY
7429         {
7430             ProbeForRead(UnsafeRect, sizeof(RECT), 1);
7431             SafeRect = *UnsafeRect;
7432         }
7433         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7434         {
7435             Status = _SEH2_GetExceptionCode();
7436         }
7437         _SEH2_END
7438         if (!NT_SUCCESS(Status))
7439         {
7440             goto cleanup;
7441         }
7442     }
7443 
7444     /* Finally call the internal routine */
7445     Result = GreExtTextOutW(hDC,
7446                             XStart,
7447                             YStart,
7448                             fuOptions,
7449                             &SafeRect,
7450                             SafeString,
7451                             Count,
7452                             SafeDx,
7453                             dwCodePage);
7454 
7455 cleanup:
7456     /* If we allocated a buffer, free it */
7457     if (Buffer != LocalBuffer)
7458     {
7459         ExFreePoolWithTag(Buffer, GDITAG_TEXT);
7460     }
7461 
7462     return Result;
7463 }
7464 
7465 
7466 /*
7467 * @implemented
7468 */
7469 BOOL
7470 APIENTRY
NtGdiGetCharABCWidthsW(IN HDC hDC,IN UINT FirstChar,IN ULONG Count,IN OPTIONAL PWCHAR UnSafepwch,IN FLONG fl,OUT PVOID Buffer)7471 NtGdiGetCharABCWidthsW(
7472     IN HDC hDC,
7473     IN UINT FirstChar,
7474     IN ULONG Count,
7475     IN OPTIONAL PWCHAR UnSafepwch,
7476     IN FLONG fl,
7477     OUT PVOID Buffer)
7478 {
7479     LPABC SafeBuff;
7480     LPABCFLOAT SafeBuffF = NULL;
7481     PDC dc;
7482     PDC_ATTR pdcattr;
7483     PTEXTOBJ TextObj;
7484     PFONTGDI FontGDI;
7485     FT_Face face;
7486     FT_CharMap charmap, found = NULL;
7487     UINT i, glyph_index, BufferSize;
7488     HFONT hFont = 0;
7489     NTSTATUS Status = STATUS_SUCCESS;
7490     PWCHAR Safepwch = NULL;
7491     LOGFONTW *plf;
7492 
7493     if (!Buffer)
7494     {
7495         EngSetLastError(ERROR_INVALID_PARAMETER);
7496         return FALSE;
7497     }
7498 
7499     if (UnSafepwch)
7500     {
7501         UINT pwchSize = Count * sizeof(WCHAR);
7502         Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
7503 
7504         if(!Safepwch)
7505         {
7506             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7507             return FALSE;
7508         }
7509 
7510         _SEH2_TRY
7511         {
7512             ProbeForRead(UnSafepwch, pwchSize, 1);
7513             RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
7514         }
7515         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7516         {
7517             Status = _SEH2_GetExceptionCode();
7518         }
7519         _SEH2_END;
7520     }
7521 
7522     if (!NT_SUCCESS(Status))
7523     {
7524         if(Safepwch)
7525             ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7526 
7527         EngSetLastError(Status);
7528         return FALSE;
7529     }
7530 
7531     BufferSize = Count * sizeof(ABC); // Same size!
7532     SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
7533     if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
7534     if (SafeBuff == NULL)
7535     {
7536 
7537         if(Safepwch)
7538             ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7539 
7540         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7541         return FALSE;
7542     }
7543 
7544     dc = DC_LockDc(hDC);
7545     if (dc == NULL)
7546     {
7547         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7548 
7549         if(Safepwch)
7550             ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7551 
7552         EngSetLastError(ERROR_INVALID_HANDLE);
7553         return FALSE;
7554     }
7555     pdcattr = dc->pdcattr;
7556     hFont = pdcattr->hlfntNew;
7557     TextObj = RealizeFontInit(hFont);
7558 
7559     DC_UnlockDc(dc);
7560 
7561     if (TextObj == NULL)
7562     {
7563         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7564 
7565         if(Safepwch)
7566             ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7567 
7568         EngSetLastError(ERROR_INVALID_HANDLE);
7569         return FALSE;
7570     }
7571 
7572     FontGDI = ObjToGDI(TextObj->Font, FONT);
7573 
7574     face = FontGDI->SharedFace->Face;
7575     if (face->charmap == NULL)
7576     {
7577         for (i = 0; i < (UINT)face->num_charmaps; i++)
7578         {
7579             charmap = face->charmaps[i];
7580             if (charmap->encoding != 0)
7581             {
7582                 found = charmap;
7583                 break;
7584             }
7585         }
7586 
7587         if (!found)
7588         {
7589             DPRINT1("WARNING: Could not find desired charmap!\n");
7590             ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7591 
7592             if(Safepwch)
7593                 ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7594 
7595             EngSetLastError(ERROR_INVALID_HANDLE);
7596             return FALSE;
7597         }
7598 
7599         IntLockFreeType();
7600         FT_Set_Charmap(face, found);
7601         IntUnLockFreeType();
7602     }
7603 
7604     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
7605 
7606     // NOTE: GetCharABCWidths simply ignores lfEscapement and XFORM.
7607     IntLockFreeType();
7608     IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
7609     FT_Set_Transform(face, NULL, NULL);
7610 
7611     for (i = FirstChar; i < FirstChar+Count; i++)
7612     {
7613         int adv, lsb, bbx, left, right;
7614 
7615         if (Safepwch)
7616         {
7617             glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], (fl & GCABCW_INDICES));
7618         }
7619         else
7620         {
7621             glyph_index = get_glyph_index_flagged(face, i, (fl & GCABCW_INDICES));
7622         }
7623         FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
7624 
7625         left = (INT)face->glyph->metrics.horiBearingX  & -64;
7626         right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
7627         adv  = (face->glyph->advance.x + 32) >> 6;
7628 
7629 //      int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
7630 //      DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same! */
7631 
7632         lsb = left >> 6;
7633         bbx = (right - left) >> 6;
7634         /*
7635               DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
7636          */
7637         if (!fl)
7638         {
7639             SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
7640             SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
7641             SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
7642         }
7643         else
7644         {
7645             SafeBuff[i - FirstChar].abcA = lsb;
7646             SafeBuff[i - FirstChar].abcB = bbx;
7647             SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
7648         }
7649     }
7650     IntUnLockFreeType();
7651     TEXTOBJ_UnlockText(TextObj);
7652     Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
7653 
7654     ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7655 
7656     if(Safepwch)
7657         ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
7658 
7659     if (!NT_SUCCESS(Status))
7660     {
7661         SetLastNtError(Status);
7662         return FALSE;
7663     }
7664 
7665     DPRINT("NtGdiGetCharABCWidths Worked!\n");
7666     return TRUE;
7667 }
7668 
7669 /*
7670 * @implemented
7671 */
7672 BOOL
7673 APIENTRY
NtGdiGetCharWidthW(IN HDC hDC,IN UINT FirstChar,IN UINT Count,IN OPTIONAL PWCHAR UnSafepwc,IN FLONG fl,OUT PVOID Buffer)7674 NtGdiGetCharWidthW(
7675     IN HDC hDC,
7676     IN UINT FirstChar,
7677     IN UINT Count,
7678     IN OPTIONAL PWCHAR UnSafepwc,
7679     IN FLONG fl,
7680     OUT PVOID Buffer)
7681 {
7682     NTSTATUS Status = STATUS_SUCCESS;
7683     LPINT SafeBuff;
7684     PFLOAT SafeBuffF = NULL;
7685     PDC dc;
7686     PDC_ATTR pdcattr;
7687     PTEXTOBJ TextObj;
7688     PFONTGDI FontGDI;
7689     FT_Face face;
7690     FT_CharMap charmap, found = NULL;
7691     UINT i, glyph_index, BufferSize;
7692     HFONT hFont = 0;
7693     PWCHAR Safepwc = NULL;
7694     LOGFONTW *plf;
7695 
7696     if (UnSafepwc)
7697     {
7698         UINT pwcSize = Count * sizeof(WCHAR);
7699         Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
7700 
7701         if(!Safepwc)
7702         {
7703             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7704             return FALSE;
7705         }
7706         _SEH2_TRY
7707         {
7708             ProbeForRead(UnSafepwc, pwcSize, 1);
7709             RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
7710         }
7711         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7712         {
7713             Status = _SEH2_GetExceptionCode();
7714         }
7715         _SEH2_END;
7716     }
7717 
7718     if (!NT_SUCCESS(Status))
7719     {
7720         EngSetLastError(Status);
7721         return FALSE;
7722     }
7723 
7724     BufferSize = Count * sizeof(INT); // Same size!
7725     SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, GDITAG_TEXT);
7726     if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
7727     if (SafeBuff == NULL)
7728     {
7729         if(Safepwc)
7730             ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7731 
7732         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
7733         return FALSE;
7734     }
7735 
7736     dc = DC_LockDc(hDC);
7737     if (dc == NULL)
7738     {
7739         if(Safepwc)
7740             ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7741 
7742         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7743         EngSetLastError(ERROR_INVALID_HANDLE);
7744         return FALSE;
7745     }
7746     pdcattr = dc->pdcattr;
7747     hFont = pdcattr->hlfntNew;
7748     TextObj = RealizeFontInit(hFont);
7749     DC_UnlockDc(dc);
7750 
7751     if (TextObj == NULL)
7752     {
7753         if(Safepwc)
7754             ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7755 
7756         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7757         EngSetLastError(ERROR_INVALID_HANDLE);
7758         return FALSE;
7759     }
7760 
7761     FontGDI = ObjToGDI(TextObj->Font, FONT);
7762 
7763     face = FontGDI->SharedFace->Face;
7764     if (face->charmap == NULL)
7765     {
7766         for (i = 0; i < (UINT)face->num_charmaps; i++)
7767         {
7768             charmap = face->charmaps[i];
7769             if (charmap->encoding != 0)
7770             {
7771                 found = charmap;
7772                 break;
7773             }
7774         }
7775 
7776         if (!found)
7777         {
7778             DPRINT1("WARNING: Could not find desired charmap!\n");
7779 
7780             if(Safepwc)
7781                 ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7782 
7783             ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7784             EngSetLastError(ERROR_INVALID_HANDLE);
7785             return FALSE;
7786         }
7787 
7788         IntLockFreeType();
7789         FT_Set_Charmap(face, found);
7790         IntUnLockFreeType();
7791     }
7792 
7793     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
7794 
7795     // NOTE: GetCharWidth simply ignores lfEscapement and XFORM.
7796     IntLockFreeType();
7797     IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
7798     FT_Set_Transform(face, NULL, NULL);
7799 
7800     for (i = FirstChar; i < FirstChar+Count; i++)
7801     {
7802         if (Safepwc)
7803         {
7804             glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], (fl & GCW_INDICES));
7805         }
7806         else
7807         {
7808             glyph_index = get_glyph_index_flagged(face, i, (fl & GCW_INDICES));
7809         }
7810         FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
7811         if (!fl)
7812             SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
7813         else
7814             SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
7815     }
7816     IntUnLockFreeType();
7817     TEXTOBJ_UnlockText(TextObj);
7818     MmCopyToCaller(Buffer, SafeBuff, BufferSize);
7819 
7820     if(Safepwc)
7821         ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
7822 
7823     ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
7824     return TRUE;
7825 }
7826 
7827 
7828 /*
7829 * @implemented
7830 */
7831 // TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
7832 // NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
7833 // NOTE: See also GreGetGlyphIndicesW.
7834 __kernel_entry
7835 W32KAPI
7836 DWORD
7837 APIENTRY
NtGdiGetGlyphIndicesW(_In_ HDC hdc,_In_reads_opt_ (cwc)LPCWSTR pwc,_In_ INT cwc,_Out_writes_opt_ (cwc)LPWORD pgi,_In_ DWORD iMode)7838 NtGdiGetGlyphIndicesW(
7839     _In_ HDC hdc,
7840     _In_reads_opt_(cwc) LPCWSTR pwc,
7841     _In_ INT cwc,
7842     _Out_writes_opt_(cwc) LPWORD pgi,
7843     _In_ DWORD iMode)
7844 {
7845     PDC dc;
7846     PDC_ATTR pdcattr;
7847     PTEXTOBJ TextObj;
7848     PFONTGDI FontGDI;
7849     HFONT hFont = NULL;
7850     NTSTATUS Status = STATUS_SUCCESS;
7851     OUTLINETEXTMETRICW *potm;
7852     INT i;
7853     WCHAR DefChar = 0xffff;
7854     PWSTR Buffer = NULL;
7855     ULONG Size, pwcSize;
7856     PWSTR Safepwc = NULL;
7857     LPCWSTR UnSafepwc = pwc;
7858     LPWORD UnSafepgi = pgi;
7859     FT_Face Face;
7860     TT_OS2 *pOS2;
7861 
7862     if (cwc < 0)
7863     {
7864         DPRINT1("cwc < 0\n");
7865         return GDI_ERROR;
7866     }
7867 
7868     if (!UnSafepwc && !UnSafepgi && cwc > 0)
7869     {
7870         DPRINT1("!UnSafepwc && !UnSafepgi && cwc > 0\n");
7871         return GDI_ERROR;
7872     }
7873 
7874     if (!UnSafepwc != !UnSafepgi)
7875     {
7876         DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
7877         return GDI_ERROR;
7878     }
7879 
7880     /* Get FontGDI */
7881     dc = DC_LockDc(hdc);
7882     if (!dc)
7883     {
7884         DPRINT1("!DC_LockDC\n");
7885         return GDI_ERROR;
7886     }
7887     pdcattr = dc->pdcattr;
7888     hFont = pdcattr->hlfntNew;
7889     TextObj = RealizeFontInit(hFont);
7890     DC_UnlockDc(dc);
7891     if (!TextObj)
7892     {
7893         DPRINT1("!TextObj\n");
7894         return GDI_ERROR;
7895     }
7896     FontGDI = ObjToGDI(TextObj->Font, FONT);
7897     TEXTOBJ_UnlockText(TextObj);
7898 
7899     if (cwc == 0)
7900     {
7901         if (!UnSafepwc && !UnSafepgi)
7902         {
7903             Face = FontGDI->SharedFace->Face;
7904             return Face->num_glyphs;
7905         }
7906         else
7907         {
7908             Status = STATUS_UNSUCCESSFUL;
7909             goto ErrorRet;
7910         }
7911     }
7912 
7913     Buffer = ExAllocatePoolWithTag(PagedPool, cwc * sizeof(WORD), GDITAG_TEXT);
7914     if (!Buffer)
7915     {
7916         DPRINT1("ExAllocatePoolWithTag\n");
7917         return GDI_ERROR;
7918     }
7919 
7920     /* Get DefChar */
7921     if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
7922     {
7923         DefChar = 0xffff;
7924     }
7925     else
7926     {
7927         Face = FontGDI->SharedFace->Face;
7928         if (FT_IS_SFNT(Face))
7929         {
7930             IntLockFreeType();
7931             pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
7932             DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
7933             IntUnLockFreeType();
7934         }
7935         else
7936         {
7937             ASSERT_FREETYPE_LOCK_NOT_HELD();
7938             Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL, FALSE);
7939             if (!Size)
7940             {
7941                 Status = STATUS_UNSUCCESSFUL;
7942                 DPRINT1("!Size\n");
7943                 goto ErrorRet;
7944             }
7945             potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
7946             if (!potm)
7947             {
7948                 Status = STATUS_INSUFFICIENT_RESOURCES;
7949                 DPRINT1("!potm\n");
7950                 goto ErrorRet;
7951             }
7952             ASSERT_FREETYPE_LOCK_NOT_HELD();
7953             Size = IntGetOutlineTextMetrics(FontGDI, Size, potm, FALSE);
7954             if (Size)
7955                 DefChar = potm->otmTextMetrics.tmDefaultChar;
7956             ExFreePoolWithTag(potm, GDITAG_TEXT);
7957         }
7958     }
7959 
7960     /* Allocate for Safepwc */
7961     pwcSize = cwc * sizeof(WCHAR);
7962     Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
7963     if (!Safepwc)
7964     {
7965         Status = STATUS_NO_MEMORY;
7966         DPRINT1("!Safepwc\n");
7967         goto ErrorRet;
7968     }
7969 
7970     _SEH2_TRY
7971     {
7972         ProbeForRead(UnSafepwc, pwcSize, 1);
7973         RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
7974     }
7975     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
7976     {
7977         Status = _SEH2_GetExceptionCode();
7978     }
7979     _SEH2_END;
7980 
7981     if (!NT_SUCCESS(Status))
7982     {
7983         DPRINT1("Status: %08lX\n", Status);
7984         goto ErrorRet;
7985     }
7986 
7987     /* Get glyph indeces */
7988     IntLockFreeType();
7989     for (i = 0; i < cwc; i++)
7990     {
7991         Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
7992         if (Buffer[i] == 0)
7993         {
7994             Buffer[i] = DefChar;
7995         }
7996     }
7997     IntUnLockFreeType();
7998 
7999     _SEH2_TRY
8000     {
8001         ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
8002         RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
8003     }
8004     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8005     {
8006         Status = _SEH2_GetExceptionCode();
8007     }
8008     _SEH2_END;
8009 
8010 ErrorRet:
8011     if (Buffer != NULL)
8012     {
8013         ExFreePoolWithTag(Buffer, GDITAG_TEXT);
8014     }
8015     if (Safepwc != NULL)
8016     {
8017         ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
8018     }
8019 
8020     if (NT_SUCCESS(Status))
8021         return cwc;
8022 
8023     return GDI_ERROR;
8024 }
8025 
8026 /* EOF */
8027