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