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