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