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